openearth / glofrim

Globally Applicable Framework for Integrated Hydrological-Hydrodynamic Modelling (GLOFRIM)
GNU General Public License v3.0
49 stars 28 forks source link

implement water balance #92

Closed JannisHoch closed 5 years ago

JannisHoch commented 5 years ago

Since results show slightly lower simulated discharge with LFP than with other models, we need to make a first-order water balance for the PCR->CMF->LFP run, also to be able to cope with reviewer comments.

To that end, some steps are required:

DirkEilander commented 5 years ago

i've tested this for the Elbe PCR2CMF2LFP test case. It seems that after a year, the CMF2LFP exchange is 16% less in volume than the PCR2CMF exchange. This could be because part of the water leafs the CMF domain elsewhere. We would need to keep of outflows from CMF additionally.

@ChippChapp: could you test with Bangladesh?

JannisHoch commented 5 years ago

hi @DirkEilander thanks for testing, I'll check for Bangladesh asap! Can you maybe add a plot or file to show your findings?

I am wondering why that is as 16% is rather significant I'd say. Indeed, the volumes exchanged between PCR and CMF and CMF and LFP, respectively, do not need to match since LFP can be discretized for only a fraction of the CMF domain. I think the "correct" test should be whether the volumes from PCR are identical to those coupled to CMF, and those from CMF identical to those coupled to LFP; i.e. not for the entire coupling change PCR->CMF->LFP but only per exchange. Wouldn't that make more sense? And do we already get this information from the added code?

JannisHoch commented 5 years ago

@DirkEilander important notice: the requirements.txt file needs updating since the WB calculations make use of pandas. Otherwise users may end up with compatibility issues between packages.

DirkEilander commented 5 years ago

In my opinion the scripts (maybe apart from glofrim_runner.py) are not necessarily part of the package itself, but just examples of how one could use the package. These examples may include new/other packages.

JannisHoch commented 5 years ago

Fair point, but think it's bit odd to have convenience scripts in the GLOFRIM package which cannot be executed with the requirement.txt in the same package. So for the scripts we will deliver together with the GLOFRIM code, the requirement.txt should cover the needed dependencies.

DirkEilander commented 5 years ago

Basically what I'm trying to say is that there is just one convience script (glofrim_runner.py) which should be covered by the requirements.txt and the other scripts are more like examples. The examples and the extra packages these use are not actually required to run glofrim and can be left out of the requirements.txt. This will also help to keep the dependencies to a minimum. If we start including all packages which are used by examples we would also need to add e.g. cartopy and bokeh which are used in the demo notebook .

JannisHoch commented 5 years ago

now I get what you want to say :) Agreed, we stick with glofrim_runner.py as the only convenience script and use the wb-version as example for possible extension/alterations of the script. Nice!

DirkEilander commented 5 years ago

I'm testing a slightly different approach to track the water balance. I'm keeping track of the total volume of water exchanged per exchange as well as the total volume of water which goes in and out of each model. To do the latter, we should should try to implement a "_get_tot_volume_out" and "_get_tot_volume_in" function for each mode (so far PCR and CMF). For instance for CMF the functions are given below. We could implement similar function to get the change in storage. But, if we assume the change in storage is neglectable over long periods we can get the approximate mass balance per model. To get the volume of water leaving the CMF outside the LFP/DFM domain we simply can substract the volume exchanged from the CMF model from the total outlfow.

def _get_tot_volume_in(self):
    # runoff in [m3/s]
    Rin = np.nansum(self.get_value('runoff')) * self._dt.total_seconds()
    return Rin

def _get_tot_volume_out(self):
    # get outlfow at pits
    Qout = np.nansum(self.get_value_at_indices('outflw', self.grid.pits)) * self._dt.total_seconds()
    return Qout

I'm doing some test runs and will update later ...