HARPgroup / HSPsquared

Hydrologic Simulation Program Python (HSPsquared)
GNU Affero General Public License v3.0
1 stars 0 forks source link

Passing referenced OUTDGT (and others) into _hydr_() #31

Closed rburghol closed 1 year ago

rburghol commented 1 year ago

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:

Tasks:

Development

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.

 xkeys = ['OUTDGT1', 'OUTDGT2']
 # xvalues = list(map(ts.get, xkeys))
 xvalues = array(ts['OUTDGT1'],ts['OUTDGT2'])
 # xvalues = array(map(ts.get, xkeys))
 # xvalues = list(map(ts.get, names))
 # print(names)
 print(xvalues)
 # print(xvalues.shape)
 # print(xvalues[0][0])
 # xvalues[0][0] = xvalues[0][0] * 2
 # print("ts['OUTDGT1']", ts['OUTDGT1'][0])
 # print("ts['OUTDGT2']", ts['OUTDGT2'][0])
rburghol commented 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:

jdkleiner commented 1 year ago

@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.

jdkleiner commented 1 year ago

@rburghol

rburghol commented 1 year ago

Easy Qs first:

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:

All those considered I think we choose to:

  1. Deconstruct and reconstruct OUTDGT into it's component pieces in _hydr_. Which makes the steps:
    • populate state
    • call specl()
    • copy vars from state back to local vars (like OUTDGT)
  2. Or, make all state vars an array even tho the majority will be 1 element long.
    • Note: I think that there is not way to create a Dict that gets values from multiple Dicts and still has things propagate via pass-by-reference, we will still need to do the populate, call specl(), harvest steps just like option 1.
  3. The most important item might be performance testing. Dicts that use a string name as a key, instead of an integer can show really slow performance. Which might be a reason that developers have passed these Dicts as separate arguments. But this is not practical with specl since ANY piece of info could change and that can quickly get absurd in terms of the number of arguments needed. See the performance testing for some interesting info here:

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?

jdkleiner commented 1 year ago

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.        ]