diff --git a/examples/state_specl_ops/compare_eq_to_specl.py b/examples/state_specl_ops/compare_eq_to_specl.py index 5e21d9b2..7cb122b3 100644 --- a/examples/state_specl_ops/compare_eq_to_specl.py +++ b/examples/state_specl_ops/compare_eq_to_specl.py @@ -10,6 +10,7 @@ from src.hsp2.hsp2tools.commands import import_uci, run from src.hsp2.hsp2tools.HDF5 import HDF5 from src.hsp2.hsp2tools.HBNOutput import HBNOutput +import tabulate def test_h5_file_exists(): assert os.path.exists('test10.h5') @@ -24,7 +25,7 @@ def test_h5_file_exists(): # get RCHRES 5 sedtrn silt ts_silt_hspf = hspf_data.get_time_series('RCHRES', 5, 'RSEDTOTSILT', 'SEDTRN', 'full') total_silt_hspf = ts_silt_hspf.mean() -quantile_silt_hspf = np.quantile(ts_silt_hspf,[0.0,0.10,0.5,0.5,0.75,0.9,0.95,1.0]) +quantile_silt_hspf = np.quantile(ts_silt_hspf,[0.0,0.25,0.5,0.75,1.0]) ############# HSPF NO SPECL hspf_nospecl_root = Path("tests/test10/HSPFresults") @@ -32,7 +33,7 @@ def test_h5_file_exists(): hspf_nospecl_data.read_data() ts_silt_nospecl_hspf = hspf_nospecl_data.get_time_series('RCHRES', 5, 'RSEDTOTSILT', 'SEDTRN', 'full') total_silt_nospecl_hspf = ts_silt_nospecl_hspf.mean() -quantile_silt_nospecl_hspf = np.quantile(ts_silt_nospecl_hspf,[0.0,0.10,0.5,0.5,0.75,0.9,0.95,1.0]) +quantile_silt_nospecl_hspf = np.quantile(ts_silt_nospecl_hspf,[0.0,0.25,0.5,0.75,1.0]) ############# hsp2 SPECL # Run and Analyze hsp2 WITH SPECL actions @@ -54,8 +55,8 @@ def test_h5_file_exists(): hsp2_specl_hydr5 = read_hdf(dstore_specl, '/RESULTS/RCHRES_R005/HYDR') hsp2_specl_sedtrn5 = read_hdf(dstore_specl, '/RESULTS/RCHRES_R005/SEDTRN') hsp2_specl_rsed5 = hsp2_specl_sedtrn5['RSED5'] -quantile_silt_hsp2 = np.quantile(hsp2_specl_rsed5,[0.0,0.10,0.5,0.5,0.75,0.9,0.95,1.0]) -quantile_ro_hsp2 = np.quantile(hsp2_specl_hydr5['RO'],[0.0,0.10,0.5,0.5,0.75,0.9,0.95,1.0]) +quantile_silt_hsp2 = np.quantile(hsp2_specl_rsed5,[0.0,0.25,0.5,0.75,1.0]) +quantile_ro_hsp2 = np.quantile(hsp2_specl_hydr5['RO'],[0.0,0.25,0.5,0.75,1.0]) total_silt_hsp2 = hsp2_specl_rsed5.mean() dstore_specl.close() @@ -63,10 +64,10 @@ def test_h5_file_exists(): # Run and Analyze hsp2 without SPECL actions nospecl_root = Path("tests/test10") nospecl_root.exists() -nospecl_root_hspf = Path(nospecl_root) / "HSPFresults" -hsp2_nospecl_uci = nospecl_root_hspf.resolve() / "test10.uci" +nospecl_root_hsp2 = Path(nospecl_root) / "HSP2results" +hsp2_nospecl_uci = nospecl_root_hsp2.resolve() / "test10.uci" hsp2_nospecl_uci.exists() -temp_nospecl_h5file = nospecl_root_hspf / "nospecl_case.h5" +temp_nospecl_h5file = nospecl_root_hsp2 / "test10.h5" # IF we want to run it from python, do this: #if temp_nospecl_h5file.exists(): @@ -79,8 +80,8 @@ def test_h5_file_exists(): hsp2_nospecl_hydr5 = read_hdf(dstore_nospecl, '/RESULTS/RCHRES_R005/HYDR') hsp2_nospecl_sedtrn5 = read_hdf(dstore_nospecl, '/RESULTS/RCHRES_R005/SEDTRN') hsp2_nospecl_rsed5 = hsp2_nospecl_sedtrn5['RSED5'] -np.quantile(hsp2_nospecl_rsed5,[0.0,0.10,0.5,0.5,0.75,0.9,0.95,1.0]) -np.quantile(hsp2_nospecl_hydr5['RO'],[0.0,0.10,0.5,0.5,0.75,0.9,0.95,1.0]) +quantile_silt_nospecl_hsp2 = np.quantile(hsp2_nospecl_rsed5,[0.0,0.25,0.5,0.75,1.0]) +np.quantile(hsp2_nospecl_hydr5['RO'],[0.0,0.25,0.5,0.75,1.0]) total_silt_nospecl_hsp2 = hsp2_nospecl_rsed5.mean() dstore_nospecl.close() @@ -105,8 +106,8 @@ def test_h5_file_exists(): hsp2_eq_hydr5 = read_hdf(dstore_eq_specl, '/RESULTS/RCHRES_R005/HYDR') hsp2_eq_sedtrn5 = read_hdf(dstore_eq_specl, '/RESULTS/RCHRES_R005/SEDTRN') hsp2_eq_rsed5 = hsp2_eq_sedtrn5['RSED5'] -quantile_silt_eq_hsp2 = np.quantile(hsp2_eq_rsed5,[0.0,0.10,0.5,0.5,0.75,0.9,0.95,1.0]) -quantile_ro_eq_hsp2 = np.quantile(hsp2_eq_hydr5['RO'],[0.0,0.10,0.5,0.5,0.75,0.9,0.95,1.0]) +quantile_silt_eq_hsp2 = np.quantile(hsp2_eq_rsed5,[0.0,0.25,0.5,0.75,1.0]) +quantile_ro_eq_hsp2 = np.quantile(hsp2_eq_hydr5['RO'],[0.0,0.25,0.5,0.75,1.0]) total_silt_eq_hsp2 = hsp2_eq_rsed5.mean() dstore_eq_specl.close() @@ -133,3 +134,19 @@ def test_h5_file_exists(): print("Total SiltHSP2 vs. HSPF, % difference = ", pct_dif_specl, "%") print("No SPECL: Total SiltHSP2 vs. HSPF, % difference = ", pct_dif_nospecl, "%") + +a = pd.DataFrame( + { + 'HSP2 no specl':quantile_silt_nospecl_hsp2, + 'HSPF no specl':quantile_silt_nospecl_hspf, + 'HSPF w/specl':quantile_silt_hspf, + 'HSP2 w/specl':quantile_silt_hsp2, + 'HSP2 w/EQ':quantile_silt_eq_hsp2 + } +) + + +tabulate(a, headers='keys', tablefmt='markdown') +tabulate(a, headers='keys', tablefmt='psql') +# Thi is better, it USES the tabulate lib but has usable format +a.to_markdown(index=False) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 8caa0ece..c2f3c50e 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -11,16 +11,16 @@ """ -from numpy import zeros, any, full, nan, array, int64, arange, asarray +from numpy import zeros, any, full, nan, array, int64, arange from pandas import DataFrame from math import sqrt, log10 -from numba import njit, types +from numba import njit from numba.typed import List from hsp2.hsp2.utilities import initm, make_numba_dict # the following imports added by rb to handle dynamic code and special actions -from hsp2.state.state import hydr_get_ix, hydr_init_ix, hydr_state_vars -from hsp2.hsp2.om import pre_step_model, step_model, model_domain_dependencies +from hsp2.state.state import hydr_get_ix, get_state_ix +from hsp2.hsp2.om import pre_step_model, step_model from numba.typed import Dict @@ -36,7 +36,7 @@ MAXLOOPS = 100 # newton method exit tolerance -def hydr(io_manager, siminfo, parameters, ts, ftables, state): +def hydr(siminfo, parameters, ts, ftables, state): """find the state of the reach/reservoir at the end of the time interval and the outflows during the interval @@ -48,7 +48,9 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): state is a dictionary that contains all dynamic code dictionaries such as: - specactions is a dictionary with all special actions """ - + # TBD: These operations are all preparatory in nature, and will be replaced by code + # in the RCHRES_handler class, which will set properties on RCHRES_class for fast + # and concide run-time execution and memory management. steps = siminfo["steps"] # number of simulation points uunits = siminfo["units"] nexits = int(parameters["PARAMETERS"]["NEXITS"]) @@ -140,41 +142,21 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): ####################################################################################### # the following section (1 of 3) added to HYDR by rb to handle dynamic code and special actions ####################################################################################### - # state_info is some generic things about the simulation - # must be numba safe, so we don't just pass the whole state which is not - state_info = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) - state_info["operation"], state_info["segment"], state_info["activity"] = ( - state["operation"], - state["segment"], - state["activity"], - ) - state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( - state["domain"], - state["state_step_hydr"], - state["state_step_om"], - ) - hsp2_local_py = state["hsp2_local_py"] + hsp2_local_py = state.hsp2_local_py # It appears necessary to load this here, instead of from main.py, otherwise, # _hydr_() does not recognize the function state_step_hydr()? if hsp2_local_py != False: from hsp2_local_py import state_step_hydr else: - from hsp2.state.state_fn_defaults import state_step_hydr - # initialize the hydr paths in case they don't already reside here - hydr_init_ix(state, state["domain"]) - # must split dicts out of state Dict since numba cannot handle mixed-type nested Dicts - state_ix, dict_ix, ts_ix = state["state_ix"], state["dict_ix"], state["ts_ix"] - state_paths = state["state_paths"] - ep_list = ( - hydr_state_vars() - ) # define all eligibile for state integration in state.py - # note: calling dependencies with 4th arg = True grabs only "runnable" types, which can save time - # in long simulations, as iterating through non-runnables like Constants consumes time. - model_exec_list = model_domain_dependencies( - state, state_info["domain"], ep_list, True - ) - model_exec_list = asarray(model_exec_list, dtype="i8") # format for use in numba - op_tokens = state["op_tokens"] + from hsp2.state.state_definitions import state_step_hydr + # note: get executable dynamic operation model components + # TBD: this will be set as a property on each RCHRES object when we move to a class framework + activity_path = state.domain + "/" + 'HYDR' + #print("HYDR activity_path", activity_path) + activity_id = get_state_ix(state.state_paths, activity_path) + model_exec_list = state.op_exec_lists[activity_id] + #print("model_exec_list", model_exec_list) + #print(state.domain, "HYDR called with", state.domain, len(model_exec_list), "op elements.") ####################################################################################### # Do the simulation with _hydr_ (ie run reaches simulation code) @@ -187,14 +169,9 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): funct, Olabels, OVOLlabels, - state_info, - state_paths, - state_ix, - dict_ix, - ts_ix, + state, state_step_hydr, - op_tokens, - model_exec_list, + model_exec_list ) if "O" in ts: @@ -206,12 +183,10 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): parameters["PARAMETERS"]["ROS"] = ui["ROS"] for i in range(nexits): parameters["PARAMETERS"]["OS" + str(i + 1)] = ui["OS" + str(i + 1)] - # copy back (modified) operational element data - state["state_ix"], state["dict_ix"], state["ts_ix"] = state_ix, dict_ix, ts_ix return errors, ERRMSGS -@njit(cache=True) +#@njit(cache=True) def _hydr_( ui, ts, @@ -221,17 +196,11 @@ def _hydr_( funct, Olabels, OVOLlabels, - state_info, - state_paths, - state_ix, - dict_ix, - ts_ix, + state, state_step_hydr, - op_tokens, - model_exec_list, + model_exec_list ): errors = zeros(int(ui["errlen"])).astype(int64) - steps = int(ui["steps"]) # number of simulation steps delts = ui["delt"] * 60.0 # seconds in simulation interval uunits = ui["uunits"] @@ -368,19 +337,24 @@ def _hydr_( # other initial vars rovol = 0.0 volev = 0.0 - IVOL0 = ts["IVOL"] # the actual inflow in simulation native units ####################################################################################### # the following section (2 of 3) added by rb to HYDR, this one to prepare for dynamic state including special actions ####################################################################################### - hydr_ix = hydr_get_ix(state_ix, state_paths, state_info["domain"]) + hydr_ix = hydr_get_ix(state, state.domain) # these are integer placeholders faster than calling the array look each timestep + # TBD: These will be replaced by class properties in HYDR_class o1_ix, o2_ix, o3_ix, ivol_ix = ( hydr_ix["O1"], hydr_ix["O2"], hydr_ix["O3"], hydr_ix["IVOL"], ) + ovol1_ix, ovol2_ix, ovol3_ix = ( + hydr_ix["OVOL1"], + hydr_ix["OVOL2"], + hydr_ix["OVOL3"], + ) ro_ix, rovol_ix, volev_ix, vol_ix = ( hydr_ix["RO"], hydr_ix["ROVOL"], @@ -389,12 +363,16 @@ def _hydr_( ) # handle varying length outdgt out_ix = arange(nexits) + ovol_ix = arange(nexits) if nexits > 0: out_ix[0] = o1_ix + ovol_ix[0] = ovol1_ix if nexits > 1: out_ix[1] = o2_ix + ovol_ix[1] = ovol2_ix if nexits > 2: out_ix[2] = o3_ix + ovol_ix[2] = ovol3_ix ####################################################################################### # HYDR (except where noted) @@ -408,40 +386,45 @@ def _hydr_( ####################################################################################### # the following section (3 of 3) added by rb to accommodate dynamic code, operations models, and special actions ####################################################################################### - # set state_ix with value of local state variables and/or needed vars - # Note: we pass IVOL0, not IVOL here since IVOL has been converted to different units - state_ix[ro_ix], state_ix[rovol_ix] = ro, rovol + # set state.state_ix with value of local state variables and/or needed vars + state.state_ix[ro_ix], state.state_ix[rovol_ix] = ro, rovol di = 0 for oi in range(nexits): - state_ix[out_ix[oi]] = outdgt[oi] - state_ix[vol_ix], state_ix[ivol_ix] = vol, IVOL0[step] - state_ix[volev_ix] = volev + # Write OVOL for use in equations/specacts. Note: this must be improved! too much code... + state.state_ix[ovol_ix[oi]] = ovol[oi] + + state.state_ix[vol_ix], state.state_ix[ivol_ix] = vol, IVOL[step] + state.state_ix[volev_ix] = volev # - these if statements may be irrelevant if default functions simply return # when no objects are defined. - if state_info["state_step_om"] == "enabled": - pre_step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step) - if state_info["state_step_hydr"] == "enabled": + if state.state_step_om == "enabled": + pre_step_model(model_exec_list, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step) + + if state.state_step_hydr == "enabled": state_step_hydr( - state_info, state_paths, state_ix, dict_ix, ts_ix, hydr_ix, step + state, step ) - if state_info["state_step_om"] == "enabled": + + if state.state_step_om == "enabled": # print("trying to execute state_step_om()") # model_exec_list contains the model exec list in dependency order # now these are all executed at once, but we need to make them only for domain end points + #if step < 2: + # print("Calling step_model with", len(model_exec_list), "out of", len(state.op_tokens), "tokens") step_model( - model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step + model_exec_list, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step ) # traditional 'ACTIONS' done in here - if (state_info["state_step_hydr"] == "enabled") or ( - state_info["state_step_om"] == "enabled" + if (state.state_step_hydr == "enabled") or ( + state.state_step_om == "enabled" ): # Do write-backs for editable STATE variables # OUTDGT is writeable for oi in range(nexits): - outdgt[oi] = state_ix[out_ix[oi]] + outdgt[oi] = state.state_ix[out_ix[oi]] # IVOL is writeable. # Note: we must convert IVOL to the units expected in _hydr_ # maybe routines should do this, and this is not needed (but pass VFACT in state) - IVOL[step] = state_ix[ivol_ix] * VFACT + IVOL[step] = state.state_ix[ivol_ix] # End dynamic code step() ####################################################################################### @@ -866,12 +849,3 @@ def expand_HYDR_masslinks(flags, parameters, dat, recs): rec["SVOL"] = dat.SVOL recs.append(rec) return recs - - -def hydr_load_om(state, io_manager, siminfo): - for i in hydr_state_vars(): - state["model_data"][seg_name][i] = { - "object_class": "ModelVariable", - "name": i, - "value": 0.0, - } diff --git a/src/hsp2/hsp2/RQUAL.py b/src/hsp2/hsp2/RQUAL.py index 81985ec8..3253ad4a 100644 --- a/src/hsp2/hsp2/RQUAL.py +++ b/src/hsp2/hsp2/RQUAL.py @@ -6,14 +6,13 @@ import numpy as np from numba import njit, types from numba.typed import Dict -from numpy import full, zeros, asarray +from numpy import full, zeros from hsp2.hsp2.RQUAL_Class import RQUAL_Class from hsp2.hsp2.utilities import initm, initmd, make_numba_dict # the following imports added to handle special actions -from hsp2.state.state import rqual_init_ix, rqual_state_vars -from hsp2.hsp2.om import model_domain_dependencies +from hsp2.state.state import get_state_ix ERRMSGS_oxrx = ( "OXRX: Warning -- SATDO is less than zero. This usually occurs when water temperature is very high (above ~66 deg. C). This usually indicates an error in input GATMP (or TW, if HTRCH is not being simulated).", @@ -251,33 +250,10 @@ def rqual( ####################################################################################### # the following section (1 of 3) added to RQUAL by pbd to handle special actions ####################################################################################### - # state_info is some generic things about the simulation - # must be numba safe, so we don't just pass the whole state which is not - state_info = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) - state_info["operation"], state_info["segment"], state_info["activity"] = ( - state["operation"], - state["segment"], - state["activity"], - ) - state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( - state["domain"], - state["state_step_hydr"], - state["state_step_om"], - ) - # must split dicts out of state Dict since numba cannot handle mixed-type nested Dicts - # initialize the rqual paths in case they don't already reside here - rqual_init_ix(state, state["domain"]) - state_ix, dict_ix, ts_ix = state["state_ix"], state["dict_ix"], state["ts_ix"] - state_paths = state["state_paths"] - op_tokens = state["op_tokens"] - # Aggregate the list of all RQUAL end point dependencies - ep_list = ( - rqual_state_vars() - ) # define all eligibile for state integration in state.py - model_exec_list = model_domain_dependencies( - state, state_info["domain"], ep_list, True - ) - model_exec_list = asarray(model_exec_list, dtype="i8") + # Aggregate the list of all SEDTRN end point dependencies + activity_path = state.domain + "/" + 'SEDTRN' + activity_id = get_state_ix(state.state_paths, activity_path) + model_exec_list = state.op_exec_lists[activity_id] ####################################################################################### # --------------------------------------------------------------------- @@ -292,12 +268,7 @@ def rqual( ui_plank, ui_phcarb, ts, - state_info, - state_paths, - state_ix, - dict_ix, - ts_ix, - op_tokens, + state, model_exec_list, ) @@ -364,12 +335,7 @@ def _rqual_run( ui_plank, ui_phcarb, ts, - state_info, - state_paths, - state_ix, - dict_ix, - ts_ix, - op_tokens, + state, model_exec_list, ): nutrx_errors = zeros((0), dtype=np.int64) @@ -382,12 +348,7 @@ def _rqual_run( # run WQ simulation: RQUAL.simulate( ts, - state_info, - state_paths, - state_ix, - dict_ix, - ts_ix, - op_tokens, + state, model_exec_list, ) diff --git a/src/hsp2/hsp2/RQUAL_Class.py b/src/hsp2/hsp2/RQUAL_Class.py index 81b3ae16..4448bcaf 100644 --- a/src/hsp2/hsp2/RQUAL_Class.py +++ b/src/hsp2/hsp2/RQUAL_Class.py @@ -823,18 +823,13 @@ def __init__(self, siminfo, ui, ui_oxrx, ui_nutrx, ui_plank, ui_phcarb, ts): def simulate( self, ts, - state_info, - state_paths, - state_ix, - dict_ix, - ts_ix, - op_tokens, + state, model_exec_list, ): ####################################################################################### # the following section (2 of 3) added by pbd to RQUAL, this one to prepare for special actions ####################################################################################### - rqual_ix = rqual_get_ix(state_ix, state_paths, state_info["domain"]) + rqual_ix = rqual_get_ix(state, state.domain) # these are integer placeholders faster than calling the array look each timestep dox_ix = rqual_ix["DOX"] bod_ix = rqual_ix["BOD"] @@ -854,40 +849,41 @@ def simulate( # the following section (3 of 3) added by pbd to accommodate special actions ####################################################################################### # set state_ix with value of local state variables and/or needed vars - state_ix[dox_ix] = self.OXRX.dox - state_ix[bod_ix] = self.OXRX.bod - state_ix[no3_ix] = self.NUTRX.no3 - state_ix[tam_ix] = self.NUTRX.tam - state_ix[no2_ix] = self.NUTRX.no2 - state_ix[po4_ix] = self.NUTRX.po4 - state_ix[brtam1_ix] = self.NUTRX.brtam[0] - state_ix[brtam2_ix] = self.NUTRX.brtam[1] - state_ix[brpo41_ix] = self.NUTRX.brpo4[0] - state_ix[brpo42_ix] = self.NUTRX.brpo4[1] - state_ix[cforea_ix] = self.OXRX.cforea - if state_info["state_step_om"] == "enabled": + state.state_ix[dox_ix] = self.OXRX.dox + state.state_ix[bod_ix] = self.OXRX.bod + state.state_ix[no3_ix] = self.NUTRX.no3 + state.state_ix[tam_ix] = self.NUTRX.tam + state.state_ix[no2_ix] = self.NUTRX.no2 + state.state_ix[po4_ix] = self.NUTRX.po4 + state.state_ix[brtam1_ix] = self.NUTRX.brtam[0] + state.state_ix[brtam2_ix] = self.NUTRX.brtam[1] + state.state_ix[brpo41_ix] = self.NUTRX.brpo4[0] + state.state_ix[brpo42_ix] = self.NUTRX.brpo4[1] + state.state_ix[cforea_ix] = self.OXRX.cforea + if state.state_step_om == "enabled": pre_step_model( - model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step=loop + model_exec_list, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step=loop ) # (todo) Insert code hook for dynamic python modification of state - if state_info["state_step_om"] == "enabled": + if state.state_step_om == "enabled": + # (todo) migrate runtime jit code to new state object model step_model( - model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step=loop + model_exec_list, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step=loop ) # traditional 'ACTIONS' done in here # Do write-backs for editable STATE variables - self.OXRX.dox = state_ix[dox_ix] - self.OXRX.bod = state_ix[bod_ix] - self.NUTRX.no3 = state_ix[no3_ix] - self.NUTRX.tam = state_ix[tam_ix] - self.NUTRX.no2 = state_ix[no2_ix] - self.NUTRX.po4 = state_ix[po4_ix] - self.NUTRX.brtam[0] = state_ix[brtam1_ix] - self.NUTRX.brtam[1] = state_ix[brtam2_ix] - self.NUTRX.brpo4[0] = state_ix[brpo41_ix] - self.NUTRX.brpo4[1] = state_ix[brpo42_ix] - self.OXRX.cforea = state_ix[cforea_ix] + self.OXRX.dox = state.state_ix[dox_ix] + self.OXRX.bod = state.state_ix[bod_ix] + self.NUTRX.no3 = state.state_ix[no3_ix] + self.NUTRX.tam = state.state_ix[tam_ix] + self.NUTRX.no2 = state.state_ix[no2_ix] + self.NUTRX.po4 = state.state_ix[po4_ix] + self.NUTRX.brtam[0] = state.state_ix[brtam1_ix] + self.NUTRX.brtam[1] = state.state_ix[brtam2_ix] + self.NUTRX.brpo4[0] = state.state_ix[brpo41_ix] + self.NUTRX.brpo4[1] = state.state_ix[brpo42_ix] + self.OXRX.cforea = state.state_ix[cforea_ix] ####################################################################################### # ------------------------------------------------------- diff --git a/src/hsp2/hsp2/SEDMNT.py b/src/hsp2/hsp2/SEDMNT.py index 6818d1e5..916665b5 100644 --- a/src/hsp2/hsp2/SEDMNT.py +++ b/src/hsp2/hsp2/SEDMNT.py @@ -59,21 +59,21 @@ def sedmnt(io_manager, siminfo, parameters, ts, state): # must be numba safe, so we don't just pass the whole state which is not state_info = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) state_info["operation"], state_info["segment"], state_info["activity"] = ( - state["operation"], - state["segment"], - state["activity"], + state.operation, + state.segment, + state.activity, ) state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( - state["domain"], - state["state_step_hydr"], - state["state_step_om"], + state.domain, + state.state_step_hydr, + state.state_step_om, ) # must split dicts out of state Dict since numba cannot handle mixed-type nested Dicts # initialize the sedmnt paths in case they don't already reside here - sedmnt_init_ix(state, state["domain"]) - state_ix, dict_ix, ts_ix = state["state_ix"], state["dict_ix"], state["ts_ix"] - state_paths = state["state_paths"] - op_tokens = state["op_tokens"] + sedmnt_init_ix(state, state.domain) + state_ix, dict_ix, ts_ix = state.state_ix, state.dict_ix, state.ts_ix + state_paths = state.state_paths + op_tokens = state.op_tokens # Aggregate the list of all SEDMNT end point dependencies ep_list = ( sedmnt_state_vars() diff --git a/src/hsp2/hsp2/SEDTRN.py b/src/hsp2/hsp2/SEDTRN.py index c6c5f1d1..99e65287 100644 --- a/src/hsp2/hsp2/SEDTRN.py +++ b/src/hsp2/hsp2/SEDTRN.py @@ -10,8 +10,8 @@ from hsp2.hsp2.utilities import make_numba_dict # the following imports added to handle special actions -from hsp2.state.state import sedtrn_get_ix, sedtrn_init_ix, sedtrn_state_vars -from hsp2.hsp2.om import pre_step_model, step_model, model_domain_dependencies +from hsp2.state.state import sedtrn_get_ix, get_state_ix +from hsp2.hsp2.om import pre_step_model, step_model from numba.typed import Dict ERRMSGS = ( @@ -25,7 +25,7 @@ ) # ERRMSG6 -def sedtrn(io_manager, siminfo, parameters, ts, state): +def sedtrn(siminfo, parameters, ts, state): """Simulate behavior of inorganic sediment""" # simlen = siminfo['steps'] @@ -91,19 +91,6 @@ def sedtrn(io_manager, siminfo, parameters, ts, state): ####################################################################################### # the following section (1 of 3) added to SEDTRN by pbd to handle special actions ####################################################################################### - # state_info is some generic things about the simulation - # must be numba safe, so we don't just pass the whole state which is not - state_info = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) - state_info["operation"], state_info["segment"], state_info["activity"] = ( - state["operation"], - state["segment"], - state["activity"], - ) - state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( - state["domain"], - state["state_step_hydr"], - state["state_step_om"], - ) # hsp2_local_py = state['hsp2_local_py'] # # It appears necessary to load this here, instead of from main.py, otherwise, # # _hydr_() does not recognize the function state_step_hydr()? @@ -112,31 +99,17 @@ def sedtrn(io_manager, siminfo, parameters, ts, state): # else: # from hsp2.state.state_fn_defaults import state_step_hydr # must split dicts out of state Dict since numba cannot handle mixed-type nested Dicts - # initialize the sedtrn paths in case they don't already reside here - sedtrn_init_ix(state, state["domain"]) - state_ix, dict_ix, ts_ix = state["state_ix"], state["dict_ix"], state["ts_ix"] - state_paths = state["state_paths"] - op_tokens = state["op_tokens"] # Aggregate the list of all SEDTRN end point dependencies - ep_list = ( - sedtrn_state_vars() - ) # define all eligibile for state integration in state.py - model_exec_list = model_domain_dependencies( - state, state_info["domain"], ep_list, True - ) - model_exec_list = asarray(model_exec_list, dtype="i8") # format for use in + activity_path = state.domain + "/" + 'SEDTRN' + activity_id = get_state_ix(state.state_paths, activity_path) + model_exec_list = state.op_exec_lists[activity_id] ####################################################################################### ############################################################################ errors = _sedtrn_( ui, ts, - state_info, - state_paths, - state_ix, - dict_ix, - ts_ix, - op_tokens, + state, model_exec_list, ) # run SEDTRN simulation code ############################################################################ @@ -165,12 +138,7 @@ def sedtrn(io_manager, siminfo, parameters, ts, state): def _sedtrn_( ui, ts, - state_info, - state_paths, - state_ix, - dict_ix, - ts_ix, - op_tokens, + state, model_exec_list, ): """Simulate behavior of inorganic sediment""" @@ -403,7 +371,7 @@ def _sedtrn_( ####################################################################################### # the following section (2 of 3) added by pbd to SEDTRN, this one to prepare for special actions ####################################################################################### - sedtrn_ix = sedtrn_get_ix(state_ix, state_paths, state_info["domain"]) + sedtrn_ix = sedtrn_get_ix(state, state.domain) # these are integer placeholders faster than calling the array look each timestep rsed4_ix, rsed5_ix, rsed6_ix = ( sedtrn_ix["RSED4"], @@ -417,24 +385,25 @@ def _sedtrn_( # the following section (3 of 3) added by pbd to accommodate special actions ####################################################################################### # set state_ix with value of local state variables and/or needed vars - state_ix[rsed4_ix] = sand_wt_rsed4 - state_ix[rsed5_ix] = silt_wt_rsed5 - state_ix[rsed6_ix] = clay_wt_rsed6 - if state_info["state_step_om"] == "enabled": + state.state_ix[rsed4_ix] = sand_wt_rsed4 + state.state_ix[rsed5_ix] = silt_wt_rsed5 + state.state_ix[rsed6_ix] = clay_wt_rsed6 + if state.state_step_om == "enabled": pre_step_model( - model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step=loop + model_exec_list, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step=loop ) # (todo) Insert code hook for dynamic python modification of state - if state_info["state_step_om"] == "enabled": + if state.state_step_om == "enabled": + # (todo) migrate runtime jit code to new state object model step_model( - model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step=loop + model_exec_list, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step=loop ) # traditional 'ACTIONS' done in here # Do write-backs for editable STATE variables - sand_wt_rsed4 = state_ix[rsed4_ix] - silt_wt_rsed5 = state_ix[rsed5_ix] - clay_wt_rsed6 = state_ix[rsed6_ix] + sand_wt_rsed4 = state.state_ix[rsed4_ix] + silt_wt_rsed5 = state.state_ix[rsed5_ix] + clay_wt_rsed6 = state.state_ix[rsed6_ix] ####################################################################################### # perform any necessary unit conversions diff --git a/src/hsp2/hsp2/SPECL.py b/src/hsp2/hsp2/SPECL.py index a4f16b42..a187cf1e 100644 --- a/src/hsp2/hsp2/SPECL.py +++ b/src/hsp2/hsp2/SPECL.py @@ -9,33 +9,33 @@ from numba import njit -def specl_load_om(state, io_manager, siminfo): - if "ACTIONS" in state["specactions"]: - dc = state["specactions"]["ACTIONS"] +def specl_load_om(om_operations, specactions): + if "ACTIONS" in specactions: + dc = specactions["ACTIONS"] for ix in dc.index: # add the items to the state['model_data'] dict speca = dc[ix : (ix + 1)] # need to add a name attribute opname = "SPEC" + "ACTION" + str(ix) - state["model_data"][opname] = {} - state["model_data"][opname]["name"] = opname + om_operations["model_data"][opname] = {} + om_operations["model_data"][opname]["name"] = opname for ik in speca.keys(): # print("looking for speca key ", ik) - state["model_data"][opname][ik] = speca.to_dict()[ik][ + om_operations["model_data"][opname][ik] = speca.to_dict()[ik][ ix ] # add subscripts? if ik == "VARI": if len(speca.to_dict()["S1"][ix]) > 0: - state["model_data"][opname][ik] += speca.to_dict()["S1"][ix] + om_operations["model_data"][opname][ik] += speca.to_dict()["S1"][ix] if len(speca.to_dict()["S2"][ix]) > 0: - state["model_data"][opname][ik] += speca.to_dict()["S2"][ix] - state["model_data"][opname]["object_class"] = "SpecialAction" + om_operations["model_data"][opname][ik] += speca.to_dict()["S2"][ix] + om_operations["model_data"][opname]["object_class"] = "SpecialAction" # print("model_data", ix, " = ", state['model_data'][opname]) return -def specl_load_state(state, io_manager, siminfo): - specl_load_om(state, io_manager, siminfo) +def specl_load_state(om_operations, specactions): + specl_load_om(om_operations, specactions) # others defined below, like: # specl_load_uvnames(state, io_manager, siminfo) # ... diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index b7ed561f..d41d2955 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -19,20 +19,24 @@ ) from hsp2.hsp2.configuration import activities, noop, expand_masslinks from hsp2.state.state import ( - init_state_dicts, state_siminfo_hsp2, state_load_dynamics_hsp2, state_init_hsp2, state_context_hsp2, + state_class, + state_class_lite, + state_copy ) from hsp2.hsp2.om import ( om_init_state, state_om_model_run_prep, state_load_dynamics_om, state_om_model_run_finish, + hsp2_domain_dependencies ) -from hsp2.hsp2.SPECL import specl_load_state - +from hsp2.hsp2.om_timer import timer_class +from hsp2.hsp2.SPECL import specl_load_om +from hsp2.state.state_definitions import state_empty from hsp2.hsp2io.io import IOManager, SupportsReadTS, Category @@ -55,6 +59,7 @@ def main( None """ + timer = timer_class() if isinstance(io_manager, str): hdf5_instance = HDF5(io_manager) io_manager = IOManager(hdf5_instance) @@ -82,33 +87,42 @@ def main( copy_instances = {} gener_instances = {} + section_timing = {} + section_timing["io_manager.read_parameters() call and config"] = str(timer.split()) + "seconds" ####################################################################################### # initialize STATE dicts ####################################################################################### # Set up Things in state that will be used in all modular activities like SPECL - state = init_state_dicts() - state_siminfo_hsp2(parameter_obj, siminfo, io_manager, state) + state = state_class( + state_empty["state_ix"], state_empty["op_tokens"], state_empty["state_paths"], + state_empty["op_exec_lists"], state_empty["model_exec_list"], state_empty["dict_ix"], + state_empty["ts_ix"], state_empty["hsp_segments"] + ) + om_operations = om_init_state() # set up operational model specific containers + state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) # Add support for dynamic functions to operate on STATE # - Load any dynamic components if present, and store variables on objects state_load_dynamics_hsp2(state, io_manager, siminfo) # Iterate through all segments and add crucial paths to state # before loading dynamic components that may reference them - state_init_hsp2(state, opseq, activities) + state_init_hsp2(state, opseq, activities, timer) + # now initialize all state variables for mutable variables + hsp2_domain_dependencies(state, opseq, activities, om_operations, False) # - finally stash specactions in state, not domain (segment) dependent so do it once - state["specactions"] = specactions # stash the specaction dict in state - om_init_state(state) # set up operational model specific state entries - specl_load_state(state, io_manager, siminfo) # traditional special actions + specl_load_om(om_operations, specactions) # load traditional special actions state_load_dynamics_om( - state, io_manager, siminfo + state, io_manager, siminfo, om_operations ) # operational model for custom python # finalize all dynamically loaded components and prepare to run the model - state_om_model_run_prep(state, io_manager, siminfo) + state_om_model_run_prep(opseq, activities, state, om_operations, siminfo) + section_timing["state om initialization()"] = str(timer.split()) + "seconds" + statenb = state_class_lite(0) + state_copy(state, statenb) ####################################################################################### # main processing loop msg(1, f"Simulation Start: {start}, Stop: {stop}") - tscat = {} for _, operation, segment, delt in opseq.itertuples(): msg(2, f"{operation} {segment} DELT(minutes): {delt}") siminfo["delt"] = delt @@ -206,7 +220,7 @@ def main( msg(3, f"{activity}") # Set context for dynamic executables and special actions state_context_hsp2(state, operation, segment, activity) - + state_copy(state, statenb) ui = model[(operation, activity, segment)] # ui is a dictionary if operation == "PERLND" and activity == "SEDMNT": # special exception here to make CSNOFG available @@ -399,11 +413,11 @@ def main( if operation not in ["COPY", "GENER"]: if activity == "HYDR": errors, errmessages = function( - io_manager, siminfo, ui, ts, ftables, state + siminfo, ui, ts, ftables, statenb ) elif activity == "SEDTRN" or activity == "SEDMNT": errors, errmessages = function( - io_manager, siminfo, ui, ts, state + siminfo, ui, ts, statenb ) elif activity != "RQUAL": errors, errmessages = function(io_manager, siminfo, ui, ts) @@ -418,7 +432,7 @@ def main( ui_phcarb, ts, monthdata, - state, + statenb, ) ############################################################### @@ -518,11 +532,12 @@ def main( jupyterlab, outstep_phcarb, ) + section_timing[operation + segment] = str(timer.split()) + "seconds" msglist = msg(1, "Done", final=True) # Finish operational models - state_om_model_run_finish(state, io_manager, siminfo) + state_om_model_run_finish(statenb, io_manager, siminfo) df = DataFrame(msglist, columns=["logfile"]) io_manager.write_log(df) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index a85f579e..ed8f9d53 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -5,24 +5,21 @@ # defined aove that are called by the object classes import json import os -import pandas as pd -import numpy as np import time -from numpy import zeros -from numba import njit # import the types -from hsp2.state.state import append_state, get_ix_path +import numpy as np +from pandas import Series, DataFrame +from numba import njit # import the types +from numpy import zeros +from hsp2.hsp2.om_timer import timer_class -def get_exec_order(model_exec_list, var_ix): - """ - Find the integer key of a variable name in state_ix - """ - model_exec_list = dict(enumerate(model_exec_list.flatten(), 1)) - for exec_order, ix in model_exec_list.items(): - if var_ix == ix: - # we need to add this to the state - return exec_order - return False +from hsp2.state.state import ( + append_state, + hydr_init_ix, + rqual_init_ix, + sedmnt_init_ix, + sedtrn_init_ix, +) def init_op_tokens(op_tokens, tops, eq_ix): @@ -56,19 +53,20 @@ def model_element_paths(mel, state): """ ixn = 1 for ix in mel: - ip = get_ix_path(state["state_paths"], ix) - im = state["model_object_cache"][ip] + ip = state.get_ix_path(ix) + im = om_operations["model_object_cache"][ip] print(ixn, ":", im.name, "->", im.state_path, "=", im.get_state()) ixn = ixn + 1 return # Import Code Classes -from hsp2.hsp2.om_model_object import ModelObject, ModelVariable, pre_step_register -from hsp2.hsp2.om_sim_timer import SimTimer, step_sim_timer from hsp2.hsp2.om_equation import Equation, step_equation from hsp2.hsp2.om_model_linkage import ModelLinkage, step_model_link +from hsp2.hsp2.om_model_object import ModelObject, ModelVariable, pre_step_register +from hsp2.hsp2.om_sim_timer import SimTimer, step_sim_timer from hsp2.hsp2.om_special_action import SpecialAction, step_special_action + # from hsp2.hsp2.om_data_matrix import * # from hsp2.hsp2.om_model_broadcast import * # from hsp2.hsp2.om_simple_channel import * @@ -88,7 +86,7 @@ def init_om_dicts(): return op_tokens, model_object_cache -def state_load_om_json(state, io_manager, siminfo): +def state_load_om_json(state, io_manager, siminfo, om_operations): # - model objects defined in file named '[model h5 base].json -- this will populate an array of object definitions that will # be loadable by "model_loader_recursive()" # JSON file would be in same path as hdf5 @@ -102,16 +100,14 @@ def state_load_om_json(state, io_manager, siminfo): jfile = open(fjson) json_data = json.load(jfile) # dict.update() combines the arg dict with the base - state["model_data"].update(json_data) - # merge in the json siminfo data - if "siminfo" in state["model_data"].keys(): - siminfo.update(state["model_data"]["siminfo"]) - else: - state["model_data"]["siminfo"] = siminfo + om_operations["model_data"].update(json_data) + # merge in the json siminfo data if provided + if "siminfo" in om_operations["model_data"].keys(): + siminfo.update(om_operations["model_data"]["siminfo"]) return -def state_load_om_python(state, io_manager, siminfo): +def state_load_om_python(state, io_manager, siminfo, om_operations): # Look for a [hdf5 file base].py file with specific named functions # - function "om_init_model": This function can be defined in the [model h5 base].py file containing things to be done # early in the model loading, like setting up model objects. This file will already have been loaded by the state module, @@ -123,34 +119,35 @@ def state_load_om_python(state, io_manager, siminfo): (fbase, fext) = os.path.splitext(hdf5_path) # see if there is a code module with custom python # print("Looking for custom om loader in python code ", (fbase + ".py")) - hsp2_local_py = state["hsp2_local_py"] + hsp2_local_py = state.state_step_hydr # Load a function from code if it exists if "om_init_model" in dir(hsp2_local_py): hsp2_local_py.om_init_model( io_manager, siminfo, - state["op_tokens"], - state["state_paths"], - state["state_ix"], - state["dict_ix"], - state["ts_ix"], - state["model_object_cache"], + state.op_tokens, + state.state_paths, + state.state_ix, + state.dict_ix, + state.ts_ix, + om_operations["model_object_cache"], ) -def om_init_state(state): +def om_init_state(): # this function will check to see if any of the multiple paths to loading - was state_initialize_om() # dynamic operational model objects has been supplied for the model. # Grab globals from state for easy handling op_tokens, model_object_cache = init_om_dicts() - state["op_tokens"], state["model_object_cache"], state["model_exec_list"] = ( - op_tokens, - model_object_cache, - [], - ) + om_operations = {} + om_operations["op_tokens"] = op_tokens + om_operations["model_object_cache"] = model_object_cache + om_operations["model_exec_list"] = [] + om_operations["model_data"] = {} + return om_operations -def state_load_dynamics_om(state, io_manager, siminfo): +def state_load_dynamics_om(state, io_manager, siminfo, om_operations): # this function will check to see if any of the multiple paths to loading # dynamic operational model objects has been supplied for the model. # om_init_state(state) must have been called already @@ -160,104 +157,97 @@ def state_load_dynamics_om(state, io_manager, siminfo): # but if things fail post develop-specact-1 pull requests we may investigate here # also, it may be that this should be loaded elsewhere? # comment state_load_om_python() to disable dynamic python - state_load_om_python(state, io_manager, siminfo) - state_load_om_json(state, io_manager, siminfo) + state_load_om_python(state, io_manager, siminfo, om_operations) + state_load_om_json(state, io_manager, siminfo, om_operations) return -def state_om_model_root_object(state, siminfo): +def state_om_model_root_object(state, om_operations, siminfo): # Create the base that everything is added to. this object does nothing except host the rest. - if "model_root_object" not in state.keys(): + timer = timer_class() + if "model_root_object" not in om_operations.keys(): model_root_object = ModelObject( - state["model_root_name"], False, {}, state + state.model_root_name, False, {}, state, om_operations["model_object_cache"] ) # we give this no name so that it does not interfer with child paths like timer, year, etc (i.e. /STATE/year, ...) - state["model_root_object"] = model_root_object + om_operations["model_root_object"] = model_root_object # set up the timer as the first element - model_root_object = state["model_root_object"] - if "/STATE/timer" not in state["state_paths"].keys(): + else: + model_root_object = om_operations["model_root_object"] + #print("model_root_object", timer.split()) + if "/STATE/timer" not in state.state_paths.keys(): timer_props = siminfo timer_props["state_path"] = "/STATE/timer" - timer = SimTimer("timer", model_root_object, timer_props, state) + sim_timer = SimTimer("timer", model_root_object, timer_props) + #print("timer", timer.split()) # add base object for the HSP2 domains and other things already added to state so they can be influenced - for seg_name, seg_path in state["hsp_segments"].items(): - if seg_path not in state["model_object_cache"].keys(): + for seg_name, seg_path in state.hsp_segments.items(): + if seg_path not in om_operations["model_object_cache"].keys(): # BUG: need to figure out if this is OK, then how do we add attributes to these River Objects # later when adding from json? # Can we simply check the model_object_cache during load step? # Create an object shell for this - segment = ModelObject(seg_name, model_root_object, {}, state) - state["model_object_cache"][segment.state_path] = segment + # just get the end of the path, which should be fine since we + # don't use model names for anything, but might be more appropriately made as full path + segment = ModelObject(seg_name, model_root_object, {}) + om_operations["model_object_cache"][segment.state_path] = segment -def state_om_model_run_prep(state, io_manager, siminfo): +def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): # insure model base is set - state_om_model_root_object(state, siminfo) + timer = timer_class() + state_om_model_root_object(state, om_operations, siminfo) # now instantiate and link objects - # state['model_data'] has alread been prepopulated from json, .py files, hdf5, etc. - model_root_object = state["model_root_object"] - model_loader_recursive(state["model_data"], model_root_object, state) + # om_operations['model_data'] has alread been prepopulated from json, .py files, hdf5, etc. + model_root_object = om_operations["model_root_object"] + model_object_cache = om_operations["model_object_cache"] + model_loader_recursive( + om_operations["model_data"], model_root_object, state, model_object_cache + ) + #print("model_loader_recursive", timer.split()) # print("Loaded objects & paths: insures all paths are valid, connects models as inputs") # both state['model_object_cache'] and the model_object_cache property of the ModelObject class def # will hold a global repo for this data this may be redundant? They DO point to the same datset? # since this is a function that accepts state as an argument and these were both set in state_load_dynamics_om # we can assume they are there and functioning - model_object_cache = model_root_object.state["model_object_cache"] model_path_loader(model_object_cache) # len() will be 1 if we only have a simtimer, but > 1 if we have a river being added - model_exec_list = state["model_exec_list"] + model_exec_list = state.model_exec_list # put all objects in token form for fast runtime execution and sort according to dependency order # print("Tokenizing models") if "ops_data_type" in siminfo.keys(): model_root_object.ops_data_type = siminfo[ "ops_data_type" ] # allow override of dat astructure settings - model_root_object.state["op_tokens"] = ModelObject.make_op_tokens( - max(model_root_object.state["state_ix"].keys()) + 1 - ) + # model_root_object.state.op_tokens = ModelObject.make_op_tokens( + # len(model_root_object.state.state_ix) + # ) model_tokenizer_recursive(model_root_object, model_object_cache, model_exec_list) - op_tokens = model_root_object.state["op_tokens"] + #print("model_tokenizer_recursive", timer.split()) + # op_tokens = model_root_object.state.op_tokens # print("op_tokens afer tokenizing", op_tokens) # model_exec_list is the ordered list of component operations # print("model_exec_list(", len(model_exec_list),"items):", model_exec_list) # This is used to stash the model_exec_list in the dict_ix, this might be slow, need to verify. # the resulting set of objects is returned. - state["state_step_om"] = "disabled" - state["model_object_cache"] = model_object_cache - state["model_exec_list"] = np.asarray(model_exec_list, dtype="i8") - if model_root_object.ops_data_type == "ndarray": - state_keyvals = np.asarray( - zeros(max(model_root_object.state["state_ix"].keys()) + 1), dtype="float64" - ) - for ix, val in model_root_object.state["state_ix"].items(): - state_keyvals[ix] = val - state["state_ix"] = state_keyvals - else: - state["state_ix"] = model_root_object.state["state_ix"] - state["op_tokens"] = ( - op_tokens # is this superfluous since the root object got op_tokens from state? - ) - if len(op_tokens) > 0: - state["state_step_om"] = "enabled" - - # print("op_tokens is type", type(op_tokens)) - # print("state_ix is type", type(state['state_ix'])) - # print("state_paths final", state['state_paths']) - # print("op_tokens final", op_tokens) - # Stash a list of runnables - state["runnables"] = ModelObject.runnable_op_list( - state["op_tokens"], list(state["state_paths"].values()) - ) - # print("Operational model status:", state['state_step_om']) - if len(model_exec_list) > 0: - # pass + state.state_step_om = "disabled" + om_operations["model_object_cache"] = model_object_cache + state.model_exec_list = np.asarray(model_exec_list, dtype="int64") + if len(state.op_tokens) > 0: + state.state_step_om = "enabled" + if len(state.op_tokens) > 0: print( "op_tokens has", - len(op_tokens), - "elements, with ", - len(model_exec_list), - "executable elements", + len(state.op_tokens), + "elements", ) +# No longer relevant, need to sum up the executables for each domain in op_exec_lists +# "with", +# len(state.model_exec_list), +# "executable elements", +# ) # print("Exec list:", model_exec_list) + # Now make sure that all HSP2 vars that can be affected by state have + hsp2_domain_dependencies(state, opseq, activities, om_operations, False) return @@ -405,7 +395,7 @@ def model_class_translate(model_props, object_class): model_props["object_class"] = "ModelObject" -def model_loader_recursive(model_data, container, state): +def model_loader_recursive(model_data, container, state, model_object_cache): k_list = model_data.keys() object_names = dict.fromkeys(k_list, 1) if type(object_names) is not dict: @@ -445,7 +435,7 @@ def model_loader_recursive(model_data, container, state): if model_props["overwrite"] == True: model_object = False else: - model_object = state["model_object_cache"][model_object_path] + model_object = model_object_cache[model_object_path] if model_object == False: # try to load this object model_object = model_class_loader( @@ -457,7 +447,7 @@ def model_loader_recursive(model_data, container, state): # now for container type objects, go through its properties and handle # print("loaded object", model_object, "with container", container) if type(model_props) is dict: - model_loader_recursive(model_props, model_object, state) + model_loader_recursive(model_props, model_object, state, model_object_cache) def model_path_loader(model_object_cache): @@ -516,7 +506,7 @@ def model_tokenizer_recursive( input_object, model_object_cache, model_exec_list, model_touch_list ) else: - if input_path in model_object.state_paths.keys(): + if input_path in model_object.state.state_paths: # this is a valid state reference without an object # thus, it is likely part of internals that are manually added # which should be fine. tho perhaps we should have an object for these too. @@ -532,11 +522,15 @@ def model_tokenizer_recursive( # now after tokenizing all inputs this should be OK to tokenize model_object.add_op_tokens() if model_object.optype in ModelObject.runnables: - model_exec_list.append(model_object.ix) + model_exec_list = np.append(model_exec_list, model_object.ix) def model_order_recursive( - model_object, model_object_cache, model_exec_list, model_touch_list=None + model_object, + model_object_cache, + model_exec_list, + model_touch_list=None, + debug=False, ): """ Given a root model_object, trace the inputs to load things in order @@ -550,12 +544,28 @@ def model_order_recursive( that are sending to that broadcast? - Or is it better to let it as it is, """ + if debug: + print( + "Handling model object:", + model_object.name, + "with path", + model_object.state_path, + ) if model_touch_list is None: model_touch_list = [] if model_object.ix in model_exec_list: + if debug: + print(model_object.name, "already added to model_exec_list. Returning.") return if model_object.ix in model_touch_list: - # print("Already touched", model_object.name, model_object.ix, model_object.state_path) + if debug: + print( + "Already touched", + model_object.name, + model_object.ix, + model_object.state_path, + ". Returning.", + ) return # record as having been called, and will ultimately return, to prevent recursions model_touch_list.append(model_object.ix) @@ -581,7 +591,7 @@ def model_order_recursive( input_object, model_object_cache, model_exec_list, model_touch_list ) else: - if input_path in model_object.state_paths.keys(): + if input_path in model_object.state.state_paths: # this is a valid state reference without an object # thus, it is likely part of internals that are manually added # which should be fine. tho perhaps we should have an object for these too. @@ -595,32 +605,34 @@ def model_order_recursive( ) return # now after loading input dependencies, add this to list + if debug: + print("Adding", model_object.ix, "to element list") model_exec_list.append(model_object.ix) -def model_input_dependencies(state, exec_list, only_runnable=False): +def model_input_dependencies(state, exec_list, model_object_cache, only_runnable=False): # TODO: is this redundant to model_domain_dependencies? # Cmment in github suggest it is not, and has specific utility # for timeseries values? https://github.com/HARPgroup/HSPsquared/issues/60#issuecomment-2231668979 mello = exec_list mtl = [] mel = [] - for model_element in state["model_object_cache"].values(): + for model_element in model_object_cache.values(): for input_path in model_element.inputs: - input_ix = get_state_ix(state["state_ix"], state["state_paths"], input_path) + input_ix = get_state_ix(state.state_ix, state.state_paths, input_path) if input_ix in exec_list: # do a recursive pull of factors affecting this element - model_order_recursive( - model_element, state["model_object_cache"], mel, mtl - ) + model_order_recursive(model_element, model_object_cache, mel, mtl) mello = mello + mel if only_runnable == True: - mello = ModelObject.runnable_op_list(state["op_tokens"], mello) - mello = pd.Series(mello).drop_duplicates().tolist() + mello = ModelObject.runnable_op_list(state.op_tokens, mello) + mello = Series(mello).drop_duplicates().tolist() return mello -def model_domain_dependencies(state, domain, ep_list, only_runnable=False): +def model_domain_dependencies( + om_operations, state, domain, ep_list, only_runnable=False, debug=False +): """ Given an hdf5 style path to a domain, and a list of variable endpoints in that domain, Find all model elements that influence the endpoints state @@ -630,24 +642,62 @@ def model_domain_dependencies(state, domain, ep_list, only_runnable=False): for ep in ep_list: mel = [] mtl = [] + if debug: + print("Searching for", (domain + "/" + ep), "in state_paths") # if the given element is NOT in model_object_cache, then nothing is acting on it, so we return empty list - if (domain + "/" + ep) in state["state_paths"]: - if (domain + "/" + ep) in state["model_object_cache"].keys(): - endpoint = state["model_object_cache"][domain + "/" + ep] - model_order_recursive(endpoint, state["model_object_cache"], mel, mtl) + if (domain + "/" + ep) in state.state_paths.keys(): + if (domain + "/" + ep) in om_operations["model_object_cache"].keys(): + if debug: + print("Found", (domain + "/" + ep), "in om_operations") + endpoint = om_operations["model_object_cache"][domain + "/" + ep] + model_order_recursive( + endpoint, om_operations["model_object_cache"], mel, mtl + ) mello = mello + mel # TODO: stash the runnable list (mellorun) as a element in dict_ix for cached access during runtime - mellorun = ModelObject.runnable_op_list(state["op_tokens"], mello) + mellorun = ModelObject.runnable_op_list(state.op_tokens, mello) if only_runnable == True: mello = mellorun return mello +def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=False): + # This sets up the state entries for all state compatible HSP2 model variables + # print("STATE initializing contexts.") + for _, operation, segment, delt in opseq.itertuples(): + if operation != "GENER" and operation != "COPY": + for activity, function in activities[operation].items(): + # set up named paths for model operations + seg_name = operation + "_" + segment + seg_path = "/STATE/" + state.model_root_name + "/" + seg_name + activity_path = seg_path + "/" + activity + activity_id = state.set_state(activity_path, 0.0) + ep_list = DataFrame() + if debug: + print("Getting init_ix for", seg_path, activity) + if activity == "HYDR": + ep_list = hydr_init_ix(state, seg_path) + elif activity == "SEDTRN": + ep_list = sedtrn_init_ix(state, seg_path) + elif activity == "SEDMNT": + ep_list = sedmnt_init_ix(state, seg_path) + elif activity == "RQUAL": + ep_list = rqual_init_ix(state, seg_path) + # Register list of elements to execute if any + op_exec_list = model_domain_dependencies( + om_operations, state, seg_path, ep_list, True, debug + ) + op_exec_list = np.asarray(op_exec_list) + # register the dependencies for each activity so we can load once here + # then just iterate through them at runtime without re-querying + state.set_exec_list(activity_id, op_exec_list) + + def save_object_ts(io_manager, siminfo, op_tokens, ts_ix, ts): # Decide on using from utilities.py: # - save_timeseries(io_manager, ts, savedict, siminfo, saveall, operation, segment, activity, compress=True) # Or, skip the save_timeseries wrapper and call write_ts() directly in io.py: - # write_ts(self, data_frame:pd.DataFrame, save_columns: List[str], category:Category, operation:Union[str,None]=None, segment:Union[str,None]=None, activity:Union[str,None]=None) + # write_ts(self, data_frame:DataFrame, save_columns: List[str], category:Category, operation:Union[str,None]=None, segment:Union[str,None]=None, activity:Union[str,None]=None) # see line 317 in utilities.py for use example of write_ts() x = 0 # dummy return @@ -665,7 +715,7 @@ def iterate_models( return checksum -@njit +@njit(cache=True) def pre_step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): for i in model_exec_list: if op_tokens[i][0] == 12: @@ -676,15 +726,23 @@ def pre_step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): @njit def step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): + n = 0 for i in model_exec_list: + # skip these - we could optimize performance and return assuming + # that the first -1 item is the end of the active components + if op_tokens[i][0] == -1: + return step_one(op_tokens, op_tokens[i], state_ix, dict_ix, ts_ix, step, 0) + n = n + 1 return def finish_model(state, io_manager, siminfo): - # print("Model object cache list", state["model_object_cache"].keys()) - for i in state["model_exec_list"]: - model_object = state["model_object_cache"][get_ix_path(state["state_paths"], i)] + # print("Model object cache list", om_operations["model_object_cache"].keys()) + for i in state.model_exec_list: + model_object = om_operations["model_object_cache"][ + state.get_ix_path(i) + ] if "io_manager" in dir(model_object): model_object.io_manager = io_manager model_object.finish() @@ -696,11 +754,11 @@ def step_one(op_tokens, ops, state_ix, dict_ix, ts_ix, step, debug=0): # op_tokens is passed in for ops like matrices that have lookups from other # locations. All others rely only on ops # todo: decide if all step_[class() functions should set value in state_ix instead of returning value? - if debug > 0: + if debug: print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) print("DEBUG: ops: ", ops) if ops[0] == 1: - step_equation(ops, state_ix) + step_equation(ops, state_ix, step) elif ops[0] == 2: # todo: this should be moved into a single function, # with the conforming name step_matrix(op_tokens, ops, state_ix, dict_ix) diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index ade606cf..58bb5d24 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -6,26 +6,19 @@ in the state_ix Dict for runtime execution. """ -from hsp2.hsp2.om import is_float_digit -from hsp2.state.state import set_state, get_state_ix -from hsp2.hsp2.om_model_object import ModelObject, ModelConstant from numba import njit -from numpy import array, append +from numpy import append, array -# from hsp2.state.state import set_state, get_state_ix -# from numba.typed import Dict -# from hsp2.hsp2.om import get_exec_order, is_float_digit -# from pandas import Series, DataFrame, concat, HDFStore, set_option, to_numeric -# from pandas import Timestamp, Timedelta, read_hdf, read_csv -# from numpy import pad, asarray, zeros, int32 -# from numba import njit, types +from hsp2.hsp2.om import is_float_digit +from hsp2.hsp2.om_model_object import ModelConstant, ModelObject +from hsp2.state.state import get_state_ix, set_state class Equation(ModelObject): # the following are supplied by the parent class: name, log_path, attribute_path, state_path, inputs def __init__(self, name, container=False, model_props={}, state=None): - super(Equation, self).__init__(name, container, model_props) + super().__init__(name, container, model_props) self.equation = self.handle_prop(model_props, "equation") self.ps = False self.ps_names = [] # Intermediate with constants turned into variable references in state_paths @@ -137,9 +130,7 @@ def tokenize_vars(self): elif is_float_digit(self.var_ops[j]): # must add this to the state array as a constant constant_path = self.state_path + "/_ops/_op" + str(j) - s_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], + s_ix = self.state.set_state( constant_path, float(self.var_ops[j]), ) @@ -147,9 +138,7 @@ def tokenize_vars(self): else: # this is a variable, must find it's data path index var_path = self.find_var_path(self.var_ops[j]) - s_ix = get_state_ix( - self.state["state_ix"], self.state["state_paths"], var_path - ) + s_ix = self.state.get_state_ix(var_path) if s_ix == False: print( "Error: unknown variable ", @@ -159,9 +148,7 @@ def tokenize_vars(self): "index", s_ix, ) - print( - "searched: ", self.state["state_paths"], self.state["state_ix"] - ) + print("searched: ", self.state.state_paths, self.state.state_ix) return else: self.var_ops[j] = s_ix @@ -178,20 +165,21 @@ def tokenize(self): self.ops = self.ops + [self.non_neg, self.min_value_ix] + self.var_ops +import math +import operator + from pyparsing import ( - Literal, - Word, - Group, + CaselessKeyword, Forward, - alphas, - alphanums, + Group, + Literal, Regex, - CaselessKeyword, Suppress, + Word, + alphanums, + alphas, delimitedList, ) -import math -import operator exprStack = [] @@ -263,7 +251,6 @@ def tokenize_ops(ps): bnf = None - def BNF(): """ expop :: '^' @@ -454,7 +441,7 @@ def evaluate_eq_ops(op, val1, val2): @njit -def step_equation(op_token, state_ix): +def step_equation(op_token, state_ix, step): result = 0 s = array([0.0]) s_ix = -1 # pointer to the top of the stack @@ -462,11 +449,10 @@ def step_equation(op_token, state_ix): # handle special equation settings like "non-negative", etc. non_neg = op_token[2] min_ix = op_token[3] - num_ops = op_token[ - 4 - ] # this index is equal to the number of ops common to all classes + 1. See om_model_object for base ops and adjust + # this index is equal to the number of ops common to all classes + 1. + # See om_model_object for base ops and adjust + num_ops = op_token[4] op_loc = 5 # where do the operators and operands start in op_token - # print(num_ops, " operations") # is the below faster since it avoids a brief loop and a couple ifs for 2 op equations? if num_ops == 1: result = evaluate_eq_ops( @@ -494,7 +480,6 @@ def step_equation(op_token, state_ix): s_ix -= 1 else: val2 = state_ix[t2] - # print(s_ix, op, val1, val2) result = evaluate_eq_ops(op, val1, val2) s_ix += 1 if s_ix >= s_len: @@ -504,5 +489,7 @@ def step_equation(op_token, state_ix): result = s[s_ix] if (non_neg == 1) and (result < 0): result = state_ix[min_ix] + #if step < 2: + # print("Eq:", op_token[1], result) state_ix[op_token[1]] = result return True diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index a09c3528..f318556f 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -4,7 +4,7 @@ during a model simulation. """ -from hsp2.state.state import state_add_ts, get_state_ix +from hsp2.state.state import state_add_ts from hsp2.hsp2.om import * from hsp2.hsp2.om_model_object import ModelObject from numba import njit @@ -14,7 +14,7 @@ class ModelLinkage(ModelObject): def __init__(self, name, container=False, model_props=None, state=None): if model_props is None: model_props = {} - super(ModelLinkage, self).__init__(name, container, model_props, state=False) + super(ModelLinkage, self).__init__(name, container, model_props, state) # ModelLinkage copies a values from right to left # right_path: is the data source for the link # left_path: is the destination of the link @@ -49,8 +49,8 @@ def __init__(self, name, container=False, model_props=None, state=None): self.left_path = self.state_path if self.link_type == 0: # if this is a simple input we remove the object from the model_object_cache, and pass back to parent as an input - del self.state["model_object_cache"][self.state_path] - del self.state["state_ix"][self.ix] + del self.om_operations["model_object_cache"][self.state_path] + del self.state.state_ix[self.ix] container.add_input(self.name, self.right_path) if self.link_type == 6: # add an entry into time series dataframe @@ -96,19 +96,26 @@ def find_paths(self): # self.insure_path(self, self.right_path) # the left path, if this is type 4 or 5, is a push, so we must require it if (self.link_type == 4) or (self.link_type == 5) or (self.link_type == 6): - self.insure_path(self.left_path) + #print("ModelLinkage", self.name, "insuring register with path", self.left_path) push_pieces = self.left_path.split("/") push_name = push_pieces[len(push_pieces) - 1] - var_register = self.insure_register( - push_name, 0.0, False, self.left_path, False - ) - print( - "Created register", - var_register.name, - "with path", - var_register.state_path, - ) - # add already created objects as inputs + left_object = self.get_object(self.left_path) + if not left_object: + # try to fin the parent and create the register since push is allowed + left_parent_path = '/'.join(push_pieces[0:len(push_pieces) - 1]) + left_parent_object = self.get_object(left_parent_path) + if not left_parent_object: + raise Exception( + "Cannot find variable path: " + + left_parent_path + + " when trying to push to object " + + push_name + ) + var_register = self.insure_register( + push_name, 0.0, left_parent_object, self.left_path, False + ) + #print("Created register", var_register.name, "with path", var_register.state_path) + # add already created objects as inputs var_register.add_object_input(self.name, self, 1) # Now, make sure that all time series paths can be found and loaded if self.link_type == 3: @@ -139,18 +146,16 @@ def read_ts(self, set_ts_ix=True): def write_ts(self, ts=None, ts_cols=None, write_path=None, tindex=None): if ts == None: - tix = get_state_ix( - self.state["state_ix"], self.state["state_paths"], self.left_path - ) + tix = self.state.get_state_ix(self.left_path) # get the ts. Note, we get the ts entry that corresponds to the left_path setting - ts = self.state["ts_ix"][tix] + ts = self.state.ts_ix[tix] if write_path == None: if self.left_path != None: write_path = self.left_path else: return False if tindex == None: - tindex = self.state["model_data"]["siminfo"]["tindex"] + tindex = self.get_tindex() tsdf = self.format_ts(ts, ts_cols, tindex) if self.io_manager == False: # to do: allow object to specify hdf path name and if so, can open and read/write @@ -187,9 +192,7 @@ def tokenize(self): # - execution hierarchy # print("Linkage/link_type ", self.name, self.link_type,"created with params", self.model_props_parsed) if self.link_type in (2, 3): - src_ix = get_state_ix( - self.state["state_ix"], self.state["state_paths"], self.right_path - ) + src_ix = self.state.get_state_ix(self.right_path) if not (src_ix == False): self.ops = self.ops + [src_ix, self.link_type] else: @@ -197,12 +200,8 @@ def tokenize(self): # print(self.name,"tokenize() result", self.ops) if (self.link_type == 4) or (self.link_type == 5) or (self.link_type == 6): # we push to the remote path in this one - left_ix = get_state_ix( - self.state["state_ix"], self.state["state_paths"], self.left_path - ) - right_ix = get_state_ix( - self.state["state_ix"], self.state["state_paths"], self.right_path - ) + left_ix = self.state.get_state_ix(self.left_path) + right_ix = self.state.get_state_ix(self.right_path) if (left_ix != False) and (right_ix != False): self.ops = self.ops + [left_ix, self.link_type, right_ix] else: @@ -226,11 +225,8 @@ def finish(self): # Function for use during model simulations of tokenized objects -@njit +@njit(cache=True) def step_model_link(op_token, state_ix, ts_ix, step): - # if step == 2: - # print("step_model_link() called at step 2 with op_token=", op_token) - # print("step_model_link() called at step 2 with op_token=", op_token) if op_token[3] == 1: return True elif op_token[3] == 2: @@ -250,15 +246,6 @@ def step_model_link(op_token, state_ix, ts_ix, step): return True elif op_token[3] == 6: # set value in a timerseries - if step < 10: - print( - "Writing ", - state_ix[op_token[4]], - "from ix=", - op_token[4], - "to", - op_token[2], - ) ts_ix[op_token[2]][step] = state_ix[op_token[4]] return True diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 30451052..b0c549d1 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -4,12 +4,13 @@ All runtime exec is done by child classes. """ -from hsp2.state.state import set_state, get_state_ix +from numba import njit, types from numba.typed import Dict -from hsp2.hsp2.om import get_exec_order, is_float_digit +from numpy import asarray, int64, pad, zeros from pandas import HDFStore -from numpy import pad, asarray, zeros, int32 -from numba import njit, types + +from hsp2.hsp2.om import is_float_digit +from hsp2.state.state import nkey_exists class ModelObject: @@ -32,27 +33,44 @@ class ModelObject: ] # runnable components important for optimization ops_data_type = "ndarray" # options are ndarray or Dict - Dict appears slower, but unsure of the cause, so keep as option. - def __init__(self, name, container=False, model_props=None, state=None): + def __init__( + self, + name, + container=False, + model_props=None, + state=None, + model_object_cache=None, + ): self.name = name - self.handle_deprecated_args(name, container, model_props, state) - # END - handle deprecated - if model_props is None: - model_props = {} self.container = container # will be a link to another object - self.state_path = self.handle_prop(model_props, "state_path", False, False) - if type(state) != dict: + if state is None: # we must verify that we have a properly formatted state Dictionary, or that our parent does. if self.container == False: raise Exception( - "Error: State dictionary must be passed to root object. ", - type(state), - "passed instead." - + name - + " cannot be created. See state::init_state_dicts()", + "Error: State object must be passed to root object. ", + +name + " cannot be created. See state::init_state_dicts()", ) else: state = self.container.state + if model_object_cache is None: + # we must verify that we have a properly formatted state Dictionary, or that our parent does. + if self.container == False: + raise Exception( + "Error: model_object_cache object must be available on to root object. " + + name + + " cannot be created. See state::init_state_dicts()" + ) + else: + model_object_cache = self.container.model_object_cache self.state = state # make a copy here. is this efficient? + self.model_object_cache = ( + model_object_cache # make a copy here. is this efficient? + ) + self.handle_deprecated_args(name, container, model_props, state) + # END - handle deprecated + if model_props is None: + model_props = {} + self.state_path = self.handle_prop(model_props, "state_path", False, False) # Local properties self.model_props_parsed = {} # a place to stash parse record for debugging self.log_path = "" # Ex: "/RESULTS/RCHRES_001/SPECL" @@ -109,7 +127,7 @@ def required_properties(): @staticmethod def make_op_tokens(num_ops=5000): if ModelObject.ops_data_type == "ndarray": - op_tokens = int32( + op_tokens = int64( zeros((num_ops, 64)) ) # was Dict.empty(key_type=types.int64, value_type=types.i8[:]) else: @@ -123,6 +141,7 @@ def runnable_op_list(op_tokens, meo, debug=False): run_ops = {} for ops in op_tokens: # the base class defines the type of objects that are runnable (i.e. have a step() method) + #print("Handling ops", ops) if ops[0] in ModelObject.runnables: run_ops[ops[1]] = ops if debug == True: @@ -191,6 +210,8 @@ def handle_prop(self, model_props, prop_name, strict=False, default_value=None): + self.name + " and strict = True. Object creation halted. Path to object with error is " + self.state_path + + "This objects inputs are:", + self.inputs, ) if (prop_val == None) and not (default_value == None): prop_val = default_value @@ -207,20 +228,12 @@ def parse_model_props(self, model_props, strict=False): return True def set_state(self, set_value): - var_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], + var_ix = self.state.set_state( self.state_path, set_value, ) return var_ix - def load_state_dicts(self, op_tokens, state_paths, state_ix, dict_ix): - self.state["op_tokens"] = op_tokens - self.state["state_paths"] = state_paths - self.state["state_ix"] = state_ix - self.state["dict_ix"] = dict_ix - def save_object_hdf(self, hdfname, overwrite=False): # save the object in the full hdf5 path # if overwrite = True replace this and all children, otherwise, just save this. @@ -232,6 +245,7 @@ def make_paths(self, base_path=False): # print("calling make_paths from", self.name, "with base path", base_path) if base_path == False: # we are NOT forcing paths if not (self.container == False): + # print("Using container path as base:", self.container.state_path + "/" + str(self.name)) self.state_path = self.container.state_path + "/" + str(self.name) self.attribute_path = ( self.container.attribute_path + "/" + str(self.name) @@ -250,55 +264,58 @@ def make_paths(self, base_path=False): def get_state(self, var_name=False): if var_name == False: - return self.state["state_ix"][self.ix] + return self.state.state_ix[self.ix] else: var_path = self.find_var_path(var_name) - var_ix = get_state_ix( - self.state["state_ix"], self.state["state_paths"], var_path - ) + # print("Looking for state ix of:", var_path) + var_ix = self.state.get_state_ix(var_path) if var_ix == False: return False - return self.state["state_ix"][var_ix] + return self.state.state_ix[var_ix] - def get_exec_order(self, var_name=False): - if var_name == False: - var_ix = self.ix - else: - var_path = self.find_var_path(var_name) - var_ix = get_state_ix( - self.state["state_ix"], self.state["state_paths"], var_path - ) - exec_order = get_exec_order(self.state["model_exec_list"], var_ix) - return exec_order + def get_tindex(self): + timer = self.get_object("timer") + tindex = self.state.dict_ix[timer.ix] + return tindex def get_object(self, var_name=False): if var_name == False: - return self.state["model_object_cache"][self.state_path] + return self.model_object_cache[self.state_path] else: var_path = self.find_var_path(var_name) - return self.state["model_object_cache"][var_path] + if var_path in self.model_object_cache: + return self.model_object_cache[var_path] + else: + return False def find_var_path(self, var_name, local_only=False): # check local inputs for name + if var_name is None: + print("NULL var searched from", self.name, "child of", self.container.name) if type(var_name) == str: # print("Expanding aliases for", var_name) var_name = self.handle_path_aliases(var_name) # sub out any wildcards # print(self.name, "called", "find_var_path(self, ", var_name, ", local_only = False)") if var_name in self.inputs.keys(): return self.inputs[var_name] + # check for state vars in my path + var_name + if nkey_exists(self.state.state_paths, self.state_path + "/" + var_name): + return self.state_path + "/" + var_name if local_only: + #print("Cannot find var", var_name, "in local scope", self.name) return False # we are limiting the scope, so just return # check parent for name if not (self.container == False): + #print("Searching for var", var_name, "in container scope", self.container.name, self.container.state_path) return self.container.find_var_path(var_name) # check for root state vars STATE + var_name - if ("/STATE/" + var_name) in self.state["state_paths"].keys(): - # return self.state['state_paths'][("/STATE/" + var_name)] + if ("/STATE/" + var_name) in self.state.state_paths: return "/STATE/" + var_name # check for full paths - if var_name in self.state["state_paths"].keys(): + if nkey_exists(self.state.state_paths, var_name): # return self.state['state_paths'][var_name] return var_name + #print("Cannot find var in global scope", self.state_path, "var", var_name) return False def constant_or_path(self, keyname, keyval, trust=False): @@ -318,14 +335,10 @@ def register_path(self): # print("register_path called for", self.name, "with state_path", self.state_path) if self.state_path == "" or self.state_path == False: self.make_paths() - self.ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - self.state_path, - self.default_value, - ) + self.ix = self.state.set_state(self.state_path, self.default_value) # store object in model_object_cache - always, if we have reached this point we need to overwrite - self.state["model_object_cache"][self.state_path] = self + # print("Adding ", self.name, "with state_path", self.state_path, "to model_object_cache") + self.model_object_cache[self.state_path] = self # this should check to see if this object has a parent, and if so, register the name on the parent # default is as a child object. if not (self.container == False): @@ -350,10 +363,10 @@ def add_input(self, var_name, var_path, input_type=1, trust=False): # BUT this only works if both var_name and var_path are month # so add_input('month', 'month', 1, True) works. found_path = self.find_var_path(var_path) - # print("Searched", var_name, "with path", var_path,"found", found_path) - var_ix = get_state_ix( - self.state["state_ix"], self.state["state_paths"], found_path - ) + if found_path == False: + var_ix = False + else: + var_ix = self.state.get_state_ix(found_path) if var_ix == False: if trust == False: raise Exception( @@ -365,6 +378,10 @@ def add_input(self, var_name, var_path, input_type=1, trust=False): + var_name + " ... process terminated. Path to object with error is " + self.state_path + + "This objects inputs are:", + self.inputs, + "State paths=", + self.state.state_paths, ) var_ix = self.insure_path(var_path) else: @@ -408,15 +425,13 @@ def insure_path(self, var_path): # if this path can be found in the hdf5 make sure that it is registered in state # and that it has needed object class to render it at runtime (some are automatic) # RIGHT NOW THIS DOES NOTHING TO CHECK IF THE VAR EXISTS THIS MUST BE FIXED - var_ix = set_state( - self.state["state_ix"], self.state["state_paths"], var_path, 0.0 - ) + var_ix = self.state.set_state(var_path, 0.0) return var_ix def get_dict_state(self, ix=-1): if ix >= 0: - return self.state["dict_ix"][ix] - return self.state["dict_ix"][self.ix] + return self.state.dict_ix[ix] + return self.state.dict_ix[self.ix] def find_paths(self): # Note: every single piece of data used by objects, even constants, are resolved to a PATH in the hdf5 @@ -446,7 +461,7 @@ def insure_register( if register_path == False: register_path = register_container.find_var_path(var_name, True) if (register_path == False) or ( - register_path not in self.state["model_object_cache"].keys() + register_path not in self.model_object_cache.keys() ): # create a register as a placeholder for the data at the hub path # in case there are no senders, or in the case of a timeseries logger, we need to register it so that its path can be set to hold data @@ -466,7 +481,7 @@ def insure_register( var_name, register_container, reg_props, self.state ) else: - var_register = self.state["model_object_cache"][register_path] + var_register = self.model_object_cache[register_path] return var_register def tokenize(self): @@ -495,18 +510,20 @@ def add_op_tokens(self): + self.state_path + "). " ) - self.state["op_tokens"][self.ix] = self.format_ops() + self.state.set_token(self.ix, self.format_ops()) def step(self, step): # this tests the model for a single timestep. # this is not the method that is used for high-speed runs, but can theoretically be used for # easier to understand demonstrations + # this has not been tested since changes to the state from array to object step_one( - self.state["op_tokens"], - self.state["op_tokens"][self.ix], - self.state["state_ix"], - self.state["dict_ix"], - self.state["ts_ix"], + self.state.op_tokens, + self.state.op_tokens[self.ix], + self.state.state_ix, + self.state.dict_ix, + self.state.state_ix, + self.state.ts_ix, step, ) # step_model({self.state['op_tokens'][self.ix]}, self.state['state_ix'], self.state['dict_ix'], self.state['ts_ix'], step) @@ -517,14 +534,10 @@ def finish(self): return True -""" -The class ModelVariable is a base cass for storing numerical values. Used for UVQUAN and misc numerical constants... -""" - - class ModelVariable(ModelObject): + #:The class ModelVariable is a base cass for storing numerical values. Used for UVQUAN and misc numerical constants... def __init__(self, name, container=False, model_props=None, state=None): - super(ModelVariable, self).__init__(name, container, model_props, state) + super().__init__(name, container, model_props, state) # print("ModelVariable named", name, "with path", self.state_path,"beginning") value = self.handle_prop(model_props, "value") self.default_value = float(value) @@ -540,28 +553,20 @@ def required_properties(): return req_props -""" -The class ModelConstant is for storing non-changing values. -""" - - class ModelConstant(ModelVariable): + #: The class ModelConstant is for storing non-changing values. def __init__(self, name, container=False, model_props=None, state=None): - super(ModelConstant, self).__init__(name, container, model_props, state) + super().__init__(name, container, model_props, state) self.optype = 16 # 0 - shell object, 1 - equation, 2 - datamatrix, 3 - input, 4 - broadcastChannel, 5 - SimTimer, 6 - Conditional, 7 - ModelVariable (numeric) # print("ModelVariable named",self.name, "with path", self.state_path,"and ix", self.ix, "value", value) -""" -The class ModelRegister is for storing push values. -Behavior is to zero each timestep. This could be amended later. -Maybe combined with stack behavior? Or accumulator? -""" - - class ModelRegister(ModelVariable): + #: The class ModelRegister is for storing push values. + #: Behavior is to zero each timestep. This could be amended later. + #: Maybe combined with stack behavior? Or accumulator? def __init__(self, name, container=None, model_props=False, state=False): - super(ModelRegister, self).__init__(name, container, model_props, state) + super().__init__(name, container, model_props, state) self.optype = 12 # # self.state['state_ix'][self.ix] = self.default_value diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index 24a93c53..5b4f9e96 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -4,20 +4,19 @@ during a model simulation. """ -from hsp2.state.state import set_state from hsp2.hsp2.om import ModelObject from hsp2.hsp2.om_model_object import ModelObject +from hsp2.state.state import set_numba_value from pandas import DataFrame from numba import njit from numpy import int64 - class SimTimer(ModelObject): def __init__(self, name, container, model_props=None, state=None): if model_props is None: model_props = {} # Note: hsp2 siminfo will match model_props here - super(SimTimer, self).__init__(name, container, model_props) + super(SimTimer, self).__init__(name, container, model_props, state) self.state_path = "/STATE/timer" self.time_array = self.dti_to_time_array( model_props @@ -28,80 +27,23 @@ def __init__(self, name, container, model_props=None, state=None): def register_components(self): # initialize the path variable if not already set - self.ix = set_state( - self.state["state_ix"], - self.state["state_paths"], + self.ix = self.state.set_state( self.state_path, - float(self.time_array[0][0]), + float(self.time_array[0][0]) ) # now register all other paths. # register "year", "month" "day", ... - year_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/year", - float(self.time_array[0][1]), - ) - month_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/month", - float(self.time_array[0][2]), - ) - day_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/day", - float(self.time_array[0][3]), - ) - hr_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/hour", - float(self.time_array[0][4]), - ) - min_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/minute", - float(self.time_array[0][5]), - ) - sec_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/second", - float(self.time_array[0][6]), - ) - wd_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/weekday", - float(self.time_array[0][7]), - ) - dt_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/dt", - float(self.time_array[0][8]), - ) - jd_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/jday", - float(self.time_array[0][9]), - ) - md_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/modays", - float(self.time_array[0][10]), - ) - dts_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], - "/STATE/dts", - float(self.time_array[0][8] * 60.0), - ) + year_ix = self.state.set_state("/STATE/year", float(self.time_array[0][1]) ) + month_ix = self.state.set_state("/STATE/month", float(self.time_array[0][2])) + day_ix = self.state.set_state( "/STATE/day", float(self.time_array[0][3])) + hr_ix = self.state.set_state( "/STATE/hour", float(self.time_array[0][4])) + min_ix = self.state.set_state( "/STATE/minute", float(self.time_array[0][5])) + sec_ix = self.state.set_state( "/STATE/second", float(self.time_array[0][6])) + wd_ix = self.state.set_state( "/STATE/weekday", float(self.time_array[0][7])) + dt_ix = self.state.set_state( "/STATE/dt", float(self.time_array[0][8])) + jd_ix = self.state.set_state( "/STATE/jday", float(self.time_array[0][9])) + md_ix = self.state.set_state( "/STATE/modays", float(self.time_array[0][10])) + dts_ix = self.state.set_state( "/STATE/dts", float(self.time_array[0][8] * 60.0)) self.date_path_ix = [ year_ix, month_ix, @@ -115,7 +57,7 @@ def register_components(self): md_ix, dts_ix, ] - self.state["dict_ix"][self.ix] = self.time_array + self.state.dict_ix = set_numba_value(self.state.dict_ix, self.ix, self.time_array) return self.ix @@ -124,12 +66,12 @@ def tokenize(self): # returns an array of data pointers super().tokenize() # resets ops to common base self.ops = self.ops + self.date_path_ix # adds timer specific items - + def add_op_tokens(self): # this puts the tokens into the global simulation queue # can be customized by subclasses to add multiple lines if needed. super().add_op_tokens() - self.state["dict_ix"][self.ix] = self.time_array + self.state.dict_ix = set_numba_value(self.state.dict_ix, self.ix, self.time_array) def dti_to_time_array(self, siminfo): dateindex = siminfo["tindex"] @@ -175,3 +117,4 @@ def step_sim_timer(op_token, state_ix, dict_ix, ts_ix, step): state_ix[op_token[11]] = dict_ix[op_token[1]][step][10] # modays state_ix[op_token[12]] = dict_ix[op_token[1]][step][11] # dts return + diff --git a/src/hsp2/hsp2/om_special_action.py b/src/hsp2/hsp2/om_special_action.py index e3042fe7..8577ff3c 100644 --- a/src/hsp2/hsp2/om_special_action.py +++ b/src/hsp2/hsp2/om_special_action.py @@ -78,7 +78,7 @@ def handle_prop(self, model_props, prop_name, strict=False, default_value=None): if prop_name == "when": # when to perform this? timestamp or time-step index prop_val = -1 # prevent a 0 indexed value from triggering return, default means execute every step - si = self.state["model_object_cache"][self.find_var_path("timer")] + si = self.model_object_cache[self.find_var_path("timer")] if len(model_props["YR"]) > 0: # translate date to equivalent model step datestring = ( @@ -168,7 +168,7 @@ def find_paths(self): + self.op_type[0] + str(self.range1).zfill(3) ) - domain = self.state["model_object_cache"][domain_path] + domain = self.model_object_cache[domain_path] var_register = self.insure_register(self.vari, 0.0, domain, False, False) # print("Created register", var_register.name, "with path", var_register.state_path) # add already created objects as inputs diff --git a/src/hsp2/hsp2/om_timer.py b/src/hsp2/hsp2/om_timer.py new file mode 100644 index 00000000..48ddaa3e --- /dev/null +++ b/src/hsp2/hsp2/om_timer.py @@ -0,0 +1,56 @@ +""" +The class timer_class/timer_class_jit is used for benchmarking and peformance inquiry. +""" + +from numba.experimental import jitclass +import ctypes +import time +from numba import njit, types + +# Access the _PyTime_AsSecondsDouble and _PyTime_GetSystemClock functions from pythonapi +get_system_clock = ctypes.pythonapi._PyTime_GetSystemClock +as_seconds_double = ctypes.pythonapi._PyTime_AsSecondsDouble +# Set the argument types and return types of the functions +get_system_clock.argtypes = [] +get_system_clock.restype = ctypes.c_int64 +as_seconds_double.argtypes = [ctypes.c_int64] +as_seconds_double.restype = ctypes.c_double + +timer_spec = [ + ("tstart", types.float64), + ("tend", types.float64), + ("tsplit", types.float64) +] + +@njit +def jitime(): + system_clock = get_system_clock() + current_time = as_seconds_double(system_clock) + return current_time + +@jitclass(timer_spec) +class timer_class_jit(): + def __init__(self): + self.tstart = jitime() + + def split(self): + self.tend = jitime() + self.tsplit = self.tend - self.tstart + self.tstart = jitime() + split = 0 + if (self.tsplit > 0): + split = self.tsplit + return split + +class timer_class(): + def __init__(self): + self.tstart = time.time() + + def split(self): + self.tend = time.time() + self.tsplit = self.tend - self.tstart + self.tstart = time.time() + split = 0 + if (self.tsplit > 0): + split = self.tsplit + return split diff --git a/src/hsp2/hsp2tools/HSP2_CLI.py b/src/hsp2/hsp2tools/HSP2_CLI.py index 2519bb63..75da0bc3 100644 --- a/src/hsp2/hsp2tools/HSP2_CLI.py +++ b/src/hsp2/hsp2tools/HSP2_CLI.py @@ -1,11 +1,12 @@ import cltoolbox -from hsp2.hsp2tools.commands import import_uci, run +from hsp2.hsp2tools.commands import import_uci, update_uci, run def main(): cltoolbox.command(run) cltoolbox.command(import_uci) + cltoolbox.command(update_uci) cltoolbox.main() diff --git a/src/hsp2/hsp2tools/commands.py b/src/hsp2/hsp2tools/commands.py index 3247fd73..057670e2 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -57,3 +57,22 @@ def import_uci(ucifile, h5file): wdmfile = (uci_dir / nline[16:].strip()).resolve() if wdmfile.exists(): readWDM(wdmfile, h5file) + + + + +def update_uci(ucifile, h5file): + """Import UCI only into HDF5 file. + + Parameters + ---------- + ucifile: str + The UCI file to import into HDF file. + h5file: str + The destination HDF5 file. + """ + # we send False here to prevent deleting and recreating the UCI + print("Updating parameters in h5 file from UCI.", ucifile) + print("Note: this will NOT update external data such as WDM, mutsin etc.") + print("To update all data, use the command 'hsp2 import_uci ...' ") + readUCI(ucifile, h5file, False) diff --git a/src/hsp2/hsp2tools/readUCI.py b/src/hsp2/hsp2tools/readUCI.py index 8299cb1f..a9011084 100644 --- a/src/hsp2/hsp2tools/readUCI.py +++ b/src/hsp2/hsp2tools/readUCI.py @@ -646,6 +646,7 @@ def specactions(info, llines): head_uvquan = [] sa_conditional = [] head_conditional = [] + open_conditionals = [] sa_distrb = [] head_distrb = [] sa_uvname = [] @@ -653,29 +654,61 @@ def specactions(info, llines): sa_if = [] head_if = [] in_if = False # are we in an if block? - curlvl = 0 + active_conditional = 0 for line in lines: if line[2:5] == "MULT": sa_mult.append(line) elif line[2:8] == "UVQUAN": sa_uvquan.append(line) - elif line[2:13] == "CONDITIONAL": + # this is NOT a table + elif line[2:13] == "CONDITIONAL": + # should lower case this since it is NOT a UCI table sa_conditional.append(line) elif line[2:8] == "DISTRB": sa_distrb.append(line) elif line[2:8] == "UVNAME": sa_uvname.append(line) - # This CURLVL code is a place-holder. This has not been thought through. + # - This CURLVL code is a place-holder. This has not been thought through. + # - IF statements may span multiple lines, so need to + # continue to parse till a "THEN" is reached + # - The variable to evaluate in a IF-THEN MUST BE A UVQUAN + # since UVQUAN must refer to a variable and UVQUAN is the ONLY + # allowable + # - IF may appear anywhere on the line as long as there are only + # blanks preceding IF + # - Any IF/ELSE statement may have a "conditional" + # like AND OR at the end of an "IF" line, + # and that + # - Do the IF-THEN parsing built off the equation parser + # using Tim's assembled CONDTIONAL statement + # Reminder: special action allows 3 kinds of parenthese + # do a global search and replace all to () elif line[0:2] == "IF": + # parses till it reaches a THEN + # todo: create a function to take our lines and parse till + # reching a THEN based on Tim's code + # Note: Tim's code combines all levels of an IF tree + # but this method requires that each IF ... THEN is a + # single entity, just potentially nested. + # function uci_parse_specl_if_then() + # maybe these sa_if should be keyed with the h5 name + # like /SPEC_ATIONS/CONDITIONALS/COND_1 sa_if.append(line) - curlvl = len(sa_if) + active_conditional = len(sa_if) - 1 # this is the numerical pointer to the current level + open_conditionals.append(active_conditional) elif line[0:7] == "END IF": - sa_if.append(line) - curlvl = curlvl - 1 + # must replace this with a stack to push/pop + # in order to track nested conditionals. + open_conditionals.pop() + if (active_conditional >= 0): + active_conditional = open_conditionals[-1] # -1 is last entry in list + else: + active_conditional = -1 else: # ACTIONS block + # todo: TIm has a single function that parses a line d = parseD(line, parse["SPEC-ACTIONS", "ACTIONS"]) - d["CURLVL"] = curlvl + d["CURLVL"] = active_conditional sa_actions.append(d.copy()) if sa_actions: dfftable = pd.DataFrame(sa_actions, columns=head_actions).replace("na", "") diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index d172a5b6..dd8c248e 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -1,31 +1,286 @@ """General routines for SPECL""" -import numpy as np -from pandas import date_range -from pandas.tseries.offsets import Minute -from numba.typed import Dict -from numpy import zeros -from numba import njit, types # import the types -import os import importlib.util +import os import sys +import numpy as np +import numba as nb +from numba import njit, types, typeof # import the types supplies int64, float64 +from numba.experimental import jitclass +from numba.typed import Dict as ntdict +from numpy import zeros, float64 as npfloat64, int64 as npint64 +from pandas import date_range, DataFrame +from pandas.tseries.offsets import Minute -def init_state_dicts(): - """ - This contains the base dictionaries used to pass model state amongst modules and custom code plugins - """ - state = {} # shared state Dictionary, contains numba-ready Dicts - state["state_paths"] = Dict.empty( - key_type=types.unicode_type, value_type=types.int64 - ) - state["state_ix"] = Dict.empty(key_type=types.int64, value_type=types.float64) - state["dict_ix"] = Dict.empty(key_type=types.int64, value_type=types.float64[:, :]) - state["ts_ix"] = Dict.empty(key_type=types.int64, value_type=types.float64[:]) - # initialize state for hydr - # add a generic place to stash model_data for dynamic components - state["model_data"] = {} - return state +# Beginning in operation these are likely to be located in model objects when we go fully to that level. +# But for now, they are here to maintain compatiility with the existing code base +# Combine these into a spec to create the class +tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) + +state_spec = [ + # the first entries here are NP arrays, fixed dimenstions, and fast + ("state_ix", typeof(np.asarray(zeros(1), dtype="float64")) ), + ("op_tokens", typeof(types.int64(zeros((1, 64)))) ), + ("op_exec_lists", typeof(types.int64(zeros((1, 1024)))) ), + ("model_exec_list", typeof(np.asarray(zeros(1), dtype="int64")) ), + ("tindex", typeof(tindex.to_numpy()) ), + # dict_ix SHOULD BE an array, this is TBD. Likely defer till OM class runtimes + ("dict_ix", types.DictType(types.int64, types.float64[:, :]) ), + # below here are dictionaries as they are not used in runtime and can be slow + ("state_paths", types.DictType(types.unicode_type, types.int64) ), + ("ts_paths", types.DictType(types.unicode_type, types.float64[:]) ), + ("ts_ix", types.DictType(types.int64, types.float64[:]) ), + ("last_id", types.int64), + ("model_root_name", types.unicode_type), + ("state_step_hydr", types.unicode_type), + ("hsp2_local_py", types.boolean), + ("num_ops", types.int64), + ("op_len", types.int64), + ("operation", types.unicode_type), + ("segment", types.unicode_type), + ("activity", types.unicode_type), + ("domain", types.unicode_type), + ("state_step_om", types.unicode_type), + ("hsp_segments", types.DictType(types.unicode_type, types.unicode_type) ) +] + + +state_lite = [ + ("num_ops", nb.int64), + # the first entries here are NP arrays, fixed dimenstions, and fast + ("state_ix", nb.float64[:]), + ("op_tokens", typeof(types.int64(zeros((1, 64)))) ), + ("op_exec_lists", typeof(types.int64(zeros((1, 1024)))) ), + ("model_exec_list", typeof(np.asarray(zeros(1), dtype="int64")) ), + ("tindex", typeof(tindex.to_numpy()) ), + # dict_ix SHOULD BE an array, this is TBD. Likely defer till OM class runtimes + ("dict_ix", types.DictType(types.int64, types.float64[:, :]) ), + ("ts_ix", types.DictType(types.int64, types.float64[:]) ), + ("state_paths", types.DictType(types.unicode_type, types.int64) ), + ("last_id", types.int64), + ("model_root_name", types.unicode_type), + ("state_step_hydr", types.unicode_type), + ("hsp2_local_py", types.boolean), + ("num_ops", types.int64), + ("operation", types.unicode_type), + ("segment", types.unicode_type), + ("activity", types.unicode_type), + ("domain", types.unicode_type), + ("state_step_om", types.unicode_type), + ("hsp_segments", types.DictType(types.unicode_type, types.unicode_type) ) +] + +@jitclass(state_lite) +class state_class_lite: + def __init__(self, num_ops): + self.num_ops = num_ops + state_ix = zeros(self.num_ops) + self.state_ix = state_ix.astype(npfloat64) + op_tokens = zeros((self.num_ops, 64)) + self.op_tokens = op_tokens.astype(npint64) + # TODO: move to individual objects in OM/RCHRES/PERLND/... + op_exec_lists = zeros((self.num_ops, 1024)) + self.op_exec_lists = op_exec_lists.astype(npint64) + # TODO: is this even needed? Since each domain has it's own exec list? + model_exec_list = zeros(self.num_ops) + self.model_exec_list = model_exec_list.astype(npint64) + self.activity = "" + self.segment = "" + self.operation = "" + self.domain = "" + self.model_root_name = "" + +@njit(cache=True) +def make_state_lite(num_ops): + sc = state_class_lite(num_ops) + return sc + +def state_copy(statesrc, statedest): + # copies from a non-jit to a jit or vice versa + statedest.num_ops = statesrc.num_ops + statedest.state_ix = statesrc.state_ix + statedest.dict_ix = statesrc.dict_ix + statedest.ts_ix = statesrc.ts_ix + statedest.op_tokens = statesrc.op_tokens + statedest.op_exec_lists = statesrc.op_exec_lists + statedest.model_exec_list = statesrc.model_exec_list + statedest.state_paths = statesrc.state_paths + statedest.hsp2_local_py = statesrc.hsp2_local_py + statedest.model_root_name = statesrc.model_root_name + statedest.hsp_segments = statesrc.hsp_segments + statedest.state_step_hydr = statesrc.state_step_hydr + statedest.state_step_om = statesrc.state_step_om + statedest.domain = statesrc.domain + +""" +This function is a simple numba compiled fn to append to a numba dict quickly +This is necessary because there is no way to just cast a normal dictionary to a numba Dict +And appending a numba Dict in regular python is super super slow. +If this does not provide good enough performance when adding a large amount of variables +We may consider using a jitted loop to copy all elements from a dictionary to Dict +""" +@njit(cache=True) +def append_numba_dict(var_dict, var_key, var_val): + var_dict[var_key] = var_val + return var_dict + +@njit(cache=True) +def set_numba_value(var_dict, var_key, var_val): + var_dict[var_key] = var_val + return var_dict + +@njit(cache=True) +def nkey_exists(var_dict, var_key): + return (var_key in var_dict) + +class state_class: + def __init__(self, state_ix, op_tokens, state_paths, op_exec_lists, model_exec_list, dict_ix, ts_ix, hsp_segments): + self.num_ops = 0 + # IMPORTANT these are handled as nparray as numba Dict would be super slow. + # Note: in the type declaration above we are alloweed to use the shortened form op_tokens = int64(zeros((1,64))) + # but in jited class that throws an error and we have to use the form op_tokens.astype(int64) + # to do the type cast + self.state_ix = state_ix.astype(npfloat64) + self.op_tokens = op_tokens.astype(npint64) + # TODO: move to individual objects in OM/RCHRES/PERLND/... + self.op_exec_lists = op_exec_lists.astype(npint64) + # TODO: is this even needed? Since each domain has it's own exec list? + self.model_exec_list = model_exec_list.astype(npint64) + # Done with nparray initializations + # this dict_ix approach is inherently slow, and should be replaced by some other np table type + # on an as-needed basis if possible. Especially for dataMatrix types which are supposed to be fast + # state can still get values via get_state, by grabbing a reference object and then accessing it's storage + self.dict_ix = dict_ix + self.ts_ix = ts_ix + self.state_paths = state_paths + self.hsp_segments = hsp_segments + self.state_step_om = "disabled" + self.state_step_hydr = "disabled" + self.model_root_name = "" + self.operation = "" + self.segment = "" + self.activity = "" + self.domain = "" + self.last_id = 0 + self.hsp2_local_py = False + self.op_len = 64 # how wide is an op list array + return + + @property + def size(self): + return self.state_ix.size + + def append_state(self, var_value): + val_ix = self.size # next ix value= size since ix starts from zero + self.state_ix = np.append(self.state_ix, var_value) + self.last_id = val_ix + self.resize() + return val_ix + + def set_token(self, var_ix, tokens, debug=False): + if var_ix not in range(len(self.state_ix)): + if debug: + print("Undefined index value,", var_ix, ", provided for set_token()") + return False + if var_ix not in range(np.shape(self.op_tokens)[0]): + if debug: + print("set_token called for ix", var_ix, ", need to expand") + self.resize() + # in a perfect world we would insure that the length of tokens is correct + # and if not, we would resize. But this is only called from ModelObject + # and its methods add_op_tokens() and model_format_ops(ops) enforce the + # length limit described by ModelObject.max_token_length (64) which must match + self.op_tokens[var_ix] = tokens + + def resize(self, debug=False): + num_ops = self.size + # print("state_ix has", num_ops, "elements") + ops_needed = num_ops - np.shape(self.op_tokens)[0] + if ops_needed == 0: + # print("resize op_tokens unneccesary, state has", self.size,"indices and op_tokens has", np.shape(self.op_tokens)[0], "elements") + return + if debug: + print("op_tokens needs", ops_needed, "slots") + add_ops = np.full((ops_needed,self.op_len),-1) # fill with -1 + zeros((ops_needed, 64)) + # print("Created add_ops with", ops_needed, "slots") + # we use the 3rd param "axis=1" to prevent flattening of array + if self.op_tokens.size == 0: + if debug: + print("Creating op_tokens") + self.op_tokens = add_ops.astype(npint64) + else: + if debug: + print("Merging op_tokens") + add_ops = np.append(self.op_tokens, add_ops, 0) + self.op_tokens = add_ops.astype(npint64) + ops_needed = num_ops - np.shape(self.op_exec_lists)[0] + el_width = np.shape(self.op_exec_lists)[1] + if debug: + print("op_exec_lists needs", ops_needed, "slots") + if ops_needed == 0: + return + add_ops = zeros((ops_needed, el_width)) + # we use the 3rd param "axis=1" to prevent flattening of array + if self.op_exec_lists.size == 0: + if debug: + print("Creating op_exec_lists") + self.op_exec_lists = add_ops.astype(npint64) + else: + if debug: + print("Merging op_exec_lists") + add_ops = np.append(self.op_exec_lists, add_ops, 0) + self.op_exec_lists = add_ops.astype(npint64) + return + + def set_exec_list(self, ix, op_exec_list): + for i in range(len(op_exec_list)): + self.op_exec_lists[ix][i] = op_exec_list[i] + + def set_state(self, var_path, var_value=0.0, debug=False): + """ + Given an hdf5 style path to a variable, set the value + If the variable does not yet exist, create it. + Returns the integer key of the variable in the state_ix Dict + """ + if not nkey_exists(self.state_paths, var_path): + #if var_path not in self.state_paths: + # we need to add this to the state + var_ix = self.append_state(var_value) + self.state_paths = append_numba_dict(self.state_paths, var_path, var_ix) + else: + var_ix = self.get_state_ix(var_path) + #self.state_ix[var_ix] = var_value + self.state_ix = set_numba_value(self.state_ix, var_ix, var_value) + #append_numba_dict(self.state_ix, var_value, var_ix) + if debug: + print("Setting state_ix[", var_ix, "], to", var_value) + return var_ix + + def get_state_ix(self, var_path): + """ + Find the integer key of a variable name in state_ix + """ + if var_path == False: + # handle a bad path with False + return False + if var_path not in self.state_paths: + # we need to add this to the state + return False # should throw an error + var_ix = self.state_paths[var_path] + return var_ix + + def get_ix_path(self, var_ix): + """ + Find the path of a variable with integer key in state_ix + """ + spath = None + for spath, ix in self.state_paths.items(): + if var_ix == ix: + # we need to add this to the state + return spath + return spath def op_path_name(operation, id): @@ -36,8 +291,8 @@ def op_path_name(operation, id): path_name = f"{operation}_{operation[0]}{tid}" return path_name - -def get_state_ix(state_ix, state_paths, var_path): +@njit(cache=True) +def get_state_ix(state_paths, var_path): """ Find the integer key of a variable name in state_ix """ @@ -48,17 +303,6 @@ def get_state_ix(state_ix, state_paths, var_path): return var_ix -def get_ix_path(state_paths, var_ix): - """ - Find the path of a variable with integer key in state_ix - """ - for spath, ix in state_paths.items(): - if var_ix == ix: - # we need to add this to the state - return spath - return False - - def set_state(state_ix, state_paths, var_path, default_value=0.0, debug=False): """ Given an hdf5 style path to a variable, set the value @@ -81,15 +325,15 @@ def state_add_ts(state, var_path, default_value=0.0, debug=False): If the variable does not yet exist, create it. Returns the integer key of the variable in the state_ix Dict """ - if var_path not in state["state_paths"].keys(): + if var_path not in state.state_paths.keys(): # we need to add this to the state - state["state_paths"][var_path] = append_state(state["state_ix"], default_value) - var_ix = get_state_ix(state["state_ix"], state["state_paths"], var_path) + state.state_paths[var_path] = append_state(state.state_ix, default_value) + var_ix = get_state_ix(state.state_ix, state.state_paths, var_path) if debug == True: print("Setting state_ix[", var_ix, "], to", default_value) # siminfo needs to be in the model_data array of state. Can be populated by HSP2 or standalone by ops model - state["ts_ix"][var_ix] = np.full_like( - zeros(state["model_data"]["siminfo"]["steps"]), default_value + state.ts_ix[var_ix] = np.full_like( + zeros(om_operations["model_data"]["steps"]), default_value ) return var_ix @@ -120,26 +364,7 @@ def append_state(state_ix, var_value): return val_ix -def state_context_hsp2(state, operation, segment, activity): - # this establishes domain info so that a module can know its paths - state["operation"] = operation - state["segment"] = segment # - state["activity"] = activity - # give shortcut to state path for the upcoming function - # insure that there is a model object container - seg_name = operation + "_" + segment - seg_path = "/STATE/" + state["model_root_name"] + "/" + seg_name - if "hsp_segments" not in state.keys(): - state[ - "hsp_segments" - ] = {} # for later use by things that need to know hsp entities and their paths - if seg_name not in state["hsp_segments"].keys(): - state["hsp_segments"][seg_name] = seg_path - - state["domain"] = seg_path # + "/" + activity # may want to comment out activity? - - -def state_siminfo_hsp2(parameter_obj, siminfo, io_manager, state): +def state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager): # Add crucial simulation info for dynamic operation support delt = parameter_obj.opseq.INDELT_minutes[0] # get initial value for STATE objects siminfo["delt"] = delt @@ -147,29 +372,63 @@ def state_siminfo_hsp2(parameter_obj, siminfo, io_manager, state): siminfo["start"], siminfo["stop"], freq=Minute(delt) )[1:] siminfo["steps"] = len(siminfo["tindex"]) + state.tindex = siminfo["tindex"].to_numpy() hdf5_path = io_manager._input.file_path (fbase, fext) = os.path.splitext(hdf5_path) - state["model_root_name"] = os.path.split(fbase)[1] # takes the text before .h5 + state.model_root_name = os.path.split(fbase)[1] # takes the text before .h5 +#@njit(cache=True) +def state_context_hsp2(state, operation, segment, activity): + # this establishes domain info so that a module can know its paths + state.operation = operation + state.segment = segment # + state.activity = activity + # give shortcut to state path for the upcoming function + # insure that there is a model object container + (seg_name, seg_path) = state_segname(state, operation, segment, activity) + #if seg_name not in state.hsp_segments.keys(): + if not nkey_exists(state.hsp_segments, seg_name): # test this for njit + state.hsp_segments = append_numba_dict(state.hsp_segments, seg_name, seg_path) + state.domain = state_domain(state, operation, segment, activity) + +def state_domain(state, operation, segment, activity): + (seg_name, seg_path) = state_segname(state, operation, segment, activity) + domain = seg_path # later we may make his custom depending on the operation/activity + # like + "/" + activity + return domain + +def state_segname(state, operation, segment, activity): + seg_name = operation + "_" + segment + seg_path = "/STATE/" + state.model_root_name + "/" + seg_name + return (seg_name, seg_path) -def state_init_hsp2(state, opseq, activities): +def state_init_hsp2(state, opseq, activities, timer): # This sets up the state entries for all state compatible HSP2 model variables - # print("STATE initializing contexts.") + print("STATE initializing contexts.") for _, operation, segment, delt in opseq.itertuples(): + seg_name = operation + "_" + segment + seg_path = "/STATE/" + state.model_root_name + "/" + seg_name + # set up named paths for model operations + state.set_state(seg_path, 0.0) if operation != "GENER" and operation != "COPY": for activity, function in activities[operation].items(): if activity == "HYDR": state_context_hsp2(state, operation, segment, activity) - hydr_init_ix(state, state["domain"]) elif activity == "SEDTRN": state_context_hsp2(state, operation, segment, activity) - sedtrn_init_ix(state, state["domain"]) elif activity == "SEDMNT": state_context_hsp2(state, operation, segment, activity) - sedmnt_init_ix(state, state["domain"]) elif activity == "RQUAL": state_context_hsp2(state, operation, segment, activity) - rqual_init_ix(state, state["domain"]) + + +def state_load_dynamics_hsp2(state, io_manager, siminfo): + # Load any dynamic components if present, and store variables on objects + # if a local file with state_step_hydr() was found in load_dynamics(), we add it to state + state.hsp2_local_py = load_dynamics( + io_manager, siminfo + ) # Stores the actual function in state + state.state_step_hydr = siminfo["state_step_hydr"] # enabled or disabled def state_load_hdf5_components( @@ -186,14 +445,6 @@ def state_load_hdf5_components( return -def state_load_dynamics_hsp2(state, io_manager, siminfo): - # Load any dynamic components if present, and store variables on objects - hsp2_local_py = load_dynamics(io_manager, siminfo) - # if a local file with state_step_hydr() was found in load_dynamics(), we add it to state - state["state_step_hydr"] = siminfo["state_step_hydr"] # enabled or disabled - state["hsp2_local_py"] = hsp2_local_py # Stores the actual function in state - - @njit def get_domain_state(state_paths, state_ix, domain, varkeys): # get values for a set of variables in a domain @@ -251,14 +502,16 @@ def hydr_state_vars(): ] -def hydr_init_ix(state, domain): +def hydr_init_ix(state, domain, debug = False): # get a list of keys for all hydr state variables hydr_state = hydr_state_vars() - hydr_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + hydr_ix = DataFrame() for i in hydr_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i - hydr_ix[i] = set_state(state["state_ix"], state["state_paths"], var_path, 0.0) + if debug: + print("initializing", var_path) + hydr_ix[i] = state.set_state(var_path, 0.0) return hydr_ix @@ -270,11 +523,11 @@ def sedtrn_state_vars(): def sedtrn_init_ix(state, domain): # get a list of keys for all sedtrn state variables sedtrn_state = sedtrn_state_vars() - sedtrn_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + sedtrn_ix = DataFrame() for i in sedtrn_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i - sedtrn_ix[i] = set_state(state["state_ix"], state["state_paths"], var_path, 0.0) + sedtrn_ix[i] = state.set_state(var_path, 0.0) return sedtrn_ix @@ -286,13 +539,14 @@ def sedmnt_state_vars(): def sedmnt_init_ix(state, domain): # get a list of keys for all sedmnt state variables sedmnt_state = sedmnt_state_vars() - sedmnt_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + sedmnt_ix = DataFrame() for i in sedmnt_state: var_path = domain + "/" + i - sedmnt_ix[i] = set_state(state["state_ix"], state["state_paths"], var_path, 0.0) + sedmnt_ix[i] = state.set_state(var_path, 0.0) return sedmnt_ix +@njit(cache=True) def rqual_state_vars(): rqual_state = [ "DOX", @@ -309,19 +563,18 @@ def rqual_state_vars(): ] return rqual_state - def rqual_init_ix(state, domain): # get a list of keys for all rqual state variables rqual_state = rqual_state_vars() - rqual_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + rqual_ix = DataFrame() for i in rqual_state: var_path = domain + "/" + i - rqual_ix[i] = set_state(state["state_ix"], state["state_paths"], var_path, 0.0) + rqual_ix[i] = state.set_state(var_path, 0.0) return rqual_ix -@njit -def hydr_get_ix(state_ix, state_paths, domain): +@njit(cache=True) +def hydr_get_ix(state, domain): # get a list of keys for all hydr state variables hydr_state = [ "DEP", @@ -341,38 +594,40 @@ def hydr_get_ix(state_ix, state_paths, domain): "VOL", "VOLEV", ] - hydr_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + # print(state.state_paths) + hydr_ix = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) for i in hydr_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i - hydr_ix[i] = state_paths[var_path] + # print("looking for:", var_path) + hydr_ix[i] = get_state_ix(state.state_paths, var_path) return hydr_ix -@njit -def sedtrn_get_ix(state_ix, state_paths, domain): +@njit(cache=True) +def sedtrn_get_ix(state, domain): # get a list of keys for all sedtrn state variables sedtrn_state = ["RSED4", "RSED5", "RSED6"] - sedtrn_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + sedtrn_ix = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) for i in sedtrn_state: var_path = domain + "/" + i - sedtrn_ix[i] = state_paths[var_path] + sedtrn_ix[i] = get_state_ix(state.state_paths, var_path) return sedtrn_ix -@njit -def sedmnt_get_ix(state_ix, state_paths, domain): +@njit(cache=True) +def sedmnt_get_ix(state, domain): # get a list of keys for all sedmnt state variables sedmnt_state = ["DETS"] - sedmnt_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + sedmnt_ix = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) for i in sedmnt_state: var_path = domain + "/" + i - sedmnt_ix[i] = state_paths[var_path] + sedmnt_ix[i] = get_state_ix(state.state_paths, var_path) return sedmnt_ix @njit -def rqual_get_ix(state_ix, state_paths, domain): +def rqual_get_ix(state, domain): # get a list of keys for all sedmnt state variables rqual_state = [ "DOX", @@ -387,10 +642,10 @@ def rqual_get_ix(state_ix, state_paths, domain): "BRPO42", "CFOREA", ] - rqual_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + rqual_ix = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) for i in rqual_state: var_path = domain + "/" + i - rqual_ix[i] = state_paths[var_path] + rqual_ix[i] = get_state_ix(state.state_paths, var_path) return rqual_ix diff --git a/src/hsp2/state/state_definitions.py b/src/hsp2/state/state_definitions.py new file mode 100644 index 00000000..cf563b0b --- /dev/null +++ b/src/hsp2/state/state_definitions.py @@ -0,0 +1,31 @@ +# null function to be loaded when not supplied by user +from numba import njit # import the types +from numba.typed import Dict +from numba import types # import the types +from numpy import zeros + +state_empty = {} # shared state Dictionary, contains numba-ready Dicts +state_empty["state_paths"] = Dict.empty( + key_type=types.unicode_type, value_type=types.int64 +) +state_empty["state_ix"] = types.float64(zeros(0)) +state_empty["dict_ix"] = Dict.empty(key_type=types.int64, value_type=types.float64[:, :]) +state_empty["ts_ix"] = Dict.empty(key_type=types.int64, value_type=types.float64[:]) +state_empty["hsp_segments"] = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) +state_empty["op_tokens"] = types.int64(zeros((0, 64))) +state_empty["model_exec_list"] = types.int64(zeros(0)) +state_empty["op_exec_lists"] = types.int64(zeros((0, 1024))) + +# initialize state for hydr +# add a generic place to stash model_data for dynamic components +state_empty["model_data"] = {} + +# variables: these could go into individual files later or in object defs +rqual_state_vars = [ + "DOX", "BOD", "NO3", "TAM", "NO2", "PO4", "BRTAM1", + "BRTAM2", "BRPO41", "BRPO42", "CFOREA" +] + +@njit +def state_step_hydr(state, step): + return diff --git a/src/hsp2/state/state_fn_defaults.py b/src/hsp2/state/state_fn_defaults.py deleted file mode 100644 index 45c7a0c0..00000000 --- a/src/hsp2/state/state_fn_defaults.py +++ /dev/null @@ -1,7 +0,0 @@ -# null function to be loaded when not supplied by user -from numba import njit # import the types - - -@njit -def state_step_hydr(state_info, state_paths, state_ix, dict_ix, ts_ix, hydr_ix, step): - return diff --git a/tests/testcbp/HSP2results/JL1_6562_6560.uci b/tests/testcbp/HSP2results/JL1_6562_6560.uci new file mode 100644 index 00000000..a6f3ad8f --- /dev/null +++ b/tests/testcbp/HSP2results/JL1_6562_6560.uci @@ -0,0 +1,261 @@ +RUN + +GLOBAL + JL1_6562_6 riv | P5 | subsheds | Beaver + START 1984/01/01 END 2020/12/31 + RUN INTERP OUTPUT LEVEL 1 1 + RESUME 0 RUN 1 UNIT SYSTEM 1 +END GLOBAL + +FILES + ***<----FILE NAME-------------------------------------------------> +WDM1 21 met_N51003.wdm +WDM2 22 prad_N51003.wdm +WDM3 23 ps_sep_div_ams_subsheds_JL1_6562_6560.wdm +WDM4 24 JL1_6562_6560.wdm +MESSU 25 JL1_6562_6560.ech + 26 JL1_6562_6560.out + 31 JL1_6562_6560.tau +END FILES + +OPN SEQUENCE + INGRP INDELT 01:00 + RCHRES 1 + PLTGEN 1 + END INGRP +END OPN SEQUENCE + +RCHRES + ACTIVITY + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG *** + 1 1 1 0 0 0 0 0 0 0 0 + END ACTIVITY + + PRINT-INFO + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG PIVL***PY + 1 5 5 0 0 0 0 0 0 0 0 0 12 + END PRINT-INFO + + GEN-INFO + RCHRES<-------Name------->Nexit Unit Systems Printer *** + # - # User t-series Engl Metr LKFG *** + 1 JL1_6562_6560 3 1 1 1 26 0 0 + END GEN-INFO + + HYDR-PARM1 + RCHRES Flags for HYDR section *** + # - # VC A1 A2 A3 ODFVFG for each ODGTFG for each *** FUNCT for each + FG FG FG FG possible exit possible exit *** possible exit + 1 2 3 4 5 1 2 3 4 5 *** 1 2 3 4 5 + VC A1 A2 A3 V1 V2 V3 V4 V5 G1 G2 G3 G4 G5 *** F1 F2 F3 F4 F5 + 1 0 1 1 1 0 0 4 0 0 1 2 0 0 0 0 0 0 0 0 + END HYDR-PARM1 + + HYDR-PARM2 + RCHRES *** + # - # FTABNO LEN DELTH STCOR KS DB50 *** + 1 1. 17.01 249.28 0.5 + END HYDR-PARM2 + + HYDR-INIT + RCHRES Initial conditions for HYDR section *** + # - # VOL Initial value of COLIND *** Initial value of OUTDGT + (ac-ft) for each possible exit *** for each possible exit + VOL CEX1 CEX2 CEX3 CEX4 CEX5 *** DEX1 DEX2 DEX3 DEX4 DEX5 + 1 293.16000 + END HYDR-INIT + + ADCALC-DATA + RCHRES Data for section ADCALC *** + # - # CRRAT VOL *** + 1 1.5 293.16 + END ADCALC-DATA + +END RCHRES + +FTABLES + FTABLE 1 +NOTE: FLOODPLAIN BASE = 5*BANKFULL WIDTH *** + FLOODPLAIN SIDE-SLOPE = SAME AS CHANNEL'S *** + ROWS COLS *** + 19 4 + DEPTH AREA VOLUME DISCH *** + (FT) (ACRES) (AC-FT) (CFS) *** + 0.000 0.000 0.00 0.00 + 0.423 11.894 4.78 23.85 + 0.846 13.061 10.06 77.00 + 1.269 14.227 15.83 154.23 + 1.691 15.393 22.09 254.22 + 2.114 16.560 28.85 376.68 + 2.537 17.726 36.10 521.75 + 2.960 18.893 43.84 689.83 + 3.383 20.059 52.07 881.43 + 3.806 21.225 60.80 1097.15 + 4.806 108.886 168.31 1305.89 + 6.108 112.478 312.43 3577.19 + 7.410 116.069 461.23 6694.41 + 8.712 119.661 614.71 10572.52 + 10.014 123.253 772.86 15161.71 + 11.316 126.845 935.69 20429.73 + 12.618 130.437 1103.20 26354.64 + 13.921 134.028 1275.38 32921.26 + 15.223 137.620 1452.24 40119.05 + END FTABLE 1 +END FTABLES + +EXT SOURCES +<-Volume-> SsysSgap<--Mult-->Tran <-Target vols> <-Grp> <-Member->*** + # # tem strg<-factor->strg # # # #*** +*** METEOROLOGY +WDM1 1000 EVAP ENGLZERO 1.000 SAME RCHRES 1 EXTNL POTEV +WDM1 1001 DEWP ENGLZERO SAME RCHRES 1 EXTNL DEWTMP +WDM1 1002 WNDH ENGLZERO SAME RCHRES 1 EXTNL WIND +WDM1 1003 RADH ENGLZERO SAME RCHRES 1 EXTNL SOLRAD +WDM1 1004 ATMP ENGLZERO SAME RCHRES 1 EXTNL GATMP +WDM1 1005 CLDC ENGLZERO SAME RCHRES 1 EXTNL CLOUD + +*** PRECIPITATION AND ATMOSPHERIC DEPOSITION LOADS +WDM2 2000 HPRC ENGLZERO SAME RCHRES 1 EXTNL PREC +WDM2 2001 NO23 ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2002 NH4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2003 NO3D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2004 NH4D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2005 ORGN ENGLZERO DIV RCHRES 1 EXTNL PLADFX 1 1 +WDM2 2006 PO4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 3 1 +WDM2 2007 ORGP ENGLZERO DIV RCHRES 1 EXTNL PLADFX 2 1 + +*** POINT SOURCE +WDM3 3000 FLOW ENGLZERO DIV RCHRES 1 INFLOW IVOL +WDM3 3001 HEAT ENGLZERO DIV RCHRES 1 INFLOW IHEAT +WDM3 3002 NH3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 2 +WDM3 3003 NO3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 1 +WDM3 3004 ORNX ENGLZERO DIV RCHRES 1 INFLOW PKIF 3 +WDM3 3005 PO4X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 4 +WDM3 3006 ORPX ENGLZERO DIV RCHRES 1 INFLOW PKIF 4 +WDM3 3021 BODX ENGLZERO DIV RCHRES 1 INFLOW OXIF 2 +WDM3 3022 TSSX ENGLZERO 0.0005 DIV RCHRES 1 INFLOW ISED 3 +WDM3 3023 DOXX ENGLZERO DIV RCHRES 1 INFLOW OXIF 1 +WDM3 3024 TOCX ENGLZERO DIV RCHRES 1 INFLOW PKIF 5 + +*** RPA LOAD +WDM3 3031 NH3R ENGLZERO 1.0000 DIV RCHRES 1 INFLOW NUIF1 2 +WDM3 3032 NO3R ENGLZERO 1.0000 DIV RCHRES 1 INFLOW NUIF1 1 +WDM3 3033 RONR ENGLZERO 1.0000 DIV RCHRES 1 INFLOW PKIF 3 +WDM3 3034 PO4R ENGLZERO 1.0000 DIV RCHRES 1 INFLOW NUIF1 4 +WDM3 3035 ROPR ENGLZERO 1.0000 DIV RCHRES 1 INFLOW PKIF 4 +WDM3 3036 BODR ENGLZERO 1.0000 DIV RCHRES 1 INFLOW OXIF 2 +WDM3 3037 SNDR ENGLZERO 1.0000 DIV RCHRES 1 INFLOW ISED 1 +WDM3 3038 SLTR ENGLZERO 1.0000 DIV RCHRES 1 INFLOW ISED 2 +WDM3 3039 CLYR ENGLZERO 1.0000 DIV RCHRES 1 INFLOW ISED 3 + +*** DIVERSIONS +WDM3 3007 DIVR ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 1 +WDM3 3008 DIVA ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 2 + +*** SEPTIC +WDM3 3010 SNO3 ENGLZERO 1.0000 DIV RCHRES 1 INFLOW NUIF1 1 + +*** RIB +WDM3 3012 NH3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 2 +WDM3 3013 NO3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 1 +WDM3 3014 ORNX ENGLZERO DIV RCHRES 1 INFLOW PKIF 3 +WDM3 3015 PO4X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 4 +WDM3 3016 ORPX ENGLZERO DIV RCHRES 1 INFLOW PKIF 4 +WDM3 3017 BODX ENGLZERO DIV RCHRES 1 INFLOW OXIF 2 + +*** AEOLIAN SEDIMENT +WDM3 3061 SFAS ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 2 +WDM3 3062 SFAC ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 3 + +*** UPSTREAM and EOS INPUT *** +WDM4 11 WATR ENGLZERO SAME RCHRES 1 INFLOW IVOL +WDM4 12 HEAT ENGLZERO SAME RCHRES 1 INFLOW IHEAT +WDM4 13 DOXY ENGLZERO SAME RCHRES 1 INFLOW OXIF 1 +WDM4 21 SAND ENGLZERO SAME RCHRES 1 INFLOW ISED 1 +WDM4 22 SILT ENGLZERO SAME RCHRES 1 INFLOW ISED 2 +WDM4 23 CLAY ENGLZERO SAME RCHRES 1 INFLOW ISED 3 +WDM4 31 NO3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 1 +WDM4 32 NH3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 2 +WDM4 33 NH3A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 1 +WDM4 34 NH3I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 1 +WDM4 35 NH3C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 1 +WDM4 36 RORN ENGLZERO SAME RCHRES 1 INFLOW PKIF 3 +WDM4 37 LORN ENGLZERO SAME RCHRES 1 INFLOW PKIF 3 +WDM4 41 PO4D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 4 +WDM4 42 PO4A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 2 +WDM4 43 PO4I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 2 +WDM4 44 PO4C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 2 +WDM4 45 RORP ENGLZERO SAME RCHRES 1 INFLOW PKIF 4 +WDM4 47 LORP ENGLZERO SAME RCHRES 1 INFLOW PKIF 4 +WDM4 51 BODA ENGLZERO SAME RCHRES 1 INFLOW OXIF 2 +WDM4 52 TORC ENGLZERO SAME RCHRES 1 INFLOW PKIF 5 +WDM4 53 PHYT ENGLZERO SAME RCHRES 1 INFLOW PKIF 1 +END EXT SOURCES + +EXT TARGETS +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Volume-> Tsys Tgap Amd *** + # # #<-factor->strg # # tem strg strg*** +RCHRES 1 OFLOW OVOL 3 SAME WDM4 111 WATR ENGL REPL +RCHRES 1 OFLOW OHEAT 3 SAME WDM4 112 HEAT ENGL REPL +RCHRES 1 OFLOW OXCF2 3 1 SAME WDM4 113 DOXY ENGL REPL +RCHRES 1 OFLOW OSED 3 1 SAME WDM4 121 SAND ENGL REPL +RCHRES 1 OFLOW OSED 3 2 SAME WDM4 122 SILT ENGL REPL +RCHRES 1 OFLOW OSED 3 3 SAME WDM4 123 CLAY ENGL REPL +RCHRES 1 OFLOW NUCF9 3 1 SAME WDM4 131 NO3D ENGL REPL +RCHRES 1 OFLOW NUCF9 3 2 SAME WDM4 132 NH3D ENGL REPL +RCHRES 1 OFLOW OSNH4 3 1 SAME WDM4 133 NH3A ENGL REPL +RCHRES 1 OFLOW OSNH4 3 2 SAME WDM4 134 NH3I ENGL REPL +RCHRES 1 OFLOW OSNH4 3 3 SAME WDM4 135 NH3C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 3 SAME WDM4 136 RORN ENGL REPL +RCHRES 1 OFLOW PKCF2 3 3 0. SAME WDM4 137 LORN ENGL REPL +RCHRES 1 OFLOW NUCF9 3 4 SAME WDM4 141 PO4D ENGL REPL +RCHRES 1 OFLOW OSPO4 3 1 SAME WDM4 142 PO4A ENGL REPL +RCHRES 1 OFLOW OSPO4 3 2 SAME WDM4 143 PO4I ENGL REPL +RCHRES 1 OFLOW OSPO4 3 3 SAME WDM4 144 PO4C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 4 SAME WDM4 145 RORP ENGL REPL +RCHRES 1 OFLOW PKCF2 3 4 0. SAME WDM4 147 LORP ENGL REPL +RCHRES 1 OFLOW OXCF2 3 2 SAME WDM4 151 BODA ENGL REPL +RCHRES 1 OFLOW PKCF2 3 5 SAME WDM4 152 TORC ENGL REPL +RCHRES 1 OFLOW PKCF2 3 1 SAME WDM4 153 PHYT ENGL REPL +RCHRES 1 SEDTRN DEPSCR 4 SAME WDM4 124 SSCR ENGL REPL +END EXT TARGETS + +NETWORK +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Target vols> <-Grp> <-Member-> *** + # # #<-factor->strg # # # # *** +RCHRES 1 HYDR TAU AVER PLTGEN 1 INPUT MEAN 1 +END NETWORK + +PLTGEN + PLOTINFO + # - # FILE NPT NMN LABL PYR PIVL *** + 1 31 1 12 24 + END PLOTINFO + + GEN-LABELS + # - #<----------------Title-----------------> *** + 1 JL1_6562_6560 daily_shear_stress_lbsft2 + END GEN-LABELS + + SCALING + #thru# YMIN YMAX IVLIN THRESH *** + 1 99 0. 100000. 20. + END SCALING + + CURV-DATA + <-Curve label--> Line Intg Col Tran *** + # - # type eqv code code *** + 1 daily_shear_stre 1 1 AVER + END CURV-DATA +END PLTGEN + + + +SPEC-ACTIONS +*** test special actions + RCHRES 1 RSED 4 += 2.50E+05 + RCHRES 1 RSED 5 += 6.89E+05 + RCHRES 1 RSED 6 += 4.01E+05 +END SPEC-ACTIONS + +END RUN diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.dynamic_wd.json b/tests/testcbp/HSP2results/PL3_5250_0001.json.dynamic_wd.json new file mode 100644 index 00000000..a61c54a4 --- /dev/null +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.dynamic_wd.json @@ -0,0 +1,19 @@ +{ + "RCHRES_R001": { + "name": "RCHRES_R001", + "object_class": "ModelObject", + "value": "0", + "wd_cfs": { + "name": "wd_cfs", + "object_class": "Equation", + "value": "0.1 * O3" + }, + "O2write": { + "name": "O2write", + "object_class": "ModelLinkage", + "left_path": "/STATE/PL3_5250_0001/RCHRES_R001/O2", + "right_path": "/STATE/PL3_5250_0001/RCHRES_R001/wd_cfs", + "link_type": 5 + } + } +} diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq b/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq new file mode 100644 index 00000000..4eb8a9a0 --- /dev/null +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq @@ -0,0 +1,2515 @@ +{ + "RCHRES_R001": { + "name": "RCHRES_R001", + "object_class": "ModelObject", + "value": "0", + "wd_1": { + "name": "wd_1", + "object_class": "Equation", + "value": "0.02 + 0.0" + }, + "wd_2": { + "name": "wd_2", + "object_class": "Equation", + "value": "0.02 + wd_1" + }, + "wd_3": { + "name": "wd_3", + "object_class": "Equation", + "value": "0.02 + wd_2" + }, + "wd_4": { + "name": "wd_4", + "object_class": "Equation", + "value": "0.02 + wd_3" + }, + "wd_5": { + "name": "wd_5", + "object_class": "Equation", + "value": "0.02 + wd_4" + }, + "wd_6": { + "name": "wd_6", + "object_class": "Equation", + "value": "0.02 + wd_5" + }, + "wd_7": { + "name": "wd_7", + "object_class": "Equation", + "value": "0.02 + wd_6" + }, + "wd_8": { + "name": "wd_8", + "object_class": "Equation", + "value": "0.02 + wd_7" + }, + "wd_9": { + "name": "wd_9", + "object_class": "Equation", + "value": "0.02 + wd_8" + }, + "wd_10": { + "name": "wd_10", + "object_class": "Equation", + "value": "0.02 + wd_9" + }, + "wd_11": { + "name": "wd_11", + "object_class": "Equation", + "value": "0.02 + wd_10" + }, + "wd_12": { + "name": "wd_12", + "object_class": "Equation", + "value": "0.02 + wd_11" + }, + "wd_13": { + "name": "wd_13", + "object_class": "Equation", + "value": "0.02 + wd_12" + }, + "wd_14": { + "name": "wd_14", + "object_class": "Equation", + "value": "0.02 + wd_13" + }, + "wd_15": { + "name": "wd_15", + "object_class": "Equation", + "value": "0.02 + wd_14" + }, + "wd_16": { + "name": "wd_16", + "object_class": "Equation", + "value": "0.02 + wd_15" + }, + "wd_17": { + "name": "wd_17", + "object_class": "Equation", + "value": "0.02 + wd_16" + }, + "wd_18": { + "name": "wd_18", + "object_class": "Equation", + "value": "0.02 + wd_17" + }, + "wd_19": { + "name": "wd_19", + "object_class": "Equation", + "value": "0.02 + wd_18" + }, + "wd_20": { + "name": "wd_20", + "object_class": "Equation", + "value": "0.02 + wd_19" + }, + "wd_21": { + "name": "wd_21", + "object_class": "Equation", + "value": "0.02 + wd_20" + }, + "wd_22": { + "name": "wd_22", + "object_class": "Equation", + "value": "0.02 + wd_21" + }, + "wd_23": { + "name": "wd_23", + "object_class": "Equation", + "value": "0.02 + wd_22" + }, + "wd_24": { + "name": "wd_24", + "object_class": "Equation", + "value": "0.02 + wd_23" + }, + "wd_25": { + "name": "wd_25", + "object_class": "Equation", + "value": "0.02 + wd_24" + }, + "wd_26": { + "name": "wd_26", + "object_class": "Equation", + "value": "0.02 + wd_25" + }, + "wd_27": { + "name": "wd_27", + "object_class": "Equation", + "value": "0.02 + wd_26" + }, + "wd_28": { + "name": "wd_28", + "object_class": "Equation", + "value": "0.02 + wd_27" + }, + "wd_29": { + "name": "wd_29", + "object_class": "Equation", + "value": "0.02 + wd_28" + }, + "wd_30": { + "name": "wd_30", + "object_class": "Equation", + "value": "0.02 + wd_29" + }, + "wd_31": { + "name": "wd_31", + "object_class": "Equation", + "value": "0.02 + wd_30" + }, + "wd_32": { + "name": "wd_32", + "object_class": "Equation", + "value": "0.02 + wd_31" + }, + "wd_33": { + "name": "wd_33", + "object_class": "Equation", + "value": "0.02 + wd_32" + }, + "wd_34": { + "name": "wd_34", + "object_class": "Equation", + "value": "0.02 + wd_33" + }, + "wd_35": { + "name": "wd_35", + "object_class": "Equation", + "value": "0.02 + wd_34" + }, + "wd_36": { + "name": "wd_36", + "object_class": "Equation", + "value": "0.02 + wd_35" + }, + "wd_37": { + "name": "wd_37", + "object_class": "Equation", + "value": "0.02 + wd_36" + }, + "wd_38": { + "name": "wd_38", + "object_class": "Equation", + "value": "0.02 + wd_37" + }, + "wd_39": { + "name": "wd_39", + "object_class": "Equation", + "value": "0.02 + wd_38" + }, + "wd_40": { + "name": "wd_40", + "object_class": "Equation", + "value": "0.02 + wd_39" + }, + "wd_41": { + "name": "wd_41", + "object_class": "Equation", + "value": "0.02 + wd_40" + }, + "wd_42": { + "name": "wd_42", + "object_class": "Equation", + "value": "0.02 + wd_41" + }, + "wd_43": { + "name": "wd_43", + "object_class": "Equation", + "value": "0.02 + wd_42" + }, + "wd_44": { + "name": "wd_44", + "object_class": "Equation", + "value": "0.02 + wd_43" + }, + "wd_45": { + "name": "wd_45", + "object_class": "Equation", + "value": "0.02 + wd_44" + }, + "wd_46": { + "name": "wd_46", + "object_class": "Equation", + "value": "0.02 + wd_45" + }, + "wd_47": { + "name": "wd_47", + "object_class": "Equation", + "value": "0.02 + wd_46" + }, + "wd_48": { + "name": "wd_48", + "object_class": "Equation", + "value": "0.02 + wd_47" + }, + "wd_49": { + "name": "wd_49", + "object_class": "Equation", + "value": "0.02 + wd_48" + }, + "wd_50": { + "name": "wd_50", + "object_class": "Equation", + "value": "0.02 + wd_49" + }, + "wd_51": { + "name": "wd_51", + "object_class": "Equation", + "value": "0.02 + wd_50" + }, + "wd_52": { + "name": "wd_52", + "object_class": "Equation", + "value": "0.02 + wd_51" + }, + "wd_53": { + "name": "wd_53", + "object_class": "Equation", + "value": "0.02 + wd_52" + }, + "wd_54": { + "name": "wd_54", + "object_class": "Equation", + "value": "0.02 + wd_53" + }, + "wd_55": { + "name": "wd_55", + "object_class": "Equation", + "value": "0.02 + wd_54" + }, + "wd_56": { + "name": "wd_56", + "object_class": "Equation", + "value": "0.02 + wd_55" + }, + "wd_57": { + "name": "wd_57", + "object_class": "Equation", + "value": "0.02 + wd_56" + }, + "wd_58": { + "name": "wd_58", + "object_class": "Equation", + "value": "0.02 + wd_57" + }, + "wd_59": { + "name": "wd_59", + "object_class": "Equation", + "value": "0.02 + wd_58" + }, + "wd_60": { + "name": "wd_60", + "object_class": "Equation", + "value": "0.02 + wd_59" + }, + "wd_61": { + "name": "wd_61", + "object_class": "Equation", + "value": "0.02 + wd_60" + }, + "wd_62": { + "name": "wd_62", + "object_class": "Equation", + "value": "0.02 + wd_61" + }, + "wd_63": { + "name": "wd_63", + "object_class": "Equation", + "value": "0.02 + wd_62" + }, + "wd_64": { + "name": "wd_64", + "object_class": "Equation", + "value": "0.02 + wd_63" + }, + "wd_65": { + "name": "wd_65", + "object_class": "Equation", + "value": "0.02 + wd_64" + }, + "wd_66": { + "name": "wd_66", + "object_class": "Equation", + "value": "0.02 + wd_65" + }, + "wd_67": { + "name": "wd_67", + "object_class": "Equation", + "value": "0.02 + wd_66" + }, + "wd_68": { + "name": "wd_68", + "object_class": "Equation", + "value": "0.02 + wd_67" + }, + "wd_69": { + "name": "wd_69", + "object_class": "Equation", + "value": "0.02 + wd_68" + }, + "wd_70": { + "name": "wd_70", + "object_class": "Equation", + "value": "0.02 + wd_69" + }, + "wd_71": { + "name": "wd_71", + "object_class": "Equation", + "value": "0.02 + wd_70" + }, + "wd_72": { + "name": "wd_72", + "object_class": "Equation", + "value": "0.02 + wd_71" + }, + "wd_73": { + "name": "wd_73", + "object_class": "Equation", + "value": "0.02 + wd_72" + }, + "wd_74": { + "name": "wd_74", + "object_class": "Equation", + "value": "0.02 + wd_73" + }, + "wd_75": { + "name": "wd_75", + "object_class": "Equation", + "value": "0.02 + wd_74" + }, + "wd_76": { + "name": "wd_76", + "object_class": "Equation", + "value": "0.02 + wd_75" + }, + "wd_77": { + "name": "wd_77", + "object_class": "Equation", + "value": "0.02 + wd_76" + }, + "wd_78": { + "name": "wd_78", + "object_class": "Equation", + "value": "0.02 + wd_77" + }, + "wd_79": { + "name": "wd_79", + "object_class": "Equation", + "value": "0.02 + wd_78" + }, + "wd_80": { + "name": "wd_80", + "object_class": "Equation", + "value": "0.02 + wd_79" + }, + "wd_81": { + "name": "wd_81", + "object_class": "Equation", + "value": "0.02 + wd_80" + }, + "wd_82": { + "name": "wd_82", + "object_class": "Equation", + "value": "0.02 + wd_81" + }, + "wd_83": { + "name": "wd_83", + "object_class": "Equation", + "value": "0.02 + wd_82" + }, + "wd_84": { + "name": "wd_84", + "object_class": "Equation", + "value": "0.02 + wd_83" + }, + "wd_85": { + "name": "wd_85", + "object_class": "Equation", + "value": "0.02 + wd_84" + }, + "wd_86": { + "name": "wd_86", + "object_class": "Equation", + "value": "0.02 + wd_85" + }, + "wd_87": { + "name": "wd_87", + "object_class": "Equation", + "value": "0.02 + wd_86" + }, + "wd_88": { + "name": "wd_88", + "object_class": "Equation", + "value": "0.02 + wd_87" + }, + "wd_89": { + "name": "wd_89", + "object_class": "Equation", + "value": "0.02 + wd_88" + }, + "wd_90": { + "name": "wd_90", + "object_class": "Equation", + "value": "0.02 + wd_89" + }, + "wd_91": { + "name": "wd_91", + "object_class": "Equation", + "value": "0.02 + wd_90" + }, + "wd_92": { + "name": "wd_92", + "object_class": "Equation", + "value": "0.02 + wd_91" + }, + "wd_93": { + "name": "wd_93", + "object_class": "Equation", + "value": "0.02 + wd_92" + }, + "wd_94": { + "name": "wd_94", + "object_class": "Equation", + "value": "0.02 + wd_93" + }, + "wd_95": { + "name": "wd_95", + "object_class": "Equation", + "value": "0.02 + wd_94" + }, + "wd_96": { + "name": "wd_96", + "object_class": "Equation", + "value": "0.02 + wd_95" + }, + "wd_97": { + "name": "wd_97", + "object_class": "Equation", + "value": "0.02 + wd_96" + }, + "wd_98": { + "name": "wd_98", + "object_class": "Equation", + "value": "0.02 + wd_97" + }, + "wd_99": { + "name": "wd_99", + "object_class": "Equation", + "value": "0.02 + wd_98" + }, + "wd_100": { + "name": "wd_100", + "object_class": "Equation", + "value": "0.02 + wd_99" + }, + "wd_101": { + "name": "wd_101", + "object_class": "Equation", + "value": "0.02 + wd_100" + }, + "wd_102": { + "name": "wd_102", + "object_class": "Equation", + "value": "0.02 + wd_101" + }, + "wd_103": { + "name": "wd_103", + "object_class": "Equation", + "value": "0.02 + wd_102" + }, + "wd_104": { + "name": "wd_104", + "object_class": "Equation", + "value": "0.02 + wd_103" + }, + "wd_105": { + "name": "wd_105", + "object_class": "Equation", + "value": "0.02 + wd_104" + }, + "wd_106": { + "name": "wd_106", + "object_class": "Equation", + "value": "0.02 + wd_105" + }, + "wd_107": { + "name": "wd_107", + "object_class": "Equation", + "value": "0.02 + wd_106" + }, + "wd_108": { + "name": "wd_108", + "object_class": "Equation", + "value": "0.02 + wd_107" + }, + "wd_109": { + "name": "wd_109", + "object_class": "Equation", + "value": "0.02 + wd_108" + }, + "wd_110": { + "name": "wd_110", + "object_class": "Equation", + "value": "0.02 + wd_109" + }, + "wd_111": { + "name": "wd_111", + "object_class": "Equation", + "value": "0.02 + wd_110" + }, + "wd_112": { + "name": "wd_112", + "object_class": "Equation", + "value": "0.02 + wd_111" + }, + "wd_113": { + "name": "wd_113", + "object_class": "Equation", + "value": "0.02 + wd_112" + }, + "wd_114": { + "name": "wd_114", + "object_class": "Equation", + "value": "0.02 + wd_113" + }, + "wd_115": { + "name": "wd_115", + "object_class": "Equation", + "value": "0.02 + wd_114" + }, + "wd_116": { + "name": "wd_116", + "object_class": "Equation", + "value": "0.02 + wd_115" + }, + "wd_117": { + "name": "wd_117", + "object_class": "Equation", + "value": "0.02 + wd_116" + }, + "wd_118": { + "name": "wd_118", + "object_class": "Equation", + "value": "0.02 + wd_117" + }, + "wd_119": { + "name": "wd_119", + "object_class": "Equation", + "value": "0.02 + wd_118" + }, + "wd_120": { + "name": "wd_120", + "object_class": "Equation", + "value": "0.02 + wd_119" + }, + "wd_121": { + "name": "wd_121", + "object_class": "Equation", + "value": "0.02 + wd_120" + }, + "wd_122": { + "name": "wd_122", + "object_class": "Equation", + "value": "0.02 + wd_121" + }, + "wd_123": { + "name": "wd_123", + "object_class": "Equation", + "value": "0.02 + wd_122" + }, + "wd_124": { + "name": "wd_124", + "object_class": "Equation", + "value": "0.02 + wd_123" + }, + "wd_125": { + "name": "wd_125", + "object_class": "Equation", + "value": "0.02 + wd_124" + }, + "wd_126": { + "name": "wd_126", + "object_class": "Equation", + "value": "0.02 + wd_125" + }, + "wd_127": { + "name": "wd_127", + "object_class": "Equation", + "value": "0.02 + wd_126" + }, + "wd_128": { + "name": "wd_128", + "object_class": "Equation", + "value": "0.02 + wd_127" + }, + "wd_129": { + "name": "wd_129", + "object_class": "Equation", + "value": "0.02 + wd_128" + }, + "wd_130": { + "name": "wd_130", + "object_class": "Equation", + "value": "0.02 + wd_129" + }, + "wd_131": { + "name": "wd_131", + "object_class": "Equation", + "value": "0.02 + wd_130" + }, + "wd_132": { + "name": "wd_132", + "object_class": "Equation", + "value": "0.02 + wd_131" + }, + "wd_133": { + "name": "wd_133", + "object_class": "Equation", + "value": "0.02 + wd_132" + }, + "wd_134": { + "name": "wd_134", + "object_class": "Equation", + "value": "0.02 + wd_133" + }, + "wd_135": { + "name": "wd_135", + "object_class": "Equation", + "value": "0.02 + wd_134" + }, + "wd_136": { + "name": "wd_136", + "object_class": "Equation", + "value": "0.02 + wd_135" + }, + "wd_137": { + "name": "wd_137", + "object_class": "Equation", + "value": "0.02 + wd_136" + }, + "wd_138": { + "name": "wd_138", + "object_class": "Equation", + "value": "0.02 + wd_137" + }, + "wd_139": { + "name": "wd_139", + "object_class": "Equation", + "value": "0.02 + wd_138" + }, + "wd_140": { + "name": "wd_140", + "object_class": "Equation", + "value": "0.02 + wd_139" + }, + "wd_141": { + "name": "wd_141", + "object_class": "Equation", + "value": "0.02 + wd_140" + }, + "wd_142": { + "name": "wd_142", + "object_class": "Equation", + "value": "0.02 + wd_141" + }, + "wd_143": { + "name": "wd_143", + "object_class": "Equation", + "value": "0.02 + wd_142" + }, + "wd_144": { + "name": "wd_144", + "object_class": "Equation", + "value": "0.02 + wd_143" + }, + "wd_145": { + "name": "wd_145", + "object_class": "Equation", + "value": "0.02 + wd_144" + }, + "wd_146": { + "name": "wd_146", + "object_class": "Equation", + "value": "0.02 + wd_145" + }, + "wd_147": { + "name": "wd_147", + "object_class": "Equation", + "value": "0.02 + wd_146" + }, + "wd_148": { + "name": "wd_148", + "object_class": "Equation", + "value": "0.02 + wd_147" + }, + "wd_149": { + "name": "wd_149", + "object_class": "Equation", + "value": "0.02 + wd_148" + }, + "wd_150": { + "name": "wd_150", + "object_class": "Equation", + "value": "0.02 + wd_149" + }, + "wd_151": { + "name": "wd_151", + "object_class": "Equation", + "value": "0.02 + wd_150" + }, + "wd_152": { + "name": "wd_152", + "object_class": "Equation", + "value": "0.02 + wd_151" + }, + "wd_153": { + "name": "wd_153", + "object_class": "Equation", + "value": "0.02 + wd_152" + }, + "wd_154": { + "name": "wd_154", + "object_class": "Equation", + "value": "0.02 + wd_153" + }, + "wd_155": { + "name": "wd_155", + "object_class": "Equation", + "value": "0.02 + wd_154" + }, + "wd_156": { + "name": "wd_156", + "object_class": "Equation", + "value": "0.02 + wd_155" + }, + "wd_157": { + "name": "wd_157", + "object_class": "Equation", + "value": "0.02 + wd_156" + }, + "wd_158": { + "name": "wd_158", + "object_class": "Equation", + "value": "0.02 + wd_157" + }, + "wd_159": { + "name": "wd_159", + "object_class": "Equation", + "value": "0.02 + wd_158" + }, + "wd_160": { + "name": "wd_160", + "object_class": "Equation", + "value": "0.02 + wd_159" + }, + "wd_161": { + "name": "wd_161", + "object_class": "Equation", + "value": "0.02 + wd_160" + }, + "wd_162": { + "name": "wd_162", + "object_class": "Equation", + "value": "0.02 + wd_161" + }, + "wd_163": { + "name": "wd_163", + "object_class": "Equation", + "value": "0.02 + wd_162" + }, + "wd_164": { + "name": "wd_164", + "object_class": "Equation", + "value": "0.02 + wd_163" + }, + "wd_165": { + "name": "wd_165", + "object_class": "Equation", + "value": "0.02 + wd_164" + }, + "wd_166": { + "name": "wd_166", + "object_class": "Equation", + "value": "0.02 + wd_165" + }, + "wd_167": { + "name": "wd_167", + "object_class": "Equation", + "value": "0.02 + wd_166" + }, + "wd_168": { + "name": "wd_168", + "object_class": "Equation", + "value": "0.02 + wd_167" + }, + "wd_169": { + "name": "wd_169", + "object_class": "Equation", + "value": "0.02 + wd_168" + }, + "wd_170": { + "name": "wd_170", + "object_class": "Equation", + "value": "0.02 + wd_169" + }, + "wd_171": { + "name": "wd_171", + "object_class": "Equation", + "value": "0.02 + wd_170" + }, + "wd_172": { + "name": "wd_172", + "object_class": "Equation", + "value": "0.02 + wd_171" + }, + "wd_173": { + "name": "wd_173", + "object_class": "Equation", + "value": "0.02 + wd_172" + }, + "wd_174": { + "name": "wd_174", + "object_class": "Equation", + "value": "0.02 + wd_173" + }, + "wd_175": { + "name": "wd_175", + "object_class": "Equation", + "value": "0.02 + wd_174" + }, + "wd_176": { + "name": "wd_176", + "object_class": "Equation", + "value": "0.02 + wd_175" + }, + "wd_177": { + "name": "wd_177", + "object_class": "Equation", + "value": "0.02 + wd_176" + }, + "wd_178": { + "name": "wd_178", + "object_class": "Equation", + "value": "0.02 + wd_177" + }, + "wd_179": { + "name": "wd_179", + "object_class": "Equation", + "value": "0.02 + wd_178" + }, + "wd_180": { + "name": "wd_180", + "object_class": "Equation", + "value": "0.02 + wd_179" + }, + "wd_181": { + "name": "wd_181", + "object_class": "Equation", + "value": "0.02 + wd_180" + }, + "wd_182": { + "name": "wd_182", + "object_class": "Equation", + "value": "0.02 + wd_181" + }, + "wd_183": { + "name": "wd_183", + "object_class": "Equation", + "value": "0.02 + wd_182" + }, + "wd_184": { + "name": "wd_184", + "object_class": "Equation", + "value": "0.02 + wd_183" + }, + "wd_185": { + "name": "wd_185", + "object_class": "Equation", + "value": "0.02 + wd_184" + }, + "wd_186": { + "name": "wd_186", + "object_class": "Equation", + "value": "0.02 + wd_185" + }, + "wd_187": { + "name": "wd_187", + "object_class": "Equation", + "value": "0.02 + wd_186" + }, + "wd_188": { + "name": "wd_188", + "object_class": "Equation", + "value": "0.02 + wd_187" + }, + "wd_189": { + "name": "wd_189", + "object_class": "Equation", + "value": "0.02 + wd_188" + }, + "wd_190": { + "name": "wd_190", + "object_class": "Equation", + "value": "0.02 + wd_189" + }, + "wd_191": { + "name": "wd_191", + "object_class": "Equation", + "value": "0.02 + wd_190" + }, + "wd_192": { + "name": "wd_192", + "object_class": "Equation", + "value": "0.02 + wd_191" + }, + "wd_193": { + "name": "wd_193", + "object_class": "Equation", + "value": "0.02 + wd_192" + }, + "wd_194": { + "name": "wd_194", + "object_class": "Equation", + "value": "0.02 + wd_193" + }, + "wd_195": { + "name": "wd_195", + "object_class": "Equation", + "value": "0.02 + wd_194" + }, + "wd_196": { + "name": "wd_196", + "object_class": "Equation", + "value": "0.02 + wd_195" + }, + "wd_197": { + "name": "wd_197", + "object_class": "Equation", + "value": "0.02 + wd_196" + }, + "wd_198": { + "name": "wd_198", + "object_class": "Equation", + "value": "0.02 + wd_197" + }, + "wd_199": { + "name": "wd_199", + "object_class": "Equation", + "value": "0.02 + wd_198" + }, + "wd_200": { + "name": "wd_200", + "object_class": "Equation", + "value": "0.02 + wd_199" + }, + "wd_201": { + "name": "wd_201", + "object_class": "Equation", + "value": "0.02 + wd_200" + }, + "wd_202": { + "name": "wd_202", + "object_class": "Equation", + "value": "0.02 + wd_201" + }, + "wd_203": { + "name": "wd_203", + "object_class": "Equation", + "value": "0.02 + wd_202" + }, + "wd_204": { + "name": "wd_204", + "object_class": "Equation", + "value": "0.02 + wd_203" + }, + "wd_205": { + "name": "wd_205", + "object_class": "Equation", + "value": "0.02 + wd_204" + }, + "wd_206": { + "name": "wd_206", + "object_class": "Equation", + "value": "0.02 + wd_205" + }, + "wd_207": { + "name": "wd_207", + "object_class": "Equation", + "value": "0.02 + wd_206" + }, + "wd_208": { + "name": "wd_208", + "object_class": "Equation", + "value": "0.02 + wd_207" + }, + "wd_209": { + "name": "wd_209", + "object_class": "Equation", + "value": "0.02 + wd_208" + }, + "wd_210": { + "name": "wd_210", + "object_class": "Equation", + "value": "0.02 + wd_209" + }, + "wd_211": { + "name": "wd_211", + "object_class": "Equation", + "value": "0.02 + wd_210" + }, + "wd_212": { + "name": "wd_212", + "object_class": "Equation", + "value": "0.02 + wd_211" + }, + "wd_213": { + "name": "wd_213", + "object_class": "Equation", + "value": "0.02 + wd_212" + }, + "wd_214": { + "name": "wd_214", + "object_class": "Equation", + "value": "0.02 + wd_213" + }, + "wd_215": { + "name": "wd_215", + "object_class": "Equation", + "value": "0.02 + wd_214" + }, + "wd_216": { + "name": "wd_216", + "object_class": "Equation", + "value": "0.02 + wd_215" + }, + "wd_217": { + "name": "wd_217", + "object_class": "Equation", + "value": "0.02 + wd_216" + }, + "wd_218": { + "name": "wd_218", + "object_class": "Equation", + "value": "0.02 + wd_217" + }, + "wd_219": { + "name": "wd_219", + "object_class": "Equation", + "value": "0.02 + wd_218" + }, + "wd_220": { + "name": "wd_220", + "object_class": "Equation", + "value": "0.02 + wd_219" + }, + "wd_221": { + "name": "wd_221", + "object_class": "Equation", + "value": "0.02 + wd_220" + }, + "wd_222": { + "name": "wd_222", + "object_class": "Equation", + "value": "0.02 + wd_221" + }, + "wd_223": { + "name": "wd_223", + "object_class": "Equation", + "value": "0.02 + wd_222" + }, + "wd_224": { + "name": "wd_224", + "object_class": "Equation", + "value": "0.02 + wd_223" + }, + "wd_225": { + "name": "wd_225", + "object_class": "Equation", + "value": "0.02 + wd_224" + }, + "wd_226": { + "name": "wd_226", + "object_class": "Equation", + "value": "0.02 + wd_225" + }, + "wd_227": { + "name": "wd_227", + "object_class": "Equation", + "value": "0.02 + wd_226" + }, + "wd_228": { + "name": "wd_228", + "object_class": "Equation", + "value": "0.02 + wd_227" + }, + "wd_229": { + "name": "wd_229", + "object_class": "Equation", + "value": "0.02 + wd_228" + }, + "wd_230": { + "name": "wd_230", + "object_class": "Equation", + "value": "0.02 + wd_229" + }, + "wd_231": { + "name": "wd_231", + "object_class": "Equation", + "value": "0.02 + wd_230" + }, + "wd_232": { + "name": "wd_232", + "object_class": "Equation", + "value": "0.02 + wd_231" + }, + "wd_233": { + "name": "wd_233", + "object_class": "Equation", + "value": "0.02 + wd_232" + }, + "wd_234": { + "name": "wd_234", + "object_class": "Equation", + "value": "0.02 + wd_233" + }, + "wd_235": { + "name": "wd_235", + "object_class": "Equation", + "value": "0.02 + wd_234" + }, + "wd_236": { + "name": "wd_236", + "object_class": "Equation", + "value": "0.02 + wd_235" + }, + "wd_237": { + "name": "wd_237", + "object_class": "Equation", + "value": "0.02 + wd_236" + }, + "wd_238": { + "name": "wd_238", + "object_class": "Equation", + "value": "0.02 + wd_237" + }, + "wd_239": { + "name": "wd_239", + "object_class": "Equation", + "value": "0.02 + wd_238" + }, + "wd_240": { + "name": "wd_240", + "object_class": "Equation", + "value": "0.02 + wd_239" + }, + "wd_241": { + "name": "wd_241", + "object_class": "Equation", + "value": "0.02 + wd_240" + }, + "wd_242": { + "name": "wd_242", + "object_class": "Equation", + "value": "0.02 + wd_241" + }, + "wd_243": { + "name": "wd_243", + "object_class": "Equation", + "value": "0.02 + wd_242" + }, + "wd_244": { + "name": "wd_244", + "object_class": "Equation", + "value": "0.02 + wd_243" + }, + "wd_245": { + "name": "wd_245", + "object_class": "Equation", + "value": "0.02 + wd_244" + }, + "wd_246": { + "name": "wd_246", + "object_class": "Equation", + "value": "0.02 + wd_245" + }, + "wd_247": { + "name": "wd_247", + "object_class": "Equation", + "value": "0.02 + wd_246" + }, + "wd_248": { + "name": "wd_248", + "object_class": "Equation", + "value": "0.02 + wd_247" + }, + "wd_249": { + "name": "wd_249", + "object_class": "Equation", + "value": "0.02 + wd_248" + }, + "wd_250": { + "name": "wd_250", + "object_class": "Equation", + "value": "0.02 + wd_249" + }, + "wd_251": { + "name": "wd_251", + "object_class": "Equation", + "value": "0.02 + wd_250" + }, + "wd_252": { + "name": "wd_252", + "object_class": "Equation", + "value": "0.02 + wd_251" + }, + "wd_253": { + "name": "wd_253", + "object_class": "Equation", + "value": "0.02 + wd_252" + }, + "wd_254": { + "name": "wd_254", + "object_class": "Equation", + "value": "0.02 + wd_253" + }, + "wd_255": { + "name": "wd_255", + "object_class": "Equation", + "value": "0.02 + wd_254" + }, + "wd_256": { + "name": "wd_256", + "object_class": "Equation", + "value": "0.02 + wd_255" + }, + "wd_257": { + "name": "wd_257", + "object_class": "Equation", + "value": "0.02 + wd_256" + }, + "wd_258": { + "name": "wd_258", + "object_class": "Equation", + "value": "0.02 + wd_257" + }, + "wd_259": { + "name": "wd_259", + "object_class": "Equation", + "value": "0.02 + wd_258" + }, + "wd_260": { + "name": "wd_260", + "object_class": "Equation", + "value": "0.02 + wd_259" + }, + "wd_261": { + "name": "wd_261", + "object_class": "Equation", + "value": "0.02 + wd_260" + }, + "wd_262": { + "name": "wd_262", + "object_class": "Equation", + "value": "0.02 + wd_261" + }, + "wd_263": { + "name": "wd_263", + "object_class": "Equation", + "value": "0.02 + wd_262" + }, + "wd_264": { + "name": "wd_264", + "object_class": "Equation", + "value": "0.02 + wd_263" + }, + "wd_265": { + "name": "wd_265", + "object_class": "Equation", + "value": "0.02 + wd_264" + }, + "wd_266": { + "name": "wd_266", + "object_class": "Equation", + "value": "0.02 + wd_265" + }, + "wd_267": { + "name": "wd_267", + "object_class": "Equation", + "value": "0.02 + wd_266" + }, + "wd_268": { + "name": "wd_268", + "object_class": "Equation", + "value": "0.02 + wd_267" + }, + "wd_269": { + "name": "wd_269", + "object_class": "Equation", + "value": "0.02 + wd_268" + }, + "wd_270": { + "name": "wd_270", + "object_class": "Equation", + "value": "0.02 + wd_269" + }, + "wd_271": { + "name": "wd_271", + "object_class": "Equation", + "value": "0.02 + wd_270" + }, + "wd_272": { + "name": "wd_272", + "object_class": "Equation", + "value": "0.02 + wd_271" + }, + "wd_273": { + "name": "wd_273", + "object_class": "Equation", + "value": "0.02 + wd_272" + }, + "wd_274": { + "name": "wd_274", + "object_class": "Equation", + "value": "0.02 + wd_273" + }, + "wd_275": { + "name": "wd_275", + "object_class": "Equation", + "value": "0.02 + wd_274" + }, + "wd_276": { + "name": "wd_276", + "object_class": "Equation", + "value": "0.02 + wd_275" + }, + "wd_277": { + "name": "wd_277", + "object_class": "Equation", + "value": "0.02 + wd_276" + }, + "wd_278": { + "name": "wd_278", + "object_class": "Equation", + "value": "0.02 + wd_277" + }, + "wd_279": { + "name": "wd_279", + "object_class": "Equation", + "value": "0.02 + wd_278" + }, + "wd_280": { + "name": "wd_280", + "object_class": "Equation", + "value": "0.02 + wd_279" + }, + "wd_281": { + "name": "wd_281", + "object_class": "Equation", + "value": "0.02 + wd_280" + }, + "wd_282": { + "name": "wd_282", + "object_class": "Equation", + "value": "0.02 + wd_281" + }, + "wd_283": { + "name": "wd_283", + "object_class": "Equation", + "value": "0.02 + wd_282" + }, + "wd_284": { + "name": "wd_284", + "object_class": "Equation", + "value": "0.02 + wd_283" + }, + "wd_285": { + "name": "wd_285", + "object_class": "Equation", + "value": "0.02 + wd_284" + }, + "wd_286": { + "name": "wd_286", + "object_class": "Equation", + "value": "0.02 + wd_285" + }, + "wd_287": { + "name": "wd_287", + "object_class": "Equation", + "value": "0.02 + wd_286" + }, + "wd_288": { + "name": "wd_288", + "object_class": "Equation", + "value": "0.02 + wd_287" + }, + "wd_289": { + "name": "wd_289", + "object_class": "Equation", + "value": "0.02 + wd_288" + }, + "wd_290": { + "name": "wd_290", + "object_class": "Equation", + "value": "0.02 + wd_289" + }, + "wd_291": { + "name": "wd_291", + "object_class": "Equation", + "value": "0.02 + wd_290" + }, + "wd_292": { + "name": "wd_292", + "object_class": "Equation", + "value": "0.02 + wd_291" + }, + "wd_293": { + "name": "wd_293", + "object_class": "Equation", + "value": "0.02 + wd_292" + }, + "wd_294": { + "name": "wd_294", + "object_class": "Equation", + "value": "0.02 + wd_293" + }, + "wd_295": { + "name": "wd_295", + "object_class": "Equation", + "value": "0.02 + wd_294" + }, + "wd_296": { + "name": "wd_296", + "object_class": "Equation", + "value": "0.02 + wd_295" + }, + "wd_297": { + "name": "wd_297", + "object_class": "Equation", + "value": "0.02 + wd_296" + }, + "wd_298": { + "name": "wd_298", + "object_class": "Equation", + "value": "0.02 + wd_297" + }, + "wd_299": { + "name": "wd_299", + "object_class": "Equation", + "value": "0.02 + wd_298" + }, + "wd_300": { + "name": "wd_300", + "object_class": "Equation", + "value": "0.02 + wd_299" + }, + "wd_301": { + "name": "wd_301", + "object_class": "Equation", + "value": "0.02 + wd_300" + }, + "wd_302": { + "name": "wd_302", + "object_class": "Equation", + "value": "0.02 + wd_301" + }, + "wd_303": { + "name": "wd_303", + "object_class": "Equation", + "value": "0.02 + wd_302" + }, + "wd_304": { + "name": "wd_304", + "object_class": "Equation", + "value": "0.02 + wd_303" + }, + "wd_305": { + "name": "wd_305", + "object_class": "Equation", + "value": "0.02 + wd_304" + }, + "wd_306": { + "name": "wd_306", + "object_class": "Equation", + "value": "0.02 + wd_305" + }, + "wd_307": { + "name": "wd_307", + "object_class": "Equation", + "value": "0.02 + wd_306" + }, + "wd_308": { + "name": "wd_308", + "object_class": "Equation", + "value": "0.02 + wd_307" + }, + "wd_309": { + "name": "wd_309", + "object_class": "Equation", + "value": "0.02 + wd_308" + }, + "wd_310": { + "name": "wd_310", + "object_class": "Equation", + "value": "0.02 + wd_309" + }, + "wd_311": { + "name": "wd_311", + "object_class": "Equation", + "value": "0.02 + wd_310" + }, + "wd_312": { + "name": "wd_312", + "object_class": "Equation", + "value": "0.02 + wd_311" + }, + "wd_313": { + "name": "wd_313", + "object_class": "Equation", + "value": "0.02 + wd_312" + }, + "wd_314": { + "name": "wd_314", + "object_class": "Equation", + "value": "0.02 + wd_313" + }, + "wd_315": { + "name": "wd_315", + "object_class": "Equation", + "value": "0.02 + wd_314" + }, + "wd_316": { + "name": "wd_316", + "object_class": "Equation", + "value": "0.02 + wd_315" + }, + "wd_317": { + "name": "wd_317", + "object_class": "Equation", + "value": "0.02 + wd_316" + }, + "wd_318": { + "name": "wd_318", + "object_class": "Equation", + "value": "0.02 + wd_317" + }, + "wd_319": { + "name": "wd_319", + "object_class": "Equation", + "value": "0.02 + wd_318" + }, + "wd_320": { + "name": "wd_320", + "object_class": "Equation", + "value": "0.02 + wd_319" + }, + "wd_321": { + "name": "wd_321", + "object_class": "Equation", + "value": "0.02 + wd_320" + }, + "wd_322": { + "name": "wd_322", + "object_class": "Equation", + "value": "0.02 + wd_321" + }, + "wd_323": { + "name": "wd_323", + "object_class": "Equation", + "value": "0.02 + wd_322" + }, + "wd_324": { + "name": "wd_324", + "object_class": "Equation", + "value": "0.02 + wd_323" + }, + "wd_325": { + "name": "wd_325", + "object_class": "Equation", + "value": "0.02 + wd_324" + }, + "wd_326": { + "name": "wd_326", + "object_class": "Equation", + "value": "0.02 + wd_325" + }, + "wd_327": { + "name": "wd_327", + "object_class": "Equation", + "value": "0.02 + wd_326" + }, + "wd_328": { + "name": "wd_328", + "object_class": "Equation", + "value": "0.02 + wd_327" + }, + "wd_329": { + "name": "wd_329", + "object_class": "Equation", + "value": "0.02 + wd_328" + }, + "wd_330": { + "name": "wd_330", + "object_class": "Equation", + "value": "0.02 + wd_329" + }, + "wd_331": { + "name": "wd_331", + "object_class": "Equation", + "value": "0.02 + wd_330" + }, + "wd_332": { + "name": "wd_332", + "object_class": "Equation", + "value": "0.02 + wd_331" + }, + "wd_333": { + "name": "wd_333", + "object_class": "Equation", + "value": "0.02 + wd_332" + }, + "wd_334": { + "name": "wd_334", + "object_class": "Equation", + "value": "0.02 + wd_333" + }, + "wd_335": { + "name": "wd_335", + "object_class": "Equation", + "value": "0.02 + wd_334" + }, + "wd_336": { + "name": "wd_336", + "object_class": "Equation", + "value": "0.02 + wd_335" + }, + "wd_337": { + "name": "wd_337", + "object_class": "Equation", + "value": "0.02 + wd_336" + }, + "wd_338": { + "name": "wd_338", + "object_class": "Equation", + "value": "0.02 + wd_337" + }, + "wd_339": { + "name": "wd_339", + "object_class": "Equation", + "value": "0.02 + wd_338" + }, + "wd_340": { + "name": "wd_340", + "object_class": "Equation", + "value": "0.02 + wd_339" + }, + "wd_341": { + "name": "wd_341", + "object_class": "Equation", + "value": "0.02 + wd_340" + }, + "wd_342": { + "name": "wd_342", + "object_class": "Equation", + "value": "0.02 + wd_341" + }, + "wd_343": { + "name": "wd_343", + "object_class": "Equation", + "value": "0.02 + wd_342" + }, + "wd_344": { + "name": "wd_344", + "object_class": "Equation", + "value": "0.02 + wd_343" + }, + "wd_345": { + "name": "wd_345", + "object_class": "Equation", + "value": "0.02 + wd_344" + }, + "wd_346": { + "name": "wd_346", + "object_class": "Equation", + "value": "0.02 + wd_345" + }, + "wd_347": { + "name": "wd_347", + "object_class": "Equation", + "value": "0.02 + wd_346" + }, + "wd_348": { + "name": "wd_348", + "object_class": "Equation", + "value": "0.02 + wd_347" + }, + "wd_349": { + "name": "wd_349", + "object_class": "Equation", + "value": "0.02 + wd_348" + }, + "wd_350": { + "name": "wd_350", + "object_class": "Equation", + "value": "0.02 + wd_349" + }, + "wd_351": { + "name": "wd_351", + "object_class": "Equation", + "value": "0.02 + wd_350" + }, + "wd_352": { + "name": "wd_352", + "object_class": "Equation", + "value": "0.02 + wd_351" + }, + "wd_353": { + "name": "wd_353", + "object_class": "Equation", + "value": "0.02 + wd_352" + }, + "wd_354": { + "name": "wd_354", + "object_class": "Equation", + "value": "0.02 + wd_353" + }, + "wd_355": { + "name": "wd_355", + "object_class": "Equation", + "value": "0.02 + wd_354" + }, + "wd_356": { + "name": "wd_356", + "object_class": "Equation", + "value": "0.02 + wd_355" + }, + "wd_357": { + "name": "wd_357", + "object_class": "Equation", + "value": "0.02 + wd_356" + }, + "wd_358": { + "name": "wd_358", + "object_class": "Equation", + "value": "0.02 + wd_357" + }, + "wd_359": { + "name": "wd_359", + "object_class": "Equation", + "value": "0.02 + wd_358" + }, + "wd_360": { + "name": "wd_360", + "object_class": "Equation", + "value": "0.02 + wd_359" + }, + "wd_361": { + "name": "wd_361", + "object_class": "Equation", + "value": "0.02 + wd_360" + }, + "wd_362": { + "name": "wd_362", + "object_class": "Equation", + "value": "0.02 + wd_361" + }, + "wd_363": { + "name": "wd_363", + "object_class": "Equation", + "value": "0.02 + wd_362" + }, + "wd_364": { + "name": "wd_364", + "object_class": "Equation", + "value": "0.02 + wd_363" + }, + "wd_365": { + "name": "wd_365", + "object_class": "Equation", + "value": "0.02 + wd_364" + }, + "wd_366": { + "name": "wd_366", + "object_class": "Equation", + "value": "0.02 + wd_365" + }, + "wd_367": { + "name": "wd_367", + "object_class": "Equation", + "value": "0.02 + wd_366" + }, + "wd_368": { + "name": "wd_368", + "object_class": "Equation", + "value": "0.02 + wd_367" + }, + "wd_369": { + "name": "wd_369", + "object_class": "Equation", + "value": "0.02 + wd_368" + }, + "wd_370": { + "name": "wd_370", + "object_class": "Equation", + "value": "0.02 + wd_369" + }, + "wd_371": { + "name": "wd_371", + "object_class": "Equation", + "value": "0.02 + wd_370" + }, + "wd_372": { + "name": "wd_372", + "object_class": "Equation", + "value": "0.02 + wd_371" + }, + "wd_373": { + "name": "wd_373", + "object_class": "Equation", + "value": "0.02 + wd_372" + }, + "wd_374": { + "name": "wd_374", + "object_class": "Equation", + "value": "0.02 + wd_373" + }, + "wd_375": { + "name": "wd_375", + "object_class": "Equation", + "value": "0.02 + wd_374" + }, + "wd_376": { + "name": "wd_376", + "object_class": "Equation", + "value": "0.02 + wd_375" + }, + "wd_377": { + "name": "wd_377", + "object_class": "Equation", + "value": "0.02 + wd_376" + }, + "wd_378": { + "name": "wd_378", + "object_class": "Equation", + "value": "0.02 + wd_377" + }, + "wd_379": { + "name": "wd_379", + "object_class": "Equation", + "value": "0.02 + wd_378" + }, + "wd_380": { + "name": "wd_380", + "object_class": "Equation", + "value": "0.02 + wd_379" + }, + "wd_381": { + "name": "wd_381", + "object_class": "Equation", + "value": "0.02 + wd_380" + }, + "wd_382": { + "name": "wd_382", + "object_class": "Equation", + "value": "0.02 + wd_381" + }, + "wd_383": { + "name": "wd_383", + "object_class": "Equation", + "value": "0.02 + wd_382" + }, + "wd_384": { + "name": "wd_384", + "object_class": "Equation", + "value": "0.02 + wd_383" + }, + "wd_385": { + "name": "wd_385", + "object_class": "Equation", + "value": "0.02 + wd_384" + }, + "wd_386": { + "name": "wd_386", + "object_class": "Equation", + "value": "0.02 + wd_385" + }, + "wd_387": { + "name": "wd_387", + "object_class": "Equation", + "value": "0.02 + wd_386" + }, + "wd_388": { + "name": "wd_388", + "object_class": "Equation", + "value": "0.02 + wd_387" + }, + "wd_389": { + "name": "wd_389", + "object_class": "Equation", + "value": "0.02 + wd_388" + }, + "wd_390": { + "name": "wd_390", + "object_class": "Equation", + "value": "0.02 + wd_389" + }, + "wd_391": { + "name": "wd_391", + "object_class": "Equation", + "value": "0.02 + wd_390" + }, + "wd_392": { + "name": "wd_392", + "object_class": "Equation", + "value": "0.02 + wd_391" + }, + "wd_393": { + "name": "wd_393", + "object_class": "Equation", + "value": "0.02 + wd_392" + }, + "wd_394": { + "name": "wd_394", + "object_class": "Equation", + "value": "0.02 + wd_393" + }, + "wd_395": { + "name": "wd_395", + "object_class": "Equation", + "value": "0.02 + wd_394" + }, + "wd_396": { + "name": "wd_396", + "object_class": "Equation", + "value": "0.02 + wd_395" + }, + "wd_397": { + "name": "wd_397", + "object_class": "Equation", + "value": "0.02 + wd_396" + }, + "wd_398": { + "name": "wd_398", + "object_class": "Equation", + "value": "0.02 + wd_397" + }, + "wd_399": { + "name": "wd_399", + "object_class": "Equation", + "value": "0.02 + wd_398" + }, + "wd_400": { + "name": "wd_400", + "object_class": "Equation", + "value": "0.02 + wd_399" + }, + "wd_401": { + "name": "wd_401", + "object_class": "Equation", + "value": "0.02 + wd_400" + }, + "wd_402": { + "name": "wd_402", + "object_class": "Equation", + "value": "0.02 + wd_401" + }, + "wd_403": { + "name": "wd_403", + "object_class": "Equation", + "value": "0.02 + wd_402" + }, + "wd_404": { + "name": "wd_404", + "object_class": "Equation", + "value": "0.02 + wd_403" + }, + "wd_405": { + "name": "wd_405", + "object_class": "Equation", + "value": "0.02 + wd_404" + }, + "wd_406": { + "name": "wd_406", + "object_class": "Equation", + "value": "0.02 + wd_405" + }, + "wd_407": { + "name": "wd_407", + "object_class": "Equation", + "value": "0.02 + wd_406" + }, + "wd_408": { + "name": "wd_408", + "object_class": "Equation", + "value": "0.02 + wd_407" + }, + "wd_409": { + "name": "wd_409", + "object_class": "Equation", + "value": "0.02 + wd_408" + }, + "wd_410": { + "name": "wd_410", + "object_class": "Equation", + "value": "0.02 + wd_409" + }, + "wd_411": { + "name": "wd_411", + "object_class": "Equation", + "value": "0.02 + wd_410" + }, + "wd_412": { + "name": "wd_412", + "object_class": "Equation", + "value": "0.02 + wd_411" + }, + "wd_413": { + "name": "wd_413", + "object_class": "Equation", + "value": "0.02 + wd_412" + }, + "wd_414": { + "name": "wd_414", + "object_class": "Equation", + "value": "0.02 + wd_413" + }, + "wd_415": { + "name": "wd_415", + "object_class": "Equation", + "value": "0.02 + wd_414" + }, + "wd_416": { + "name": "wd_416", + "object_class": "Equation", + "value": "0.02 + wd_415" + }, + "wd_417": { + "name": "wd_417", + "object_class": "Equation", + "value": "0.02 + wd_416" + }, + "wd_418": { + "name": "wd_418", + "object_class": "Equation", + "value": "0.02 + wd_417" + }, + "wd_419": { + "name": "wd_419", + "object_class": "Equation", + "value": "0.02 + wd_418" + }, + "wd_420": { + "name": "wd_420", + "object_class": "Equation", + "value": "0.02 + wd_419" + }, + "wd_421": { + "name": "wd_421", + "object_class": "Equation", + "value": "0.02 + wd_420" + }, + "wd_422": { + "name": "wd_422", + "object_class": "Equation", + "value": "0.02 + wd_421" + }, + "wd_423": { + "name": "wd_423", + "object_class": "Equation", + "value": "0.02 + wd_422" + }, + "wd_424": { + "name": "wd_424", + "object_class": "Equation", + "value": "0.02 + wd_423" + }, + "wd_425": { + "name": "wd_425", + "object_class": "Equation", + "value": "0.02 + wd_424" + }, + "wd_426": { + "name": "wd_426", + "object_class": "Equation", + "value": "0.02 + wd_425" + }, + "wd_427": { + "name": "wd_427", + "object_class": "Equation", + "value": "0.02 + wd_426" + }, + "wd_428": { + "name": "wd_428", + "object_class": "Equation", + "value": "0.02 + wd_427" + }, + "wd_429": { + "name": "wd_429", + "object_class": "Equation", + "value": "0.02 + wd_428" + }, + "wd_430": { + "name": "wd_430", + "object_class": "Equation", + "value": "0.02 + wd_429" + }, + "wd_431": { + "name": "wd_431", + "object_class": "Equation", + "value": "0.02 + wd_430" + }, + "wd_432": { + "name": "wd_432", + "object_class": "Equation", + "value": "0.02 + wd_431" + }, + "wd_433": { + "name": "wd_433", + "object_class": "Equation", + "value": "0.02 + wd_432" + }, + "wd_434": { + "name": "wd_434", + "object_class": "Equation", + "value": "0.02 + wd_433" + }, + "wd_435": { + "name": "wd_435", + "object_class": "Equation", + "value": "0.02 + wd_434" + }, + "wd_436": { + "name": "wd_436", + "object_class": "Equation", + "value": "0.02 + wd_435" + }, + "wd_437": { + "name": "wd_437", + "object_class": "Equation", + "value": "0.02 + wd_436" + }, + "wd_438": { + "name": "wd_438", + "object_class": "Equation", + "value": "0.02 + wd_437" + }, + "wd_439": { + "name": "wd_439", + "object_class": "Equation", + "value": "0.02 + wd_438" + }, + "wd_440": { + "name": "wd_440", + "object_class": "Equation", + "value": "0.02 + wd_439" + }, + "wd_441": { + "name": "wd_441", + "object_class": "Equation", + "value": "0.02 + wd_440" + }, + "wd_442": { + "name": "wd_442", + "object_class": "Equation", + "value": "0.02 + wd_441" + }, + "wd_443": { + "name": "wd_443", + "object_class": "Equation", + "value": "0.02 + wd_442" + }, + "wd_444": { + "name": "wd_444", + "object_class": "Equation", + "value": "0.02 + wd_443" + }, + "wd_445": { + "name": "wd_445", + "object_class": "Equation", + "value": "0.02 + wd_444" + }, + "wd_446": { + "name": "wd_446", + "object_class": "Equation", + "value": "0.02 + wd_445" + }, + "wd_447": { + "name": "wd_447", + "object_class": "Equation", + "value": "0.02 + wd_446" + }, + "wd_448": { + "name": "wd_448", + "object_class": "Equation", + "value": "0.02 + wd_447" + }, + "wd_449": { + "name": "wd_449", + "object_class": "Equation", + "value": "0.02 + wd_448" + }, + "wd_450": { + "name": "wd_450", + "object_class": "Equation", + "value": "0.02 + wd_449" + }, + "wd_451": { + "name": "wd_451", + "object_class": "Equation", + "value": "0.02 + wd_450" + }, + "wd_452": { + "name": "wd_452", + "object_class": "Equation", + "value": "0.02 + wd_451" + }, + "wd_453": { + "name": "wd_453", + "object_class": "Equation", + "value": "0.02 + wd_452" + }, + "wd_454": { + "name": "wd_454", + "object_class": "Equation", + "value": "0.02 + wd_453" + }, + "wd_455": { + "name": "wd_455", + "object_class": "Equation", + "value": "0.02 + wd_454" + }, + "wd_456": { + "name": "wd_456", + "object_class": "Equation", + "value": "0.02 + wd_455" + }, + "wd_457": { + "name": "wd_457", + "object_class": "Equation", + "value": "0.02 + wd_456" + }, + "wd_458": { + "name": "wd_458", + "object_class": "Equation", + "value": "0.02 + wd_457" + }, + "wd_459": { + "name": "wd_459", + "object_class": "Equation", + "value": "0.02 + wd_458" + }, + "wd_460": { + "name": "wd_460", + "object_class": "Equation", + "value": "0.02 + wd_459" + }, + "wd_461": { + "name": "wd_461", + "object_class": "Equation", + "value": "0.02 + wd_460" + }, + "wd_462": { + "name": "wd_462", + "object_class": "Equation", + "value": "0.02 + wd_461" + }, + "wd_463": { + "name": "wd_463", + "object_class": "Equation", + "value": "0.02 + wd_462" + }, + "wd_464": { + "name": "wd_464", + "object_class": "Equation", + "value": "0.02 + wd_463" + }, + "wd_465": { + "name": "wd_465", + "object_class": "Equation", + "value": "0.02 + wd_464" + }, + "wd_466": { + "name": "wd_466", + "object_class": "Equation", + "value": "0.02 + wd_465" + }, + "wd_467": { + "name": "wd_467", + "object_class": "Equation", + "value": "0.02 + wd_466" + }, + "wd_468": { + "name": "wd_468", + "object_class": "Equation", + "value": "0.02 + wd_467" + }, + "wd_469": { + "name": "wd_469", + "object_class": "Equation", + "value": "0.02 + wd_468" + }, + "wd_470": { + "name": "wd_470", + "object_class": "Equation", + "value": "0.02 + wd_469" + }, + "wd_471": { + "name": "wd_471", + "object_class": "Equation", + "value": "0.02 + wd_470" + }, + "wd_472": { + "name": "wd_472", + "object_class": "Equation", + "value": "0.02 + wd_471" + }, + "wd_473": { + "name": "wd_473", + "object_class": "Equation", + "value": "0.02 + wd_472" + }, + "wd_474": { + "name": "wd_474", + "object_class": "Equation", + "value": "0.02 + wd_473" + }, + "wd_475": { + "name": "wd_475", + "object_class": "Equation", + "value": "0.02 + wd_474" + }, + "wd_476": { + "name": "wd_476", + "object_class": "Equation", + "value": "0.02 + wd_475" + }, + "wd_477": { + "name": "wd_477", + "object_class": "Equation", + "value": "0.02 + wd_476" + }, + "wd_478": { + "name": "wd_478", + "object_class": "Equation", + "value": "0.02 + wd_477" + }, + "wd_479": { + "name": "wd_479", + "object_class": "Equation", + "value": "0.02 + wd_478" + }, + "wd_480": { + "name": "wd_480", + "object_class": "Equation", + "value": "0.02 + wd_479" + }, + "wd_481": { + "name": "wd_481", + "object_class": "Equation", + "value": "0.02 + wd_480" + }, + "wd_482": { + "name": "wd_482", + "object_class": "Equation", + "value": "0.02 + wd_481" + }, + "wd_483": { + "name": "wd_483", + "object_class": "Equation", + "value": "0.02 + wd_482" + }, + "wd_484": { + "name": "wd_484", + "object_class": "Equation", + "value": "0.02 + wd_483" + }, + "wd_485": { + "name": "wd_485", + "object_class": "Equation", + "value": "0.02 + wd_484" + }, + "wd_486": { + "name": "wd_486", + "object_class": "Equation", + "value": "0.02 + wd_485" + }, + "wd_487": { + "name": "wd_487", + "object_class": "Equation", + "value": "0.02 + wd_486" + }, + "wd_488": { + "name": "wd_488", + "object_class": "Equation", + "value": "0.02 + wd_487" + }, + "wd_489": { + "name": "wd_489", + "object_class": "Equation", + "value": "0.02 + wd_488" + }, + "wd_490": { + "name": "wd_490", + "object_class": "Equation", + "value": "0.02 + wd_489" + }, + "wd_491": { + "name": "wd_491", + "object_class": "Equation", + "value": "0.02 + wd_490" + }, + "wd_492": { + "name": "wd_492", + "object_class": "Equation", + "value": "0.02 + wd_491" + }, + "wd_493": { + "name": "wd_493", + "object_class": "Equation", + "value": "0.02 + wd_492" + }, + "wd_494": { + "name": "wd_494", + "object_class": "Equation", + "value": "0.02 + wd_493" + }, + "wd_495": { + "name": "wd_495", + "object_class": "Equation", + "value": "0.02 + wd_494" + }, + "wd_496": { + "name": "wd_496", + "object_class": "Equation", + "value": "0.02 + wd_495" + }, + "wd_497": { + "name": "wd_497", + "object_class": "Equation", + "value": "0.02 + wd_496" + }, + "wd_498": { + "name": "wd_498", + "object_class": "Equation", + "value": "0.02 + wd_497" + }, + "wd_499": { + "name": "wd_499", + "object_class": "Equation", + "value": "0.02 + wd_498" + }, + "wd_500": { + "name": "wd_500", + "object_class": "Equation", + "value": "0.02 + wd_499" + }, + "O2write": { + "name": "O2write", + "object_class": "ModelLinkage", + "left_path": "/STATE/PL3_5250_0001/RCHRES_R001/O2", + "right_path": "/STATE/PL3_5250_0001/RCHRES_R001/wd_500", + "link_type": 5 + } + } +} + diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.uci b/tests/testcbp/HSP2results/PL3_5250_0001.uci index 0f9de5ad..25d7a004 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.uci +++ b/tests/testcbp/HSP2results/PL3_5250_0001.uci @@ -224,7 +224,4 @@ PLTGEN END CURV-DATA END PLTGEN -SPEC-ACTIONS -END SPEC-ACTIONS - END RUN diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eq.json b/tests/testcbp/HSP2results/PL3_5250_0001eq.json new file mode 100644 index 00000000..82aaec29 --- /dev/null +++ b/tests/testcbp/HSP2results/PL3_5250_0001eq.json @@ -0,0 +1,24 @@ +{ + "RCHRES_R001": { + "name": "RCHRES_R001", + "object_class": "ModelObject", + "value": "0", + "wd_cfs": { + "name": "wd_cfs", + "object_class": "Equation", + "value": "0.1 * IVOL" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "value": "OVOL3 * 12.1" + }, + "IVOLwrite": { + "name": "IVOLwrite", + "object_class": "ModelLinkage", + "left_path": "/STATE/PL3_5250_0001eq/RCHRES_R001/O2", + "right_path": "/STATE/PL3_5250_0001eq/RCHRES_R001/wd_cfs", + "link_type": 5 + } + } +} diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eq.uci b/tests/testcbp/HSP2results/PL3_5250_0001eq.uci new file mode 100644 index 00000000..2dd128e8 --- /dev/null +++ b/tests/testcbp/HSP2results/PL3_5250_0001eq.uci @@ -0,0 +1,228 @@ +RUN +*** This UCI will load a companion file with JSON in it + +GLOBAL + PL3_5250_0 riv | P5 | hsp2_2022 | Occoquan + START 2001/01/01 END 2001/12/31 + RUN INTERP OUTPUT LEVEL 1 1 + RESUME 0 RUN 1 UNIT SYSTEM 1 +END GLOBAL + +FILES + ***<----FILE NAME-------------------------------------------------> +WDM1 21 met_A51059.wdm +WDM2 22 prad_A51059.wdm +WDM3 23 ps_sep_div_ams_hsp2_2022_PL3_5250_0001.wdm +WDM4 24 PL3_5250_0001.wdm +MESSU 25 PL3_5250_0001.ech + 26 PL3_5250_0001.out + 31 PL3_5250_0001.tau +END FILES + +OPN SEQUENCE + INGRP INDELT 01:00 + RCHRES 1 + PLTGEN 1 + END INGRP +END OPN SEQUENCE + +RCHRES + ACTIVITY + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG *** + 1 1 1 0 0 0 0 0 0 0 0 + END ACTIVITY + + PRINT-INFO + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG PIVL***PY + 1 5 5 0 0 0 0 0 0 0 0 0 12 + END PRINT-INFO + + GEN-INFO + RCHRES<-------Name------->Nexit Unit Systems Printer *** + # - # User t-series Engl Metr LKFG *** + 1 PL3_5250_0001 3 1 1 1 26 0 1 + END GEN-INFO + + HYDR-PARM1 + RCHRES Flags for HYDR section *** + # - # VC A1 A2 A3 ODFVFG for each ODGTFG for each *** FUNCT for each + FG FG FG FG possible exit possible exit *** possible exit + 1 2 3 4 5 1 2 3 4 5 *** 1 2 3 4 5 + VC A1 A2 A3 V1 V2 V3 V4 V5 G1 G2 G3 G4 G5 *** F1 F2 F3 F4 F5 + 1 0 1 1 1 0 0 4 0 0 1 2 0 0 0 0 0 0 0 0 + END HYDR-PARM1 + + HYDR-PARM2 + RCHRES *** + # - # FTABNO LEN DELTH STCOR KS DB50 *** + 1 1. 10. 2. 0.5 + END HYDR-PARM2 + + HYDR-INIT + RCHRES Initial conditions for HYDR section *** + # - # VOL Initial value of COLIND *** Initial value of OUTDGT + (ac-ft) for each possible exit *** for each possible exit + VOL CEX1 CEX2 CEX3 CEX4 CEX5 *** DEX1 DEX2 DEX3 DEX4 DEX5 + 1 12175.000 + END HYDR-INIT + + ADCALC-DATA + RCHRES Data for section ADCALC *** + # - # CRRAT VOL *** + 1 1.5 12175. + END ADCALC-DATA + +END RCHRES + +FTABLES + FTABLE 1 + ROWS COLS *** + 20 4 + DEPTH AREA VOLUME DISCH *** + (FT) (ACRES) (AC-FT) (CFS) *** + 0 0 0 0 + 20 124 1007 0 + 30 240 2781 0 + 40 444 6106 0 + 50 804 12175 0 + 52 909 13886 39 + 54 1024 15819 78 + 56 1155 17999 117 + 57 1226 19227 136 + 58 1296 20456 137 + 60 1413 23180 138 + 62 1524 26140 140 + 63 1586 27745 1922 + 64 1647 29351 5179 + 65 1701 31247 9398 + 66 1755 33143 14393 + 67 1803 34984 20645 + 69 1879 38705 36532 + 70 1908 40585 44603 + 76 2100 54000 103071 + END FTABLE 1 +END FTABLES + +EXT SOURCES +<-Volume-> SsysSgap<--Mult-->Tran <-Target vols> <-Grp> <-Member->*** + # # tem strg<-factor->strg # # # #*** +*** METEOROLOGY +WDM1 1000 EVAP ENGLZERO 1.000 SAME RCHRES 1 EXTNL POTEV +WDM1 1001 DEWP ENGLZERO SAME RCHRES 1 EXTNL DEWTMP +WDM1 1002 WNDH ENGLZERO SAME RCHRES 1 EXTNL WIND +WDM1 1003 RADH ENGLZERO SAME RCHRES 1 EXTNL SOLRAD +WDM1 1004 ATMP ENGLZERO SAME RCHRES 1 EXTNL GATMP +WDM1 1005 CLDC ENGLZERO SAME RCHRES 1 EXTNL CLOUD + +*** PRECIPITATION AND ATMOSPHERIC DEPOSITION LOADS +WDM2 2000 HPRC ENGLZERO SAME RCHRES 1 EXTNL PREC +WDM2 2001 NO23 ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2002 NH4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2003 NO3D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2004 NH4D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2005 ORGN ENGLZERO DIV RCHRES 1 EXTNL PLADFX 1 1 +WDM2 2006 PO4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 3 1 +WDM2 2007 ORGP ENGLZERO DIV RCHRES 1 EXTNL PLADFX 2 1 + +*** POINT SOURCE +WDM3 3000 FLOW ENGLZERO DIV RCHRES 1 INFLOW IVOL +WDM3 3001 HEAT ENGLZERO DIV RCHRES 1 INFLOW IHEAT +WDM3 3002 NH3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 2 +WDM3 3003 NO3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 1 +WDM3 3004 ORNX ENGLZERO DIV RCHRES 1 INFLOW PKIF 3 +WDM3 3005 PO4X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 4 +WDM3 3006 ORPX ENGLZERO DIV RCHRES 1 INFLOW PKIF 4 +WDM3 3021 BODX ENGLZERO DIV RCHRES 1 INFLOW OXIF 2 +WDM3 3022 TSSX ENGLZERO 0.0005 DIV RCHRES 1 INFLOW ISED 3 +WDM3 3023 DOXX ENGLZERO DIV RCHRES 1 INFLOW OXIF 1 +WDM3 3024 TOCX ENGLZERO DIV RCHRES 1 INFLOW PKIF 5 + +*** DIVERSIONS +WDM3 3007 DIVR ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 1 +WDM3 3008 DIVA ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 2 + +*** SEPTIC +WDM3 3010 SNO3 ENGLZERO 1.0000 DIV RCHRES 1 INFLOW NUIF1 1 + +*** AEOLIAN SEDIMENT +WDM3 3061 SFAS ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 2 +WDM3 3062 SFAC ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 3 + +*** UPSTREAM and EOS INPUT *** +WDM4 11 WATR ENGLZERO SAME RCHRES 1 INFLOW IVOL +WDM4 12 HEAT ENGLZERO SAME RCHRES 1 INFLOW IHEAT +WDM4 13 DOXY ENGLZERO SAME RCHRES 1 INFLOW OXIF 1 +WDM4 21 SAND ENGLZERO SAME RCHRES 1 INFLOW ISED 1 +WDM4 22 SILT ENGLZERO SAME RCHRES 1 INFLOW ISED 2 +WDM4 23 CLAY ENGLZERO SAME RCHRES 1 INFLOW ISED 3 +WDM4 31 NO3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 1 +WDM4 32 NH3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 2 +WDM4 33 NH3A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 1 +WDM4 34 NH3I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 1 +WDM4 35 NH3C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 1 +WDM4 36 RORN ENGLZERO SAME RCHRES 1 INFLOW PKIF 3 +WDM4 41 PO4D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 4 +WDM4 42 PO4A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 2 +WDM4 43 PO4I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 2 +WDM4 44 PO4C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 2 +WDM4 45 RORP ENGLZERO SAME RCHRES 1 INFLOW PKIF 4 +WDM4 51 BODA ENGLZERO SAME RCHRES 1 INFLOW OXIF 2 +WDM4 52 TORC ENGLZERO SAME RCHRES 1 INFLOW PKIF 5 +WDM4 53 PHYT ENGLZERO SAME RCHRES 1 INFLOW PKIF 1 +END EXT SOURCES + +EXT TARGETS +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Volume-> Tsys Tgap Amd *** + # # #<-factor->strg # # tem strg strg*** +RCHRES 1 OFLOW OVOL 3 SAME WDM4 111 WATR ENGL REPL +RCHRES 1 OFLOW OHEAT 3 SAME WDM4 112 HEAT ENGL REPL +RCHRES 1 OFLOW OXCF2 3 1 SAME WDM4 113 DOXY ENGL REPL +RCHRES 1 OFLOW OSED 3 1 SAME WDM4 121 SAND ENGL REPL +RCHRES 1 OFLOW OSED 3 2 SAME WDM4 122 SILT ENGL REPL +RCHRES 1 OFLOW OSED 3 3 SAME WDM4 123 CLAY ENGL REPL +RCHRES 1 OFLOW NUCF9 3 1 SAME WDM4 131 NO3D ENGL REPL +RCHRES 1 OFLOW NUCF9 3 2 SAME WDM4 132 NH3D ENGL REPL +RCHRES 1 OFLOW OSNH4 3 1 SAME WDM4 133 NH3A ENGL REPL +RCHRES 1 OFLOW OSNH4 3 2 SAME WDM4 134 NH3I ENGL REPL +RCHRES 1 OFLOW OSNH4 3 3 SAME WDM4 135 NH3C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 3 SAME WDM4 136 RORN ENGL REPL +RCHRES 1 OFLOW NUCF9 3 4 SAME WDM4 141 PO4D ENGL REPL +RCHRES 1 OFLOW OSPO4 3 1 SAME WDM4 142 PO4A ENGL REPL +RCHRES 1 OFLOW OSPO4 3 2 SAME WDM4 143 PO4I ENGL REPL +RCHRES 1 OFLOW OSPO4 3 3 SAME WDM4 144 PO4C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 4 SAME WDM4 145 RORP ENGL REPL +RCHRES 1 OFLOW OXCF2 3 2 SAME WDM4 151 BODA ENGL REPL +RCHRES 1 OFLOW PKCF2 3 5 SAME WDM4 152 TORC ENGL REPL +RCHRES 1 OFLOW PKCF2 3 1 SAME WDM4 153 PHYT ENGL REPL +END EXT TARGETS + +NETWORK +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Target vols> <-Grp> <-Member-> *** + # # #<-factor->strg # # # # *** +RCHRES 1 HYDR TAU AVER PLTGEN 1 INPUT MEAN 1 +END NETWORK + +PLTGEN + PLOTINFO + # - # FILE NPT NMN LABL PYR PIVL *** + 1 31 1 12 24 + END PLOTINFO + + GEN-LABELS + # - #<----------------Title-----------------> *** + 1 PL3_5250_0001 daily_shear_stress_lbsft2 + END GEN-LABELS + + SCALING + #thru# YMIN YMAX IVLIN THRESH *** + 1 99 0. 100000. 20. + END SCALING + + CURV-DATA + <-Curve label--> Line Intg Col Tran *** + # - # type eqv code code *** + 1 daily_shear_stre 1 1 AVER + END CURV-DATA +END PLTGEN + +END RUN diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci b/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci new file mode 100644 index 00000000..5cc08fab --- /dev/null +++ b/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci @@ -0,0 +1,228 @@ +RUN +*** This UCI will load a companion file with JSON in it + +GLOBAL + PL3_5250_0 riv | P5 | hsp2_2022 | Occoquan + START 1984/01/01 END 2019/12/31 + RUN INTERP OUTPUT LEVEL 1 1 + RESUME 0 RUN 1 UNIT SYSTEM 1 +END GLOBAL + +FILES + ***<----FILE NAME-------------------------------------------------> +WDM1 21 met_A51059.wdm +WDM2 22 prad_A51059.wdm +WDM3 23 ps_sep_div_ams_hsp2_2022_PL3_5250_0001.wdm +WDM4 24 PL3_5250_0001.wdm +MESSU 25 PL3_5250_0001.ech + 26 PL3_5250_0001.out + 31 PL3_5250_0001.tau +END FILES + +OPN SEQUENCE + INGRP INDELT 01:00 + RCHRES 1 + PLTGEN 1 + END INGRP +END OPN SEQUENCE + +RCHRES + ACTIVITY + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG *** + 1 1 1 0 0 0 0 0 0 0 0 + END ACTIVITY + + PRINT-INFO + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG PIVL***PY + 1 5 5 0 0 0 0 0 0 0 0 0 12 + END PRINT-INFO + + GEN-INFO + RCHRES<-------Name------->Nexit Unit Systems Printer *** + # - # User t-series Engl Metr LKFG *** + 1 PL3_5250_0001 3 1 1 1 26 0 1 + END GEN-INFO + + HYDR-PARM1 + RCHRES Flags for HYDR section *** + # - # VC A1 A2 A3 ODFVFG for each ODGTFG for each *** FUNCT for each + FG FG FG FG possible exit possible exit *** possible exit + 1 2 3 4 5 1 2 3 4 5 *** 1 2 3 4 5 + VC A1 A2 A3 V1 V2 V3 V4 V5 G1 G2 G3 G4 G5 *** F1 F2 F3 F4 F5 + 1 0 1 1 1 0 0 4 0 0 1 2 0 0 0 0 0 0 0 0 + END HYDR-PARM1 + + HYDR-PARM2 + RCHRES *** + # - # FTABNO LEN DELTH STCOR KS DB50 *** + 1 1. 10. 2. 0.5 + END HYDR-PARM2 + + HYDR-INIT + RCHRES Initial conditions for HYDR section *** + # - # VOL Initial value of COLIND *** Initial value of OUTDGT + (ac-ft) for each possible exit *** for each possible exit + VOL CEX1 CEX2 CEX3 CEX4 CEX5 *** DEX1 DEX2 DEX3 DEX4 DEX5 + 1 12175.000 + END HYDR-INIT + + ADCALC-DATA + RCHRES Data for section ADCALC *** + # - # CRRAT VOL *** + 1 1.5 12175. + END ADCALC-DATA + +END RCHRES + +FTABLES + FTABLE 1 + ROWS COLS *** + 20 4 + DEPTH AREA VOLUME DISCH *** + (FT) (ACRES) (AC-FT) (CFS) *** + 0 0 0 0 + 20 124 1007 0 + 30 240 2781 0 + 40 444 6106 0 + 50 804 12175 0 + 52 909 13886 39 + 54 1024 15819 78 + 56 1155 17999 117 + 57 1226 19227 136 + 58 1296 20456 137 + 60 1413 23180 138 + 62 1524 26140 140 + 63 1586 27745 1922 + 64 1647 29351 5179 + 65 1701 31247 9398 + 66 1755 33143 14393 + 67 1803 34984 20645 + 69 1879 38705 36532 + 70 1908 40585 44603 + 76 2100 54000 103071 + END FTABLE 1 +END FTABLES + +EXT SOURCES +<-Volume-> SsysSgap<--Mult-->Tran <-Target vols> <-Grp> <-Member->*** + # # tem strg<-factor->strg # # # #*** +*** METEOROLOGY +WDM1 1000 EVAP ENGLZERO 1.000 SAME RCHRES 1 EXTNL POTEV +WDM1 1001 DEWP ENGLZERO SAME RCHRES 1 EXTNL DEWTMP +WDM1 1002 WNDH ENGLZERO SAME RCHRES 1 EXTNL WIND +WDM1 1003 RADH ENGLZERO SAME RCHRES 1 EXTNL SOLRAD +WDM1 1004 ATMP ENGLZERO SAME RCHRES 1 EXTNL GATMP +WDM1 1005 CLDC ENGLZERO SAME RCHRES 1 EXTNL CLOUD + +*** PRECIPITATION AND ATMOSPHERIC DEPOSITION LOADS +WDM2 2000 HPRC ENGLZERO SAME RCHRES 1 EXTNL PREC +WDM2 2001 NO23 ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2002 NH4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2003 NO3D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2004 NH4D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2005 ORGN ENGLZERO DIV RCHRES 1 EXTNL PLADFX 1 1 +WDM2 2006 PO4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 3 1 +WDM2 2007 ORGP ENGLZERO DIV RCHRES 1 EXTNL PLADFX 2 1 + +*** POINT SOURCE +WDM3 3000 FLOW ENGLZERO DIV RCHRES 1 INFLOW IVOL +WDM3 3001 HEAT ENGLZERO DIV RCHRES 1 INFLOW IHEAT +WDM3 3002 NH3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 2 +WDM3 3003 NO3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 1 +WDM3 3004 ORNX ENGLZERO DIV RCHRES 1 INFLOW PKIF 3 +WDM3 3005 PO4X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 4 +WDM3 3006 ORPX ENGLZERO DIV RCHRES 1 INFLOW PKIF 4 +WDM3 3021 BODX ENGLZERO DIV RCHRES 1 INFLOW OXIF 2 +WDM3 3022 TSSX ENGLZERO 0.0005 DIV RCHRES 1 INFLOW ISED 3 +WDM3 3023 DOXX ENGLZERO DIV RCHRES 1 INFLOW OXIF 1 +WDM3 3024 TOCX ENGLZERO DIV RCHRES 1 INFLOW PKIF 5 + +*** DIVERSIONS +WDM3 3007 DIVR ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 1 +WDM3 3008 DIVA ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 2 + +*** SEPTIC +WDM3 3010 SNO3 ENGLZERO 1.0000 DIV RCHRES 1 INFLOW NUIF1 1 + +*** AEOLIAN SEDIMENT +WDM3 3061 SFAS ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 2 +WDM3 3062 SFAC ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 3 + +*** UPSTREAM and EOS INPUT *** +WDM4 11 WATR ENGLZERO SAME RCHRES 1 INFLOW IVOL +WDM4 12 HEAT ENGLZERO SAME RCHRES 1 INFLOW IHEAT +WDM4 13 DOXY ENGLZERO SAME RCHRES 1 INFLOW OXIF 1 +WDM4 21 SAND ENGLZERO SAME RCHRES 1 INFLOW ISED 1 +WDM4 22 SILT ENGLZERO SAME RCHRES 1 INFLOW ISED 2 +WDM4 23 CLAY ENGLZERO SAME RCHRES 1 INFLOW ISED 3 +WDM4 31 NO3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 1 +WDM4 32 NH3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 2 +WDM4 33 NH3A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 1 +WDM4 34 NH3I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 1 +WDM4 35 NH3C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 1 +WDM4 36 RORN ENGLZERO SAME RCHRES 1 INFLOW PKIF 3 +WDM4 41 PO4D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 4 +WDM4 42 PO4A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 2 +WDM4 43 PO4I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 2 +WDM4 44 PO4C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 2 +WDM4 45 RORP ENGLZERO SAME RCHRES 1 INFLOW PKIF 4 +WDM4 51 BODA ENGLZERO SAME RCHRES 1 INFLOW OXIF 2 +WDM4 52 TORC ENGLZERO SAME RCHRES 1 INFLOW PKIF 5 +WDM4 53 PHYT ENGLZERO SAME RCHRES 1 INFLOW PKIF 1 +END EXT SOURCES + +EXT TARGETS +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Volume-> Tsys Tgap Amd *** + # # #<-factor->strg # # tem strg strg*** +RCHRES 1 OFLOW OVOL 3 SAME WDM4 111 WATR ENGL REPL +RCHRES 1 OFLOW OHEAT 3 SAME WDM4 112 HEAT ENGL REPL +RCHRES 1 OFLOW OXCF2 3 1 SAME WDM4 113 DOXY ENGL REPL +RCHRES 1 OFLOW OSED 3 1 SAME WDM4 121 SAND ENGL REPL +RCHRES 1 OFLOW OSED 3 2 SAME WDM4 122 SILT ENGL REPL +RCHRES 1 OFLOW OSED 3 3 SAME WDM4 123 CLAY ENGL REPL +RCHRES 1 OFLOW NUCF9 3 1 SAME WDM4 131 NO3D ENGL REPL +RCHRES 1 OFLOW NUCF9 3 2 SAME WDM4 132 NH3D ENGL REPL +RCHRES 1 OFLOW OSNH4 3 1 SAME WDM4 133 NH3A ENGL REPL +RCHRES 1 OFLOW OSNH4 3 2 SAME WDM4 134 NH3I ENGL REPL +RCHRES 1 OFLOW OSNH4 3 3 SAME WDM4 135 NH3C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 3 SAME WDM4 136 RORN ENGL REPL +RCHRES 1 OFLOW NUCF9 3 4 SAME WDM4 141 PO4D ENGL REPL +RCHRES 1 OFLOW OSPO4 3 1 SAME WDM4 142 PO4A ENGL REPL +RCHRES 1 OFLOW OSPO4 3 2 SAME WDM4 143 PO4I ENGL REPL +RCHRES 1 OFLOW OSPO4 3 3 SAME WDM4 144 PO4C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 4 SAME WDM4 145 RORP ENGL REPL +RCHRES 1 OFLOW OXCF2 3 2 SAME WDM4 151 BODA ENGL REPL +RCHRES 1 OFLOW PKCF2 3 5 SAME WDM4 152 TORC ENGL REPL +RCHRES 1 OFLOW PKCF2 3 1 SAME WDM4 153 PHYT ENGL REPL +END EXT TARGETS + +NETWORK +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Target vols> <-Grp> <-Member-> *** + # # #<-factor->strg # # # # *** +RCHRES 1 HYDR TAU AVER PLTGEN 1 INPUT MEAN 1 +END NETWORK + +PLTGEN + PLOTINFO + # - # FILE NPT NMN LABL PYR PIVL *** + 1 31 1 12 24 + END PLOTINFO + + GEN-LABELS + # - #<----------------Title-----------------> *** + 1 PL3_5250_0001 daily_shear_stress_lbsft2 + END GEN-LABELS + + SCALING + #thru# YMIN YMAX IVLIN THRESH *** + 1 99 0. 100000. 20. + END SCALING + + CURV-DATA + <-Curve label--> Line Intg Col Tran *** + # - # type eqv code code *** + 1 daily_shear_stre 1 1 AVER + END CURV-DATA +END PLTGEN + +END RUN diff --git a/tests/testcbp/HSP2results/PL3_5250_0001spec.uci b/tests/testcbp/HSP2results/PL3_5250_0001spec.uci new file mode 100644 index 00000000..1a4df762 --- /dev/null +++ b/tests/testcbp/HSP2results/PL3_5250_0001spec.uci @@ -0,0 +1,236 @@ +RUN + +GLOBAL + PL3_5250_0 riv | P5 | hsp2_2022 | Occoquan + START 2001/01/01 END 2001/12/31 + RUN INTERP OUTPUT LEVEL 1 1 + RESUME 0 RUN 1 UNIT SYSTEM 1 +END GLOBAL + +FILES + ***<----FILE NAME-------------------------------------------------> +WDM1 21 met_A51059.wdm +WDM2 22 prad_A51059.wdm +WDM3 23 ps_sep_div_ams_hsp2_2022_PL3_5250_0001.wdm +WDM4 24 PL3_5250_0001.wdm +MESSU 25 PL3_5250_0001.ech + 26 PL3_5250_0001.out + 31 PL3_5250_0001.tau +END FILES + +OPN SEQUENCE + INGRP INDELT 01:00 + RCHRES 1 + PLTGEN 1 + END INGRP +END OPN SEQUENCE + +RCHRES + ACTIVITY + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG *** + 1 1 1 0 0 0 0 0 0 0 0 + END ACTIVITY + + PRINT-INFO + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG PIVL***PY + 1 5 5 0 0 0 0 0 0 0 0 0 12 + END PRINT-INFO + + GEN-INFO + RCHRES<-------Name------->Nexit Unit Systems Printer *** + # - # User t-series Engl Metr LKFG *** + 1 PL3_5250_0001 3 1 1 1 26 0 1 + END GEN-INFO + + HYDR-PARM1 + RCHRES Flags for HYDR section *** + # - # VC A1 A2 A3 ODFVFG for each ODGTFG for each *** FUNCT for each + FG FG FG FG possible exit possible exit *** possible exit + 1 2 3 4 5 1 2 3 4 5 *** 1 2 3 4 5 + VC A1 A2 A3 V1 V2 V3 V4 V5 G1 G2 G3 G4 G5 *** F1 F2 F3 F4 F5 + 1 0 1 1 1 0 0 4 0 0 1 2 0 0 0 0 0 0 0 0 + END HYDR-PARM1 + + HYDR-PARM2 + RCHRES *** + # - # FTABNO LEN DELTH STCOR KS DB50 *** + 1 1. 10. 2. 0.5 + END HYDR-PARM2 + + HYDR-INIT + RCHRES Initial conditions for HYDR section *** + # - # VOL Initial value of COLIND *** Initial value of OUTDGT + (ac-ft) for each possible exit *** for each possible exit + VOL CEX1 CEX2 CEX3 CEX4 CEX5 *** DEX1 DEX2 DEX3 DEX4 DEX5 + 1 12175.000 + END HYDR-INIT + + ADCALC-DATA + RCHRES Data for section ADCALC *** + # - # CRRAT VOL *** + 1 1.5 12175. + END ADCALC-DATA + +END RCHRES + +FTABLES + FTABLE 1 + ROWS COLS *** + 20 4 + DEPTH AREA VOLUME DISCH *** + (FT) (ACRES) (AC-FT) (CFS) *** + 0 0 0 0 + 20 124 1007 0 + 30 240 2781 0 + 40 444 6106 0 + 50 804 12175 0 + 52 909 13886 39 + 54 1024 15819 78 + 56 1155 17999 117 + 57 1226 19227 136 + 58 1296 20456 137 + 60 1413 23180 138 + 62 1524 26140 140 + 63 1586 27745 1922 + 64 1647 29351 5179 + 65 1701 31247 9398 + 66 1755 33143 14393 + 67 1803 34984 20645 + 69 1879 38705 36532 + 70 1908 40585 44603 + 76 2100 54000 103071 + END FTABLE 1 +END FTABLES + +EXT SOURCES +<-Volume-> SsysSgap<--Mult-->Tran <-Target vols> <-Grp> <-Member->*** + # # tem strg<-factor->strg # # # #*** +*** METEOROLOGY +WDM1 1000 EVAP ENGLZERO 1.000 SAME RCHRES 1 EXTNL POTEV +WDM1 1001 DEWP ENGLZERO SAME RCHRES 1 EXTNL DEWTMP +WDM1 1002 WNDH ENGLZERO SAME RCHRES 1 EXTNL WIND +WDM1 1003 RADH ENGLZERO SAME RCHRES 1 EXTNL SOLRAD +WDM1 1004 ATMP ENGLZERO SAME RCHRES 1 EXTNL GATMP +WDM1 1005 CLDC ENGLZERO SAME RCHRES 1 EXTNL CLOUD + +*** PRECIPITATION AND ATMOSPHERIC DEPOSITION LOADS +WDM2 2000 HPRC ENGLZERO SAME RCHRES 1 EXTNL PREC +WDM2 2001 NO23 ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2002 NH4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2003 NO3D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2004 NH4D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2005 ORGN ENGLZERO DIV RCHRES 1 EXTNL PLADFX 1 1 +WDM2 2006 PO4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 3 1 +WDM2 2007 ORGP ENGLZERO DIV RCHRES 1 EXTNL PLADFX 2 1 + +*** POINT SOURCE +WDM3 3000 FLOW ENGLZERO DIV RCHRES 1 INFLOW IVOL +WDM3 3001 HEAT ENGLZERO DIV RCHRES 1 INFLOW IHEAT +WDM3 3002 NH3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 2 +WDM3 3003 NO3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 1 +WDM3 3004 ORNX ENGLZERO DIV RCHRES 1 INFLOW PKIF 3 +WDM3 3005 PO4X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 4 +WDM3 3006 ORPX ENGLZERO DIV RCHRES 1 INFLOW PKIF 4 +WDM3 3021 BODX ENGLZERO DIV RCHRES 1 INFLOW OXIF 2 +WDM3 3022 TSSX ENGLZERO 0.0005 DIV RCHRES 1 INFLOW ISED 3 +WDM3 3023 DOXX ENGLZERO DIV RCHRES 1 INFLOW OXIF 1 +WDM3 3024 TOCX ENGLZERO DIV RCHRES 1 INFLOW PKIF 5 + +*** DIVERSIONS +WDM3 3007 DIVR ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 1 +WDM3 3008 DIVA ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 2 + +*** SEPTIC +WDM3 3010 SNO3 ENGLZERO 1.0000 DIV RCHRES 1 INFLOW NUIF1 1 + +*** AEOLIAN SEDIMENT +WDM3 3061 SFAS ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 2 +WDM3 3062 SFAC ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 3 + +*** UPSTREAM and EOS INPUT *** +WDM4 11 WATR ENGLZERO SAME RCHRES 1 INFLOW IVOL +WDM4 12 HEAT ENGLZERO SAME RCHRES 1 INFLOW IHEAT +WDM4 13 DOXY ENGLZERO SAME RCHRES 1 INFLOW OXIF 1 +WDM4 21 SAND ENGLZERO SAME RCHRES 1 INFLOW ISED 1 +WDM4 22 SILT ENGLZERO SAME RCHRES 1 INFLOW ISED 2 +WDM4 23 CLAY ENGLZERO SAME RCHRES 1 INFLOW ISED 3 +WDM4 31 NO3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 1 +WDM4 32 NH3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 2 +WDM4 33 NH3A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 1 +WDM4 34 NH3I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 1 +WDM4 35 NH3C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 1 +WDM4 36 RORN ENGLZERO SAME RCHRES 1 INFLOW PKIF 3 +WDM4 41 PO4D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 4 +WDM4 42 PO4A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 2 +WDM4 43 PO4I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 2 +WDM4 44 PO4C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 2 +WDM4 45 RORP ENGLZERO SAME RCHRES 1 INFLOW PKIF 4 +WDM4 51 BODA ENGLZERO SAME RCHRES 1 INFLOW OXIF 2 +WDM4 52 TORC ENGLZERO SAME RCHRES 1 INFLOW PKIF 5 +WDM4 53 PHYT ENGLZERO SAME RCHRES 1 INFLOW PKIF 1 +END EXT SOURCES + +EXT TARGETS +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Volume-> Tsys Tgap Amd *** + # # #<-factor->strg # # tem strg strg*** +RCHRES 1 OFLOW OVOL 3 SAME WDM4 111 WATR ENGL REPL +RCHRES 1 OFLOW OHEAT 3 SAME WDM4 112 HEAT ENGL REPL +RCHRES 1 OFLOW OXCF2 3 1 SAME WDM4 113 DOXY ENGL REPL +RCHRES 1 OFLOW OSED 3 1 SAME WDM4 121 SAND ENGL REPL +RCHRES 1 OFLOW OSED 3 2 SAME WDM4 122 SILT ENGL REPL +RCHRES 1 OFLOW OSED 3 3 SAME WDM4 123 CLAY ENGL REPL +RCHRES 1 OFLOW NUCF9 3 1 SAME WDM4 131 NO3D ENGL REPL +RCHRES 1 OFLOW NUCF9 3 2 SAME WDM4 132 NH3D ENGL REPL +RCHRES 1 OFLOW OSNH4 3 1 SAME WDM4 133 NH3A ENGL REPL +RCHRES 1 OFLOW OSNH4 3 2 SAME WDM4 134 NH3I ENGL REPL +RCHRES 1 OFLOW OSNH4 3 3 SAME WDM4 135 NH3C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 3 SAME WDM4 136 RORN ENGL REPL +RCHRES 1 OFLOW NUCF9 3 4 SAME WDM4 141 PO4D ENGL REPL +RCHRES 1 OFLOW OSPO4 3 1 SAME WDM4 142 PO4A ENGL REPL +RCHRES 1 OFLOW OSPO4 3 2 SAME WDM4 143 PO4I ENGL REPL +RCHRES 1 OFLOW OSPO4 3 3 SAME WDM4 144 PO4C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 4 SAME WDM4 145 RORP ENGL REPL +RCHRES 1 OFLOW OXCF2 3 2 SAME WDM4 151 BODA ENGL REPL +RCHRES 1 OFLOW PKCF2 3 5 SAME WDM4 152 TORC ENGL REPL +RCHRES 1 OFLOW PKCF2 3 1 SAME WDM4 153 PHYT ENGL REPL +END EXT TARGETS + +NETWORK +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Target vols> <-Grp> <-Member-> *** + # # #<-factor->strg # # # # *** +RCHRES 1 HYDR TAU AVER PLTGEN 1 INPUT MEAN 1 +END NETWORK + +PLTGEN + PLOTINFO + # - # FILE NPT NMN LABL PYR PIVL *** + 1 31 1 12 24 + END PLOTINFO + + GEN-LABELS + # - #<----------------Title-----------------> *** + 1 PL3_5250_0001 daily_shear_stress_lbsft2 + END GEN-LABELS + + SCALING + #thru# YMIN YMAX IVLIN THRESH *** + 1 99 0. 100000. 20. + END SCALING + + CURV-DATA + <-Curve label--> Line Intg Col Tran *** + # - # type eqv code code *** + 1 daily_shear_stre 1 1 AVER + END CURV-DATA +END PLTGEN + +SPEC-ACTIONS +*** test special actions +*** I don't think this does anything because CBP is hydro only? +*** They should LOAD into the STATE context but not be executed + RCHRES 1 RSED 4 += 2.50E+05 + RCHRES 1 RSED 5 += 6.89E+05 + RCHRES 1 RSED 6 += 4.01E+05 +END SPEC-ACTIONS + +END RUN diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd b/tests/testcbp/HSP2results/PL3_5250_0001wd.json similarity index 73% rename from tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd rename to tests/testcbp/HSP2results/PL3_5250_0001wd.json index 3a4a0439..5c50a667 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd +++ b/tests/testcbp/HSP2results/PL3_5250_0001wd.json @@ -11,8 +11,8 @@ "IVOLwrite": { "name": "IVOLwrite", "object_class": "ModelLinkage", - "left_path": "/STATE/RCHRES_R001/O2", - "right_path": "/STATE/RCHRES_R001/wd_cfs", + "left_path": "/STATE/PL3_5250_0001wd/RCHRES_R001/O2", + "right_path": "/STATE/PL3_5250_0001wd/RCHRES_R001/wd_cfs", "link_type": 5 } } diff --git a/tests/testcbp/HSP2results/PL3_5250_0001wd.uci b/tests/testcbp/HSP2results/PL3_5250_0001wd.uci new file mode 100644 index 00000000..25d7a004 --- /dev/null +++ b/tests/testcbp/HSP2results/PL3_5250_0001wd.uci @@ -0,0 +1,227 @@ +RUN + +GLOBAL + PL3_5250_0 riv | P5 | hsp2_2022 | Occoquan + START 2001/01/01 END 2001/12/31 + RUN INTERP OUTPUT LEVEL 1 1 + RESUME 0 RUN 1 UNIT SYSTEM 1 +END GLOBAL + +FILES + ***<----FILE NAME-------------------------------------------------> +WDM1 21 met_A51059.wdm +WDM2 22 prad_A51059.wdm +WDM3 23 ps_sep_div_ams_hsp2_2022_PL3_5250_0001.wdm +WDM4 24 PL3_5250_0001.wdm +MESSU 25 PL3_5250_0001.ech + 26 PL3_5250_0001.out + 31 PL3_5250_0001.tau +END FILES + +OPN SEQUENCE + INGRP INDELT 01:00 + RCHRES 1 + PLTGEN 1 + END INGRP +END OPN SEQUENCE + +RCHRES + ACTIVITY + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG *** + 1 1 1 0 0 0 0 0 0 0 0 + END ACTIVITY + + PRINT-INFO + # - # HYFG ADFG CNFG HTFG SDFG GQFG OXFG NUFG PKFG PHFG PIVL***PY + 1 5 5 0 0 0 0 0 0 0 0 0 12 + END PRINT-INFO + + GEN-INFO + RCHRES<-------Name------->Nexit Unit Systems Printer *** + # - # User t-series Engl Metr LKFG *** + 1 PL3_5250_0001 3 1 1 1 26 0 1 + END GEN-INFO + + HYDR-PARM1 + RCHRES Flags for HYDR section *** + # - # VC A1 A2 A3 ODFVFG for each ODGTFG for each *** FUNCT for each + FG FG FG FG possible exit possible exit *** possible exit + 1 2 3 4 5 1 2 3 4 5 *** 1 2 3 4 5 + VC A1 A2 A3 V1 V2 V3 V4 V5 G1 G2 G3 G4 G5 *** F1 F2 F3 F4 F5 + 1 0 1 1 1 0 0 4 0 0 1 2 0 0 0 0 0 0 0 0 + END HYDR-PARM1 + + HYDR-PARM2 + RCHRES *** + # - # FTABNO LEN DELTH STCOR KS DB50 *** + 1 1. 10. 2. 0.5 + END HYDR-PARM2 + + HYDR-INIT + RCHRES Initial conditions for HYDR section *** + # - # VOL Initial value of COLIND *** Initial value of OUTDGT + (ac-ft) for each possible exit *** for each possible exit + VOL CEX1 CEX2 CEX3 CEX4 CEX5 *** DEX1 DEX2 DEX3 DEX4 DEX5 + 1 12175.000 + END HYDR-INIT + + ADCALC-DATA + RCHRES Data for section ADCALC *** + # - # CRRAT VOL *** + 1 1.5 12175. + END ADCALC-DATA + +END RCHRES + +FTABLES + FTABLE 1 + ROWS COLS *** + 20 4 + DEPTH AREA VOLUME DISCH *** + (FT) (ACRES) (AC-FT) (CFS) *** + 0 0 0 0 + 20 124 1007 0 + 30 240 2781 0 + 40 444 6106 0 + 50 804 12175 0 + 52 909 13886 39 + 54 1024 15819 78 + 56 1155 17999 117 + 57 1226 19227 136 + 58 1296 20456 137 + 60 1413 23180 138 + 62 1524 26140 140 + 63 1586 27745 1922 + 64 1647 29351 5179 + 65 1701 31247 9398 + 66 1755 33143 14393 + 67 1803 34984 20645 + 69 1879 38705 36532 + 70 1908 40585 44603 + 76 2100 54000 103071 + END FTABLE 1 +END FTABLES + +EXT SOURCES +<-Volume-> SsysSgap<--Mult-->Tran <-Target vols> <-Grp> <-Member->*** + # # tem strg<-factor->strg # # # #*** +*** METEOROLOGY +WDM1 1000 EVAP ENGLZERO 1.000 SAME RCHRES 1 EXTNL POTEV +WDM1 1001 DEWP ENGLZERO SAME RCHRES 1 EXTNL DEWTMP +WDM1 1002 WNDH ENGLZERO SAME RCHRES 1 EXTNL WIND +WDM1 1003 RADH ENGLZERO SAME RCHRES 1 EXTNL SOLRAD +WDM1 1004 ATMP ENGLZERO SAME RCHRES 1 EXTNL GATMP +WDM1 1005 CLDC ENGLZERO SAME RCHRES 1 EXTNL CLOUD + +*** PRECIPITATION AND ATMOSPHERIC DEPOSITION LOADS +WDM2 2000 HPRC ENGLZERO SAME RCHRES 1 EXTNL PREC +WDM2 2001 NO23 ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2002 NH4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2003 NO3D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 1 1 +WDM2 2004 NH4D ENGLZERO DIV RCHRES 1 EXTNL NUADFX 2 1 +WDM2 2005 ORGN ENGLZERO DIV RCHRES 1 EXTNL PLADFX 1 1 +WDM2 2006 PO4A ENGLZERO DIV RCHRES 1 EXTNL NUADFX 3 1 +WDM2 2007 ORGP ENGLZERO DIV RCHRES 1 EXTNL PLADFX 2 1 + +*** POINT SOURCE +WDM3 3000 FLOW ENGLZERO DIV RCHRES 1 INFLOW IVOL +WDM3 3001 HEAT ENGLZERO DIV RCHRES 1 INFLOW IHEAT +WDM3 3002 NH3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 2 +WDM3 3003 NO3X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 1 +WDM3 3004 ORNX ENGLZERO DIV RCHRES 1 INFLOW PKIF 3 +WDM3 3005 PO4X ENGLZERO DIV RCHRES 1 INFLOW NUIF1 4 +WDM3 3006 ORPX ENGLZERO DIV RCHRES 1 INFLOW PKIF 4 +WDM3 3021 BODX ENGLZERO DIV RCHRES 1 INFLOW OXIF 2 +WDM3 3022 TSSX ENGLZERO 0.0005 DIV RCHRES 1 INFLOW ISED 3 +WDM3 3023 DOXX ENGLZERO DIV RCHRES 1 INFLOW OXIF 1 +WDM3 3024 TOCX ENGLZERO DIV RCHRES 1 INFLOW PKIF 5 + +*** DIVERSIONS +WDM3 3007 DIVR ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 1 +WDM3 3008 DIVA ENGLZERO SAME RCHRES 1 EXTNL OUTDGT 2 + +*** SEPTIC +WDM3 3010 SNO3 ENGLZERO 1.0000 DIV RCHRES 1 INFLOW NUIF1 1 + +*** AEOLIAN SEDIMENT +WDM3 3061 SFAS ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 2 +WDM3 3062 SFAC ENGLZERO 7.027e-06DIV RCHRES 1 INFLOW ISED 3 + +*** UPSTREAM and EOS INPUT *** +WDM4 11 WATR ENGLZERO SAME RCHRES 1 INFLOW IVOL +WDM4 12 HEAT ENGLZERO SAME RCHRES 1 INFLOW IHEAT +WDM4 13 DOXY ENGLZERO SAME RCHRES 1 INFLOW OXIF 1 +WDM4 21 SAND ENGLZERO SAME RCHRES 1 INFLOW ISED 1 +WDM4 22 SILT ENGLZERO SAME RCHRES 1 INFLOW ISED 2 +WDM4 23 CLAY ENGLZERO SAME RCHRES 1 INFLOW ISED 3 +WDM4 31 NO3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 1 +WDM4 32 NH3D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 2 +WDM4 33 NH3A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 1 +WDM4 34 NH3I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 1 +WDM4 35 NH3C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 1 +WDM4 36 RORN ENGLZERO SAME RCHRES 1 INFLOW PKIF 3 +WDM4 41 PO4D ENGLZERO SAME RCHRES 1 INFLOW NUIF1 4 +WDM4 42 PO4A ENGLZERO SAME RCHRES 1 INFLOW NUIF2 1 2 +WDM4 43 PO4I ENGLZERO SAME RCHRES 1 INFLOW NUIF2 2 2 +WDM4 44 PO4C ENGLZERO SAME RCHRES 1 INFLOW NUIF2 3 2 +WDM4 45 RORP ENGLZERO SAME RCHRES 1 INFLOW PKIF 4 +WDM4 51 BODA ENGLZERO SAME RCHRES 1 INFLOW OXIF 2 +WDM4 52 TORC ENGLZERO SAME RCHRES 1 INFLOW PKIF 5 +WDM4 53 PHYT ENGLZERO SAME RCHRES 1 INFLOW PKIF 1 +END EXT SOURCES + +EXT TARGETS +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Volume-> Tsys Tgap Amd *** + # # #<-factor->strg # # tem strg strg*** +RCHRES 1 OFLOW OVOL 3 SAME WDM4 111 WATR ENGL REPL +RCHRES 1 OFLOW OHEAT 3 SAME WDM4 112 HEAT ENGL REPL +RCHRES 1 OFLOW OXCF2 3 1 SAME WDM4 113 DOXY ENGL REPL +RCHRES 1 OFLOW OSED 3 1 SAME WDM4 121 SAND ENGL REPL +RCHRES 1 OFLOW OSED 3 2 SAME WDM4 122 SILT ENGL REPL +RCHRES 1 OFLOW OSED 3 3 SAME WDM4 123 CLAY ENGL REPL +RCHRES 1 OFLOW NUCF9 3 1 SAME WDM4 131 NO3D ENGL REPL +RCHRES 1 OFLOW NUCF9 3 2 SAME WDM4 132 NH3D ENGL REPL +RCHRES 1 OFLOW OSNH4 3 1 SAME WDM4 133 NH3A ENGL REPL +RCHRES 1 OFLOW OSNH4 3 2 SAME WDM4 134 NH3I ENGL REPL +RCHRES 1 OFLOW OSNH4 3 3 SAME WDM4 135 NH3C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 3 SAME WDM4 136 RORN ENGL REPL +RCHRES 1 OFLOW NUCF9 3 4 SAME WDM4 141 PO4D ENGL REPL +RCHRES 1 OFLOW OSPO4 3 1 SAME WDM4 142 PO4A ENGL REPL +RCHRES 1 OFLOW OSPO4 3 2 SAME WDM4 143 PO4I ENGL REPL +RCHRES 1 OFLOW OSPO4 3 3 SAME WDM4 144 PO4C ENGL REPL +RCHRES 1 OFLOW PKCF2 3 4 SAME WDM4 145 RORP ENGL REPL +RCHRES 1 OFLOW OXCF2 3 2 SAME WDM4 151 BODA ENGL REPL +RCHRES 1 OFLOW PKCF2 3 5 SAME WDM4 152 TORC ENGL REPL +RCHRES 1 OFLOW PKCF2 3 1 SAME WDM4 153 PHYT ENGL REPL +END EXT TARGETS + +NETWORK +<-Volume-> <-Grp> <-Member-><--Mult-->Tran <-Target vols> <-Grp> <-Member-> *** + # # #<-factor->strg # # # # *** +RCHRES 1 HYDR TAU AVER PLTGEN 1 INPUT MEAN 1 +END NETWORK + +PLTGEN + PLOTINFO + # - # FILE NPT NMN LABL PYR PIVL *** + 1 31 1 12 24 + END PLOTINFO + + GEN-LABELS + # - #<----------------Title-----------------> *** + 1 PL3_5250_0001 daily_shear_stress_lbsft2 + END GEN-LABELS + + SCALING + #thru# YMIN YMAX IVLIN THRESH *** + 1 99 0. 100000. 20. + END SCALING + + CURV-DATA + <-Curve label--> Line Intg Col Tran *** + # - # type eqv code code *** + 1 daily_shear_stre 1 1 AVER + END CURV-DATA +END PLTGEN + +END RUN diff --git a/tests/testcbp/HSP2results/check_endpoint_ts.py b/tests/testcbp/HSP2results/check_endpoint_ts.py index f42e1d19..e0d94b58 100644 --- a/tests/testcbp/HSP2results/check_endpoint_ts.py +++ b/tests/testcbp/HSP2results/check_endpoint_ts.py @@ -17,7 +17,7 @@ # # f.close() hdf5_instance = HDF5(fpath) io_manager = IOManager(hdf5_instance) -uci_obj = io_manager.read_uci() +uci_obj = io_manager.read_parameters() siminfo = uci_obj.siminfo opseq = uci_obj.opseq # Note: now that the UCI is read in and hdf5 loaded, you can see things like: @@ -44,7 +44,7 @@ ) # this creates all objects from the UCI and previous loads # state['model_root_object'].find_var_path('RCHRES_R001') # Get the timeseries naked, without an object -rchres1 = state["model_object_cache"]["/STATE/RCHRES_R001"] +rchres1 = om_operations["model_object_cache"]["/STATE/RCHRES_R001"] precip_ts = ModelLinkage( "PRCP", rchres1, diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 3289c4ed..52624294 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -1,52 +1,105 @@ # Must be run from the HSPsquared source directory, the h5 file has already been setup with hsp import_uci test10.uci # bare bones tester - must be run from the HSPsquared source directory -import os +import os import numpy from hsp2.hsp2.main import * +from hsp2.state.state import * from hsp2.hsp2.om import * +from hsp2.hsp2.SPECL import * from hsp2.hsp2io.hdf import HDF5 from hsp2.hsp2io.io import IOManager from hsp2.state.state import * -fpath = "./tests/testcbp/HSP2results/JL1_6562_6560.h5" +fpath = "./tests/testcbp/HSP2results/PL3_5250_0001.h5" # try also: # fpath = './tests/testcbp/HSP2results/JL1_6562_6560.h5' + # sometimes when testing you may need to close the file, so try: # f = h5py.File(fpath,'a') # use mode 'a' which allows read, write, modify # # f.close() hdf5_instance = HDF5(fpath) io_manager = IOManager(hdf5_instance) -uci_obj = io_manager.read_uci() -siminfo = uci_obj.siminfo -opseq = uci_obj.opseq -# Note: now that the UCI is read in and hdf5 loaded, you can see things like: -# - hdf5_instance._store.keys() - all the paths in the UCI/hdf5 -# - finally stash specactions in state, not domain (segment) dependent so do it once -# now load state and the special actions -state = init_state_dicts() -state_initialize_om(state) -state["specactions"] = uci_obj.specactions # stash the specaction dict in state - -state_siminfo_hsp2(uci_obj, siminfo) + +parameter_obj = io_manager.read_parameters() +opseq = parameter_obj.opseq +ddlinks = parameter_obj.ddlinks +ddmasslinks = parameter_obj.ddmasslinks +ddext_sources = parameter_obj.ddext_sources +ddgener = parameter_obj.ddgener +model = parameter_obj.model +siminfo = parameter_obj.siminfo +ftables = parameter_obj.ftables +specactions = parameter_obj.specactions +monthdata = parameter_obj.monthdata + +start, stop = siminfo["start"], siminfo["stop"] + +copy_instances = {} +gener_instances = {} +print("io_manager.read_parameters() call and config", timer.split(), "seconds") +####################################################################################### +# initialize STATE dicts +####################################################################################### +# Set up Things in state that will be used in all modular activities like SPECL +state = state_class( + state_empty["state_ix"], state_empty["op_tokens"], state_empty["state_paths"], + state_empty["op_exec_lists"], state_empty["model_exec_list"], state_empty["dict_ix"], + state_empty["ts_ix"], state_empty["hsp_segments"] +) +print("init_state_dicts()", timer.split(), "seconds") +om_operations = om_init_state() # set up operational model specific containers +state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) # Add support for dynamic functions to operate on STATE # - Load any dynamic components if present, and store variables on objects state_load_dynamics_hsp2(state, io_manager, siminfo) +print("state_load_dynamics_hsp2() call and config", timer.split(), "seconds") # Iterate through all segments and add crucial paths to state # before loading dynamic components that may reference them -state_init_hsp2(state, opseq, activities) -state_load_dynamics_specl(state, io_manager, siminfo) # traditional special actions +state_init_hsp2(state, opseq, activities, timer) +print("state_init_hsp2() call and config", timer.split(), "seconds") +hsp2_domain_dependencies(state, opseq, activities, om_operations, False) +print("hsp2_domain_dependencies() call and config", timer.split(), "seconds") +specl_load_om(om_operations, specactions) # load traditional special actions +print("specl_load_om() call and config", timer.split(), "seconds") state_load_dynamics_om( - state, io_manager, siminfo -) # operational model for custom python -state_om_model_run_prep( - state, io_manager, siminfo -) # this creates all objects from the UCI and previous loads + state, io_manager, siminfo, om_operations +) # operational model for custom python +print("state_load_dynamics_om() call and config", timer.split(), "seconds") +# finalize all dynamically loaded components and prepare to run the model +state_om_model_run_prep(opseq, activities, state, om_operations, siminfo) +print("state_om_model_run_prep() call and config", timer.split(), "seconds") +####################################################################################### + +# debug loading: +# mtl = [] +# mel = [] +# model_order_recursive(endpoint, om_operations["model_object_cache"], mel, mtl, True) + +RCHRES = om_operations["model_object_cache"]["/STATE/PL3_5250_0001/RCHRES_R001"] +O2 = om_operations["model_object_cache"]["/STATE/PL3_5250_0001eq/RCHRES_R001/O2"] +wd_500 = om_operations["model_object_cache"][RCHRES.find_var_path('wd_500')] + +wd_cfs = om_operations["model_object_cache"]["/STATE/PL3_5250_0001eq/RCHRES_R001/wd_cfs"] + +state.get_ix_path(wd_cfs.ops[6]) +state.get_ix_path(wd_cfs.ops[7]) + +wd_cfs.find_var_path("O2") + + +##### Check exec list +ep_list = hydr_init_ix(state, RCHRES.state_path) +op_exec_list = model_domain_dependencies( + om_operations, state, RCHRES.state_path, ep_list, True, False +) +op_exec_list = np.asarray(op_exec_list) + # state['model_root_object'].find_var_path('RCHRES_R001') # Get the timeseries naked, without an object -Rlocal = state["model_object_cache"]["/STATE/RCHRES_R001/Rlocal"] +Rlocal = om_operations["model_object_cache"]["/STATE/RCHRES_R001/Rlocal"] Rlocal_ts = Rlocal.read_ts() -rchres1 = state["model_object_cache"]["/STATE/RCHRES_R001"] +rchres1 = om_operations["model_object_cache"]["/STATE/RCHRES_R001"] Rlocal_check = ModelLinkage( "Rlocal1", rchres1, {"right_path": "/TIMESERIES/TS010", "link_type": 3} ) @@ -78,3 +131,56 @@ end - start, "seconds", ) + + +# try also: +# Must be run from the HSPsquared source directory, the h5 file has already been setup with hsp import_uci test10.uci +# bare bones tester - must be run from the HSPsquared source directory +# sometimes when testing you may need to close the file, so try: +# import h5py;f = h5py.File(fpath,'a') # use mode 'a' which allows read, write, modify +# # f.close() +import os +import numpy +import h5py +from hsp2.hsp2.main import * +from hsp2.state.state import * +from hsp2.hsp2.om import * +from hsp2.hsp2.SPECL import * +from hsp2.hsp2io.hdf import HDF5 +from hsp2.hsp2io.io import IOManager +from hsp2.hsp2tools.readUCI import * +from src.hsp2.hsp2tools.commands import import_uci, run +from pandas import read_hdf + +fpath = "./tests/testcbp/HSP2results/PL3_5250_0001.h5" +# to run use this: +# run(fpath, saveall=True, compress=False) +dstore_hydr = pd.HDFStore(str(fpath), mode='r') +hsp2_hydr = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') +np.quantile(hsp2_hydr[:]['O2'], [0,0.25,0.5,0.75,1.0]) +# To re-run: +dstore_hydr.close() + +fpath = "./tests/testcbp/HSP2results/PL3_5250_0001wd.h5" +# to run use this: +# run(fpath, saveall=True, compress=False) +dstore_hydr = pd.HDFStore(str(fpath), mode='r') +hsp2_wd_hydr = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') +dstore_hydr.close() +np.quantile(hsp2_wd_hydr[:]['O2'], [0,0.25,0.5,0.75,1.0]) +# To re-run: + + +fpath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.h5" +# to run use this: +# run(fpath, saveall=True, compress=False) +dstore_hydreq = pd.HDFStore(str(fpath), mode='r') +hsp2_eq_hydr = read_hdf(dstore_hydreq, '/RESULTS/RCHRES_R001/HYDR') +dstore_hydreq.close() +np.quantile(hsp2_eq_hydr[:]['O2'], [0,0.25,0.5,0.75,1.0]) +# To re-run: + +np.mean(hsp2_hydr[:]['IVOL']) +np.mean(hsp2_eq_hydr[:]['IVOL']) +np.mean(hsp2_hydr[:]['OVOL3']) +np.mean(hsp2_eq_hydr[:]['OVOL3'])