Comments (10)
@madMatchstick, we could also consider more elegant solutions in the future. I can't track it down at the moment, but I believe one of the Kratzert papers suggested limiting runoff to an observed baseflow value. We could then predict this for ungaged basins using the CAMELS attribute sets.
For now, though, I agree with your suggestion on where to put the logic that prevents negative values.
def scale_output(self):
if self.cfg_train['target_variables'][0] == 'qobs_mm_per_hour':
self.surface_runoff_mm = (self.lstm_output[0,0,0].numpy().tolist() * self.out_std + self.out_mean)
elif self.cfg_train['target_variables'][0] == 'QObs(mm/d)':
self.surface_runoff_mm = (self.lstm_output[0,0,0].numpy().tolist() * self.out_std + self.out_mean) * (1/24)
if self.surface_runoff_mm < 0: self.surface_runoff_mm = 0
self._values['land_surface_water__runoff_depth'] = self.surface_runoff_mm/1000.0
setattr(self, 'land_surface_water__runoff_depth', self.surface_runoff_mm/1000.0)
self.streamflow_cms = self.surface_runoff_mm * self.output_factor_cms
self._values['land_surface_water__runoff_volume_flux'] = self.streamflow_cms
setattr(self, 'land_surface_water__runoff_volume_flux', self.streamflow_cms)
from lstm.
There are two bmi outputs in this lstm model, land_surface_water__runoff_volume_flux
& land_surface_water__runoff_depth
. Called in bmi.update()
, we have scaled_output()
,
def scale_output(self):
if self.cfg_train['target_variables'][0] == 'qobs_mm_per_hour':
self.surface_runoff_mm = (self.lstm_output[0,0,0].numpy().tolist() * self.out_std + self.out_mean)
elif self.cfg_train['target_variables'][0] == 'QObs(mm/d)':
self.surface_runoff_mm = (self.lstm_output[0,0,0].numpy().tolist() * self.out_std + self.out_mean) * (1/24)
self._values['land_surface_water__runoff_depth'] = self.surface_runoff_mm/1000.0
setattr(self, 'land_surface_water__runoff_depth', self.surface_runoff_mm/1000.0)
self.streamflow_cms = self.surface_runoff_mm * self.output_factor_cms
self._values['land_surface_water__runoff_volume_flux'] = self.streamflow_cms
setattr(self, 'land_surface_water__runoff_volume_flux', self.streamflow_cms)
@peckhams I believe the most appropriate place to apply the lower bound is just after the if-else
statement? Id est
if self.surface_runoff_mm < 0: self.surface_runoff_mm = 0
This way, both outputs are guaranteed a positive value.
from lstm.
I can't track it down at the moment, but I believe one of the Kratzert papers suggested limiting runoff to an observed baseflow value.
@SnowHydrology, is this the paper you are after? Section 3.2 Using LSTMs as hydrological models states, about Fig 9,
A rather simple solution for this issue is to introduce just one additional parameter and to limit the simulated discharge not to zero, but to the minimum observed flow from the calibration period
Also, from A glimpse into the Unobserved: Runoff simulation for ungauged catchments with LSTMs, section 2.2 Model,
Furthermore, because negative predictions of the runoff are physically implausible, we clip negative
predictions to 0.
To your point, let's just set lower bound to zero for now :)
from lstm.
@madMatchstick thanks for tracking that down. And agreed on the fix for now.
from lstm.
There are two bmi outputs in this lstm model,
land_surface_water__runoff_volume_flux
&land_surface_water__runoff_depth
. Called inbmi.update()
, we havescaled_output()
,def scale_output(self): if self.cfg_train['target_variables'][0] == 'qobs_mm_per_hour': self.surface_runoff_mm = (self.lstm_output[0,0,0].numpy().tolist() * self.out_std + self.out_mean) elif self.cfg_train['target_variables'][0] == 'QObs(mm/d)': self.surface_runoff_mm = (self.lstm_output[0,0,0].numpy().tolist() * self.out_std + self.out_mean) * (1/24) self._values['land_surface_water__runoff_depth'] = self.surface_runoff_mm/1000.0 setattr(self, 'land_surface_water__runoff_depth', self.surface_runoff_mm/1000.0) self.streamflow_cms = self.surface_runoff_mm * self.output_factor_cms self._values['land_surface_water__runoff_volume_flux'] = self.streamflow_cms setattr(self, 'land_surface_water__runoff_volume_flux', self.streamflow_cms)
@peckhams I believe the most appropriate place to apply the lower bound is just after the
if-else
statement? Id estif self.surface_runoff_mm < 0: self.surface_runoff_mm = 0
This way, both outputs are guaranteed a positive value.
from lstm.
This seems fine here, but I would normally do this kind of thing with the following syntax:
np.maximum( self.surface_runoff_mm, 0, self.surface_runoff_mm)
This numpy function says to replace the value with whichever is bigger, the value or 0, and to write the new value "in-place" (in the same memory location). A numpy function is compiled C code, so a Python conditional (if-then-else) will likely be slower. Since the statement gets evaluated many times, this speed difference can add up.
from lstm.
And this syntax works the same for variables that are scalars or n-dimensional arrays.
from lstm.
@peckhams Thanks for that explanation. A fair bit of Fortran code is written with that syntax, as well. Is it common for a compiled language's max
statement to be faster than its if-else
function?
from lstm.
For compiled languages (vs. an interpreted language like Python), it may not matter. But to get maximum performance from Python code, you want to use compiled numpy (or other) functions whenever possible. Several of the numpy functions, like maximum, have an optional third argument, which is the memory location to place the result -- in this case, overwriting in-place. Note the syntax; it's not of the form: self.x = np.maximum(self.x, 0), but rather just: np.maximum(self.x, 0, self.x). When modifying a variable, especially if it's a big array, you want to just overwrite the same memory location, which is faster. Another example of this kind of in-place modification is: self.x[:] = self.x + dx; instead of self.x = self.x + dx.
from lstm.
@peckhams Thanks for suggestion. I'll use this method,
np.maximum( self.surface_runoff_mm, 0, self.surface_runoff_mm)
from lstm.
Related Issues (20)
- Decide on an output unit, and make output available in get_value HOT 1
- Option to run as sequence-to-one and sequence-to-sequence HOT 5
- Add functions for read_initial_state and save_current_state HOT 4
- put serialization example in a .py file HOT 2
- Get rid of the second basin area variable HOT 17
- Temperature should actually be in kelvin HOT 2
- Ensure correct implementations for getter and setter functions HOT 2
- Using newly trained lstm models HOT 7
- Config file path should be type string HOT 1
- Simulated output in jupyter notebooks
- csdms standard name for precip HOT 2
- Broken link to example configuration file HOT 1
- GH Actions Fail for py v3.7 HOT 13
- Add ngen integration workflow to gh actions HOT 3
- Set_value functionality is mostly commented out. HOT 18
- Compatibility with heat model example from CSDMS HOT 7
- Unit Test Workflow Fails; NumPy v2.0
- Initialize all the possible forcings, and don't hard code any specific forcings. HOT 1
- set_values_dictionary is redundant, get rid of it and organize input values from _values HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from lstm.