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

Issue:
Problem inputs cannot have shape_by_conn=True
**Describe the bug**
If a problem has an input with variable shape, the problem cannot be run.

**To Reproduce**
With files in this [archive](https://github.com/fast-aircraft-design/FAST-OAD/files/6695352/bug_shape_by_conn.zip) (reproduced below), the command line `fastoad eval conf.yml` crashes.

-   file **`model.py`**
    ```python
    import openmdao.api as om
    import fastoad.api as oad
    
    
    @oad.RegisterOpenMDAOSystem("custom.foo")
    class Foo(om.ExplicitComponent):
        def setup(self):
            self.add_input("foo", shape_by_conn=True)
            self.add_output("bar")
    
        def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
            outputs["bar"] = 1.0
    ```

-   file **`conf.yml`**
    ```yaml
    module_folders: modules
    
    input_file: ./problem_inputs.xml
    output_file: ./problem_outputs.xml
    
    model:
      foo:
        id: "custom.foo"
    ```

-   file **`problem_inputs.xml`**
    ```xml
    <FASTOAD_model>
        <foo>[1.0, 2.0]</foo>
    </FASTOAD_model>
    ```

**Expected behavior**
The defined problem has an input with undefined shape, but this shape could be retrieved from the provided XML file.

**Error message**
```
$ fastoad eval conf.yml 
INFO    : Loading bundles from ****/modules
INFO    : Installed bundle modules.model (ID 178 )
INFO    : Installed bundle modules (ID 177 )
Traceback (most recent call last):
  File "****/.venv/bin/fastoad", line 8, in <module>
    sys.exit(main())
  File "****/.venv/lib/python3.9/site-packages/fastoad/cmd/fast.py", line 394, in main
    Main().run()
  File "****/.venv/lib/python3.9/site-packages/fastoad/cmd/fast.py", line 370, in run
    args.func(args)
  File "****/.venv/lib/python3.9/site-packages/fastoad/cmd/fast.py", line 132, in _evaluate
    api.evaluate_problem(args.conf_file, args.force)
  File "****/.venv/lib/python3.9/site-packages/fastoad/cmd/api.py", line 471, in evaluate_problem
    return _run_problem(configuration_file_path, overwrite, "run_model")
  File "****/.venv/lib/python3.9/site-packages/fastoad/cmd/api.py", line 432, in _run_problem
    problem = conf.get_problem(read_inputs=True, auto_scaling=auto_scaling)
  File "****/.venv/lib/python3.9/site-packages/fastoad/io/configuration/configuration.py", line 119, in get_problem
    problem_with_no_inputs.setup()
  File "****/.venv/lib/python3.9/site-packages/openmdao/core/problem.py", line 915, in setup
    model._setup(model_comm, mode, self._metadata)
  File "****/.venv/lib/python3.9/site-packages/openmdao/core/system.py", line 789, in _setup
    self._setup_dynamic_shapes()
  File "****/.venv/lib/python3.9/site-packages/openmdao/core/group.py", line 1716, in _setup_dynamic_shapes
    raise RuntimeError(f"{self.msginfo}: 'shape_by_conn' was set for "
RuntimeError: <model> <class AutoUnitsDefaultGroup>: 'shape_by_conn' was set for unconnected variable 'foo.foo'.
(.venv) TofiMac:bug_shape_by_conn tof$ 

```
**Environment**
- Operating System: macOS 11.4
- Python environment: 3.8.10
- Packages: FAST-OAD 1.0.1, OpenMDAO 3.9.2

Issue 357 - Problem inputs cannot have shape_by_conn=True
This PR initiated the changes needed to use shape_by_conn parameters to be extracted from the input .xml file.

The basic idea is to make a partial setup of the problem (problem.setup() fail and return Runtime error but part of the metadata is available except keys: value/shape/size) to know which inputs are given in the .xml file, add them as IVC and retry a setup if needed.

This is just a proposal that seems to work for FASTGA OAD process, feel free to adapt it and correct.


Discussion / hints:

Fix patch:
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 13f9d95c5..4a6b9ef7a 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -12,10 +12,10 @@ backcall==0.2.0; python_full_version >= "3.6.2" and python_version >= "3.7"
 backports.entry-points-selectable==1.1.0; python_version >= "2.7" and python_full_version >= "3.6.1"
 black==21.9b0; python_full_version >= "3.6.2"
 bleach==4.1.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
-certifi==2021.10.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
+certifi==2021.10.8; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7"
 cffi==1.15.0; implementation_name == "pypy" and python_version >= "3.6"
 cfgv==3.3.1; python_full_version >= "3.6.1"
-charset-normalizer==2.0.7; python_full_version >= "3.6.0" and python_version >= "3.6"
+charset-normalizer==2.0.7; python_full_version >= "3.6.0" and python_version >= "3.7"
 click==8.0.3; python_version >= "3.6"
 colorama==0.4.4; platform_system == "Windows" and python_version >= "3.7" and python_full_version >= "3.6.2" and sys_platform == "win32" and python_version < "4.0" and (python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.6" and python_full_version >= "3.5.0") and (python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6") or sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6") and python_full_version >= "3.5.0")
 coverage==5.5; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0" and python_version < "4")
@@ -31,7 +31,7 @@ entrypoints==0.3; python_version >= "3.6" and python_full_version < "3.0.0" or p
 filelock==3.3.0; python_version >= "3.6" and python_full_version >= "3.6.1"
 flake8==4.0.1; python_version >= "3.6"
 identify==2.3.0; python_full_version >= "3.6.1"
-idna==3.3; python_full_version >= "3.6.2" and python_version >= "3.6"
+idna==3.3; python_full_version >= "3.6.2" and python_version >= "3.7"
 imagesize==1.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
 importlib-metadata==4.2.0; python_version == "3.7" and python_full_version >= "3.6.2" or python_version < "3.10"
 iniconfig==1.1.1; python_version >= "3.6"
@@ -70,8 +70,8 @@ networkx==2.6.3; python_version >= "3.7"
 nodeenv==1.6.0; python_full_version >= "3.6.1"
 notebook==6.0.0; python_version >= "3.5"
 numpy==1.19.3; python_version >= "3.6"
+openmdao @ git+https://github.com/OpenMDAO/OpenMDAO.git@master ; python_version >= "3.7"
 openmdao-extensions==1.0.2; python_version >= "3.6"
-openmdao==3.10.0; python_version >= "3.6"
 packaging==21.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
 pandas==1.2.1; python_full_version >= "3.7.1"
 pandocfilters==1.5.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
@@ -92,7 +92,7 @@ pybtex-docutils==1.0.1; python_version >= "3.6"
 pybtex==0.24.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
 pycodestyle==2.8.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
 pycparser==2.20; python_version >= "3.6" and python_full_version < "3.0.0" and implementation_name == "pypy" or implementation_name == "pypy" and python_version >= "3.6" and python_full_version >= "3.4.0"
-pydoe2==1.3.0; python_version >= "3.6"
+pydoe2==1.3.0; python_version >= "3.7"
 pyflakes==2.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
 pygments==2.10.0; python_full_version >= "3.6.2" and python_version >= "3.7" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6")
 pylint==2.11.1; python_version >= "3.6" and python_version < "4.0"
@@ -108,7 +108,7 @@ pyyaml==6.0; python_version >= "3.6" and python_full_version >= "3.6.1" and (pyt
 pyzmq==22.3.0; python_version >= "3.7"
 regex==2021.10.8; python_full_version >= "3.6.2"
 requests-unixsocket==0.2.0; python_version >= "3.6"
-requests==2.26.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
+requests==2.26.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7"
 ruamel.yaml.clib==0.2.6; platform_python_implementation == "CPython" and python_version < "3.8" and python_version >= "3.5"
 ruamel.yaml==0.16.0
 scipy==1.5.4; python_version >= "3.6"
@@ -138,7 +138,7 @@ tornado==6.1; python_version >= "3.7"
 traitlets==5.1.0; python_full_version >= "3.6.2" and python_version >= "3.7" and (python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7")
 typed-ast==1.4.3; python_version < "3.8" and python_full_version >= "3.6.2" and implementation_name == "cpython" and python_version >= "3.6"
 typing-extensions==3.10.0.2
-urllib3==1.26.7; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.6"
+urllib3==1.26.7; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.7"
 virtualenv==20.8.1; python_full_version >= "3.6.1"
 wcwidth==0.2.5; python_full_version >= "3.6.2" and python_version >= "3.7"
 webencodings==0.5.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
diff --git a/poetry.lock b/poetry.lock
index d01858003..a67c21b3f 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -945,11 +945,12 @@ python-versions = ">=3.6"
 
 [[package]]
 name = "openmdao"
-version = "3.10.0"
+version = "3.16.1.dev0"
 description = "OpenMDAO framework infrastructure"
 category = "main"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
+develop = false
 
 [package.dependencies]
 networkx = ">=2.0"
@@ -960,12 +961,18 @@ requests = "*"
 scipy = "*"
 
 [package.extras]
-all = ["aiounittest", "bokeh (>=1.3.4)", "colorama", "ipyparallel", "ipython", "jupyter", "jupyter-book", "jupyter-sphinx (==0.3.1)", "matplotlib", "nbconvert", "notebook", "numpydoc (>=0.9.1)", "numpydoc (>=0.9.1)", "parameterized", "pycodestyle (>=2.4.0)", "pydocstyle (==2.0.0)", "pyppeteer", "sphinx-sitemap", "tabulate", "tabulate", "testflo", "testflo (>=1.3.6websockets)"]
-docs = ["matplotlib", "jupyter", "nbconvert", "testflo", "ipyparallel", "numpydoc (>=0.9.1)", "tabulate", "jupyter-book", "jupyter-sphinx (==0.3.1)", "sphinx-sitemap"]
+all = ["aiounittest", "bokeh (>=1.3.4)", "colorama", "ipyparallel (<7)", "ipython", "jupyter", "jupyter-book", "jupyter-sphinx (==0.3.1)", "matplotlib", "nbconvert", "notebook", "numpydoc (>=1.1)", "parameterized", "playwright (<1.15)", "pycodestyle (>=2.4.0)", "pydocstyle (==2.0.0)", "sphinx-sitemap", "tabulate", "testflo", "testflo (>=1.3.6websockets)"]
+docs = ["matplotlib", "jupyter", "nbconvert", "testflo", "ipyparallel (<7)", "numpydoc (>=1.1)", "tabulate", "jupyter-book", "jupyter-sphinx (==0.3.1)", "sphinx-sitemap"]
 notebooks = ["notebook", "tabulate", "ipython"]
-test = ["parameterized", "numpydoc (>=0.9.1)", "pycodestyle (>=2.4.0)", "pydocstyle (==2.0.0)", "testflo (>=1.3.6websockets)", "pyppeteer", "aiounittest"]
+test = ["parameterized", "numpydoc (>=1.1)", "pycodestyle (>=2.4.0)", "pydocstyle (==2.0.0)", "testflo (>=1.3.6websockets)", "aiounittest", "playwright (<1.15)"]
 visualization = ["bokeh (>=1.3.4)", "colorama"]
 
+[package.source]
+type = "git"
+url = "https://github.com/OpenMDAO/OpenMDAO.git"
+reference = "master"
+resolved_reference = "b0b8c3d1ca0ddbc3ff11c8c581127b3fc4a0efc7"
+
 [[package]]
 name = "openmdao-extensions"
 version = "1.0.2"
@@ -1838,7 +1845,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.7"
-content-hash = "f0fe476f8faca863555f8408791b8c64be2d094df6126d3eb58d8789ef698bd5"
+content-hash = "655141a0c38647f1dddc70fa7c1e7d6e281fd173b83a6ae24c58bfa5e6f53267"
 
 [metadata.files]
 aenum = [
@@ -2321,12 +2328,28 @@ lxml = [
     {file = "lxml-4.6.5.tar.gz", hash = "sha256:6e84edecc3a82f90d44ddee2ee2a2630d4994b8471816e226d2b771cda7ac4ca"},
 ]
 markupsafe = [
+    {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"},
+    {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"},
+    {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"},
+    {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"},
+    {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"},
+    {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"},
+    {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"},
+    {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"},
+    {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"},
+    {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"},
     {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
     {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"},
     {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"},
     {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"},
     {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"},
     {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"},
     {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"},
     {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"},
     {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"},
@@ -2335,14 +2358,27 @@ markupsafe = [
     {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"},
     {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"},
     {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"},
     {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"},
     {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"},
     {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"},
     {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"},
     {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"},
     {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"},
     {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"},
     {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"},
     {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"},
     {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"},
     {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"},
@@ -2352,6 +2388,12 @@ markupsafe = [
     {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"},
     {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"},
     {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"},
     {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"},
     {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"},
     {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
@@ -2457,9 +2499,7 @@ numpy = [
     {file = "numpy-1.19.3-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:9a0669787ba8c9d3bb5de5d9429208882fb47764aa79123af25c5edc4f5966b9"},
     {file = "numpy-1.19.3.zip", hash = "sha256:35bf5316af8dc7c7db1ad45bec603e5fb28671beb98ebd1d65e8059efcfd3b72"},
 ]
-openmdao = [
-    {file = "openmdao-3.10.0.tar.gz", hash = "sha256:4152b6179cc823be5800b837a80674c2baa78989a6d348099aafc521c58c909e"},
-]
+openmdao = []
 openmdao-extensions = [
     {file = "openmdao_extensions-1.0.2.tar.gz", hash = "sha256:10d63ba2cb0cb8a30346dca6ebb467df0d8c31555e6505f9a27ed284ad1e3055"},
 ]
@@ -2715,24 +2755,32 @@ pyzmq = [
     {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f89468059ebc519a7acde1ee50b779019535db8dcf9b8c162ef669257fef7a93"},
     {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea12133df25e3a6918718fbb9a510c6ee5d3fdd5a346320421aac3882f4feeea"},
     {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c532fd68b93998aab92356be280deec5de8f8fe59cd28763d2cc8a58747b7f"},
+    {file = "pyzmq-22.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f907c7359ce8bf7f7e63c82f75ad0223384105f5126f313400b7e8004d9b33c3"},
+    {file = "pyzmq-22.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:902319cfe23366595d3fa769b5b751e6ee6750a0a64c5d9f757d624b2ac3519e"},
     {file = "pyzmq-22.3.0-cp310-cp310-win32.whl", hash = "sha256:67db33bea0a29d03e6eeec55a8190e033318cee3cbc732ba8fd939617cbf762d"},
     {file = "pyzmq-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:7661fc1d5cb73481cf710a1418a4e1e301ed7d5d924f91c67ba84b2a1b89defd"},
     {file = "pyzmq-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79244b9e97948eaf38695f4b8e6fc63b14b78cc37f403c6642ba555517ac1268"},
     {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab888624ed68930442a3f3b0b921ad7439c51ba122dbc8c386e6487a658e4a4e"},
     {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18cd854b423fce44951c3a4d3e686bac8f1243d954f579e120a1714096637cc0"},
     {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:de8df0684398bd74ad160afdc2a118ca28384ac6f5e234eb0508858d8d2d9364"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:62bcade20813796c426409a3e7423862d50ff0639f5a2a95be4b85b09a618666"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:ea5a79e808baef98c48c884effce05c31a0698c1057de8fc1c688891043c1ce1"},
     {file = "pyzmq-22.3.0-cp36-cp36m-win32.whl", hash = "sha256:3c1895c95be92600233e476fe283f042e71cf8f0b938aabf21b7aafa62a8dac9"},
     {file = "pyzmq-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:851977788b9caa8ed011f5f643d3ee8653af02c5fc723fa350db5125abf2be7b"},
     {file = "pyzmq-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b4ebed0977f92320f6686c96e9e8dd29eed199eb8d066936bac991afc37cbb70"},
     {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42abddebe2c6a35180ca549fadc7228d23c1e1f76167c5ebc8a936b5804ea2df"},
     {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1e41b32d6f7f9c26bc731a8b529ff592f31fc8b6ef2be9fa74abd05c8a342d7"},
     {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:be4e0f229cf3a71f9ecd633566bd6f80d9fa6afaaff5489492be63fe459ef98c"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08c4e315a76ef26eb833511ebf3fa87d182152adf43dedee8d79f998a2162a0b"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:badb868fff14cfd0e200eaa845887b1011146a7d26d579aaa7f966c203736b92"},
     {file = "pyzmq-22.3.0-cp37-cp37m-win32.whl", hash = "sha256:7c58f598d9fcc52772b89a92d72bf8829c12d09746a6d2c724c5b30076c1f11d"},
     {file = "pyzmq-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2b97502c16a5ec611cd52410bdfaab264997c627a46b0f98d3f666227fd1ea2d"},
     {file = "pyzmq-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d728b08448e5ac3e4d886b165385a262883c34b84a7fe1166277fe675e1c197a"},
     {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:480b9931bfb08bf8b094edd4836271d4d6b44150da051547d8c7113bf947a8b0"},
     {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7dc09198e4073e6015d9a8ea093fc348d4e59de49382476940c3dd9ae156fba8"},
     {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ca6cd58f62a2751728016d40082008d3b3412a7f28ddfb4a2f0d3c130f69e74"},
+    {file = "pyzmq-22.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:468bd59a588e276961a918a3060948ae68f6ff5a7fa10bb2f9160c18fe341067"},
+    {file = "pyzmq-22.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c88fa7410e9fc471e0858638f403739ee869924dd8e4ae26748496466e27ac59"},
     {file = "pyzmq-22.3.0-cp38-cp38-win32.whl", hash = "sha256:c0f84360dcca3481e8674393bdf931f9f10470988f87311b19d23cda869bb6b7"},
     {file = "pyzmq-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:f762442bab706fd874064ca218b33a1d8e40d4938e96c24dafd9b12e28017f45"},
     {file = "pyzmq-22.3.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:954e73c9cd4d6ae319f1c936ad159072b6d356a92dcbbabfd6e6204b9a79d356"},
@@ -2740,6 +2788,8 @@ pyzmq = [
     {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:acebba1a23fb9d72b42471c3771b6f2f18dcd46df77482612054bd45c07dfa36"},
     {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cf98fd7a6c8aaa08dbc699ffae33fd71175696d78028281bc7b832b26f00ca57"},
     {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d072f7dfbdb184f0786d63bda26e8a0882041b1e393fbe98940395f7fab4c5e2"},
+    {file = "pyzmq-22.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:53f4fd13976789ffafedd4d46f954c7bb01146121812b72b4ddca286034df966"},
+    {file = "pyzmq-22.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1b5d457acbadcf8b27561deeaa386b0217f47626b29672fa7bd31deb6e91e1b"},
     {file = "pyzmq-22.3.0-cp39-cp39-win32.whl", hash = "sha256:e6a02cf7271ee94674a44f4e62aa061d2d049001c844657740e156596298b70b"},
     {file = "pyzmq-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d3dcb5548ead4f1123851a5ced467791f6986d68c656bc63bfff1bf9e36671e2"},
     {file = "pyzmq-22.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3a4c9886d61d386b2b493377d980f502186cd71d501fffdba52bd2a0880cef4f"},
@@ -2749,7 +2799,9 @@ pyzmq = [
     {file = "pyzmq-22.3.0.tar.gz", hash = "sha256:8eddc033e716f8c91c6a2112f0a8ebc5e00532b4a6ae1eb0ccc48e027f9c671c"},
 ]
 regex = [
+    {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:094a905e87a4171508c2a0e10217795f83c636ccc05ddf86e7272c26e14056ae"},
     {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:981c786293a3115bc14c103086ae54e5ee50ca57f4c02ce7cf1b60318d1e8072"},
+    {file = "regex-2021.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b0f2f874c6a157c91708ac352470cb3bef8e8814f5325e3c5c7a0533064c6a24"},
     {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51feefd58ac38eb91a21921b047da8644155e5678e9066af7bcb30ee0dca7361"},
     {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8de658d7db5987b11097445f2b1f134400e2232cb40e614e5f7b6f5428710e"},
     {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1ce02f420a7ec3b2480fe6746d756530f69769292eca363218c2291d0b116a01"},
@@ -2773,7 +2825,9 @@ regex = [
     {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a37305eb3199d8f0d8125ec2fb143ba94ff6d6d92554c4b8d4a8435795a6eccd"},
     {file = "regex-2021.10.8-cp37-cp37m-win32.whl", hash = "sha256:2efd47704bbb016136fe34dfb74c805b1ef5c7313aef3ce6dcb5ff844299f432"},
     {file = "regex-2021.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:924079d5590979c0e961681507eb1773a142553564ccae18d36f1de7324e71ca"},
+    {file = "regex-2021.10.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19b8f6d23b2dc93e8e1e7e288d3010e58fafed323474cf7f27ab9451635136d9"},
     {file = "regex-2021.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b09d3904bf312d11308d9a2867427479d277365b1617e48ad09696fa7dfcdf59"},
+    {file = "regex-2021.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:951be934dc25d8779d92b530e922de44dda3c82a509cdb5d619f3a0b1491fafa"},
     {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f125fce0a0ae4fd5c3388d369d7a7d78f185f904c90dd235f7ecf8fe13fa741"},
     {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f199419a81c1016e0560c39773c12f0bd924c37715bffc64b97140d2c314354"},
     {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:09e1031e2059abd91177c302da392a7b6859ceda038be9e015b522a182c89e4f"},
@@ -2781,7 +2835,9 @@ regex = [
     {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:176796cb7f82a7098b0c436d6daac82f57b9101bb17b8e8119c36eecf06a60a3"},
     {file = "regex-2021.10.8-cp38-cp38-win32.whl", hash = "sha256:5e5796d2f36d3c48875514c5cd9e4325a1ca172fc6c78b469faa8ddd3d770593"},
     {file = "regex-2021.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:e4204708fa116dd03436a337e8e84261bc8051d058221ec63535c9403a1582a1"},
+    {file = "regex-2021.10.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6dcf53d35850ce938b4f044a43b33015ebde292840cef3af2c8eb4c860730fff"},
     {file = "regex-2021.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b8b6ee6555b6fbae578f1468b3f685cdfe7940a65675611365a7ea1f8d724991"},
+    {file = "regex-2021.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e2ec1c106d3f754444abf63b31e5c4f9b5d272272a491fa4320475aba9e8157c"},
     {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973499dac63625a5ef9dfa4c791aa33a502ddb7615d992bdc89cf2cc2285daa3"},
     {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88dc3c1acd3f0ecfde5f95c32fcb9beda709dbdf5012acdcf66acbc4794468eb"},
     {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4786dae85c1f0624ac77cb3813ed99267c9adb72e59fdc7297e1cf4d6036d493"},
@@ -2804,6 +2860,10 @@ requests-unixsocket = [
     {file = "ruamel.yaml-0.16.0.tar.gz", hash = "sha256:4c1dbad22790b5ea8587c2a0cae97ebc7a9d0d88de5d0edb70dea2eab7d8534a"},
 ]
 "ruamel.yaml.clib" = [
+    {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6e7be2c5bcb297f5b82fee9c665eb2eb7001d1050deaba8471842979293a80b0"},
+    {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:221eca6f35076c6ae472a531afa1c223b9c29377e62936f61bc8e6e8bdc5f9e7"},
+    {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win32.whl", hash = "sha256:1070ba9dd7f9370d0513d649420c3b362ac2d687fe78c6e888f5b12bf8bc7bee"},
+    {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:77df077d32921ad46f34816a9a16e6356d8100374579bc35e15bab5d4e9377de"},
     {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:cfdb9389d888c5b74af297e51ce357b800dd844898af9d4a547ffc143fa56751"},
     {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7b2927e92feb51d830f531de4ccb11b320255ee95e791022555971c466af4527"},
     {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-win32.whl", hash = "sha256:ada3f400d9923a190ea8b59c8f60680c4ef8a4b0dfae134d2f2ff68429adfab5"},
diff --git a/pyproject.toml b/pyproject.toml
index 7c367dbc2..27d7c8b93 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -46,7 +46,7 @@ python = "^3.7"
 numpy = "^1.17.3"
 scipy = "^1.4.1"
 pandas = "^1.1.0"
-openmdao = "^3.10"
+openmdao = { git = "https://github.com/OpenMDAO/OpenMDAO.git" }
 ipopo = "^1.0.0"
 ipywidgets = "^7.5.0"
 ipysheet = ">=0.5.0, <1"
diff --git a/src/fastoad/cmd/cli.py b/src/fastoad/cmd/cli.py
index 0c074d141..e624b00f0 100644
--- a/src/fastoad/cmd/cli.py
+++ b/src/fastoad/cmd/cli.py
@@ -25,6 +25,7 @@
 )
 from fastoad.cmd.exceptions import FastNoAvailableNotebookError
 from fastoad.module_management.exceptions import (
+    FastNoAvailableConfigurationFileError,
     FastNoDistPluginError,
     FastSeveralConfigurationFilesError,
     FastSeveralDistPluginsError,
@@ -84,6 +85,7 @@ def gen_conf(conf_file, from_package, source, force):
         FastUnknownDistPluginError,
         FastSeveralConfigurationFilesError,
         FastUnknownConfigurationFileError,
+        FastNoAvailableConfigurationFileError,
     ) as exc:
         click.echo(exc.args[0])
 
diff --git a/src/fastoad/io/configuration/configuration.py b/src/fastoad/io/configuration/configuration.py
index ed578dc75..ec7653ce8 100644
--- a/src/fastoad/io/configuration/configuration.py
+++ b/src/fastoad/io/configuration/configuration.py
@@ -2,7 +2,7 @@
 Module for building OpenMDAO problem from configuration file
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2022 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
@@ -112,7 +112,8 @@ def get_problem(self, read_inputs: bool = False, auto_scaling: bool = False) ->
         if self._serializer.data is None:
             raise RuntimeError("read configuration file first")
 
-        problem = FASTOADProblem(self._build_model())
+        problem = FASTOADProblem()
+        self._build_model(problem)
         problem.input_file_path = self.input_file_path
         problem.output_file_path = self.output_file_path
 
@@ -266,17 +267,14 @@ def set_optimization_definition(self, optimization_definition: Dict):
         subpart = {"optimization": subpart}
         self._serializer.data.update(subpart)
 
-    def _build_model(self) -> om.Group:
+    def _build_model(self, problem: FASTOADProblem):
         """
-        Builds the model as defined in the configuration file.
+        Builds the problem model as defined in the configuration file.
 
-        The model is initialized as a new group and populated with subsystems
-        indicated in configuration file.
-
-        :return: the built model
+        The problem model is populated with subsystems indicated in configuration file.
         """
 
-        model = FASTOADModel()
+        model = problem.model
         model.active_submodels = self._serializer.data.get(KEY_SUBMODELS, {})
 
         model_definition = self._serializer.data.get(KEY_MODEL)
@@ -296,8 +294,6 @@ def _build_model(self) -> om.Group:
             _LOGGER.error(log_err)
             raise log_err
 
-        return model
-
     def _parse_problem_table(self, group: om.Group, table: dict):
         """
         Feeds provided *group*, using definition in provided TOML *table*.
@@ -430,48 +426,6 @@ def _om_eval(string_to_eval: str):
     return eval(string_to_eval, {"__builtins__": {}}, {"om": om})
 
 
-class AutoUnitsDefaultGroup(om.Group):
-    """
-    OpenMDAO group that automatically use self.set_input_defaults() to resolve declaration
-    conflicts in variable units.
-    """
-
-    def configure(self):
-        var_units = {}
-        system: om.Group
-        for system in self.system_iter(recurse=False):
-            system_metadata = system.get_io_metadata("input", metadata_keys=["units"])
-            var_units.update(
-                {
-                    metadata["prom_name"]: metadata["units"]
-                    for name, metadata in system_metadata.items()
-                    if "." not in metadata["prom_name"]  # tells that var is promoted
-                }
-            )
-        for name, units in var_units.items():
-            self.set_input_defaults(name, units=units)
-
-
-class FASTOADModel(AutoUnitsDefaultGroup):
-    """
-    OpenMDAO group that defines active submodels after the initialization
-    of all its subsystems, and inherits from :class:`AutoUnitsDefaultGroup` for resolving
-    declaration conflicts in variable units.
-
-    It allows to have a submodel choice in the initialize() method of a FAST-OAD module, but
-    to possibly override it with the definition of :attr:`active_submodels` (i.e. from the
-    configuration file).
-    """
-
-    def __init__(self, **kwargs):
-        super().__init__(**kwargs)
-        #: Definition of active submodels that will be applied during setup()
-        self.active_submodels = {}
-
-    def setup(self):
-        RegisterSubmodel.active_models.update(self.active_submodels)
-
-
 class _IDictSerializer(ABC):
     """Interface for reading and writing dict-like data"""
 
diff --git a/src/fastoad/models/performances/mission/openmdao/mission_wrapper.py b/src/fastoad/models/performances/mission/openmdao/mission_wrapper.py
index 51d3ff563..a6d231214 100644
--- a/src/fastoad/models/performances/mission/openmdao/mission_wrapper.py
+++ b/src/fastoad/models/performances/mission/openmdao/mission_wrapper.py
@@ -22,7 +22,6 @@
 from openmdao.vectors.vector import Vector
 
 from fastoad.model_base import FlightPoint
-from fastoad.models.aerodynamics.constants import POLAR_POINT_COUNT
 from ..mission_definition.mission_builder import MissionBuilder
 from ..mission_definition.schema import (
     CLIMB_PARTS_TAG,
@@ -76,7 +75,7 @@ def setup(self, component: om.ExplicitComponent, mission_name: str = None):
         }
         for name, (units, desc) in input_definition.items():
             if name.endswith(":CD") or name.endswith(":CL"):
-                component.add_input(name, np.nan, shape=POLAR_POINT_COUNT, desc=desc)
+                component.add_input(name, np.nan, shape_by_conn=True, desc=desc)
             else:
                 component.add_input(name, np.nan, units=units, desc=desc)
 
diff --git a/src/fastoad/module_management/_plugins.py b/src/fastoad/module_management/_plugins.py
index 0bae9973b..c92ef72a5 100644
--- a/src/fastoad/module_management/_plugins.py
+++ b/src/fastoad/module_management/_plugins.py
@@ -26,6 +26,7 @@
 from fastoad.openmdao.variables import Variable
 from ._bundle_loader import BundleLoader
 from .exceptions import (
+    FastNoAvailableConfigurationFileError,
     FastNoDistPluginError,
     FastSeveralConfigurationFilesError,
     FastSeveralDistPluginsError,
@@ -166,6 +167,9 @@ def get_configuration_file_info(self, file_name=None, plugin_name=None) -> Resou
                                                   available.
         """
         conf_file_list = self.get_configuration_file_list(plugin_name)
+        if not conf_file_list:
+            raise FastNoAvailableConfigurationFileError()
+
         if file_name is None:
             if len(conf_file_list) > 1:
                 raise FastSeveralConfigurationFilesError(self.dist_name)
diff --git a/src/fastoad/module_management/exceptions.py b/src/fastoad/module_management/exceptions.py
index bee132725..d08232877 100644
--- a/src/fastoad/module_management/exceptions.py
+++ b/src/fastoad/module_management/exceptions.py
@@ -163,6 +163,13 @@ def __init__(self):
         )
 
 
+class FastNoAvailableConfigurationFileError(FastError):
+    """Raised when a configuration file is asked, but none is available in plugins."""
+
+    def __init__(self):
+        super().__init__("No configuration file provided with currently installed plugins.")
+
+
 class FastUnknownConfigurationFileError(FastError):
     """Raised when a configuration file is not found for named distribution."""
 
diff --git a/src/fastoad/openmdao/problem.py b/src/fastoad/openmdao/problem.py
index 79c997365..c65a8c53b 100644
--- a/src/fastoad/openmdao/problem.py
+++ b/src/fastoad/openmdao/problem.py
@@ -1,5 +1,5 @@
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2022 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
@@ -11,20 +11,24 @@
 #  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 copy import deepcopy
 from typing import Tuple
 
 import numpy as np
 import openmdao.api as om
 from openmdao.core.constants import _SetupStatus
 
-from fastoad.io import VariableIO, DataFile
+from fastoad.io import DataFile, VariableIO
+from fastoad.module_management.service_registry import RegisterSubmodel
 from fastoad.openmdao.validity_checker import ValidityDomainChecker
 from fastoad.openmdao.variables import VariableList
-from fastoad.openmdao.exceptions import (
-    FASTOpenMDAONanInInputFile,
-)
+from .exceptions import FASTOpenMDAONanInInputFile
 
-INPUT_SYSTEM_NAME = "inputs"
+# Name of IVC that will contain input values
+INPUT_SYSTEM_NAME = "fastoad_inputs"
+
+# Name of IVC that will temporarily set shapes for dynamically shaped inputs
+SHAPER_SYSTEM_NAME = "fastoad_shaper"
 
 
 class FASTOADProblem(om.Problem):
@@ -49,6 +53,8 @@ def __init__(self, *args, **kwargs):
         #: If True inputs will be read after setup.
         self._read_inputs_after_setup = False
 
+        self.model = FASTOADModel()
+
     def run_model(self, case_prefix=None, reset_iter_counts=True):
         status = super().run_model(case_prefix, reset_iter_counts)
         ValidityDomainChecker.check_problem_variables(self)
@@ -63,9 +69,25 @@ def setup(self, *args, **kwargs):
         """
         Set up the problem before run.
         """
+        problem_copy = deepcopy(self)
+        try:
+            super(FASTOADProblem, problem_copy).setup(*args, **kwargs)
+        except RuntimeError:
+            vars_metadata = self._get_undetermined_dynamic_vars_metadata(problem_copy)
+            if vars_metadata:
+                # If vars_metadata is empty, it means the RuntimeError was not because
+                # of dynamic shapes, and the incoming self.setup() will raise it.
+                ivc = om.IndepVarComp()
+                for name, meta in vars_metadata.items():
+                    # We use a (2,)-shaped array as value here. This way, it will be easier to
+                    # identify dynamic-shaped data in an input file generated from current problem.
+                    ivc.add_output(name, [np.nan, np.nan], units=meta["units"])
+                self.model.add_subsystem(SHAPER_SYSTEM_NAME, ivc, promotes=["*"])
+
         super().setup(*args, **kwargs)
+
         if self._read_inputs_after_setup:
-            self._read_inputs()
+            self._read_inputs_with_setup_done()
 
     def write_outputs(self):
         """
@@ -88,9 +110,12 @@ def read_inputs(self):
         """
         Reads inputs of the problem.
         """
-        if self._metadata is not None and self._metadata["setup_status"] == _SetupStatus.POST_SETUP:
-            self._read_inputs()
+        if self._metadata and self._metadata["setup_status"] == _SetupStatus.POST_SETUP:
+            self._read_inputs_with_setup_done()
         else:
+            self._read_inputs_without_setup_done()
+            # Input reading still needs to be done after setup, to ensure that IVC values
+            # will be properly set by new inputs.
             self._read_inputs_after_setup = True
 
     def _get_problem_inputs(self) -> Tuple[VariableList, VariableList]:
@@ -120,11 +145,123 @@ def _get_problem_inputs(self) -> Tuple[VariableList, VariableList]:
 
         return input_variables, unused_variables
 
-    def _read_inputs(self):
+    def _read_inputs_with_setup_done(self):
         """
-        Set initial values of inputs for the configured problem.
+        Set initial values of inputs. self.setup() must have been run.
         """
         input_variables, unused_variables = self._get_problem_inputs()
         self.additional_variables = unused_variables
         for input_var in input_variables:
+            # set_val() will crash if input_var.metadata["val"] is a list, so
+            # we ensure it is a numpy array
+            input_var.metadata["val"] = np.asarray(input_var.metadata["val"])
             self.set_val(input_var.name, **input_var.metadata)
+
+    def _read_inputs_without_setup_done(self):
+        """
+        Set initial values of inputs. self.setup() must have NOT been run.
+
+        Input values that match an existing IVC are not taken into account
+        """
+        input_variables, unused_variables = self._get_problem_inputs()
+        self.additional_variables = unused_variables
+        tmp_prob = deepcopy(self)
+        tmp_prob.setup()
+        # At this point, there may be non-fed dynamically shaped inputs, so the setup may
+        # create the "shaper" IVC, but we ignore it because we need to redefine these variables
+        # in input file.
+        ivc_vars = tmp_prob.model.get_io_metadata(
+            "output", tags="indep_var", excludes=f"{SHAPER_SYSTEM_NAME}.*"
+        )
+        for meta in ivc_vars.values():
+            try:
+                del input_variables[meta["prom_name"]]
+            except ValueError:
+                pass
+        if input_variables:
+            self._insert_input_ivc(input_variables.to_ivc())
+
+    def _insert_input_ivc(self, ivc: om.IndepVarComp, subsystem_name=INPUT_SYSTEM_NAME):
+        tmp_prob = deepcopy(self)
+        tmp_prob.setup()
+
+        # We get order from copied problem, but we have to ignore the "shaper" and the auto IVCs.
+        previous_order = [
+            system.name
+            for system in tmp_prob.model.system_iter(recurse=False)
+            if system.name != "_auto_ivc" and system.name != SHAPER_SYSTEM_NAME
+        ]
+
+        self.model.add_subsystem(subsystem_name, ivc, promotes=["*"])
+        self.model.set_order([subsystem_name] + previous_order)
+
+    @staticmethod
+    def _get_undetermined_dynamic_vars_metadata(problem):
+        """
+        Provides dict (name, metadata) for dynamically shaped inputs that are not
+        fed by an existing output (assuming overall variable promotion).
+
+        Assumes problem.setup() has been run, at least partially.
+
+        :param problem:
+        """
+        # First all outputs are identified. If a dynamically shaped input is fed by a matching
+        # output, its shaped will be determined.
+        output_var_names = []
+        for system in problem.model.system_iter(recurse=False):
+            io_metadata = system.get_io_metadata("output")
+            output_var_names += [meta["prom_name"] for meta in io_metadata.values()]
+
+        dynamic_vars = {}
+        for system in problem.model.system_iter(recurse=False):
+            io_metadata = system.get_io_metadata("input")
+            dynamic_vars.update(
+                {
+                    meta["prom_name"]: meta
+                    for name, meta in io_metadata.items()
+                    if meta["shape_by_conn"] and meta["prom_name"] not in output_var_names
+                }
+            )
+        return dynamic_vars
+
+
+class AutoUnitsDefaultGroup(om.Group):
+    """
+    OpenMDAO group that automatically use self.set_input_defaults() to resolve declaration
+    conflicts in variable units.
+    """
+
+    def configure(self):
+        var_units = {}
+        system: om.Group
+        for system in self.system_iter(recurse=False):
+            system_metadata = system.get_io_metadata("input", metadata_keys=["units"])
+            var_units.update(
+                {
+                    metadata["prom_name"]: metadata["units"]
+                    for name, metadata in system_metadata.items()
+                    if "." not in metadata["prom_name"]  # tells that var is promoted
+                }
+            )
+        for name, units in var_units.items():
+            self.set_input_defaults(name, units=units)
+
+
+class FASTOADModel(AutoUnitsDefaultGroup):
+    """
+    OpenMDAO group that defines active submodels after the initialization
+    of all its subsystems, and inherits from :class:`AutoUnitsDefaultGroup` for resolving
+    declaration conflicts in variable units.
+
+    It allows to have a submodel choice in the initialize() method of a FAST-OAD module, but
+    to possibly override it with the definition of :attr:`active_submodels` (i.e. from the
+    configuration file).
+    """
+
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+        #: Definition of active submodels that will be applied during setup()
+        self.active_submodels = {}
+
+    def setup(self):
+        RegisterSubmodel.active_models.update(self.active_submodels)
diff --git a/src/fastoad/openmdao/variables/__init__.py b/src/fastoad/openmdao/variables/__init__.py
new file mode 100644
index 000000000..02fe81758
--- /dev/null
+++ b/src/fastoad/openmdao/variables/__init__.py
@@ -0,0 +1,20 @@
+"""
+Package for managing OpenMDAO variables
+"""
+#  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
+#  Copyright (C) 2022 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/>.
+
+# flake8: noqa
+
+from .variable import Variable
+from .variable_list import VariableList
diff --git a/src/fastoad/openmdao/variables/variable.py b/src/fastoad/openmdao/variables/variable.py
new file mode 100644
index 000000000..6bec36325
--- /dev/null
+++ b/src/fastoad/openmdao/variables/variable.py
@@ -0,0 +1,313 @@
+"""
+Class for managing an OpenMDAO variable.
+"""
+#  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
+#  Copyright (C) 2022 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/>.
+
+import logging
+import os.path as pth
+from importlib.resources import open_text
+from typing import Dict, Hashable, Iterable, Mapping, Tuple, Union
+
+import numpy as np
+import openmdao.api as om
+
+from fastoad._utils.resource_management.contents import PackageReader
+
+_LOGGER = logging.getLogger(__name__)  # Logger for this module
+
+DESCRIPTION_FILENAME = "variable_descriptions.txt"
+
+# Metadata that will be ignore when checking variable equality and when adding variable
+# to an OpenMDAO component
+METADATA_TO_IGNORE = [
+    "is_input",
+    "tags",
+    "size",
+    "src_indices",
+    "src_slice",
+    "flat_src_indices",
+    "distributed",
+    "res_units",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
+    "lower",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
+    "upper",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
+    "ref",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
+    "ref0",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
+    "res_ref",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
+    "ref",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
+    "global_shape",
+    "global_size",
+    "discrete",  # currently inconsistent in openMDAO 3.4
+    "prom_name",
+    "desc",
+]
+
+
+class Variable(Hashable):
+    """
+    A class for storing data of OpenMDAO variables.
+
+    Instantiation is expected to be done through keyword arguments only.
+
+    Beside the mandatory parameter 'name, kwargs is expected to have keys
+    'value', 'units' and 'desc', that are accessible respectively through
+    properties :meth:`name`, :meth:`value`, :meth:`units` and :meth:`description`.
+
+    Other keys are possible. They match the definition of OpenMDAO's method
+    :meth:`Component.add_output` described
+    `here <http://openmdao.org/twodocs/versions/latest/_srcdocs/packages/core/
+    component.html#openmdao.core.component.Component.add_output>`_.
+
+    These keys can be listed with class method :meth:`get_openmdao_keys`.
+    **Any other key in kwargs will be silently ignored.**
+
+    Special behaviour: :meth:`description` will return the content of kwargs['desc']
+    unless these 2 conditions are met:
+     - kwargs['desc'] is None or 'desc' key is missing
+     - a description exists in FAST-OAD internal data for the variable name
+    Then, the internal description will be returned by :meth:`description`
+
+    :param kwargs: the attributes of the variable, as keyword arguments
+    """
+
+    # Will store content of description files
+    _variable_descriptions = {}
+
+    # The list of modules of path where description files have been read
+    _loaded_descriptions = set()
+
+    # Default metadata
+    _base_metadata = {}
+
+    def __init__(self, name, **kwargs):
+        super().__init__()
+
+        self.name = name
+        """ Name of the variable """
+
+        self.metadata: Dict = {}
+        """ Dictionary for metadata of the variable """
+
+        # Initialize class attributes once at first instantiation -------------
+        if not self._base_metadata:
+            # Get variable base metadata from an ExplicitComponent
+            comp = om.ExplicitComponent()
+            # get attributes
+            metadata = comp.add_output(name="a")
+
+            self.__class__._base_metadata = metadata
+            self.__class__._base_metadata["val"] = 1.0
+            self.__class__._base_metadata["tags"] = set()
+            self.__class__._base_metadata["shape"] = None
+        # Done with class attributes ------------------------------------------
+
+        # Feed self.metadata with kwargs, but remove first attributes with "Unavailable" as
+        # value, which is a value that can be provided by OpenMDAO.
+        self.metadata = self.__class__._base_metadata.copy()
+        self.metadata.update(
+            {
+                key: value
+                for key, value in kwargs.items()
+                # The isinstance check is needed if value is a numpy array. In this case, a
+                # FutureWarning is issued because it is compared to a scalar.
+                if not isinstance(value, str) or value != "Unavailable"
+            }
+        )
+
+        if "value" in self.metadata:
+            self.metadata["val"] = self.metadata.pop("value")
+        if "description" in self.metadata:
+            self.metadata["desc"] = self.metadata.pop("description")
+
+        self._set_default_shape()
+
+        # If no description, use the one from self._variable_descriptions, if available
+        if not self.description and self.name in self._variable_descriptions:
+            self.description = self._variable_descriptions[self.name]
+
+    @classmethod
+    def read_variable_descriptions(cls, file_parent: str, update_existing: bool = True):
+        """
+        Reads variable descriptions in indicated folder or package, if it contains some.
+
+        The file variable_descriptions.txt is looked for. Nothing is done if it is not
+        found (no error raised also).
+
+        Each line of the file should be formatted like::
+
+            my:variable||The description of my:variable, as long as needed, but on one line.
+
+        :param file_parent: the folder path or the package name that should contain the file
+        :param update_existing: if True, previous descriptions will be updated.
+                                if False, previous descriptions will be erased.
+        """
+        if not update_existing:
+            cls._variable_descriptions = {}
+            cls._loaded_descriptions = set()
+
+        variable_descriptions = None
+        description_file = None
+
+        if file_parent:
+            if pth.isdir(file_parent):
+                file_path = pth.join(file_parent, DESCRIPTION_FILENAME)
+                if pth.isfile(file_path):
+                    description_file = open(file_path)
+            else:
+                # Then it is a module name
+                if DESCRIPTION_FILENAME in PackageReader(file_parent).contents:
+                    description_file = open_text(file_parent, DESCRIPTION_FILENAME)
+
+        if description_file is not None:
+            try:
+                variable_descriptions = np.genfromtxt(
+                    description_file, delimiter="||", dtype=str, autostrip=True
+                )
+            except Exception as exc:
+                # Reading the file is not mandatory, so let's just log the error.
+                _LOGGER.error(
+                    "Could not read file %s in %s. Error log is:\n%s",
+                    DESCRIPTION_FILENAME,
+                    file_parent,
+                    exc,
+                )
+            description_file.close()
+
+        if variable_descriptions is not None:
+            if np.shape(variable_descriptions) == (2,):
+                # If the file contains only one line, np.genfromtxt() will return a (2,)-shaped
+                # array. We need a reshape for dict.update() to work correctly.
+                variable_descriptions = np.reshape(variable_descriptions, (1, 2))
+
+            cls._loaded_descriptions.add(file_parent)
+            cls.update_variable_descriptions(variable_descriptions)
+            _LOGGER.info("Loaded variable descriptions in %s", file_parent)
+
+    @classmethod
+    def update_variable_descriptions(
+        cls, variable_descriptions: Union[Mapping[str, str], Iterable[Tuple[str, str]]]
+    ):
+        """
+        Updates description of variables.
+
+        :param variable_descriptions: dict-like object with variable names as keys and descriptions
+                                      as values
+        """
+        cls._variable_descriptions.update(variable_descriptions)
+
+    @classmethod
+    def get_openmdao_keys(cls):
+        """
+
+        :return: the keys that are used in OpenMDAO variables
+        """
+        # As _base_metadata is initialized at first instantiation, we create an instance to
+        # ensure it has been done
+        cls("dummy")
+
+        return cls._base_metadata.keys()
+
+    @property
+    def value(self):
+        """value of the variable"""
+        return self.metadata.get("val")
+
+    @value.setter
+    def value(self, value):
+        self.metadata["val"] = value
+        self._set_default_shape()
+
+    @property
+    def val(self):
+        """value of the variable (alias of property "value")"""
+        return self.value
+
+    @val.setter
+    def val(self, value):
+        self.value = value
+
+    @property
+    def units(self):
+        """units associated to value (or None if not found)"""
+        return self.metadata.get("units")
+
+    @units.setter
+    def units(self, value):
+        self.metadata["units"] = value
+
+    @property
+    def description(self):
+        """description of the variable (or None if not found)"""
+        return self.metadata.get("desc")
+
+    @description.setter
+    def description(self, value):
+        self.metadata["desc"] = value
+
+    @property
+    def desc(self):
+        """description of the variable (or None if not found) (alias of property "description")"""
+        return self.description
+
+    @desc.setter
+    def desc(self, value):
+        self.description = value
+
+    @property
+    def is_input(self):
+        """I/O status of the variable.
+
+        - True if variable is a problem input
+        - False if it is an output
+        - None if information not found
+        """
+        return self.metadata.get("is_input")
+
+    @is_input.setter
+    def is_input(self, value):
+        self.metadata["is_input"] = value
+
+    def _set_default_shape(self):
+        """Automatically sets shape if not set"""
+        if self.metadata["shape"] is None:
+            shape = np.shape(self.value)
+            if not shape:
+                shape = (1,)
+            self.metadata["shape"] = shape
+
+    def __eq__(self, other):
+        # same arrays with nan are declared non equals, so we need a workaround
+        my_metadata = dict(self.metadata)
+        other_metadata = dict(other.metadata)
+        my_value = np.asarray(my_metadata.pop("val"))
+        other_value = np.asarray(other_metadata.pop("val"))
+
+        # Let's also ignore unimportant keys
+        for key in METADATA_TO_IGNORE:
+            if key in my_metadata:
+                del my_metadata[key]
+            if key in other_metadata:
+                del other_metadata[key]
+
+        return (
+            isinstance(other, Variable)
+            and self.name == other.name
+            and np.all(np.isclose(my_value, other_value, equal_nan=True))
+            and my_metadata == other_metadata
+        )
+
+    def __repr__(self):
+        return "Variable(name=%s, metadata=%s)" % (self.name, self.metadata)
+
+    def __hash__(self) -> int:
+        return hash("var=" + self.name)  # Name is normally unique
diff --git a/src/fastoad/openmdao/variables.py b/src/fastoad/openmdao/variables/variable_list.py
similarity index 54%
rename from src/fastoad/openmdao/variables.py
rename to src/fastoad/openmdao/variables/variable_list.py
index 34a8ffde2..1cb264026 100644
--- a/src/fastoad/openmdao/variables.py
+++ b/src/fastoad/openmdao/variables/variable_list.py
@@ -1,5 +1,5 @@
 """
-Module for managing OpenMDAO variables
+Class for managing a list of OpenMDAO variables.
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
 #  Copyright (C) 2022 ONERA & ISAE-SUPAERO
@@ -15,308 +15,17 @@
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 import itertools
-import logging
-import os.path as pth
-from builtins import isinstance
 from copy import deepcopy
-from importlib.resources import open_text
-from typing import Dict, Hashable, Iterable, List, Mapping, Tuple, Union
-from deprecated import deprecated
+from typing import Iterable, List, Mapping, Tuple, Union
 
 import numpy as np
 import openmdao.api as om
 import pandas as pd
+from deprecated import deprecated
+from openmdao.core.constants import _SetupStatus
 
-from fastoad._utils.resource_management.contents import PackageReader
 from fastoad.openmdao._utils import get_unconnected_input_names
-
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
-DESCRIPTION_FILENAME = "variable_descriptions.txt"
-
-# Metadata that will be ignore when checking variable equality and when adding variable
-# to an OpenMDAO component
-METADATA_TO_IGNORE = [
-    "is_input",
-    "tags",
-    "size",
-    "src_indices",
-    "src_slice",
-    "flat_src_indices",
-    "distributed",
-    "res_units",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
-    "lower",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
-    "upper",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
-    "ref",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
-    "ref0",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
-    "res_ref",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
-    "ref",  # deprecated in IndepVarComp.add_output() since OpenMDAO 3.2
-    "global_shape",
-    "global_size",
-    "discrete",  # currently inconsistent in openMDAO 3.4
-    "prom_name",
-    "desc",
-]
-
-
-class Variable(Hashable):
-    """
-    A class for storing data of OpenMDAO variables.
-
-    Instantiation is expected to be done through keyword arguments only.
-
-    Beside the mandatory parameter 'name, kwargs is expected to have keys
-    'value', 'units' and 'desc', that are accessible respectively through
-    properties :meth:`name`, :meth:`value`, :meth:`units` and :meth:`description`.
-
-    Other keys are possible. They match the definition of OpenMDAO's method
-    :meth:`Component.add_output` described
-    `here <http://openmdao.org/twodocs/versions/latest/_srcdocs/packages/core/
-    component.html#openmdao.core.component.Component.add_output>`_.
-
-    These keys can be listed with class method :meth:`get_openmdao_keys`.
-    **Any other key in kwargs will be silently ignored.**
-
-    Special behaviour: :meth:`description` will return the content of kwargs['desc']
-    unless these 2 conditions are met:
-     - kwargs['desc'] is None or 'desc' key is missing
-     - a description exists in FAST-OAD internal data for the variable name
-    Then, the internal description will be returned by :meth:`description`
-
-    :param kwargs: the attributes of the variable, as keyword arguments
-    """
-
-    # Will store content of description files
-    _variable_descriptions = {}
-
-    # The list of modules of path where description files have been read
-    _loaded_descriptions = set()
-
-    # Default metadata
-    _base_metadata = {}
-
-    def __init__(self, name, **kwargs):
-        super().__init__()
-
-        self.name = name
-        """ Name of the variable """
-
-        self.metadata: Dict = {}
-        """ Dictionary for metadata of the variable """
-
-        # Initialize class attributes once at first instantiation -------------
-        if not self._base_metadata:
-            # Get variable base metadata from an ExplicitComponent
-            comp = om.ExplicitComponent()
-            # get attributes
-            metadata = comp.add_output(name="a")
-
-            self.__class__._base_metadata = metadata
-            self.__class__._base_metadata["val"] = 1.0
-            self.__class__._base_metadata["tags"] = set()
-            self.__class__._base_metadata["shape"] = None
-        # Done with class attributes ------------------------------------------
-
-        # Feed self.metadata with kwargs, but remove first attributes with "Unavailable" as
-        # value, which is a value that can be provided by OpenMDAO.
-        self.metadata = self.__class__._base_metadata.copy()
-        self.metadata.update(
-            {
-                key: value
-                for key, value in kwargs.items()
-                # The isinstance check is needed if value is a numpy array. In this case, a
-                # FutureWarning is issued because it is compared to a scalar.
-                if not isinstance(value, str) or value != "Unavailable"
-            }
-        )
-
-        if "value" in self.metadata:
-            self.metadata["val"] = self.metadata.pop("value")
-        if "description" in self.metadata:
-            self.metadata["desc"] = self.metadata.pop("description")
-
-        self._set_default_shape()
-
-        # If no description, use the one from self._variable_descriptions, if available
-        if not self.description and self.name in self._variable_descriptions:
-            self.description = self._variable_descriptions[self.name]
-
-    @classmethod
-    def read_variable_descriptions(cls, file_parent: str, update_existing: bool = True):
-        """
-        Reads variable descriptions in indicated folder or package, if it contains some.
-
-        The file variable_descriptions.txt is looked for. Nothing is done if it is not
-        found (no error raised also).
-
-        Each line of the file should be formatted like::
-
-            my:variable||The description of my:variable, as long as needed, but on one line.
-
-        :param file_parent: the folder path or the package name that should contain the file
-        :param update_existing: if True, previous descriptions will be updated.
-                                if False, previous descriptions will be erased.
-        """
-        if not update_existing:
-            cls._variable_descriptions = {}
-            cls._loaded_descriptions = set()
-
-        variable_descriptions = None
-        description_file = None
-
-        if file_parent:
-            if pth.isdir(file_parent):
-                file_path = pth.join(file_parent, DESCRIPTION_FILENAME)
-                if pth.isfile(file_path):
-                    description_file = open(file_path)
-            else:
-                # Then it is a module name
-                if DESCRIPTION_FILENAME in PackageReader(file_parent).contents:
-                    description_file = open_text(file_parent, DESCRIPTION_FILENAME)
-
-        if description_file is not None:
-            try:
-                variable_descriptions = np.genfromtxt(
-                    description_file, delimiter="||", dtype=str, autostrip=True
-                )
-            except Exception as exc:
-                # Reading the file is not mandatory, so let's just log the error.
-                _LOGGER.error(
-                    "Could not read file %s in %s. Error log is:\n%s",
-                    DESCRIPTION_FILENAME,
-                    file_parent,
-                    exc,
-                )
-            description_file.close()
-
-        if variable_descriptions is not None:
-            if np.shape(variable_descriptions) == (2,):
-                # If the file contains only one line, np.genfromtxt() will return a (2,)-shaped
-                # array. We need a reshape for dict.update() to work correctly.
-                variable_descriptions = np.reshape(variable_descriptions, (1, 2))
-
-            cls._loaded_descriptions.add(file_parent)
-            cls.update_variable_descriptions(variable_descriptions)
-            _LOGGER.info("Loaded variable descriptions in %s", file_parent)
-
-    @classmethod
-    def update_variable_descriptions(
-        cls, variable_descriptions: Union[Mapping[str, str], Iterable[Tuple[str, str]]]
-    ):
-        """
-        Updates description of variables.
-
-        :param variable_descriptions: dict-like object with variable names as keys and descriptions
-                                      as values
-        """
-        cls._variable_descriptions.update(variable_descriptions)
-
-    @classmethod
-    def get_openmdao_keys(cls):
-        """
-
-        :return: the keys that are used in OpenMDAO variables
-        """
-        # As _base_metadata is initialized at first instantiation, we create an instance to
-        # ensure it has been done
-        cls("dummy")
-
-        return cls._base_metadata.keys()
-
-    @property
-    def value(self):
-        """value of the variable"""
-        return self.metadata.get("val")
-
-    @value.setter
-    def value(self, value):
-        self.metadata["val"] = value
-        self._set_default_shape()
-
-    @property
-    def val(self):
-        """value of the variable (alias of property "value")"""
-        return self.value
-
-    @val.setter
-    def val(self, value):
-        self.value = value
-
-    @property
-    def units(self):
-        """units associated to value (or None if not found)"""
-        return self.metadata.get("units")
-
-    @units.setter
-    def units(self, value):
-        self.metadata["units"] = value
-
-    @property
-    def description(self):
-        """description of the variable (or None if not found)"""
-        return self.metadata.get("desc")
-
-    @description.setter
-    def description(self, value):
-        self.metadata["desc"] = value
-
-    @property
-    def desc(self):
-        """description of the variable (or None if not found) (alias of property "description")"""
-        return self.description
-
-    @desc.setter
-    def desc(self, value):
-        self.description = value
-
-    @property
-    def is_input(self):
-        """I/O status of the variable.
-
-        - True if variable is a problem input
-        - False if it is an output
-        - None if information not found
-        """
-        return self.metadata.get("is_input")
-
-    @is_input.setter
-    def is_input(self, value):
-        self.metadata["is_input"] = value
-
-    def _set_default_shape(self):
-        """Automatically sets shape if not set"""
-        if self.metadata["shape"] is None:
-            shape = np.shape(self.value)
-            if not shape:
-                shape = (1,)
-            self.metadata["shape"] = shape
-
-    def __eq__(self, other):
-        # same arrays with nan are declared non equals, so we need a workaround
-        my_metadata = dict(self.metadata)
-        other_metadata = dict(other.metadata)
-        my_value = np.asarray(my_metadata.pop("val"))
-        other_value = np.asarray(other_metadata.pop("val"))
-
-        # Let's also ignore unimportant keys
-        for key in METADATA_TO_IGNORE:
-            if key in my_metadata:
-                del my_metadata[key]
-            if key in other_metadata:
-                del other_metadata[key]
-
-        return (
-            isinstance(other, Variable)
-            and self.name == other.name
-            and np.all(np.isclose(my_value, other_value, equal_nan=True))
-            and my_metadata == other_metadata
-        )
-
-    def __repr__(self):
-        return "Variable(name=%s, metadata=%s)" % (self.name, self.metadata)
-
-    def __hash__(self) -> int:
-        return hash("var=" + self.name)  # Name is normally unique
+from .variable import METADATA_TO_IGNORE, Variable
 
 
 class VariableList(list):
@@ -394,9 +103,8 @@ def update(self, other_var_list: "VariableList", add_variables: bool = True):
             if add_variables or var.name in self.names():
                 # To avoid to lose variables description when the variable list is updated with a
                 # list without descriptions (issue # 319)
-                if var.name in self.names():
-                    if self[var.name].description and not var.description:
-                        var.description = self[var.name].description
+                if var.name in self.names() and self[var.name].description and not var.description:
+                    var.description = self[var.name].description
                 self.append(deepcopy(var))
 
     def to_ivc(self) -> om.IndepVarComp:
@@ -427,18 +135,8 @@ def to_dataframe(self) -> pd.DataFrame:
         var_dict = {"name": []}
         var_dict.update({metadata_name: [] for metadata_name in self.metadata_keys()})
 
-        # To be able to edit floats and integer
-        def _check_shape(value):
-            if np.shape(value) == (1,):
-                value = float(value[0])
-            elif np.shape(value) == ():
-                pass
-            else:
-                value = np.asarray(value).tolist()
-            return value
-
         for variable in self:
-            value = _check_shape(variable.value)
+            value = self._as_list_or_float(variable.value)
             var_dict["name"].append(variable.name)
             for metadata_name in self.metadata_keys():
                 if metadata_name == "val":
@@ -446,7 +144,7 @@ def _check_shape(value):
                 else:
                     # TODO: make this more generic
                     if metadata_name in ["val", "initial_value", "lower", "upper"]:
-                        metadata = _check_shape(variable.metadata[metadata_name])
+                        metadata = self._as_list_or_float(variable.metadata[metadata_name])
                     else:
                         metadata = variable.metadata[metadata_name]
                     var_dict[metadata_name].append(metadata)
@@ -490,17 +188,25 @@ def from_ivc(cls, ivc: om.IndepVarComp) -> "VariableList":
         ).items():
             metadata = metadata.copy()
             value = metadata.pop("val")
-            if np.shape(value) == (1,):
-                value = float(value[0])
-            elif np.shape(value) == ():
-                pass
-            else:
-                value = np.asarray(value)
+            value = cls._as_list_or_float(value)
             metadata.update({"val": value})
             variables[name] = metadata
 
         return variables
 
+    @classmethod
+    def _as_list_or_float(cls, value):
+        value = np.asarray(value)
+        if np.size(value) == 1:
+            value = value.item()
+            try:
+                value = float(value)
+            except (TypeError, ValueError):
+                pass
+            return value
+
+        return value.tolist()
+
     @classmethod
     def from_dataframe(cls, df: pd.DataFrame) -> "VariableList":
         """
@@ -514,26 +220,12 @@ def from_dataframe(cls, df: pd.DataFrame) -> "VariableList":
         """
         column_names = [name for name in df.columns]
 
-        # To be able to edit floats and integer
-        def _check_shape(value):
-            if np.shape(value) == (1,):
-                value = float(value[0])
-            elif np.shape(value) == ():
-                if type(value) == str:
-                    value = float(value)
-                else:
-                    # Integer
-                    pass
-            else:
-                value = np.asarray(value).tolist()
-            return value
-
         def _get_variable(row):
             var_as_dict = {key: val for key, val in zip(column_names, row)}
             # TODO: make this more generic
             for key, val in var_as_dict.items():
                 if key in ["val", "initial_value", "lower", "upper"]:
-                    var_as_dict[key] = _check_shape(val)
+                    var_as_dict[key] = cls._as_list_or_float(val)
                 else:
                     pass
             return Variable(**var_as_dict)
@@ -552,10 +244,6 @@ def from_problem(
         """
         Creates a VariableList instance containing inputs and outputs of an OpenMDAO Problem.
 
-        .. warning::
-
-            problem.setup() must have been run.
-
         The inputs (is_input=True) correspond to the variables of IndepVarComp
         components and all the unconnected variables.
 
@@ -572,8 +260,9 @@ def from_problem(
         :return: VariableList instance
         """
 
-        # from_problem affects integrity of problem instance
         problem = deepcopy(problem)
+        if not problem._metadata or problem._metadata["setup_status"] < _SetupStatus.POST_SETUP:
+            problem.setup()
 
         # Get inputs and outputs
         metadata_keys = (
@@ -593,7 +282,7 @@ def from_problem(
             "output", metadata_keys=metadata_keys, excludes="_auto_ivc.*"
         )
         indep_outputs = problem.model.get_io_metadata(
-            "output", metadata_keys=metadata_keys, tags="indep_var", excludes="_auto_ivc.*"
+            "output", metadata_keys=metadata_keys, tags="indep_var"
         )
 
         # Move outputs from IndepVarComps into inputs
@@ -618,7 +307,10 @@ def from_problem(
                 # Check connections
                 for name, metadata in inputs.copy().items():
                     source_name = problem.model.get_source(name)
-                    if not source_name.startswith("_auto_ivc.") and source_name != name:
+                    if (
+                        not (source_name in indep_outputs or source_name.startswith("_auto_ivc."))
+                        and source_name != name
+                    ):
                         # This variable is connected to another variable of the problem: it is
                         # not an actual problem input. Let's move it to outputs.
                         del inputs[name]
@@ -635,47 +327,10 @@ def from_problem(
             final_inputs = inputs
             final_outputs = outputs
         else:
-            # Remove from inputs the variables that are outputs of some other component
-            promoted_inputs = {
+            final_inputs = {
                 metadata["prom_name"]: dict(metadata, is_input=True) for metadata in inputs.values()
             }
-
-            promoted_outputs = {}
-            for metadata in outputs.values():
-                prom_name = metadata["prom_name"]
-                # In case we get promoted names, several variables can match the same
-                # promoted name, with possibly different declaration for default values.
-                # We retain the first non-NaN value with defined units. If no units is
-                # ever defined, the first non-NaN value is kept.
-                # A non-NaN value with no units will be retained against a NaN value with
-                # defined units.
-
-                if prom_name in promoted_outputs:
-                    # prom_name has already been encountered.
-                    # Note: the succession of "if" is to help understanding, hopefully :)
-
-                    if not np.all(np.isnan(promoted_outputs[prom_name]["val"])):
-                        if promoted_outputs[prom_name]["units"] is not None:
-                            # We already have a non-NaN value with defined units for current
-                            # promoted name. No need for using the current variable.
-                            continue
-                        if np.all(np.isnan(metadata["val"])):
-                            # We already have a non-NaN value and current variable has a NaN value,
-                            # so it can only add information about units. We keep the non-NaN value
-                            continue
-
-                    if (
-                        np.all(np.isnan(promoted_outputs[prom_name]["val"]))
-                        and metadata["units"] is None
-                    ):
-                        # We already have a non-NaN value and current variable provides no unit.
-                        # No need for using the current variable.
-                        continue
-                if prom_name not in promoted_inputs:
-                    promoted_outputs[prom_name] = metadata
-
-            final_inputs = promoted_inputs
-            final_outputs = promoted_outputs
+            final_outputs = cls._get_promoted_outputs(outputs)
 
             # When variables are promoted, we may have retained a definition of the variable
             # that does not have any description, whereas a description is available in
@@ -712,10 +367,52 @@ def from_problem(
         elif io_status == "outputs":
             variables = output_vars
         else:
-            raise TypeError("Unknown value for io_status")
+            raise ValueError("Unknown value for io_status")
 
         return variables
 
+    @classmethod
+    def _get_promoted_outputs(cls, outputs: dict) -> dict:
+        """
+
+        :param outputs: dict (name, metadata) with non-promoted names as keys
+        :return: dict (name, metadata) with promoted names as keys
+        """
+        promoted_outputs = {}
+        for metadata in outputs.values():
+            prom_name = metadata["prom_name"]
+            # In case we get promoted names, several variables can match the same
+            # promoted name, with possibly different declaration for default values.
+            # We retain the first non-NaN value with defined units. If no units is
+            # ever defined, the first non-NaN value is kept.
+            # A non-NaN value with no units will be retained against a NaN value with
+            # defined units.
+
+            if prom_name in promoted_outputs:
+                # prom_name has already been encountered.
+                # Note: the succession of "if" is to help understanding, hopefully :)
+
+                if not np.all(np.isnan(promoted_outputs[prom_name]["val"])):
+                    if promoted_outputs[prom_name]["units"] is not None:
+                        # We already have a non-NaN value with defined units for current
+                        # promoted name. No need for using the current variable.
+                        continue
+                    if np.all(np.isnan(metadata["val"])):
+                        # We already have a non-NaN value and current variable has a NaN value,
+                        # so it can only add information about units. We keep the non-NaN value
+                        continue
+
+                if (
+                    np.all(np.isnan(promoted_outputs[prom_name]["val"]))
+                    and metadata["units"] is None
+                ):
+                    # We already have a non-NaN value and current variable provides no unit.
+                    # No need for using the current variable.
+                    continue
+            promoted_outputs[prom_name] = metadata
+
+        return promoted_outputs
+
     @classmethod
     @deprecated(
         version="1.3.0",


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index c9795e1c2..591a446bd 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -32,16 +32,13 @@ jobs:
         run: echo "$HOME/.poetry/bin" >> $GITHUB_PATH
         shell: bash
 
-      - uses: actions/cache@v2
-        if: ${{ startsWith(runner.os, 'Linux') }}
-        with:
-          path: ~/.cache/pypoetry
-          key: ${{ runner.os }}-Py${{ matrix.python-version }}-pypoetry-${{ hashFiles('**/poetry.lock') }}
+      - name: Sets unique cache directory for Poetry
+        run: poetry config cache-dir ~/poetry_cache
+        shell: bash
 
       - uses: actions/cache@v2
-        if: ${{ startsWith(runner.os, 'macOS') }}
         with:
-          path: ~/Library/Caches/pypoetry
+          path: ~/poetry_cache
           key: ${{ runner.os }}-Py${{ matrix.python-version }}-pypoetry-${{ hashFiles('**/poetry.lock') }}
 
       - name: Activate environment and install dependencies
diff --git a/src/conftest.py b/src/conftest.py
index 4ec2cd2ff..5f024aa53 100644
--- a/src/conftest.py
+++ b/src/conftest.py
@@ -137,6 +137,30 @@ def with_dummy_plugin_2():
     _teardown()
 
 
+@pytest.fixture
+def with_dummy_plugin_4():
+    """
+    Reduces plugin list to dummy-dist-1 with plugin test_plugin_4
+    (no configuration file, no model folder, notebooks).
+
+    Any previous state of plugins is restored during teardown.
+    """
+    _setup()
+    dummy_dist_1 = Mock(Distribution)
+    dummy_dist_1.name = "dummy-dist-1"
+    entry_points = [
+        EntryPoint(
+            name="test_plugin_4",
+            value="tests.dummy_plugins.dist_1.dummy_plugin_4",
+            group=MODEL_PLUGIN_ID,
+        )
+    ]
+    entry_points[0].dist = dummy_dist_1
+    _update_entry_map(entry_points)
+    yield
+    _teardown()
+
+
 @pytest.fixture
 def with_dummy_plugin_distribution_1():
     """
diff --git a/src/fastoad/module_management/tests/test_plugins.py b/src/fastoad/module_management/tests/test_plugins.py
index 4f030cd6c..acb83e735 100644
--- a/src/fastoad/module_management/tests/test_plugins.py
+++ b/src/fastoad/module_management/tests/test_plugins.py
@@ -19,6 +19,7 @@
 from .._plugins import FastoadLoader, SubPackageNames
 from ..exceptions import (
     FastBundleLoaderUnknownFactoryNameError,
+    FastNoAvailableConfigurationFileError,
     FastNoDistPluginError,
     FastSeveralConfigurationFilesError,
     FastSeveralDistPluginsError,
@@ -200,6 +201,13 @@ def test_get_configuration_file_info_with_1_plugin(with_dummy_plugin_1):
     assert file_info_bis == file_info
 
 
+def test_get_configuration_file_info_without_conf_file_available(with_dummy_plugin_4):
+    dist_def = FastoadLoader().get_distribution_plugin_definition("dummy-dist-1")
+
+    with pytest.raises(FastNoAvailableConfigurationFileError):
+        dist_def.get_configuration_file_info("unknown.yml")
+
+
 def test_get_configuration_file_info_with_plugins(with_dummy_plugins):
     dist_def = FastoadLoader().get_distribution_plugin_definition("dummy-dist-1")
 
diff --git a/src/fastoad/openmdao/tests/data/dynamic_shape_inputs_1.xml b/src/fastoad/openmdao/tests/data/dynamic_shape_inputs_1.xml
new file mode 100644
index 000000000..06ae8349e
--- /dev/null
+++ b/src/fastoad/openmdao/tests/data/dynamic_shape_inputs_1.xml
@@ -0,0 +1,18 @@
+<!--
+  ~ This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
+  ~ Copyright (C) 2022 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/>.
+  -->
+
+<aircraft>
+  <x>[1,2,5]</x>
+</aircraft>
\ No newline at end of file
diff --git a/src/fastoad/openmdao/tests/openmdao_sellar_example/sellar.py b/src/fastoad/openmdao/tests/openmdao_sellar_example/sellar.py
index c04b6cfa3..8b5cb10b3 100644
--- a/src/fastoad/openmdao/tests/openmdao_sellar_example/sellar.py
+++ b/src/fastoad/openmdao/tests/openmdao_sellar_example/sellar.py
@@ -1,6 +1,6 @@
 """Sellar openMDAO group"""
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2022 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,8 +16,7 @@
 import abc
 from typing import Type
 
-from openmdao.api import Group, IndepVarComp
-from openmdao.api import NonlinearBlockGS
+from openmdao.api import Group, IndepVarComp, NonlinearBlockGS
 
 from .disc1 import Disc1
 from .disc2 import Disc2
@@ -86,7 +85,6 @@ def __init__(self, sellar_factory: Type[ISellarFactory] = StandardSellarFactory,
     def setup(self):
         indeps = self.add_subsystem("indeps", IndepVarComp(), promotes=["*"])
         indeps.add_output("x", 2)
-        indeps.add_output("z", [5, 2], units="m**2")
         self.add_subsystem("Disc1", self._sellar_factory.create_disc1(), promotes=["x", "z", "y2"])
         self.add_subsystem("Disc2", self._sellar_factory.create_disc2(), promotes=["z", "y2"])
         self.add_subsystem(
diff --git a/src/fastoad/openmdao/tests/test_problem.py b/src/fastoad/openmdao/tests/test_problem.py
index 2736353da..3a5eb9f85 100644
--- a/src/fastoad/openmdao/tests/test_problem.py
+++ b/src/fastoad/openmdao/tests/test_problem.py
@@ -1,5 +1,5 @@
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2022 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,16 +14,18 @@
 import os.path as pth
 from shutil import rmtree
 
-import pytest
 import numpy as np
+import openmdao.api as om
+import pytest
+from numpy.testing import assert_allclose
 
-from fastoad.openmdao.problem import FASTOADProblem
-from fastoad.openmdao.variables import Variable
-from .openmdao_sellar_example.sellar import Sellar
-from ...io import VariableIO
 from fastoad.openmdao.exceptions import (
     FASTOpenMDAONanInInputFile,
 )
+from fastoad.openmdao.problem import FASTOADProblem
+from fastoad.openmdao.variables import Variable, VariableList
+from .openmdao_sellar_example.sellar import Sellar
+from ...io import VariableIO
 
 DATA_FOLDER_PATH = pth.join(pth.dirname(__file__), "data")
 RESULTS_FOLDER_PATH = pth.join(pth.dirname(__file__), "results", "problem")
@@ -46,11 +48,12 @@ def test_write_outputs():
         Variable(name="f", val=1.0),
         Variable(name="g1", val=1.0),
         Variable(name="g2", val=1.0),
-        Variable(name="x", val=2),
+        Variable(name="x", val=2.0),
         Variable(name="y2", val=1.0),
-        Variable(name="z", val=[5.0, 2.0], units="m**2"),
+        Variable(name="z", val=[np.nan, np.nan], units="m**2"),
     ]
 
+    problem["x"] = 2.0
     problem.run_model()
     problem.write_outputs()
     variables = VariableIO(problem.output_file_path).read()
@@ -58,13 +61,13 @@ def test_write_outputs():
         Variable(name="f", val=32.569100892077444),
         Variable(name="g1", val=-23.409095627564167),
         Variable(name="g2", val=-11.845478137832359),
-        Variable(name="x", val=2),
+        Variable(name="x", val=2.0),
         Variable(name="y2", val=12.154521862167641),
         Variable(name="z", val=[5.0, 2.0], units="m**2"),
     ]
 
 
-def test_problem_read_inputs_with_ref_inputs(cleanup):
+def test_problem_read_inputs_after_setup(cleanup):
     """Tests what happens when reading inputs using existing XML with correct var"""
 
     problem = FASTOADProblem()
@@ -74,12 +77,31 @@ def test_problem_read_inputs_with_ref_inputs(cleanup):
 
     problem.setup()
 
-    assert problem.get_val(name="x", units=None) == [2.0]
-    assert np.all(problem.get_val(name="z", units="m**2") == [5.0, 2.0])
+    assert problem.get_val(name="x") == [2.0]
+    with pytest.raises(RuntimeError):
+        # Several default values are defined for "z", thus OpenMDAO raises an error that
+        # will be solved only after run_model() has been used.
+        _ = problem.get_val(name="z", units="m**2")
+
+    problem.read_inputs()
+
+    problem.run_model()
+    assert problem.get_val(name="x") == [2000.0]
+    assert_allclose(problem.get_val(name="z", units="m**2"), [5000, 2000.0])
+
+
+def test_problem_read_inputs_before_setup(cleanup):
+    """Tests what happens when reading inputs using existing XML with correct var"""
+
+    problem = FASTOADProblem()
+    problem.model.add_subsystem("sellar", Sellar(), promotes=["*"])
+
+    problem.input_file_path = pth.join(DATA_FOLDER_PATH, "ref_inputs.xml")
 
     problem.read_inputs()
+    problem.setup()
 
-    assert problem.get_val(name="x", units=None) == [2000.0]
+    assert problem.get_val(name="x") == [2000.0]
     assert np.all(problem.get_val(name="z", units="m**2") == [5000.0, 2000.0])
 
 
@@ -93,9 +115,109 @@ def test_problem_read_inputs_with_nan_inputs(cleanup):
 
     problem.input_file_path = pth.join(DATA_FOLDER_PATH, "nan_inputs.xml")
 
+    with pytest.raises(FASTOpenMDAONanInInputFile) as exc_info:
+        problem.read_inputs()
+        assert exc_info.value.input_file_path == input_data_path
+        assert exc_info.value.nan_variable_names == ["x"]
+
     problem.setup()
 
-    with pytest.raises(FASTOpenMDAONanInInputFile) as exc:
+    with pytest.raises(FASTOpenMDAONanInInputFile) as exc_info:
         problem.read_inputs()
-        assert exc.input_file_path == input_data_path
-        assert exc.nan_variable_names == ["x"]
+        assert exc_info.value.input_file_path == input_data_path
+        assert exc_info.value.nan_variable_names == ["x"]
+
+
+def test_problem_with_dynamically_shaped_inputs(cleanup):
+    class MyComp1(om.ExplicitComponent):
+        def setup(self):
+            self.add_input("x", shape_by_conn=True, copy_shape="y")
+            self.add_output("y", shape_by_conn=True, copy_shape="x")
+
+        def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
+            outputs["y"] = 10 * inputs["x"]
+
+    class MyComp2(om.ExplicitComponent):
+        def setup(self):
+            self.add_input("y", shape_by_conn=True, copy_shape="z")
+            self.add_output("z", shape_by_conn=True, copy_shape="y")
+
+        def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
+            outputs["z"] = 0.1 * inputs["y"]
+
+    # --------------------------------------------------------------------------
+    # With these 2 components, an OpenMDAO problem won't pass the setup due to
+    # the non-determined shapes
+    vanilla_problem = om.Problem()
+    vanilla_problem.model.add_subsystem("comp1", MyComp1(), promotes=["*"])
+    vanilla_problem.model.add_subsystem("comp2", MyComp2(), promotes=["*"])
+    with pytest.raises(RuntimeError):
+        vanilla_problem.setup()
+
+    # --------------------------------------------------------------------------
+    # ... But fastoad problem will do the setup and provide dummy shapes
+    # when needed
+    fastoad_problem = FASTOADProblem()
+    fastoad_problem.model.add_subsystem("comp1", MyComp1(), promotes=["*"])
+    fastoad_problem.model.add_subsystem("comp2", MyComp2(), promotes=["*"])
+    fastoad_problem.setup()
+    assert (
+        fastoad_problem["x"].shape
+        == fastoad_problem["y"].shape
+        == fastoad_problem["z"].shape
+        == (2,)
+    )
+
+    # In such case, reading inputs after the setup will make run_model fail, because dummy shapes
+    # have already been provided, and will probably not match the ones in input file.
+    fastoad_problem.input_file_path = pth.join(DATA_FOLDER_PATH, "dynamic_shape_inputs_1.xml")
+    fastoad_problem.read_inputs()
+    with pytest.raises(ValueError):
+        fastoad_problem.run_model()
+
+    # --------------------------------------------------------------------------
+    # If input reading is done before setup, all is fine.
+    fastoad_problem = FASTOADProblem()
+    fastoad_problem.model.add_subsystem("comp1", MyComp1(), promotes=["*"])
+    fastoad_problem.model.add_subsystem("comp2", MyComp2(), promotes=["*"])
+    fastoad_problem.input_file_path = pth.join(DATA_FOLDER_PATH, "dynamic_shape_inputs_1.xml")
+    fastoad_problem.read_inputs()
+    fastoad_problem.setup()
+
+    inputs = VariableList.from_problem(fastoad_problem, io_status="inputs")
+    assert inputs.names() == ["x"]
+    outputs = VariableList.from_problem(fastoad_problem, io_status="outputs")
+    assert outputs.names() == ["y", "z"]
+    variables = VariableList.from_problem(fastoad_problem)
+    assert variables.names() == ["x", "y", "z"]
+
+    fastoad_problem.run_model()
+
+    assert_allclose(fastoad_problem["x"], [1.0, 2.0, 5.0])
+    assert_allclose(fastoad_problem["y"], [10.0, 20.0, 50.0])
+    assert_allclose(fastoad_problem["z"], [1.0, 2.0, 5.0])
+
+    # --------------------------------------------------------------------------
+    # In the case variables are shaped from "downstream", OpenMDAO works OK.
+    class MyComp3(om.ExplicitComponent):
+        def setup(self):
+            self.add_input("z", shape=(3,))
+            self.add_output("a")
+
+        def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
+            outputs["a"] = np.sum(inputs["z"])
+
+    fastoad_problem = FASTOADProblem()
+    fastoad_problem.model.add_subsystem("comp1", MyComp1(), promotes=["*"])
+    fastoad_problem.model.add_subsystem("comp2", MyComp2(), promotes=["*"])
+    fastoad_problem.model.add_subsystem("comp3", MyComp3(), promotes=["*"])
+
+    inputs = VariableList.from_problem(fastoad_problem, io_status="inputs")
+    assert inputs.names() == ["x"]
+    outputs = VariableList.from_problem(fastoad_problem, io_status="outputs")
+    assert outputs.names() == ["y", "z", "a"]
+    variables = VariableList.from_problem(fastoad_problem)
+    assert variables.names() == ["x", "y", "z", "a"]
+
+    fastoad_problem.setup()
+    fastoad_problem.run_model()
diff --git a/src/fastoad/openmdao/tests/test_utils.py b/src/fastoad/openmdao/tests/test_utils.py
index 633be23de..c59d8c6b9 100644
--- a/src/fastoad/openmdao/tests/test_utils.py
+++ b/src/fastoad/openmdao/tests/test_utils.py
@@ -2,7 +2,7 @@
 Test module for OpenMDAO checks
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2022 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
@@ -76,11 +76,13 @@ def test_get_unconnected_input_names_sellar_components():
 
 
 def test_get_unconnected_input_names_full_sellar():
-    expected_mandatory_variables = set()
-    expected_optional_variables = set()
+    expected_mandatory_variables = {"Functions.z"}
+    expected_optional_variables = {"Disc1.z", "Disc2.z"}
     _test_problem(
         om.Problem(Sellar()), expected_mandatory_variables, expected_optional_variables, False
     )
+    expected_mandatory_variables = {"z"}
+    expected_optional_variables = set()
     _test_problem(
         om.Problem(Sellar()), expected_mandatory_variables, expected_optional_variables, True
     )
diff --git a/src/fastoad/openmdao/tests/test_variables.py b/src/fastoad/openmdao/tests/test_variables.py
index add72e743..13520cbb4 100644
--- a/src/fastoad/openmdao/tests/test_variables.py
+++ b/src/fastoad/openmdao/tests/test_variables.py
@@ -2,7 +2,7 @@
 Module for testing VariableList.py
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2022 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
@@ -188,7 +188,13 @@ def _compare_variable_lists(vars: List[Variable], expected_vars: List[Variable])
 def test_get_variables_from_problem_with_an_explicit_component():
     problem = om.Problem()
     problem.model.add_subsystem("disc1", Disc1(), promotes=["*"])
+
+    vars_before_setup = VariableList.from_problem(
+        problem, use_initial_values=False, get_promoted_names=True
+    )
     problem.setup()
+    vars = VariableList.from_problem(problem, use_initial_values=False, get_promoted_names=True)
+    assert vars_before_setup == vars
 
     expected_vars = [
         Variable(name="x", val=np.array([np.nan]), units=None, desc="input x", is_input=True),
@@ -197,7 +203,6 @@ def test_get_variables_from_problem_with_an_explicit_component():
         Variable(name="y1", val=np.array([1.0]), units=None, is_input=False, desc="variable y1"),
     ]
 
-    vars = VariableList.from_problem(problem, use_initial_values=False, get_promoted_names=True)
     _compare_variable_lists(vars, expected_vars)
 
 
@@ -206,7 +211,12 @@ def test_get_variables_from_problem_with_a_group():
     group.add_subsystem("disc1", Disc1(), promotes=["*"])
     group.add_subsystem("disc2", Disc2(), promotes=["*"])
     problem = om.Problem(group)
+    vars_before_setup = VariableList.from_problem(
+        problem, use_initial_values=False, get_promoted_names=True
+    )
     problem.setup()
+    vars = VariableList.from_problem(problem, use_initial_values=False, get_promoted_names=True)
+    assert vars_before_setup == vars
 
     expected_vars = [
         Variable(name="x", val=np.array([np.nan]), units=None, is_input=True, desc="input x"),
@@ -217,7 +227,6 @@ def test_get_variables_from_problem_with_a_group():
         ),
     ]
 
-    vars = VariableList.from_problem(problem, use_initial_values=False, get_promoted_names=True)
     _compare_variable_lists(vars, expected_vars)
 
 
@@ -763,9 +772,12 @@ def test_get_variables_from_problem_sellar_with_promotion_and_connect():
     group.connect("disc2.y2", "y2")
 
     problem = om.Problem(group)
+    vars_before_setup = VariableList.from_problem(
+        problem, use_initial_values=False, get_promoted_names=True
+    )
     problem.setup()
-
     vars = VariableList.from_problem(problem, use_initial_values=False, get_promoted_names=True)
+    assert vars_before_setup == vars
 
     # y1 and y2 should be outputs
     assert not vars["y1"].is_input
diff --git a/tests/integration_tests/oad_process/data/CeRAS01_legacy_mission_result.xml b/tests/integration_tests/oad_process/data/CeRAS01_legacy_mission_result.xml
index 2e0be12ba..5f5ad0725 100644
--- a/tests/integration_tests/oad_process/data/CeRAS01_legacy_mission_result.xml
+++ b/tests/integration_tests/oad_process/data/CeRAS01_legacy_mission_result.xml
@@ -1,6 +1,6 @@
 <!--
   ~ This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-  ~ Copyright (C) 2020  ONERA & ISAE-SUPAERO
+  ~ Copyright (C) 2022 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
@@ -590,6 +590,8 @@
     <aerodynamics>
       <aircraft>
         <cruise>
+          <CD is_input="False">[0.0208184022833719, 0.02082055396394672, 0.020828989948703466, 0.020843809367620102, 0.0208651113506746, 0.020892995027844922, 0.020927559529109022, 0.020968903984444877, 0.02101712752383045, 0.021072329277243698, 0.021134608374662592, 0.021204063946065096, 0.021280795121429167, 0.021364901030732786, 0.021456480803953897, 0.021555633571070477, 0.021662458462060486, 0.021777054606901894, 0.021899521135572655, 0.022029957178050747, 0.022168461864314124, 0.02231513432434075, 0.022470073688108598, 0.022633379085595626, 0.0228051496467798, 0.02298548450163909, 0.023174482780151447, 0.02337224361229484, 0.023578866128047243, 0.023794449457386613, 0.024019092730290913, 0.024252895076738112, 0.02449595562670618, 0.024748373510173064, 0.02501024785711674, 0.02528167779751517, 0.025564891742818997, 0.025862144667086688, 0.02617361594116239, 0.026499540289419286, 0.02684021063629316, 0.027195982207853527, 0.027567278010101455, 0.027954595848245254, 0.028358517100106412, 0.02877971751403842, 0.029218980369688858, 0.029677212421508274, 0.030155463143686237, 0.03065494791561501, 0.031177075934583746, 0.031723483824142, 0.03229607613118985, 0.03289707418341098, 0.03352907512518065, 0.03419512338236505, 0.03489879734718683, 0.03564431475257311, 0.03643666105828615, 0.03728174624638654, 0.03818659678262794, 0.039159591222520315, 0.040210750128605824, 0.041352093752021646, 0.042598084489685314, 0.043966175683962584, 0.04547749417921529, 0.047157691575383597, 0.04903800883006826, 0.05115661142565193, 0.053560268619214216, 0.056306471498646794, 0.05946611222942037, 0.06312688305735117, 0.06739760108888393, 0.07241372728943551, 0.07834443047084572, 0.08540165594011283, 0.09385180293911358, 0.10403080717793661, 0.11636368115190043, 0.13138990798574338, 0.14979654490586147, 0.17246151203199217, 0.2005103785495483, 0.2353910906814247, 0.2789726235651877, 0.33367563353868734, 0.4026460486411772, 0.4899864560777494, 0.5568009531046682, 0.5577657077233641, 0.5587456683442587, 0.55974093409733, 0.5607516041125561, 0.5617777775199146, 0.5628195534493838, 0.5638770310309417, 0.5649503093945659, 0.5660394876702347, 0.5671446649879258, 0.5682659404776175, 0.5694034132692873, 0.5705571824929138, 0.5717273472784743, 0.5729140067559473, 0.5741172600553103, 0.5753372063065415, 0.5765739446396191, 0.5778275741845206, 0.5790981940712244, 0.5803859034297081, 0.5816908013899498, 0.5830129870819275, 0.5843525596356192, 0.5857096181810028, 0.5870842618480561, 0.5884765897667574, 0.5898867010670845, 0.5913146948790153, 0.5927606703325279, 0.5942247265576001, 0.5957069626842102, 0.5972074778423356, 0.5987263711619549, 0.6002637417730455, 0.6018196888055857, 0.6033943113895535, 0.6049877086549265, 0.6065999797316832, 0.6082312237498011, 0.6098815398392583, 0.6115510271300328, 0.6132397847521028, 0.6149479118354458, 0.6166755075100402, 0.6184226709058637, 0.6201895011528942, 0.6219760973811099, 0.6237825587204886, 0.6256089843010082, 0.627455473252647, 0.6293221247053826, 0.6312090377891932, 0.6331163116340568, 0.6350440453699511, 0.6369923381268541, 0.6389612890347439, 0.6409509972235987, 0.6429615618233958]<!--Input defined by the mission.--><compressibility is_input="False">[0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.001025528490322346, 0.0010276577717950224, 0.0010340721788208763, 0.001044851952266096, 0.001060132686525893, 0.001080108176058095, 0.0011050345169542509, 0.0011352355852374634, 0.0011711100561380642, 0.0012131401774996004, 0.0012619025676975858, 0.0013180813764016425, 0.0013824842280843375, 0.0014560614669572966, 0.0015399293424348073, 0.001635397921828059, 0.0017440046987086473, 0.0018675550899986708, 0.0020081712934038637, 0.002168351323321527, 0.0023510404756398656, 0.002559718012603585, 0.002798502537161831, 0.0030722803790988957, 0.0033868623904974157, 0.0037491759071330683, 0.004167500354537878, 0.00465175716527602, 0.00521386746050672, 0.005868194507169543, 0.006632092517652276, 0.007526589206338793, 0.008577237043191297, 0.009815177855832573, 0.01127847799666732, 0.013013807592797168, 0.015078558602135845, 0.017543524060176063, 0.02049629708275611, 0.02404559564634274, 0.02832678158637488, 0.033508924584714314, 0.03980387081838143, 0.047477920399274925, 0.05686690990750556, 0.06839575270841378, 0.08260383279676002, 0.10017810826896235, 0.1219964001147802, 0.1491841783896485, 0.18318929018648408, 0.2258806115128753, 0.27967869957669433, 0.34772938328721664, 0.43413515071955644, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]<!--increment of drag coefficient due to compressibility effects (shock waves) w.r.t. data:aerodynamics:aircraft:cruise:CL--></compressibility><trim is_input="False">[0.0, 5.89e-06, 1.178e-05, 1.767e-05, 2.356e-05, 2.945e-05, 3.534e-05, 4.123e-05, 4.712e-05, 5.3009999999999996e-05, 5.89e-05, 6.479e-05, 7.068e-05, 7.657000000000001e-05, 8.246e-05, 8.834999999999999e-05, 9.424e-05, 0.00010013, 0.00010601999999999999, 0.00011191, 0.0001178, 0.00012369, 0.00012958, 0.00013547, 0.00014136, 0.00014725, 0.00015314000000000001, 0.00015903, 0.00016492, 0.00017081, 0.00017669999999999999, 0.00018259, 0.00018848, 0.00019437, 0.00020026, 0.00020615000000000002, 0.00021203999999999998, 0.00021793, 0.00022382, 0.00022971000000000002, 0.0002356, 0.00024149000000000002, 0.00024738, 0.00025327, 0.00025916, 0.00026505, 0.00027094, 0.00027683000000000004, 0.00028272, 0.00028861, 0.0002945, 0.00030039, 0.00030628000000000003, 0.00031217, 0.00031806, 0.00032395000000000004, 0.00032984, 0.00033573, 0.00034162, 0.00034751, 0.00035339999999999997, 0.00035929, 0.00036518, 0.00037107, 0.00037696, 0.00038285, 0.00038874, 0.00039463000000000004, 0.00040052, 0.00040641000000000006, 0.00041230000000000005, 0.00041819, 0.00042407999999999996, 0.00042997, 0.00043586, 0.00044175, 0.00044764, 0.00045353, 0.00045942000000000004, 0.00046531000000000003, 0.0004712, 0.00047709000000000006, 0.00048298000000000004, 0.0004888700000000001, 0.00049476, 0.0005006499999999999, 0.00050654, 0.00051243, 0.00051832, 0.00052421, 0.0005301, 0.00053599, 0.00054188, 0.00054777, 0.0005536600000000001, 0.00055955, 0.00056544, 0.00057133, 0.00057722, 0.00058311, 0.000589, 0.00059489, 0.00060078, 0.00060667, 0.0006125600000000001, 0.00061845, 0.00062434, 0.0006302300000000001, 0.00063612, 0.00064201, 0.0006479000000000001, 0.00065379, 0.00065968, 0.0006655700000000001, 0.00067146, 0.0006773500000000001, 0.00068324, 0.0006891299999999999, 0.00069502, 0.00070091, 0.0007067999999999999, 0.00071269, 0.00071858, 0.00072447, 0.00073036, 0.00073625, 0.00074214, 0.00074803, 0.00075392, 0.00075981, 0.0007657, 0.0007715900000000001, 0.00077748, 0.00078337, 0.0007892600000000001, 0.0007951500000000001, 0.00080104, 0.0008069300000000001, 0.0008128200000000001, 0.00081871, 0.0008246000000000001, 0.0008304899999999999, 0.00083638, 0.00084227, 0.0008481599999999999, 0.00085405, 0.00085994, 0.0008658299999999999, 0.00087172, 0.00087761]<!--increment of drag coefficient due to aircraft trim w.r.t. data:aerodynamics:aircraft:cruise:CL--></trim></CD>
+          <CL is_input="False">[0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35000000000000003, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41000000000000003, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47000000000000003, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.5700000000000001, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.6900000000000001, 0.7000000000000001, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.8200000000000001, 0.8300000000000001, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.9400000000000001, 0.9500000000000001, 0.96, 0.97, 0.98, 0.99, 1.0, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, 1.1300000000000001, 1.1400000000000001, 1.1500000000000001, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, 1.36, 1.37, 1.3800000000000001, 1.3900000000000001, 1.4000000000000001, 1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, 1.49]<!--Input defined by the mission.--></CL>
           <CL_alpha>6.41798064378<!--derivative of lift coefficient with respect to angle of attack in cruise conditions--></CL_alpha>
           <L_D_max>16.306202106<!--max lift/drag ratio in cruise conditions--></L_D_max>
         </cruise>
@@ -599,6 +601,8 @@
           <CL_max_clean_2D>1.94</CL_max_clean_2D>
         </landing>
         <takeoff>
+          <CD is_input="False">[0.0451807533274431, 0.0455508789449031, 0.0459265487940891, 0.04630787161405342, 0.046694956143848415, 0.04708791112252643, 0.047486845289139795, 0.047891867382740864, 0.04830308614238197, 0.04872061030711546, 0.04914454861599369, 0.049575009808068976, 0.05001210262239369, 0.05045593579802015, 0.05090661807400071, 0.05136425818938771, 0.05182896488323349, 0.05230084689459041, 0.05278001296251078, 0.053266571826046966, 0.053760632224251315, 0.054262302896176146, 0.05477169258087383, 0.055288910017396685, 0.05581406394479707, 0.05634726310212733, 0.056888616228439784, 0.05743823206278679, 0.057996219344220695, 0.05856268681179384, 0.05913774320455857, 0.05972149726156721, 0.06031405772187212, 0.060915533324525636, 0.061526032808580114, 0.062145664913087865, 0.06277453837710126, 0.06341276193967263, 0.06406044433985432, 0.06471769431669869, 0.06538462060925804, 0.06606133195658474, 0.06674793709773114, 0.06744454477174959, 0.0681512637176924, 0.06886820267461193, 0.06959547038156051, 0.07033317557759051, 0.07108142700175425, 0.07184033339310408, 0.07261000349069234, 0.07339054603357138, 0.07418206976079353, 0.07498468341141114, 0.07579849572447656, 0.07662361543904211, 0.07746015129416016, 0.07830821202888305, 0.07916790638226306, 0.08003934309335264, 0.08092263090120405, 0.0818178785448697, 0.08272519476340184, 0.0836446882958529, 0.08457646788127515, 0.08552064225872102, 0.08647732016724277, 0.08744661034589282, 0.08842862153372341, 0.089423462469787, 0.09043124189313581, 0.09145206854282227, 0.09248605115789871, 0.09353329847741745, 0.09459391924043085, 0.09566802218599126, 0.09675571605315098, 0.09785710958096241, 0.09897231150847785, 0.10010143057474966, 0.10124457551883019, 0.10240185507977174, 0.10357337799662672, 0.10475925300844742, 0.1059595888542862, 0.10717449427319538, 0.10840407800422737, 0.10964844878643444, 0.11090771535886898, 0.11218198646058329, 0.11347137083062978, 0.11477597720806068, 0.11609591433192847, 0.11743129094128535, 0.11878221577518382, 0.12014879757267606, 0.12153114507281453, 0.12292936701465151, 0.1243435721372394, 0.1257738691796305, 0.12722036688087715, 0.12868317398003168, 0.13016239921614653, 0.13165815132827388, 0.13317053905546625, 0.13469967113677583, 0.13624565631125504, 0.13780860331795625, 0.13938862089593174, 0.14098581778423386, 0.14260030272191496, 0.14423218444802743, 0.14588157170162352, 0.14754857322175566, 0.14923329774747615, 0.15093585401783732, 0.15265635077189155, 0.15439489674869114, 0.1561516006872885, 0.15792657132673593, 0.15971991740608577, 0.16153174766439032, 0.163362170840702, 0.16521129567407317, 0.1670792309035561, 0.16896608526820311, 0.17087196750706662, 0.17279698635919893, 0.17474125056365242, 0.1767048688594794, 0.17868794998573218, 0.18069060268146317, 0.18271293568572472, 0.1847550577375691, 0.18681707757604868, 0.18889910394021583, 0.1910012455691229, 0.19312361120182214, 0.19526630957736602, 0.1974294494348068, 0.19961313951319687, 0.20181748855158846, 0.20404260528903406, 0.20628859846458597, 0.2085555768172965, 0.21084364908621803, 0.21315292401040284, 0.21548351032890334, 0.21783551678077184, 0.2202090521050607]<!--Input defined by the mission.--></CD>
+          <CL is_input="False">[0.5117266638080304, 0.5217266638080305, 0.5317266638080305, 0.5417266638080305, 0.5517266638080305, 0.5617266638080305, 0.5717266638080305, 0.5817266638080305, 0.5917266638080304, 0.6017266638080304, 0.6117266638080304, 0.6217266638080304, 0.6317266638080304, 0.6417266638080305, 0.6517266638080305, 0.6617266638080305, 0.6717266638080305, 0.6817266638080305, 0.6917266638080304, 0.7017266638080304, 0.7117266638080304, 0.7217266638080304, 0.7317266638080304, 0.7417266638080304, 0.7517266638080304, 0.7617266638080304, 0.7717266638080305, 0.7817266638080305, 0.7917266638080305, 0.8017266638080305, 0.8117266638080305, 0.8217266638080305, 0.8317266638080305, 0.8417266638080305, 0.8517266638080305, 0.8617266638080305, 0.8717266638080304, 0.8817266638080304, 0.8917266638080305, 0.9017266638080305, 0.9117266638080305, 0.9217266638080305, 0.9317266638080304, 0.9417266638080304, 0.9517266638080304, 0.9617266638080304, 0.9717266638080304, 0.9817266638080304, 0.9917266638080304, 1.0017266638080304, 1.0117266638080304, 1.0217266638080305, 1.0317266638080305, 1.0417266638080305, 1.0517266638080305, 1.0617266638080305, 1.0717266638080305, 1.0817266638080305, 1.0917266638080303, 1.1017266638080305, 1.1117266638080303, 1.1217266638080305, 1.1317266638080303, 1.1417266638080306, 1.1517266638080303, 1.1617266638080306, 1.1717266638080304, 1.1817266638080306, 1.1917266638080304, 1.2017266638080306, 1.2117266638080304, 1.2217266638080304, 1.2317266638080304, 1.2417266638080304, 1.2517266638080304, 1.2617266638080304, 1.2717266638080305, 1.2817266638080305, 1.2917266638080305, 1.3017266638080305, 1.3117266638080305, 1.3217266638080305, 1.3317266638080305, 1.3417266638080305, 1.3517266638080305, 1.3617266638080303, 1.3717266638080305, 1.3817266638080303, 1.3917266638080306, 1.4017266638080303, 1.4117266638080306, 1.4217266638080304, 1.4317266638080306, 1.4417266638080304, 1.4517266638080306, 1.4617266638080304, 1.4717266638080304, 1.4817266638080304, 1.4917266638080304, 1.5017266638080304, 1.5117266638080304, 1.5217266638080305, 1.5317266638080305, 1.5417266638080305, 1.5517266638080305, 1.5617266638080305, 1.5717266638080305, 1.5817266638080305, 1.5917266638080305, 1.6017266638080305, 1.6117266638080305, 1.6217266638080305, 1.6317266638080306, 1.6417266638080306, 1.6517266638080306, 1.6617266638080306, 1.6717266638080304, 1.6817266638080304, 1.6917266638080304, 1.7017266638080304, 1.7117266638080304, 1.7217266638080304, 1.7317266638080304, 1.7417266638080304, 1.7517266638080304, 1.7617266638080304, 1.7717266638080305, 1.7817266638080305, 1.7917266638080305, 1.8017266638080305, 1.8117266638080305, 1.8217266638080305, 1.8317266638080305, 1.8417266638080305, 1.8517266638080305, 1.8617266638080305, 1.8717266638080305, 1.8817266638080306, 1.8917266638080306, 1.9017266638080306, 1.9117266638080306, 1.9217266638080304, 1.9317266638080304, 1.9417266638080304, 1.9517266638080304, 1.9617266638080304, 1.9717266638080304, 1.9817266638080304, 1.9917266638080304, 2.0017266638080304]<!--Input defined by the mission.--></CL>
           <CL0_clean>0.2<!--value of lift coefficient at angle of attack 0 in clean configuration at takeoff--></CL0_clean>
           <CL_alpha>4.949271<!--derivative of lift coefficient with respect to angle of attack in takeoff conditions--></CL_alpha>
         </takeoff>
diff --git a/tests/integration_tests/oad_process/data/oad_process_mission_only.yml b/tests/integration_tests/oad_process/data/oad_process_mission_only.yml
index c81832102..34a9c0ac1 100644
--- a/tests/integration_tests/oad_process/data/oad_process_mission_only.yml
+++ b/tests/integration_tests/oad_process/data/oad_process_mission_only.yml
@@ -8,15 +8,6 @@ output_file: ./oad_process_mission_outputs.xml
 model:
   nonlinear_solver: om.NonlinearBlockGS(maxiter=100, atol=1e-2)
   linear_solver: om.DirectSolver()
-  aerodynamics_highspeed:
-    id: fastoad.aerodynamics.highspeed.legacy
-  aerodynamics_lowspeed:
-    id: fastoad.aerodynamics.lowspeed.legacy
-  aerodynamics_takeoff:
-    id: fastoad.aerodynamics.takeoff.legacy
-  aerodynamics_landing:
-    id: fastoad.aerodynamics.landing.legacy
-    use_xfoil: false
   performance:
         id: fastoad.performances.mission
         propulsion_id: fastoad.wrapper.propulsion.rubber_engine