-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Water demand #226
Water demand #226
Conversation
code also useful for rootingdepth, but should require additional information before being useful for wflow
Thanks for adding irrigation and crop factor maps @JoostBuitink ! For a test version I think it would be good to also add a soil profile for irrigated paddy areas: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice developments @dalmijn and @JoostBuitink ! And a good start to get demand data from pcr_globwb or irrigation/paddy areas!
I reviewed mainly the functions from @dalmijn, as I don't think setup_irrigation
is fully done yet.
There's a few comments and suggestions here and there. Maybe one function I did not fully understand is how the allocation areas are derived so would be happy to discuss further!
hydromt_wflow/wflow.py
Outdated
def setup_allocation( | ||
self, | ||
min_area: float | int = 0, | ||
admin_bounds_fn: str = "gadm", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are cleaning this up still for wflow but we do not want to assume a default dataset value anymore, they are just mandatory arguments :) the example from artifact_data can be mentioned in the examples. Which might be good to add here! (update water demands example to showcase the new methods)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed!
hydromt_wflow/wflow.py
Outdated
self, | ||
min_area: float | int = 0, | ||
admin_bounds_fn: str = "gadm", | ||
admin_level: int = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is too specific to gadm and people should be able to use their own geometry. I think in the data catalog, it's actually gadm_level1 that you can call so just use this in admin_bounds_fn (in testing / examples).
Possibly you can add **kwargs here to the get_geodataframe method so that a user is able to select a specific layer in their data via the driver_kwargs (if they did not do that in their own data catalog)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.
hydromt_wflow/wflow.py
Outdated
@@ -2494,6 +2498,292 @@ def setup_rootzoneclim( | |||
# update config | |||
self.set_config("input.vertical.rootingdepth", update_toml_rootingdepth) | |||
|
|||
def setup_allocation( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def setup_allocation( | |
def setup_allocation_areas( |
To match better wflow names. Makes it also clearer for me that you are only preparing areas here not demand or actual allocation data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
hydromt_wflow/wflow.py
Outdated
|
||
def setup_non_irigation( | ||
self, | ||
non_irigation_fn: str = "pcr_globwb", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either None if optional or required argument
non_irigation_fn: str = "pcr_globwb", | |
non_irigation_fn: Union[str, Path, xr.Dataset], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed.
hydromt_wflow/workflows/demand.py
Outdated
sub_basins = sub_basins.dissolve("uid", sort=False, as_index=False) | ||
_count += 1 | ||
|
||
alloc = full_like(ds_like["dem_subgrid"], nodata=-9999, lazy=True).astype(int) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why dem_subgrid? If kinematic wave models, I'm not event sure the map is available... "wflow_dem" or "wflow_ldd" or "wflow_subcatch" are safer as they should always be there (especially wflow_subcatch that you should actually use rather than self.basins actually as self.basins is unfortunately basins at merit_hydro resolution rather than wflow model resolution...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the code to no longer rely on dem_subgrid
. Other remark about self.basins vs. wflow_subcatch is still open I guess
hydromt_wflow/workflows/demand.py
Outdated
ds_like.raster.bounds, | ||
) | ||
|
||
# Create dummy dataset from this info |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is to ensure better mass conservation? Ie you are not creating or removing m3 just because or up or downscaling? Then I think it's nice to apply to not just domestic demand.
If you make a nice enough I would also move this to hydromt core. It's useful to have this kind of mass conservation reprojection for water demands or population or livestock or any count data :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite sure anymore what this is referring to.
some todo's still open, but contains all required functionality
They both point to the same map currently
ToDo's still open:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First comments from the review, mainly for allocation_areas
and surfacewaterfrac
and docs. I will continue tomorrow or later this week for the other functions.
I also ran the example notebook and it looks really good!
I have one comment already on setup_irrigation
from that notebook: to simplify inputs, I think it would be good to have consistent maps for the irrigated areas. I assume anyway wflow internally will not apply crop_factor or irrigation_trigger for non irrigated lands but would be good to also then get consistent maps from hydromt on this to better understand what really happens in Wflow.jl
docs/changelog.rst
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes from this PR should move to the unreleased section
docs/user_guide/wflow_update.rst
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also need to update the table in docs/user_guide/wflow_model_setup.rst to include the new setup methods
hydromt_wflow/workflows/demand.py
Outdated
# Get the fractions based on area count | ||
w_pixels = np.take( | ||
np.bincount( | ||
waterareas_mr.values[x, y], | ||
weights=gwbodies_mr.values[x, y], | ||
), | ||
waterareas_mr.values[x, y], | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little reluctant to use numpy instead of xarray and if I understand bincount well if you have poorly named waterareas you may get bins from a very wide range of numbers (eg two basins with id 1 and 1000 or more).
Could you maybe use a groupby and count? https://docs.xarray.dev/en/stable/generated/xarray.DataArray.groupby.html
If too complex this is okay for now
hydromt_wflow/workflows/demand.py
Outdated
gwfrac_val = np.minimum( | ||
gwfrac_raw_mr.values[x, y] * (a_pixels / (w_pixels + 0.01)), | ||
1 - ncfrac_mr.values[x, y], | ||
) | ||
gwfrac_val[np.where(gwbodies_mr.values[x, y] == 0)] = 0 | ||
# invert to get surface water frac | ||
gwfrac_val = 1 - gwfrac_val |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I need to read the paper but I would say sw_frac = 1 - gwfrac - ncfrac no?
But here let's say gwfrac is 0.4 and ncfrac 0.2 then swfrac is 0.6 and not 0.4?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Second batch of comments ^^' only a couple of workflow functions I still need to go through.
hydromt_wflow/wflow.py
Outdated
if "time" in data.dims: | ||
tname = "time" | ||
time_axes = { | ||
k: v for k, v in dict(self.grid.dims).items() if k.startswith("time") | ||
} | ||
if data["time"].size not in time_axes.values(): | ||
tname = f"time_{data['time'].size}" if "time" in time_axes else tname | ||
else: | ||
k = list( | ||
filter(lambda x: time_axes[x] == data["time"].size, time_axes) | ||
)[0] | ||
tname = k | ||
|
||
if tname != "time": | ||
data = data.rename_dims({"time": tname}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this??
Does Wflow supports new types of cyclic inputs?
Is this really needed or can't we standardize in the workflows?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well review is complete!
This is a massive amount of work and very important so well done to you both :)
I (of course) have some comments from the "hydromt" and user side so let's discuss the main feedbacks from the review together.
A recap here of the main TODOS / things to discuss:
- Update changelog
- Update setup methods table for wflow in the docs
- Replace key
[input.vertical.waterallocation]
with[input.vertical.allocation]
- Add setup_surfacewater to example
- Use of _MAPS dictionnary
- All setup methods: document required variables and units in the input datasets
- Setup_irrigation: Vertical.paddy h_min, h_opt, h_max do not appear in toml
- Discuss renaming of the following methods:
setup_allocation_areas
,setup_surfacewaterfrac
,setup_non_irrigation
- Discuss the implementation of
setup_allocation_areas
: intersection is good but would like to discuss deriving the subbasins after that - Discuss the implementation of
setup_surfacewaterfrac
: default values and mistake in the calculation method? + take out the preparation of the allocation areas map? - Discuss the implementation of
setup_non_irrigation
: resampling method and use of an extra low res grid (res_factor !=0) - Discuss the implementation of
setup_irrigation
: Split for paddy and non-paddy? Simplify arguments (and code)? Harmonise crop_factor and irrigation_trigger - Discuss the implementation of
set_grid
: multiple time dims in wflow staticmaps? - Optional ie something from the Wflow.jl side or just a new hydromt feature that becomes more than nice to have for v1 of wflow: new TOML arguments are even more "subdivided"
Finally, when all comments are addressed:
- Do a check that the produced model does indeed run with the latest version of the wflow code
hydromt_wflow/workflows/demand.py
Outdated
_count = 0 | ||
|
||
# Create touched and not touched by rivers datasets | ||
while True: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And why not the outflow_idxs method above instead of your long while loop? You have to trust the user to use an uparea threshold more than their river but it's already the case for the setup_floodplains method so we can actually do a check on this in the setup method first :)
Unless you would like to allow for exchanges between subbasins in terms of water allocation areas? I guess this would mainly be for small coastal basins as in your example above?
Then you can maybe decide to interpolate/extrapolate with nearest neighbor?
Co-authored-by: hboisgon <[email protected]>
Co-authored-by: hboisgon <[email protected]>
Co-authored-by: hboisgon <[email protected]>
Now includes fix when layers have a different dimension, and includes a better docstring
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice work, and great additions to make the code more flexible and easier to use! Just some very small comments!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ready to merge
Issue addressed
Fixes #87
Explanation
Explain how you addressed the bug/feature request, what choices you made and why.
Checklist
main
Additional Notes (optional)
Add any additional notes or information that may be helpful.