Closed rburghol closed 1 year ago
@jdkleiner I want to get some proposed ways forward on this one, specifically to address the goal in the 2nd bullet.
Thoughts:
Dict
called state
(in addition to ui
and ts
) for exchanging values such as OUTDGT
specl()
are responsible for setting things into state such as OUTDGT
which have been explicitly separated from the ts Dict
by the calling function (as is done by _hydr_
) specl()
to automatically populate the state
variable based on a list of local state variables of interest (also used by specl
to limit the computations to only those variables that are used by the calling function)@rburghol
I think the idea of using a separate state
dictionary is sensible. I had some trouble running hsp2 last week, but all seems to be running smoothly this morning! I plan on focusing on this today, so should be able to test the bullets you've proposed here and will report back on progress.
@rburghol
ts
dictionary is an input to hydr()
ts
dictionary has many keys including OUTDGT1
and OUTDGT2
OUTDGT
is a NumPy array created from ts
within hydr()
OUTDGT
is a two dimensional array of type float64 in FORTRAN array order array(float64, 2d, F)
Tested building a state
dictionary within _hydr_()
(working on branch specdev
)
OUTDGT
is being passed into _hydr_()
as a separate input param, because there's no easy way to add a numpy array to a dictionary # import numpy as np
# from numba import types
# from numba.typed import Dict
# Dict.empty() constructs a typed dictionary
# The key and value types must be explicitly declared
# This will create a dict with keys as string and values of type float
state = Dict.empty(key_type=types.unicode_type, value_type=types.float64)
print(state)
{}
state['hello'] = 1.5
print(state)
{hello: 1.5}
# tried many variations of setting an outdgt variable on the state dict
state['OUTDGT'] = OUTDGT
results in errors
make_numba_dict()
which is set up specifically for uci filesQ: why not just pass in OUTDGT
directly to specl()
?
def specl(ui, ts, OUTDGT, step, specactions):
def _specl_(ui, ts, OUTDGT, step, specactions):
# before specl() call:
# OUTDGT:
[[73.66304779 -0. 0. ]
[73.66304779 -0. 0. ]
[73.66304779 -0. 0. ]
...
[83.55184937 -0. 0. ]
[83.55184937 -0. 0. ]
[83.55184937 -0. 0. ]]
# within _specl_():
OUTDGT[step, 0] = 99
# after specl() call:
# OUTDGT:
[[99. -0. 0.]
[99. -0. 0.]
[99. -0. 0.]
...
[99. -0. 0.]
[99. -0. 0.]
[99. -0. 0.]]
OUTDGT[step, 0] = 99
inside _specl_()
does result in O1 = 99
in the output HYDR table.
RESULTS/RCHRES_R001/HYDR/table
specl()
call happens before setting of outdgt[:] = OUTDGT[step, :]
OUTDGT
with this method does not automatically get reflected in ts
Easy Qs first:
OUTDGT
gets changed which results in the final /RESULTS/RCHRES...
array having the altered O1
, O2
, ...The difficult stuff: I think that the reason that OUTDGT caused an error is the Dict declaration:
state = Dict.empty(key_type=types.unicode_type, value_type=types.float64)
Does not accept arrays, so changing to this would remove the error:
state = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:])
However:
OUTDGT
is stored as O1
,O2
,... we could put them in state in that way.specl()
function to handle a custom variable especially one that is domain specific like OUTDGT
. Thus, conversions to and from array notation like that should be handled by the calling routineAll those considered I think we choose to:
_hydr_
. Which makes the steps:
populate
, call specl()
, harvest
steps just like option 1. Also, for computational efficiency we may want to pass a var to specl() that checks to see if anything has been changed and if nothing gets changed no need to copy.
@jdkleiner thoughts on the above?
Test implementation of state dictionary approach for specl:
See HYDR.py:
# The following occurs at the beginning of the HYDR for-loop
# set up state dictionary
state = Dict.empty(key_type=types.int64, value_type=types.float64)
state[1] = OUTDGT[step, 0]
state[2] = OUTDGT[step, 1]
state[3] = OUTDGT[step, 2]
# specl calls _specl_ which modifies state variables
errors_specl = specl(ui, ts, state, step, specactions)
# set OUTDGT arry using the modified state variables
OUTDGT[step, :] = [state[1], state[2], state[3]]
See SPECL.py:
@njit
def _specl_(ui, ts, state, step, specactions):
errors_specl = zeros(int(1)).astype(int64)
state[1] += 1000
state[2] = 99
return errors_specl
Result console output:
# hsp2 run PL3_5250_0001.h5
step 8669 of 8760
state before specl()
1 : 83.55184936523438
2 : -0.0
3 : 0.0
state after specl()
1 : 1083.5518493652344
2 : 99.0
3 : 0.0
OUTDGT[step, :] [1083.55184937 99. 0. ]
Overview
Special actions can pull and alter data from all locations in the simulation, i.e., from multiple RCHRES or PERLND entities. In order to support special actions with minimal data retrieval and read/write overhead, it is desirable to pass in a python
view
of all relevant data, but there are some challenges in the existing code base:hydr()
function theOUTDGT
data should be modifiable byspecl()
when called inside_hydr_()
. However, in the currenthsp2
implementation,OUTDGT
is passed fromhydr()
to_hydr_()
as a clone, i.e., it is not a pass by reference view.ui
andts
as slices of theuci
and based on theoperation
andsegment
.ts = get_timeseries(io_manager,ddext_sources[(operation,segment)],siminfo)
Tasks:
_hydr_()
specl()
function call and data-prep approach (inside the calling function) for passing referenced objects intospecl()
without needing extra attributes to link back to local state variables in the calling function, such as OUTDGT.ts['OUTDGT2'][step] = 99
HYDR.py: OUTDGT[step, :] = [ts['OUTDGT1'][step], ts['OUTDGT2'][step], 0.0]
O2
= 99 for many timestepsOUTDGT
instate
(i.e.ts[step -1]
) change the variableoutdgt
in the main_hydr_()
calling function?OUTDGT2
ints
does not automatically alteroutdgt
: see notes on modifying OUTDGT2: https://github.com/HARPgroup/HSPsquared/wiki/JK-HSP2-Log#work-session-92322Development
The following code snippet enables this referenced data, however we have not yet gotten it to function inside of
_hydr_()
, however, that may be because we hard-coded the array of OUTDGT values to only grab 2 of the 3 that are in there.