respec / HSPsquared

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

specl: ACTIONS (parser and code) #105

Open rburghol opened 1 year ago

rburghol commented 1 year ago

Tasks

hdf5 Data Model

index OPTYP RANGE1 RANGE2 DC DS YR MO DA HR MN D T VARI S1 S2 AC VALUE TC TS NUM CURLVL
0 PERLND 1 DY 1984 1 1 12 2 3 FNO3 += 0.000000 1
1 PERLND 1 DY 1984 2 1 12 2 3 FNO3 += 0.090044 1

HSPF UCI Data Model

image

Execution Code

Runtime steps to integrate with STATE

  1. Find integer key for source and destination data pointing to storage slot in state_ix
    • Use get_state(state_ix, state_paths, var_path); where var_path is the full hdf5 path to the data quantity
      • Note: if var_ix == False: var_ix = set_state(state_ix, state_paths, var_path, default_value)
      • This should be done at the beginning of model execution so that all entities that are used in state simulation exist. This is a fairly simple process, outlined in this PR: https://github.com/respec/HSPsquared/pull/123/files
  2. Load source data for operation from STATE (get values from state_ix)
    • var_value = state_ix[var_ix]
  3. Execute code for operation
    • var_value = some_function(var_value, some_other_operand)
  4. Set value of target STATE var to result of state
    • state_ix[var_ix] = var_value

Manual STATE Example

# get the state index key for IVOL1 in Reach 001 with:

src_var_path = state_info['domain'] + "/IVOL1"; 
# note: src_var_path is by definition the "domain" + the variable name, so, 
src_var_ix = get_state(state_ix, state_paths, var_path)`
ivol1_val = state_ix[var_ix]
# Perform operation
ivol1_val = 1.1 * ivol1_val
# Store data (since ivol1 is source and target data we use same ix
state_ix[var_ix] = ivol1_val

Using ModelObject STATE Example

This outlines a process that use an object class to handle pre-run parsing of operation data to tokenization and runtime execution and state integration via the variable op_tokens. Details of this can be found in branch hydrocomp https://github.com/HARPgroup/HSPsquared/tree/hydrocomp

Supporting STATE inside an hsp2 njit function

Testing / Debugging

Parse UCI

Parser now successfully handle simple "classic" actions.

Verify ACTIONS parsing in R

UCI 1: Excerpt of ACTION block

SPEC-ACTIONS
*** ACTIONS
***optyp range dc ds yr  mo da hr mn d t   vari  s1 s2 s3 ac  value    tc ts num
  <****><-><--><><-><--><-><-><-><-><><>  <----><-><-><-><-><--------> <> <-><->
  RCHRES  1    DY  11984  1  1 12    2 3  IVOL           +=         10.
END SPEC-ACTIONS

Code 1: View contents of uci parsed to hdf5 in R.

library("rhdf5")
# open the file in R
h5_file_name = "hwmA51800.h5" 
# open the file in R
h5f = H5Fopen(h5_file_name)

h5read(h5f , "/SPEC_ACTIONS/ACTIONS/table")[1:2,]

Outputs:

  index  OPTYP RANGE1 RANGE2 DC DS   YR MO DA HR MN D T VARI S1 S2 AC    VALUE
1     0 PERLND      1        DY    1984  1  1 12    2 3 FNO3       += 0.000000
2     1 PERLND      1        DY    1984  2  1 12    2 3 FNO3       += 0.090044
  TC TS NUM CURLVL
1                1
2                1

View contents of uci parsed to hdf5 in python.

Code 2: Print in python, and convert byte encoding.

import h5py
h5_file_name = "hwmA51800.h5"
f = h5py.File(h5_file_name,'r')
f['/SPEC_ACTIONS/ACTIONS/table']
f['/SPEC_ACTIONS/ACTIONS/table'][0:2,]
specla=f['/SPEC_ACTIONS/ACTIONS/table']
for idx, x in np.ndenumerate(specla):
   print(x[1].decode("utf-8"),x[2].decode("utf-8"), x[13].decode("utf-8"), x[16].decode("utf-8"), x[17])

Outputs:

array([(0, b'PERLND', b'1', b'', b'DY', b'', b'1984', b'1', b'1', b'12', b'', b'2', 3, b'FNO3', b'', b'', b'+=', 0.      , b'', b'', b'', 1),
       (1, b'PERLND', b'1', b'', b'DY', b'', b'1984', b'2', b'1', b'12', b'', b'2', 3, b'FNO3', b'', b'', b'+=', 0.090044, b'', b'', b'', 1)],
      dtype=[('index', '<i8'), ('OPTYP', 'S6'), ('RANGE1', 'S1'), ('RANGE2', 'S1'), ('DC', 'S2'), ('DS', 'S1'), ('YR', 'S4'), ('MO', 'S1'), ('DA', 'S1'), ('HR', 'S2'), ('MN', 'S1'), ('D', 'S1'), ('T', '<i8'), ('VARI', 'S4'), ('S1', 'S1'), ('S2', 'S1'), ('AC', 'S2'), ('VALUE', '<f8'), ('TC', 'S1'), ('TS', 'S1'), ('NUM', 'S1'), ('CURLVL', '<i8')])
...
PERLND 1 FNO3 += 0.0
PERLND 1 FNO3 += 0.090044
PERLND 1 FNO3 += 1.91746
PERLND 1 FNO3 += 2.733176
PERLND 1 FNO3 += 1.23e-07
PERLND 1 FNO3 += 6.302083
PERLND 1 FNO3 += 0.207089
rburghol commented 7 months ago

Making the actions work with STATE.

Table 1: Example for class ACTIONS that increases IVOL by 1.0 on January 1st, 1984 . index OPTYP RANGE1 RANGE2 DC DS YR MO DA HR MN D T VARI S1 S2 AC VALUE TC TS NUM CURLVL
0 RCHRES 1 DY 1984 1 1 12 2 3 IVOL += 1.000000 1