unifhy-org / unifhy

A Unified Framework for Hydrology
https://unifhy-org.github.io/unifhy
BSD 3-Clause "New" or "Revised" License
11 stars 5 forks source link

Bug when using DataComponent #87

Closed ThibHlln closed 1 year ago

ThibHlln commented 1 year ago

When putting together a Model containing a DataComponent, the instantiation fails because it finds a mismatch between the outwards of the DataComponent and the inwards of a "real" Component. For example, if subsurface is a successfully instantiated DataComponent and openwater is some successfully instantiated OpenWaterComponent, the following error message is thrown:

File ~/anaconda3/envs/unifhy/lib/python3.9/site-packages/unifhy/model.py:126, in Model._check_components_plugging(self)
    123 print(src.outwards_info)
    124 if (trf not in src.outwards_info
    125         or cat not in src.outwards_info[trf]['to']):
--> 126     raise RuntimeError(
    127         f"{cat} component inward transfer '{trf}' "
    128         f"not available from {src.category} component"
    129     )

RuntimeError: openwater component inward transfer 'surface_runoff_flux_delivered_to_rivers' not available from subsurface component

I believe that this behaviour exists since https://github.com/unifhy-org/unifhy/pull/76. This is due to the fact that the framework components SurfaceLayerComponent/SubSurfaceComponent/OpenWaterComponent define their interfaces in their _inwards_info and _outwards_info, but they do not assign anything to their _inwards and _outwards attributes (which are the new attributes introduced in #76 to allow contributors to create components only featuring subsets of the inwards/outwards). But then the property outwards_info of MetaComponent has a condition to only return those outwards that are actually produced by the component (as listed in _outwards attribute), see: https://github.com/unifhy-org/unifhy/blob/26fa890c524b2815edaaa012d157511e098f1d2c/unifhy/component.py#L61-L66

So for the case of a DataComponent getting its outwards and outwards_info from the substituted component, i.e. either SurfaceLayerComponent, SubSurfaceComponent, or OpenWaterComponent, it gets an empty dict for outwards even though it is getting a non empty outwards_info. This is why the metaclass property returns an empty dictionary too.

This behaviour has not been picked up by the unit tests because the DataComponent we use in there are substituting for our dummy Components whose interfaces are intentionally overwritten, and unlike in the actual framework components, _inwards and _outwards are populated this time, see e.g.: https://github.com/unifhy-org/unifhy/blob/26fa890c524b2815edaaa012d157511e098f1d2c/tests/tests/components/surfacelayer/dummy.py#L50-L58

Credit and thank you go to @mattjbr123 for reporting and diagnosing this one.