From 938f68e7b21574bf7e5fbd5e44a3dd1821ec6714 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 16 Oct 2025 14:33:38 -0400 Subject: [PATCH 001/378] added state mods including draft class def --- src/hsp2/state/state.py | 149 +++++++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 56 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index d172a5b6..fbfc515a 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -4,29 +4,58 @@ 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 +from numba.experimental import jitclass +from numpy import zeros, int32, asarray as npasarray +from numba import njit, types, typeof # import the types import os import importlib.util import sys +from hsp2.hsp2.utilities import make_class_spec + + +# this is temporary, these will be merged with state soon +state_ix = npasarray(zeros(1), dtype="float64") +op_tokens = int32(zeros((1,64))) +op_exec_lists = int32(zeros((1,1024))) +# note: tested 32-bit key and saw absolutely no improvement, so test 32bit value +state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64) +ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) +ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) + +state_paths_ty = ('state_paths', typeof(state_paths)) +op_tokens_ty = ('op_tokens', typeof(op_tokens)) +state_ix_ty = ('state_ix', typeof(state_ix)) +ts_ix_ty = ('ts_ix', typeof(ts_ix)) +ts_paths_ty = ('ts_paths', typeof(ts_paths)) +model_root_name_ty = ('model_root_name', types.unicode_type) +state_step_hydr_ty = ('state_step_hydr', types.unicode_type) +hsp2_local_py_ty = ('hsp2_local_py', types.boolean) +op_exec_lists_ty = ('op_exec_lists', typeof(op_exec_lists)) +state_spec = [state_paths_ty, state_ix_ty, ts_paths_ty, ts_ix_ty, + model_root_name_ty, state_step_hydr_ty, hsp2_local_py_ty, + op_tokens_ty, op_exec_lists_ty] + +@jitclass(state_spec) +class state_object: + def __init__(self, num_ops=5000): + self.state_ix = zeros(num_ops) + self.state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + self.ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) + self.ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) + self.state_step_hydr = "disabled" + self.model_root_name = "" + self.hsp2_local_py = False + # Note: in the type declaration above we are alloweed to use the shortened form + # op_tokens = int32(zeros((1,64))) + # but in jited class that throws an error and we have to use the + # form op_tokens.astype(int32) to do the type cast + op_tokens = zeros( (num_ops,64) ) + self.op_tokens = op_tokens.astype(int32) + op_exec_lists = zeros( (num_ops,1024) ) + self.op_exec_lists = op_exec_lists.astype(int32) + return -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 - def op_path_name(operation, id): """ @@ -81,10 +110,10 @@ 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 @@ -120,6 +149,19 @@ def append_state(state_ix, var_value): return val_ix +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 + siminfo["tindex"] = date_range( + siminfo["start"], siminfo["stop"], freq=Minute(delt) + )[1:] + siminfo["steps"] = len(siminfo["tindex"]) + 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 + + def state_context_hsp2(state, operation, segment, activity): # this establishes domain info so that a module can know its paths state["operation"] = operation @@ -128,29 +170,14 @@ def state_context_hsp2(state, operation, segment, 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 + 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): - # Add crucial simulation info for dynamic operation support - delt = parameter_obj.opseq.INDELT_minutes[0] # get initial value for STATE objects - siminfo["delt"] = delt - siminfo["tindex"] = date_range( - siminfo["start"], siminfo["stop"], freq=Minute(delt) - )[1:] - siminfo["steps"] = len(siminfo["tindex"]) - 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.domain = seg_path # + "/" + activity # may want to comment out activity? def state_init_hsp2(state, opseq, activities): # This sets up the state entries for all state compatible HSP2 model variables @@ -158,19 +185,36 @@ def state_init_hsp2(state, opseq, activities): 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 = op_path_name(operation, segment) + seg_path = "/STATE/" + state.model_root_name + "/" + seg_name + segid = set_state( + state.state_ix, state.state_paths, seg_path, 0.0 + ) + ep_list = [] if activity == "HYDR": state_context_hsp2(state, operation, segment, activity) - hydr_init_ix(state, state["domain"]) + ep_list = hydr_init_ix(state, state.domain) elif activity == "SEDTRN": state_context_hsp2(state, operation, segment, activity) - sedtrn_init_ix(state, state["domain"]) + ep_list = sedtrn_init_ix(state, state.domain) elif activity == "SEDMNT": state_context_hsp2(state, operation, segment, activity) - sedmnt_init_ix(state, state["domain"]) + ep_list = sedmnt_init_ix(state, state.domain) elif activity == "RQUAL": state_context_hsp2(state, operation, segment, activity) - rqual_init_ix(state, state["domain"]) - + ep_list = rqual_init_ix(state, state.domain) + # Register list of elements to execute if any + op_exec_list = model_domain_dependencies( + state, state.domain, ep_list, True + ) + state.op_exec_lists[segid] = op_exec_list + +def 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.state_step_hydr = siminfo.state_step_hydr # enabled or disabled + state.hsp2_local_py = load_dynamics(io_manager, siminfo) # Stores the actual function in state def state_load_hdf5_components( io_manager, @@ -186,13 +230,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): @@ -258,7 +295,7 @@ def hydr_init_ix(state, domain): 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) + hydr_ix[i] = set_state(state.state_ix, state.state_paths, var_path, 0.0) return hydr_ix @@ -274,7 +311,7 @@ def sedtrn_init_ix(state, domain): 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] = set_state(state.state_ix, state.state_paths, var_path, 0.0) return sedtrn_ix @@ -289,7 +326,7 @@ def sedmnt_init_ix(state, domain): sedmnt_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) 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] = set_state(state.state_ix, state.state_paths, var_path, 0.0) return sedmnt_ix @@ -316,7 +353,7 @@ def rqual_init_ix(state, domain): rqual_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) 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] = set_state(state.state_ix, state.state_paths, var_path, 0.0) return rqual_ix @@ -429,9 +466,9 @@ def load_dynamics(io_manager, siminfo): # see if there is a code module with custom python # print("Looking for SPECL with custom python code ", (fbase + ".py")) hsp2_local_py = dynamic_module_import(fbase, fbase + ".py", "hsp2_local_py") - siminfo["state_step_hydr"] = "disabled" + siminfo.state_step_hydr = "disabled" if "state_step_hydr" in dir(hsp2_local_py): - siminfo["state_step_hydr"] = "enabled" + siminfo.state_step_hydr = "enabled" print("state_step_hydr function defined, using custom python code") else: # print("state_step_hydr function not defined. Using default") From 4f1239d5d64dfbd9f5ba9f76bb1006a465bd2320 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 16 Oct 2025 17:26:05 -0400 Subject: [PATCH 002/378] first steps towards including the new state data model --- src/hsp2/hsp2/SPECL.py | 22 ++++++++-------- src/hsp2/hsp2/main.py | 7 +++-- src/hsp2/hsp2/om.py | 45 ++++++++++++++++++-------------- src/hsp2/hsp2/om_model_object.py | 14 +++++----- src/hsp2/state/state.py | 17 ++++++------ 5 files changed, 56 insertions(+), 49 deletions(-) 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..d5d0a719 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -96,14 +96,13 @@ def main( # before loading dynamic components that may reference them state_init_hsp2(state, opseq, activities) # - 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 + om_operations = om_init_state() # set up operational model specific containers + specl_load_om(om_operations, specactions) # load traditional special actions state_load_dynamics_om( state, io_manager, siminfo ) # 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(state, om_operations, siminfo) ####################################################################################### # main processing loop diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index a85f579e..4f626277 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -56,7 +56,7 @@ def model_element_paths(mel, state): """ ixn = 1 for ix in mel: - ip = get_ix_path(state["state_paths"], ix) + ip = get_ix_path(state.state_paths, ix) im = state["model_object_cache"][ip] print(ixn, ":", im.name, "->", im.state_path, "=", im.get_state()) ixn = ixn + 1 @@ -130,7 +130,7 @@ def state_load_om_python(state, io_manager, siminfo): io_manager, siminfo, state["op_tokens"], - state["state_paths"], + state.state_paths, state["state_ix"], state["dict_ix"], state["ts_ix"], @@ -138,16 +138,18 @@ def state_load_om_python(state, io_manager, siminfo): ) -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"] = ( + om_operations = {} + om_operations["op_tokens"], om_operations["model_object_cache"], om_operations["model_exec_list"] = ( op_tokens, model_object_cache, [], ) + return(om_operations) def state_load_dynamics_om(state, io_manager, siminfo): @@ -165,43 +167,46 @@ def state_load_dynamics_om(state, io_manager, siminfo): 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(): + if "model_root_object" not in om_operations.keys(): model_root_object = ModelObject( - state["model_root_name"], False, {}, state + om_operations["model_root_name"], False, {}, state ) # 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(): + model_root_object = om_operations["model_root_object"] + 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) # 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(): + for seg_path in state.hsp_segments.items(): if seg_path not in state["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 + # 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 + seg_name = seg_path.rsplit('/',1)[-1] segment = ModelObject(seg_name, model_root_object, {}, state) - state["model_object_cache"][segment.state_path] = segment + 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(state, om_operations, siminfo): # insure model base is set - state_om_model_root_object(state, siminfo) + 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_root_object = om_operations["model_root_object"] model_loader_recursive(state["model_data"], model_root_object, state) # 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_object_cache = om_operations["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"] @@ -245,7 +250,7 @@ def state_om_model_run_prep(state, io_manager, siminfo): # 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()) + state["op_tokens"], list(state.state_paths.values()) ) # print("Operational model status:", state['state_step_om']) if len(model_exec_list) > 0: @@ -607,7 +612,7 @@ def model_input_dependencies(state, exec_list, only_runnable=False): mel = [] for model_element in state["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( @@ -631,7 +636,7 @@ def model_domain_dependencies(state, domain, ep_list, only_runnable=False): mel = [] mtl = [] # 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.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) @@ -684,7 +689,7 @@ def step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): 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)] + model_object = state["model_object_cache"][get_ix_path(state.state_paths, i)] if "io_manager" in dir(model_object): model_object.io_manager = io_manager model_object.finish() diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 30451052..59809077 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -32,7 +32,7 @@ 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 @@ -52,7 +52,9 @@ def __init__(self, name, container=False, model_props=None, state=None): ) else: state = self.container.state + 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? # Local properties self.model_props_parsed = {} # a place to stash parse record for debugging self.log_path = "" # Ex: "/RESULTS/RCHRES_001/SPECL" @@ -273,10 +275,10 @@ def get_exec_order(self, var_name=False): 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] + return self.model_object_cache[var_path] def find_var_path(self, var_name, local_only=False): # check local inputs for name @@ -325,7 +327,7 @@ def register_path(self): 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 + 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): @@ -446,7 +448,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 +468,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): diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index fbfc515a..a1c50a64 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -15,14 +15,18 @@ # this is temporary, these will be merged with state soon state_ix = npasarray(zeros(1), dtype="float64") +model_exec_list = npasarray(zeros(1), dtype="int64") op_tokens = int32(zeros((1,64))) op_exec_lists = int32(zeros((1,1024))) # note: tested 32-bit key and saw absolutely no improvement, so test 32bit value state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64) +hsp_segments = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) state_paths_ty = ('state_paths', typeof(state_paths)) +model_exec_list_ty = ('model_exec_list', typeof(model_exec_list)) +hsp_segments_ty = ('hsp_segments', typeof(hsp_segments)) op_tokens_ty = ('op_tokens', typeof(op_tokens)) state_ix_ty = ('state_ix', typeof(state_ix)) ts_ix_ty = ('ts_ix', typeof(ts_ix)) @@ -33,13 +37,14 @@ op_exec_lists_ty = ('op_exec_lists', typeof(op_exec_lists)) state_spec = [state_paths_ty, state_ix_ty, ts_paths_ty, ts_ix_ty, model_root_name_ty, state_step_hydr_ty, hsp2_local_py_ty, - op_tokens_ty, op_exec_lists_ty] + hsp_segments_ty, op_tokens_ty, op_exec_lists_ty, model_exec_list_ty] @jitclass(state_spec) class state_object: def __init__(self, num_ops=5000): self.state_ix = zeros(num_ops) self.state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + self.hsp_segments = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) self.ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) self.ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) self.state_step_hydr = "disabled" @@ -169,14 +174,10 @@ def state_context_hsp2(state, operation, segment, activity): 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_name = op_path_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 + 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_init_hsp2(state, opseq, activities): From 4cf3c5312e7e039ca5f44e6e020b73cedc46bde1 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 16 Oct 2025 17:33:27 -0400 Subject: [PATCH 003/378] add model_exec_list to state object --- src/hsp2/hsp2/HYDR.py | 12 ++++---- src/hsp2/hsp2/RQUAL.py | 8 ++--- src/hsp2/hsp2/SEDMNT.py | 8 ++--- src/hsp2/hsp2/SEDTRN.py | 8 ++--- src/hsp2/hsp2/om.py | 28 ++++++++--------- src/hsp2/hsp2/om_equation.py | 6 ++-- src/hsp2/hsp2/om_model_linkage.py | 10 +++---- src/hsp2/hsp2/om_model_object.py | 50 +++++++++++++++---------------- src/hsp2/hsp2/om_sim_timer.py | 28 ++++++++--------- src/hsp2/state/state.py | 4 ++- 10 files changed, 82 insertions(+), 80 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 8caa0ece..9d0fe8b0 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -150,10 +150,10 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): ) state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( state["domain"], - state["state_step_hydr"], + state.state_step_hydr, state["state_step_om"], ) - hsp2_local_py = state["hsp2_local_py"] + hsp2_local_py = state.state_step_hydr # 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: @@ -163,8 +163,8 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): # 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"] + 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 @@ -174,7 +174,7 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): 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"] + op_tokens = state.op_tokens ####################################################################################### # Do the simulation with _hydr_ (ie run reaches simulation code) @@ -207,7 +207,7 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): 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 + state["state_ix"], state.dict_ix, state.ts_ix = state_ix, dict_ix, ts_ix return errors, ERRMSGS diff --git a/src/hsp2/hsp2/RQUAL.py b/src/hsp2/hsp2/RQUAL.py index 81985ec8..27796043 100644 --- a/src/hsp2/hsp2/RQUAL.py +++ b/src/hsp2/hsp2/RQUAL.py @@ -261,15 +261,15 @@ def rqual( ) state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( state["domain"], - state["state_step_hydr"], + 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"] + 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() diff --git a/src/hsp2/hsp2/SEDMNT.py b/src/hsp2/hsp2/SEDMNT.py index 6818d1e5..fc5f6683 100644 --- a/src/hsp2/hsp2/SEDMNT.py +++ b/src/hsp2/hsp2/SEDMNT.py @@ -65,15 +65,15 @@ def sedmnt(io_manager, siminfo, parameters, ts, state): ) state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( state["domain"], - state["state_step_hydr"], + 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"] + 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..5f6bb754 100644 --- a/src/hsp2/hsp2/SEDTRN.py +++ b/src/hsp2/hsp2/SEDTRN.py @@ -101,7 +101,7 @@ def sedtrn(io_manager, siminfo, parameters, ts, state): ) state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( state["domain"], - state["state_step_hydr"], + state.state_step_hydr, state["state_step_om"], ) # hsp2_local_py = state['hsp2_local_py'] @@ -114,9 +114,9 @@ def sedtrn(io_manager, siminfo, parameters, ts, state): # 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"] + 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() diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 4f626277..cd9be28b 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -123,17 +123,17 @@ 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.op_tokens, state.state_paths, state["state_ix"], - state["dict_ix"], - state["ts_ix"], + state.dict_ix, + state.ts_ix, state["model_object_cache"], ) @@ -206,21 +206,21 @@ def state_om_model_run_prep(state, om_operations, siminfo): # 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 = om_operations["model_object_cache"] + 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( + model_root_object.state.op_tokens = ModelObject.make_op_tokens( max(model_root_object.state["state_ix"].keys()) + 1 ) model_tokenizer_recursive(model_root_object, model_object_cache, model_exec_list) - op_tokens = model_root_object.state["op_tokens"] + 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) @@ -228,7 +228,7 @@ def state_om_model_run_prep(state, om_operations, siminfo): # 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") + 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" @@ -238,7 +238,7 @@ def state_om_model_run_prep(state, om_operations, siminfo): state["state_ix"] = state_keyvals else: state["state_ix"] = model_root_object.state["state_ix"] - state["op_tokens"] = ( + state.op_tokens = ( op_tokens # is this superfluous since the root object got op_tokens from state? ) if len(op_tokens) > 0: @@ -250,7 +250,7 @@ def state_om_model_run_prep(state, om_operations, siminfo): # 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()) + state.op_tokens, list(state.state_paths.values()) ) # print("Operational model status:", state['state_step_om']) if len(model_exec_list) > 0: @@ -620,7 +620,7 @@ def model_input_dependencies(state, exec_list, only_runnable=False): ) mello = mello + mel if only_runnable == True: - mello = ModelObject.runnable_op_list(state["op_tokens"], mello) + mello = ModelObject.runnable_op_list(state.op_tokens, mello) mello = pd.Series(mello).drop_duplicates().tolist() return mello @@ -642,7 +642,7 @@ def model_domain_dependencies(state, domain, ep_list, only_runnable=False): model_order_recursive(endpoint, state["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 @@ -688,7 +688,7 @@ def step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): def finish_model(state, io_manager, siminfo): # print("Model object cache list", state["model_object_cache"].keys()) - for i in state["model_exec_list"]: + for i in state.model_exec_list: model_object = state["model_object_cache"][get_ix_path(state.state_paths, i)] if "io_manager" in dir(model_object): model_object.io_manager = io_manager diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index ade606cf..1c7f8e95 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -139,7 +139,7 @@ def tokenize_vars(self): constant_path = self.state_path + "/_ops/_op" + str(j) s_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, constant_path, float(self.var_ops[j]), ) @@ -148,7 +148,7 @@ def tokenize_vars(self): # 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 + self.state["state_ix"], self.state.state_paths, var_path ) if s_ix == False: print( @@ -160,7 +160,7 @@ def tokenize_vars(self): s_ix, ) print( - "searched: ", self.state["state_paths"], self.state["state_ix"] + "searched: ", self.state.state_paths, self.state["state_ix"] ) return else: diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index a09c3528..e76e9daa 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -140,10 +140,10 @@ 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 + self.state["state_ix"], self.state.state_paths, 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 @@ -188,7 +188,7 @@ def tokenize(self): # 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 + self.state["state_ix"], self.state.state_paths, self.right_path ) if not (src_ix == False): self.ops = self.ops + [src_ix, self.link_type] @@ -198,10 +198,10 @@ def tokenize(self): 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 + 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 + self.state["state_ix"], self.state.state_paths, self.right_path ) if (left_ix != False) and (right_ix != False): self.ops = self.ops + [left_ix, self.link_type, right_ix] diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 59809077..d8b7cf38 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -210,18 +210,18 @@ def parse_model_props(self, model_props, strict=False): def set_state(self, set_value): var_ix = set_state( - self.state["state_ix"], - self.state["state_paths"], + self.state_ix, + self.state_paths, 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 + self.state.op_tokens = op_tokens + self.state_paths = state_paths + self.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 @@ -252,15 +252,15 @@ 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_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 + self.state_ix, self.state_paths, var_path ) if var_ix == False: return False - return self.state["state_ix"][var_ix] + return self.state_ix[var_ix] def get_exec_order(self, var_name=False): if var_name == False: @@ -268,9 +268,9 @@ def get_exec_order(self, var_name=False): else: var_path = self.find_var_path(var_name) var_ix = get_state_ix( - self.state["state_ix"], self.state["state_paths"], var_path + self.state_ix, self.state_paths, var_path ) - exec_order = get_exec_order(self.state["model_exec_list"], var_ix) + exec_order = get_exec_order(self.self.model_exec_list, var_ix) return exec_order def get_object(self, var_name=False): @@ -294,11 +294,11 @@ def find_var_path(self, var_name, local_only=False): if not (self.container == False): 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(): + if ("/STATE/" + var_name) in self.state_paths.keys(): # return self.state['state_paths'][("/STATE/" + var_name)] return "/STATE/" + var_name # check for full paths - if var_name in self.state["state_paths"].keys(): + if var_name in self.state_paths.keys(): # return self.state['state_paths'][var_name] return var_name return False @@ -321,8 +321,8 @@ def register_path(self): 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_ix, + self.state_paths, self.state_path, self.default_value, ) @@ -354,7 +354,7 @@ def add_input(self, var_name, var_path, input_type=1, trust=False): 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 + self.state_ix, self.state_paths, found_path ) if var_ix == False: if trust == False: @@ -411,14 +411,14 @@ def insure_path(self, var_path): # 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 + self.state_ix, self.state_paths, 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 @@ -497,18 +497,18 @@ def add_op_tokens(self): + self.state_path + "). " ) - self.state["op_tokens"][self.ix] = self.format_ops() + self.state.op_tokens[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 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_ix, + self.state.dict_ix, + self.state_ixts_ix"], step, ) # step_model({self.state['op_tokens'][self.ix]}, self.state['state_ix'], self.state['dict_ix'], self.state['ts_ix'], step) diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index 24a93c53..c54ad30b 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -30,7 +30,7 @@ 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.state.state_paths, self.state_path, float(self.time_array[0][0]), ) @@ -38,67 +38,67 @@ def register_components(self): # register "year", "month" "day", ... year_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/year", float(self.time_array[0][1]), ) month_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/month", float(self.time_array[0][2]), ) day_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/day", float(self.time_array[0][3]), ) hr_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/hour", float(self.time_array[0][4]), ) min_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/minute", float(self.time_array[0][5]), ) sec_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/second", float(self.time_array[0][6]), ) wd_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/weekday", float(self.time_array[0][7]), ) dt_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/dt", float(self.time_array[0][8]), ) jd_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/jday", float(self.time_array[0][9]), ) md_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/modays", float(self.time_array[0][10]), ) dts_ix = set_state( self.state["state_ix"], - self.state["state_paths"], + self.state.state_paths, "/STATE/dts", float(self.time_array[0][8] * 60.0), ) @@ -115,7 +115,7 @@ def register_components(self): md_ix, dts_ix, ] - self.state["dict_ix"][self.ix] = self.time_array + self.state.dict_ix[self.ix] = self.time_array return self.ix @@ -129,7 +129,7 @@ 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[self.ix] = self.time_array def dti_to_time_array(self, siminfo): dateindex = siminfo["tindex"] diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index a1c50a64..c2d985c0 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -58,6 +58,8 @@ def __init__(self, num_ops=5000): self.op_tokens = op_tokens.astype(int32) op_exec_lists = zeros( (num_ops,1024) ) self.op_exec_lists = op_exec_lists.astype(int32) + model_exec_list = zeros(num_ops) + self.model_exec_list = model_exec_list.astype(types.int64) return @@ -122,7 +124,7 @@ def state_add_ts(state, var_path, default_value=0.0, debug=False): 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( + state.ts_ix[var_ix] = np.full_like( zeros(state["model_data"]["siminfo"]["steps"]), default_value ) return var_ix From a2f87437621768325a547c4f25f6df7eed4c3dbe Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 17 Oct 2025 09:16:49 -0400 Subject: [PATCH 004/378] add domain info to state --- src/hsp2/state/state.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index c2d985c0..5ba4563c 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -13,12 +13,12 @@ from hsp2.hsp2.utilities import make_class_spec -# this is temporary, these will be merged with state soon +# Define the complex datatypes state_ix = npasarray(zeros(1), dtype="float64") model_exec_list = npasarray(zeros(1), dtype="int64") op_tokens = int32(zeros((1,64))) op_exec_lists = int32(zeros((1,1024))) -# note: tested 32-bit key and saw absolutely no improvement, so test 32bit value +# note: tested 32-bit key and saw absolutely no improvement, so go with 64 bit state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64) hsp_segments = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) @@ -32,12 +32,21 @@ ts_ix_ty = ('ts_ix', typeof(ts_ix)) ts_paths_ty = ('ts_paths', typeof(ts_paths)) model_root_name_ty = ('model_root_name', types.unicode_type) +# 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 state_step_hydr_ty = ('state_step_hydr', types.unicode_type) +operation_ty = ('operation', types.unicode_type) +segment_ty = ('segment', types.unicode_type) +activity_ty = ('activity', types.unicode_type) +domain_ty = ('domain', types.unicode_type) hsp2_local_py_ty = ('hsp2_local_py', types.boolean) op_exec_lists_ty = ('op_exec_lists', typeof(op_exec_lists)) + +# Combine these into a spec to create the class state_spec = [state_paths_ty, state_ix_ty, ts_paths_ty, ts_ix_ty, model_root_name_ty, state_step_hydr_ty, hsp2_local_py_ty, - hsp_segments_ty, op_tokens_ty, op_exec_lists_ty, model_exec_list_ty] + hsp_segments_ty, op_tokens_ty, op_exec_lists_ty, model_exec_list_ty, + operation_ty, segment_ty, activity_ty, domain_ty] @jitclass(state_spec) class state_object: @@ -49,6 +58,10 @@ def __init__(self, num_ops=5000): self.ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) self.state_step_hydr = "disabled" self.model_root_name = "" + self.operation = "" + self.segment = "" + self.activity = "" + self.domain = "" self.hsp2_local_py = False # Note: in the type declaration above we are alloweed to use the shortened form # op_tokens = int32(zeros((1,64))) From ba3c38f5f06a8b2bdbfb95a20eca3b2cb7cea262 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 17 Oct 2025 09:31:47 -0400 Subject: [PATCH 005/378] undo renaming of state_load_dynamics_hsp2 (I think it was accidental? search and replace?) --- src/hsp2/hsp2/HYDR.py | 10 +++++----- src/hsp2/hsp2/RQUAL.py | 10 +++++----- src/hsp2/hsp2/SEDMNT.py | 10 +++++----- src/hsp2/hsp2/SEDTRN.py | 10 +++++----- src/hsp2/state/state.py | 8 ++++---- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 9d0fe8b0..84461065 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -144,12 +144,12 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, 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.domain, state.state_step_hydr, state["state_step_om"], ) @@ -161,7 +161,7 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): 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"]) + 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 diff --git a/src/hsp2/hsp2/RQUAL.py b/src/hsp2/hsp2/RQUAL.py index 27796043..c903d363 100644 --- a/src/hsp2/hsp2/RQUAL.py +++ b/src/hsp2/hsp2/RQUAL.py @@ -255,18 +255,18 @@ def rqual( # 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.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"]) + 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 diff --git a/src/hsp2/hsp2/SEDMNT.py b/src/hsp2/hsp2/SEDMNT.py index fc5f6683..8dda8cdc 100644 --- a/src/hsp2/hsp2/SEDMNT.py +++ b/src/hsp2/hsp2/SEDMNT.py @@ -59,18 +59,18 @@ 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.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"]) + 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 diff --git a/src/hsp2/hsp2/SEDTRN.py b/src/hsp2/hsp2/SEDTRN.py index 5f6bb754..f0a2ecdb 100644 --- a/src/hsp2/hsp2/SEDTRN.py +++ b/src/hsp2/hsp2/SEDTRN.py @@ -95,12 +95,12 @@ def sedtrn(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.domain, state.state_step_hydr, state["state_step_om"], ) @@ -113,7 +113,7 @@ def sedtrn(io_manager, siminfo, parameters, ts, state): # 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"]) + 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 diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 5ba4563c..8aa7b33c 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -184,9 +184,9 @@ def state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager): 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 + 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 = op_path_name(operation, segment) @@ -226,7 +226,7 @@ def state_init_hsp2(state, opseq, activities): ) state.op_exec_lists[segid] = op_exec_list -def load_dynamics_hsp2(state, io_manager, siminfo): +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.state_step_hydr = siminfo.state_step_hydr # enabled or disabled From 5a6579399107a3047c21dc07b4d5f575c4aa8483 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 12:28:38 -0400 Subject: [PATCH 006/378] migrated from array state to object --- src/hsp2/hsp2/HYDR.py | 15 +--- src/hsp2/hsp2/RQUAL.py | 4 +- src/hsp2/hsp2/SEDMNT.py | 4 +- src/hsp2/hsp2/SEDTRN.py | 4 +- src/hsp2/hsp2/main.py | 2 +- src/hsp2/hsp2/om.py | 74 +++++++++---------- src/hsp2/hsp2/om_equation.py | 6 +- src/hsp2/hsp2/om_model_linkage.py | 14 ++-- src/hsp2/hsp2/om_model_object.py | 5 ++ src/hsp2/hsp2/om_sim_timer.py | 26 +++---- src/hsp2/hsp2/om_special_action.py | 4 +- src/hsp2/state/state.py | 27 ++++++- .../testcbp/HSP2results/check_endpoint_ts.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 4 +- 14 files changed, 102 insertions(+), 89 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 84461065..1e92b8a2 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -151,7 +151,7 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( state.domain, state.state_step_hydr, - state["state_step_om"], + state.state_step_om, ) hsp2_local_py = state.state_step_hydr # It appears necessary to load this here, instead of from main.py, otherwise, @@ -163,7 +163,7 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): # 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_ix, dict_ix, ts_ix = state.state_ix, state.dict_ix, state.ts_ix state_paths = state.state_paths ep_list = ( hydr_state_vars() @@ -207,7 +207,7 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): 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 + state.state_ix, state.dict_ix, state.ts_ix = state_ix, dict_ix, ts_ix return errors, ERRMSGS @@ -866,12 +866,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 c903d363..b69e3911 100644 --- a/src/hsp2/hsp2/RQUAL.py +++ b/src/hsp2/hsp2/RQUAL.py @@ -262,12 +262,12 @@ def rqual( state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( state.domain, state.state_step_hydr, - state["state_step_om"], + 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_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 diff --git a/src/hsp2/hsp2/SEDMNT.py b/src/hsp2/hsp2/SEDMNT.py index 8dda8cdc..916665b5 100644 --- a/src/hsp2/hsp2/SEDMNT.py +++ b/src/hsp2/hsp2/SEDMNT.py @@ -66,12 +66,12 @@ def sedmnt(io_manager, siminfo, parameters, ts, state): state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( state.domain, state.state_step_hydr, - state["state_step_om"], + 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_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 diff --git a/src/hsp2/hsp2/SEDTRN.py b/src/hsp2/hsp2/SEDTRN.py index f0a2ecdb..4b0debe0 100644 --- a/src/hsp2/hsp2/SEDTRN.py +++ b/src/hsp2/hsp2/SEDTRN.py @@ -102,7 +102,7 @@ def sedtrn(io_manager, siminfo, parameters, ts, state): state_info["domain"], state_info["state_step_hydr"], state_info["state_step_om"] = ( state.domain, state.state_step_hydr, - state["state_step_om"], + state.state_step_om, ) # hsp2_local_py = state['hsp2_local_py'] # # It appears necessary to load this here, instead of from main.py, otherwise, @@ -114,7 +114,7 @@ def sedtrn(io_manager, siminfo, parameters, ts, state): # 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_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 diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index d5d0a719..1ce99556 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -99,7 +99,7 @@ def main( om_operations = om_init_state() # set up operational model specific containers 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, om_operations, siminfo) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index cd9be28b..f00f4dbb 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -57,7 +57,7 @@ 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] + im = om_operations["model_object_cache"][ip] print(ixn, ":", im.name, "->", im.state_path, "=", im.get_state()) ixn = ixn + 1 return @@ -88,7 +88,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 +102,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, @@ -131,10 +129,10 @@ def state_load_om_python(state, io_manager, siminfo): siminfo, state.op_tokens, state.state_paths, - state["state_ix"], + state.state_ix, state.dict_ix, state.ts_ix, - state["model_object_cache"], + om_operations["model_object_cache"], ) @@ -152,7 +150,7 @@ def om_init_state(): 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 @@ -162,8 +160,8 @@ 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 @@ -182,7 +180,7 @@ def state_om_model_root_object(state, om_operations, siminfo): timer = SimTimer("timer", model_root_object, timer_props, state) # add base object for the HSP2 domains and other things already added to state so they can be influenced for seg_path in state.hsp_segments.items(): - if seg_path not in state["model_object_cache"].keys(): + 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? @@ -198,15 +196,15 @@ def state_om_model_run_prep(state, om_operations, siminfo): # insure model base is set 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. + # om_operations['model_data'] has alread been prepopulated from json, .py files, hdf5, etc. model_root_object = om_operations["model_root_object"] - model_loader_recursive(state["model_data"], model_root_object, state) + model_object_cache = om_operations["model_object_cache"] + model_loader_recursive(om_operations["model_data"], model_root_object, state, model_object_cache) # 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 @@ -217,7 +215,7 @@ def state_om_model_run_prep(state, om_operations, 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 + max(model_root_object.state.state_ix.keys()) + 1 ) model_tokenizer_recursive(model_root_object, model_object_cache, model_exec_list) op_tokens = model_root_object.state.op_tokens @@ -226,23 +224,23 @@ def state_om_model_run_prep(state, om_operations, siminfo): # 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.state_step_om = "disabled" + om_operations["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" + zeros(max(model_root_object.state.state_ix.keys()) + 1), dtype="float64" ) - for ix, val in model_root_object.state["state_ix"].items(): + for ix, val in model_root_object.state.state_ix.items(): state_keyvals[ix] = val - state["state_ix"] = state_keyvals + state.state_ix = state_keyvals else: - state["state_ix"] = model_root_object.state["state_ix"] + 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" + state.state_step_om = "enabled" # print("op_tokens is type", type(op_tokens)) # print("state_ix is type", type(state['state_ix'])) @@ -410,7 +408,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: @@ -450,7 +448,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( @@ -462,7 +460,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): @@ -603,20 +601,20 @@ def model_order_recursive( 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_element, model_object_cache, mel, mtl ) mello = mello + mel if only_runnable == True: @@ -637,9 +635,9 @@ def model_domain_dependencies(state, domain, ep_list, only_runnable=False): mtl = [] # 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 om_operations["model_object_cache"].keys(): + 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) @@ -687,9 +685,9 @@ def step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): def finish_model(state, io_manager, siminfo): - # print("Model object cache list", state["model_object_cache"].keys()) + # print("Model object cache list", om_operations["model_object_cache"].keys()) for i in state.model_exec_list: - model_object = state["model_object_cache"][get_ix_path(state.state_paths, i)] + model_object = om_operations["model_object_cache"][get_ix_path(state.state_paths, i)] if "io_manager" in dir(model_object): model_object.io_manager = io_manager model_object.finish() diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index 1c7f8e95..be8a9170 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -138,7 +138,7 @@ def tokenize_vars(self): # 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_ix, self.state.state_paths, constant_path, float(self.var_ops[j]), @@ -148,7 +148,7 @@ def tokenize_vars(self): # 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 + self.state.state_ix, self.state.state_paths, var_path ) if s_ix == False: print( @@ -160,7 +160,7 @@ def tokenize_vars(self): s_ix, ) print( - "searched: ", self.state.state_paths, self.state["state_ix"] + "searched: ", self.state.state_paths, self.state.state_ix ) return else: diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index e76e9daa..6f662106 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -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 @@ -140,7 +140,7 @@ 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 + self.state.state_ix, self.state.state_paths, 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] @@ -150,7 +150,7 @@ def write_ts(self, ts=None, ts_cols=None, write_path=None, tindex=None): 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 @@ -188,7 +188,7 @@ def tokenize(self): # 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 + self.state.state_ix, self.state.state_paths, self.right_path ) if not (src_ix == False): self.ops = self.ops + [src_ix, self.link_type] @@ -198,10 +198,10 @@ def tokenize(self): 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 + 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 + self.state.state_ix, self.state.state_paths, self.right_path ) if (left_ix != False) and (right_ix != False): self.ops = self.ops + [left_ix, self.link_type, right_ix] diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index d8b7cf38..17e4c732 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -273,6 +273,11 @@ def get_exec_order(self, var_name=False): exec_order = get_exec_order(self.self.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.model_object_cache[self.state_path] diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index c54ad30b..cb52d330 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -13,7 +13,7 @@ class SimTimer(ModelObject): - def __init__(self, name, container, model_props=None, state=None): + def __init__(self, name, container, model_props=None): if model_props is None: model_props = {} # Note: hsp2 siminfo will match model_props here @@ -29,7 +29,7 @@ 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_ix, self.state.state_paths, self.state_path, float(self.time_array[0][0]), @@ -37,67 +37,67 @@ def register_components(self): # now register all other paths. # register "year", "month" "day", ... year_ix = set_state( - self.state["state_ix"], + 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_ix, self.state.state_paths, "/STATE/month", float(self.time_array[0][2]), ) day_ix = set_state( - self.state["state_ix"], + 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_ix, self.state.state_paths, "/STATE/hour", float(self.time_array[0][4]), ) min_ix = set_state( - self.state["state_ix"], + 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_ix, self.state.state_paths, "/STATE/second", float(self.time_array[0][6]), ) wd_ix = set_state( - self.state["state_ix"], + 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_ix, self.state.state_paths, "/STATE/dt", float(self.time_array[0][8]), ) jd_ix = set_state( - self.state["state_ix"], + 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_ix, self.state.state_paths, "/STATE/modays", float(self.time_array[0][10]), ) dts_ix = set_state( - self.state["state_ix"], + self.state.state_ix, self.state.state_paths, "/STATE/dts", float(self.time_array[0][8] * 60.0), diff --git a/src/hsp2/hsp2/om_special_action.py b/src/hsp2/hsp2/om_special_action.py index e3042fe7..fa8f4133 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.om_operations["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.om_operations["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/state/state.py b/src/hsp2/state/state.py index 8aa7b33c..9eba1527 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -16,6 +16,8 @@ # Define the complex datatypes state_ix = npasarray(zeros(1), dtype="float64") model_exec_list = npasarray(zeros(1), dtype="int64") +# Create a sample tindex for typing +tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) op_tokens = int32(zeros((1,64))) op_exec_lists = int32(zeros((1,1024))) # note: tested 32-bit key and saw absolutely no improvement, so go with 64 bit @@ -25,6 +27,7 @@ ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) state_paths_ty = ('state_paths', typeof(state_paths)) +tindex_ty = ('tindex', typeof(tindex)) model_exec_list_ty = ('model_exec_list', typeof(model_exec_list)) hsp_segments_ty = ('hsp_segments', typeof(hsp_segments)) op_tokens_ty = ('op_tokens', typeof(op_tokens)) @@ -35,6 +38,7 @@ # 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 state_step_hydr_ty = ('state_step_hydr', types.unicode_type) +state_step_om_ty = ('state_step_om_ty', types.unicode_type) operation_ty = ('operation', types.unicode_type) segment_ty = ('segment', types.unicode_type) activity_ty = ('activity', types.unicode_type) @@ -46,7 +50,7 @@ state_spec = [state_paths_ty, state_ix_ty, ts_paths_ty, ts_ix_ty, model_root_name_ty, state_step_hydr_ty, hsp2_local_py_ty, hsp_segments_ty, op_tokens_ty, op_exec_lists_ty, model_exec_list_ty, - operation_ty, segment_ty, activity_ty, domain_ty] + operation_ty, segment_ty, activity_ty, domain_ty, state_step_om_ty] @jitclass(state_spec) class state_object: @@ -56,6 +60,7 @@ def __init__(self, num_ops=5000): self.hsp_segments = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) self.ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) self.ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) + self.state_step_om = "disabled" self.state_step_hydr = "disabled" self.model_root_name = "" self.operation = "" @@ -66,7 +71,9 @@ def __init__(self, num_ops=5000): # Note: in the type declaration above we are alloweed to use the shortened form # op_tokens = int32(zeros((1,64))) # but in jited class that throws an error and we have to use the - # form op_tokens.astype(int32) to do the type cast + # form + # op_tokens.astype(int32) + # to do the type cast op_tokens = zeros( (num_ops,64) ) self.op_tokens = op_tokens.astype(int32) op_exec_lists = zeros( (num_ops,1024) ) @@ -138,7 +145,7 @@ def state_add_ts(state, var_path, default_value=0.0, debug=False): 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 + zeros(om_operations["model_data"]["steps"]), default_value ) return var_ix @@ -177,6 +184,7 @@ def state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager): 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 @@ -207,6 +215,10 @@ def state_init_hsp2(state, opseq, activities): segid = set_state( state.state_ix, state.state_paths, seg_path, 0.0 ) + activity_path = seg_path + "/" + activity + activity_id = set_state( + state.state_ix, state.state_paths, activity_path, 0.0 + ) ep_list = [] if activity == "HYDR": state_context_hsp2(state, operation, segment, activity) @@ -224,7 +236,14 @@ def state_init_hsp2(state, opseq, activities): op_exec_list = model_domain_dependencies( state, state.domain, ep_list, True ) - state.op_exec_lists[segid] = op_exec_list + """ + Note: the domain is just the path to the entity that has the properties, and the + properties (variables) in hsp* are unique, in that there are no duplicate + names between areas like HYDR and PQUAL etc. So, they are properties on the + RCHRES or PERLND etc. The actual operations that are triggered ARE specific + to the activity, so the path to save these operations should reflect the activity + """ + state.op_exec_lists[activity_id] = op_exec_list def state_load_dynamics_hsp2(state, io_manager, siminfo): # Load any dynamic components if present, and store variables on objects diff --git a/tests/testcbp/HSP2results/check_endpoint_ts.py b/tests/testcbp/HSP2results/check_endpoint_ts.py index f42e1d19..e768573d 100644 --- a/tests/testcbp/HSP2results/check_endpoint_ts.py +++ b/tests/testcbp/HSP2results/check_endpoint_ts.py @@ -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 643967b4..fe00147e 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -43,9 +43,9 @@ ) # 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 -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} ) From f0399e2d008439b6c7bf372dad43ff4fd8e29a19 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 12:59:34 -0400 Subject: [PATCH 007/378] added test uci --- tests/testcbp/HSP2results/JL1_6562_6560.uci | 261 ++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 tests/testcbp/HSP2results/JL1_6562_6560.uci 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 From 01c9cf5f2f395aeb399cca7048db34803a2ebd10 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 13:04:01 -0400 Subject: [PATCH 008/378] not using make_class_spec yet --- src/hsp2/state/state.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 9eba1527..597a1c54 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -10,7 +10,7 @@ import os import importlib.util import sys -from hsp2.hsp2.utilities import make_class_spec +#from hsp2.hsp2.utilities import make_class_spec # Define the complex datatypes diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index fe00147e..7eaf2bbc 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -7,8 +7,10 @@ from hsp2.hsp2.om import * from hsp2.hsp2io.hdf import HDF5 from hsp2.hsp2io.io import IOManager +from hsp2.hsp2tools.readUCI import * fpath = "./tests/testcbp/HSP2results/JL1_6562_6560.h5" +ucipath = "./tests/testcbp/HSP2results/JL1_6562_6560.uci" # try also: # fpath = './tests/testcbp/HSP2results/JL1_6562_6560.h5' # sometimes when testing you may need to close the file, so try: @@ -16,7 +18,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: From c1f5a778afd3c8c64e421edf6069144ee1e2f3a0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 13:07:26 -0400 Subject: [PATCH 009/378] not using tindex yet --- src/hsp2/state/state.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 597a1c54..01297d7f 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -16,8 +16,9 @@ # Define the complex datatypes state_ix = npasarray(zeros(1), dtype="float64") model_exec_list = npasarray(zeros(1), dtype="int64") -# Create a sample tindex for typing -tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) +# TBD: Create a sample tindex for typing +#tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) +#tindex_ty = ('tindex', typeof(tindex)) op_tokens = int32(zeros((1,64))) op_exec_lists = int32(zeros((1,1024))) # note: tested 32-bit key and saw absolutely no improvement, so go with 64 bit @@ -27,7 +28,6 @@ ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) state_paths_ty = ('state_paths', typeof(state_paths)) -tindex_ty = ('tindex', typeof(tindex)) model_exec_list_ty = ('model_exec_list', typeof(model_exec_list)) hsp_segments_ty = ('hsp_segments', typeof(hsp_segments)) op_tokens_ty = ('op_tokens', typeof(op_tokens)) From 9d6b55e797b0eebdda9740126e2fcc688be04591 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 13:11:12 -0400 Subject: [PATCH 010/378] fix bad copy/paste --- src/hsp2/hsp2/om_model_object.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 17e4c732..16f84221 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -508,12 +508,14 @@ 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_ix, self.state.dict_ix, - self.state_ixts_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) From 6e04ba7a5aec44f7f74f5ad9eb78112e2435745b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 13:13:07 -0400 Subject: [PATCH 011/378] fix bad copy/paste --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 16f84221..8e93fc39 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -515,7 +515,7 @@ def step(self, step): self.state_ix, self.state.dict_ix, self.state.state_ix, - self.state.ts_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) From 652cb3c1ab8196b0541bbc99518cdff48110b477 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 20 Oct 2025 13:16:40 -0400 Subject: [PATCH 012/378] remove deleted function call --- src/hsp2/hsp2/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 1ce99556..7d7dd8b0 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -19,7 +19,6 @@ ) 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, From dad900620adf3fd89bec9dae65ea527316804b5a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 13:41:51 -0400 Subject: [PATCH 013/378] put a ouple spoofy specacts in PL1 --- tests/testcbp/HSP2results/PL3_5250_0001.uci | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.uci b/tests/testcbp/HSP2results/PL3_5250_0001.uci index 0f9de5ad..ba530527 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.uci +++ b/tests/testcbp/HSP2results/PL3_5250_0001.uci @@ -225,6 +225,10 @@ PLTGEN 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 From ca3ea43fe69f818d339784ed5b36d776f00a9c6e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 13:52:25 -0400 Subject: [PATCH 014/378] fixed type typo --- src/hsp2/state/state.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 01297d7f..ae42d27a 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -38,7 +38,7 @@ # 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 state_step_hydr_ty = ('state_step_hydr', types.unicode_type) -state_step_om_ty = ('state_step_om_ty', types.unicode_type) +state_step_om_ty = ('state_step_om', types.unicode_type) operation_ty = ('operation', types.unicode_type) segment_ty = ('segment', types.unicode_type) activity_ty = ('activity', types.unicode_type) diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 7eaf2bbc..e2b8cd21 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -4,13 +4,16 @@ import numpy from hsp2.hsp2.main import * +from hsp2.state.state import * from hsp2.hsp2.om import * from hsp2.hsp2io.hdf import HDF5 from hsp2.hsp2io.io import IOManager from hsp2.hsp2tools.readUCI import * -fpath = "./tests/testcbp/HSP2results/JL1_6562_6560.h5" -ucipath = "./tests/testcbp/HSP2results/JL1_6562_6560.uci" +fpath = "./tests/testcbp/HSP2results/PL3_5250_0001.h5" +ucipath = "./tests/testcbp/HSP2results/PL3_5250_0001.uci" +uci = readUCI(ucipath, fpath) + # try also: # fpath = './tests/testcbp/HSP2results/JL1_6562_6560.h5' # sometimes when testing you may need to close the file, so try: @@ -25,8 +28,8 @@ # - 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 = state_object() +om_operations = om_init_state(state) state["specactions"] = uci_obj.specactions # stash the specaction dict in state state_siminfo_hsp2(uci_obj, siminfo) From 7244160f0e9791b7abbfde52974b0d9feccf2593 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 13:59:01 -0400 Subject: [PATCH 015/378] added tindex --- src/hsp2/state/state.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ae42d27a..b9baf833 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -17,8 +17,8 @@ state_ix = npasarray(zeros(1), dtype="float64") model_exec_list = npasarray(zeros(1), dtype="int64") # TBD: Create a sample tindex for typing -#tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) -#tindex_ty = ('tindex', typeof(tindex)) +tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) +tindex_ty = ('tindex', typeof(tindex.to_numpy())) op_tokens = int32(zeros((1,64))) op_exec_lists = int32(zeros((1,1024))) # note: tested 32-bit key and saw absolutely no improvement, so go with 64 bit @@ -50,7 +50,8 @@ state_spec = [state_paths_ty, state_ix_ty, ts_paths_ty, ts_ix_ty, model_root_name_ty, state_step_hydr_ty, hsp2_local_py_ty, hsp_segments_ty, op_tokens_ty, op_exec_lists_ty, model_exec_list_ty, - operation_ty, segment_ty, activity_ty, domain_ty, state_step_om_ty] + operation_ty, segment_ty, activity_ty, domain_ty, state_step_om_ty, + tindex_ty] @jitclass(state_spec) class state_object: From dd8bc7994bb5ef8fd65fa9e0fb780b28c11b2a55 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 14:04:58 -0400 Subject: [PATCH 016/378] fixed siminfo state step method reference --- src/hsp2/state/state.py | 6 +++--- tests/testcbp/HSP2results/check_equation.py | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index b9baf833..0bc75154 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -249,7 +249,7 @@ def state_init_hsp2(state, opseq, activities): 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.state_step_hydr = siminfo.state_step_hydr # enabled or disabled + state.state_step_hydr = siminfo['state_step_hydr'] # enabled or disabled state.hsp2_local_py = load_dynamics(io_manager, siminfo) # Stores the actual function in state def state_load_hdf5_components( @@ -502,9 +502,9 @@ def load_dynamics(io_manager, siminfo): # see if there is a code module with custom python # print("Looking for SPECL with custom python code ", (fbase + ".py")) hsp2_local_py = dynamic_module_import(fbase, fbase + ".py", "hsp2_local_py") - siminfo.state_step_hydr = "disabled" + siminfo['state_step_hydr'] = "disabled" if "state_step_hydr" in dir(hsp2_local_py): - siminfo.state_step_hydr = "enabled" + siminfo['state_step_hydr'] = "enabled" print("state_step_hydr function defined, using custom python code") else: # print("state_step_hydr function not defined. Using default") diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index e2b8cd21..aec67f8f 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -29,10 +29,9 @@ # - finally stash specactions in state, not domain (segment) dependent so do it once # now load state and the special actions state = state_object() -om_operations = om_init_state(state) -state["specactions"] = uci_obj.specactions # stash the specaction dict in state +om_operations = om_init_state() -state_siminfo_hsp2(uci_obj, siminfo) +state_siminfo_hsp2(state, uci_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) From 0701235c6f633877bdabc328d515bf44bb1fdfc8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 20 Oct 2025 14:10:19 -0400 Subject: [PATCH 017/378] set the state step local code before trying to reference it --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 0bc75154..e9e3670c 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -249,8 +249,8 @@ def state_init_hsp2(state, opseq, activities): 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.state_step_hydr = siminfo['state_step_hydr'] # enabled or disabled 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( io_manager, From 10eec90c130e832e90e65bcac31b2319e0ab7e8d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 09:56:40 -0400 Subject: [PATCH 018/378] must shape the list to match the dimensions of the state object --- src/hsp2/hsp2/om.py | 6 +- src/hsp2/state/state.py | 64 +++++++++++++++------ tests/testcbp/HSP2results/check_equation.py | 13 +++++ 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index f00f4dbb..6317e658 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -246,10 +246,6 @@ def state_om_model_run_prep(state, om_operations, siminfo): # 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 @@ -623,7 +619,7 @@ def model_input_dependencies(state, exec_list, model_object_cache, only_runnable 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): """ 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 diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index e9e3670c..6c82c041 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -26,6 +26,7 @@ hsp_segments = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) +last_id_ty = ('last_id', types.int64) state_paths_ty = ('state_paths', typeof(state_paths)) model_exec_list_ty = ('model_exec_list', typeof(model_exec_list)) @@ -47,7 +48,7 @@ op_exec_lists_ty = ('op_exec_lists', typeof(op_exec_lists)) # Combine these into a spec to create the class -state_spec = [state_paths_ty, state_ix_ty, ts_paths_ty, ts_ix_ty, +state_spec = [state_paths_ty, state_ix_ty, ts_paths_ty, ts_ix_ty, last_id_ty, model_root_name_ty, state_step_hydr_ty, hsp2_local_py_ty, hsp_segments_ty, op_tokens_ty, op_exec_lists_ty, model_exec_list_ty, operation_ty, segment_ty, activity_ty, domain_ty, state_step_om_ty, @@ -68,6 +69,7 @@ def __init__(self, num_ops=5000): self.segment = "" self.activity = "" self.domain = "" + self.last_id = 0 self.hsp2_local_py = False # Note: in the type declaration above we are alloweed to use the shortened form # op_tokens = int32(zeros((1,64))) @@ -82,6 +84,40 @@ def __init__(self, num_ops=5000): model_exec_list = zeros(num_ops) self.model_exec_list = model_exec_list.astype(types.int64) return + + def append_state(self, var_value): + val_ix = self.last_id + 1 # next ix value + self.state_ix[val_ix] = var_value + self.last_id = val_ix + return(val_ix) + + 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 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[var_path] = var_ix + else: + var_ix = self.get_state_ix(var_path) + self.state_ix[var_ix] = var_value + 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 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) + @@ -198,28 +234,24 @@ def state_context_hsp2(state, operation, segment, activity): state.activity = activity # give shortcut to state path for the upcoming function # insure that there is a model object container - seg_name = op_path_name(operation, segment) + seg_name = operation + "_" + segment seg_path = "/STATE/" + state.model_root_name + "/" + seg_name 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_init_hsp2(state, opseq, activities): +def state_init_hsp2(state, opseq, activities, om_operations): # 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 = op_path_name(operation, segment) + seg_name = operation + "_" + segment seg_path = "/STATE/" + state.model_root_name + "/" + seg_name - segid = set_state( - state.state_ix, state.state_paths, seg_path, 0.0 - ) + state.set_state(seg_path, 0.0) activity_path = seg_path + "/" + activity - activity_id = set_state( - state.state_ix, state.state_paths, activity_path, 0.0 - ) + activity_id = state.set_state(activity_path, 0.0) ep_list = [] if activity == "HYDR": state_context_hsp2(state, operation, segment, activity) @@ -235,7 +267,7 @@ def state_init_hsp2(state, opseq, activities): ep_list = rqual_init_ix(state, state.domain) # Register list of elements to execute if any op_exec_list = model_domain_dependencies( - state, state.domain, ep_list, True + om_operations, state, state.domain, ep_list, True ) """ Note: the domain is just the path to the entity that has the properties, and the @@ -244,7 +276,7 @@ def state_init_hsp2(state, opseq, activities): RCHRES or PERLND etc. The actual operations that are triggered ARE specific to the activity, so the path to save these operations should reflect the activity """ - state.op_exec_lists[activity_id] = op_exec_list + state.op_exec_lists[activity_id] = np.pad(op_exec_list,(0,state.op_exec_lists.shape[1] - len(op_exec_list))) def state_load_dynamics_hsp2(state, io_manager, siminfo): # Load any dynamic components if present, and store variables on objects @@ -331,7 +363,7 @@ def hydr_init_ix(state, domain): 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) + hydr_ix[i] = state.set_state(var_path, 0.0) return hydr_ix @@ -347,7 +379,7 @@ def sedtrn_init_ix(state, domain): 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 @@ -362,7 +394,7 @@ def sedmnt_init_ix(state, domain): sedmnt_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) 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 @@ -389,7 +421,7 @@ def rqual_init_ix(state, domain): rqual_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) 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 diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index aec67f8f..d6f1fcee 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -35,6 +35,19 @@ # 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, om_operations) +# - finally stash specactions in state, not domain (segment) dependent so do it once +om_operations = om_init_state() # set up operational model specific containers +specl_load_om(om_operations, specactions) # load traditional special actions +state_load_dynamics_om( + 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, om_operations, 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) From c79e8554a8e7e88a13ba755d598e52cc5696d860 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 12:59:22 -0400 Subject: [PATCH 019/378] include deps function --- src/hsp2/hsp2/om.py | 29 +++++++++++++++++++++++++++++ src/hsp2/state/state.py | 20 +------------------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 6317e658..a90cb660 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -619,6 +619,35 @@ def model_input_dependencies(state, exec_list, model_object_cache, only_runnable return mello +def hsp2_domain_dependencies(state, opseq, activities, om_operations): + # 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 = [] + if activity == "HYDR": + ep_list = hydr_init_ix(state, state.domain) + elif activity == "SEDTRN": + ep_list = sedtrn_init_ix(state, state.domain) + elif activity == "SEDMNT": + ep_list = sedmnt_init_ix(state, state.domain) + elif activity == "RQUAL": + ep_list = rqual_init_ix(state, state.domain) + # Register list of elements to execute if any + op_exec_list = model_domain_dependencies( + om_operations, state, state.domain, ep_list, True + ) + # register the dependencies for each activity so we can load once here + # then just iterate through them at runtime without re-querying + state.op_exec_lists[activity_id] = np.pad(op_exec_list,(0,state.op_exec_lists.shape[1] - len(op_exec_list))) + + def model_domain_dependencies(om_operations, state, domain, ep_list, only_runnable=False): """ Given an hdf5 style path to a domain, and a list of variable endpoints in that domain, diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 6c82c041..f89e6183 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -250,33 +250,15 @@ def state_init_hsp2(state, opseq, activities, om_operations): seg_name = operation + "_" + segment seg_path = "/STATE/" + state.model_root_name + "/" + seg_name state.set_state(seg_path, 0.0) - activity_path = seg_path + "/" + activity - activity_id = state.set_state(activity_path, 0.0) - ep_list = [] if activity == "HYDR": state_context_hsp2(state, operation, segment, activity) - ep_list = hydr_init_ix(state, state.domain) elif activity == "SEDTRN": state_context_hsp2(state, operation, segment, activity) - ep_list = sedtrn_init_ix(state, state.domain) elif activity == "SEDMNT": state_context_hsp2(state, operation, segment, activity) - ep_list = sedmnt_init_ix(state, state.domain) elif activity == "RQUAL": state_context_hsp2(state, operation, segment, activity) - ep_list = rqual_init_ix(state, state.domain) - # Register list of elements to execute if any - op_exec_list = model_domain_dependencies( - om_operations, state, state.domain, ep_list, True - ) - """ - Note: the domain is just the path to the entity that has the properties, and the - properties (variables) in hsp* are unique, in that there are no duplicate - names between areas like HYDR and PQUAL etc. So, they are properties on the - RCHRES or PERLND etc. The actual operations that are triggered ARE specific - to the activity, so the path to save these operations should reflect the activity - """ - state.op_exec_lists[activity_id] = np.pad(op_exec_list,(0,state.op_exec_lists.shape[1] - len(op_exec_list))) + def state_load_dynamics_hsp2(state, io_manager, siminfo): # Load any dynamic components if present, and store variables on objects From e29b89bd1aa7a7f478daecaf096ac09b2d701ff3 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 13:01:22 -0400 Subject: [PATCH 020/378] include init functions from state --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index a90cb660..e50df022 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -10,7 +10,7 @@ import time from numpy import zeros from numba import njit # import the types -from hsp2.state.state import append_state, get_ix_path +from hsp2.state.state import append_state, get_ix_path, hydr_init_ix, sedtrn_init_ix, sedmnt_init_ix, rqual_init_ix def get_exec_order(model_exec_list, var_ix): From b4eae086938c162cfd8bd336fa06796c104e82c4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 13:16:43 -0400 Subject: [PATCH 021/378] include model_data and rearrange testing sequence --- src/hsp2/hsp2/om.py | 22 ++++++++++----------- tests/testcbp/HSP2results/check_equation.py | 5 +++-- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index e50df022..99766280 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -142,11 +142,10 @@ def om_init_state(): # Grab globals from state for easy handling op_tokens, model_object_cache = init_om_dicts() om_operations = {} - om_operations["op_tokens"], om_operations["model_object_cache"], om_operations["model_exec_list"] = ( - op_tokens, - model_object_cache, - [], - ) + 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) @@ -631,18 +630,17 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations): activity_path = seg_path + "/" + activity activity_id = state.set_state(activity_path, 0.0) ep_list = [] + print("Getting init_ix for", seg_path, activity) if activity == "HYDR": - ep_list = hydr_init_ix(state, state.domain) + ep_list = hydr_init_ix(state, seg_path) elif activity == "SEDTRN": - ep_list = sedtrn_init_ix(state, state.domain) + ep_list = sedtrn_init_ix(state, seg_path) elif activity == "SEDMNT": - ep_list = sedmnt_init_ix(state, state.domain) + ep_list = sedmnt_init_ix(state, seg_path) elif activity == "RQUAL": - ep_list = rqual_init_ix(state, state.domain) + 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, state.domain, ep_list, True - ) + op_exec_list = model_domain_dependencies( om_operations, state, seg_path, ep_list, True) # register the dependencies for each activity so we can load once here # then just iterate through them at runtime without re-querying state.op_exec_lists[activity_id] = np.pad(op_exec_list,(0,state.op_exec_lists.shape[1] - len(op_exec_list))) diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index d6f1fcee..ac133065 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -6,6 +6,7 @@ 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 * @@ -40,12 +41,12 @@ # before loading dynamic components that may reference them state_init_hsp2(state, opseq, activities, om_operations) # - finally stash specactions in state, not domain (segment) dependent so do it once -om_operations = om_init_state() # set up operational model specific containers -specl_load_om(om_operations, specactions) # load traditional special actions +specl_load_om(om_operations, uci_obj.specactions) # load traditional special actions state_load_dynamics_om( state, io_manager, siminfo, om_operations ) # operational model for custom python # finalize all dynamically loaded components and prepare to run the model +hsp2_domain_dependencies(state, opseq, activities, om_operations) state_om_model_run_prep(state, om_operations, siminfo) # Iterate through all segments and add crucial paths to state From 321bf7ea7e3299116e4189b92ba24248c61ad3e8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 13:36:29 -0400 Subject: [PATCH 022/378] find model_root_name in state (dubious, but for now ok) --- src/hsp2/hsp2/om.py | 56 +++++++++++---------- tests/testcbp/HSP2results/check_equation.py | 3 +- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 99766280..12d00da9 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -168,7 +168,7 @@ 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 om_operations.keys(): model_root_object = ModelObject( - om_operations["model_root_name"], False, {}, state + state["model_root_name"], False, {}, state ) # we give this no name so that it does not interfer with child paths like timer, year, etc (i.e. /STATE/year, ...) om_operations["model_root_object"] = model_root_object # set up the timer as the first element @@ -618,7 +618,34 @@ def model_input_dependencies(state, exec_list, model_object_cache, only_runnable return mello -def hsp2_domain_dependencies(state, opseq, activities, om_operations): +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 + Returns them as a sorted list of index values suitable as a model_exec_list + """ + mello = [] + 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.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) + 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(): @@ -640,35 +667,12 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations): 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) + op_exec_list = model_domain_dependencies( om_operations, state, seg_path, ep_list, True, debug) # register the dependencies for each activity so we can load once here # then just iterate through them at runtime without re-querying state.op_exec_lists[activity_id] = np.pad(op_exec_list,(0,state.op_exec_lists.shape[1] - len(op_exec_list))) -def model_domain_dependencies(om_operations, state, domain, ep_list, only_runnable=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 - Returns them as a sorted list of index values suitable as a model_exec_list - """ - mello = [] - for ep in ep_list: - mel = [] - mtl = [] - # 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 om_operations["model_object_cache"].keys(): - 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) - if only_runnable == True: - mello = mellorun - return mello - - 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) diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index ac133065..ca36cfe8 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -46,8 +46,9 @@ state, io_manager, siminfo, om_operations ) # operational model for custom python # finalize all dynamically loaded components and prepare to run the model -hsp2_domain_dependencies(state, opseq, activities, om_operations) state_om_model_run_prep(state, om_operations, siminfo) +# Set up order of execution +hsp2_domain_dependencies(state, opseq, activities, om_operations, True) # Iterate through all segments and add crucial paths to state # before loading dynamic components that may reference them From db6bb1a0ef3afacbf378c9a4dc5c80a5d837b690 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 13:58:31 -0400 Subject: [PATCH 023/378] remnant state non-object calls --- src/hsp2/hsp2/om.py | 9 +---- src/hsp2/hsp2/om_model_linkage.py | 18 +++------ src/hsp2/hsp2/om_model_object.py | 65 +++++++++++-------------------- 3 files changed, 29 insertions(+), 63 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 12d00da9..cb5c6668 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -168,7 +168,7 @@ 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 om_operations.keys(): model_root_object = ModelObject( - state["model_root_name"], False, {}, state + state.model_root_name, False, {}, state ) # we give this no name so that it does not interfer with child paths like timer, year, etc (i.e. /STATE/year, ...) om_operations["model_root_object"] = model_root_object # set up the timer as the first element @@ -240,14 +240,7 @@ def state_om_model_run_prep(state, om_operations, siminfo): ) 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) - # print("Operational model status:", state['state_step_om']) if len(model_exec_list) > 0: - # pass print( "op_tokens has", len(op_tokens), diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index 6f662106..f69b813f 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 @@ -139,9 +139,7 @@ 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] if write_path == None: @@ -187,9 +185,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 +193,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: diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 8e93fc39..22719cea 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -31,7 +31,7 @@ class ModelObject: 100, ] # 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, model_object_cache=None): self.name = name self.handle_deprecated_args(name, container, model_props, state) @@ -40,13 +40,11 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob 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 type(state) == 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." + "Error: State object must be passed to root object. ", + name + " cannot be created. See state::init_state_dicts()", ) @@ -80,7 +78,7 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob # 100 - SpecialAction, 101 - UVNAME, 102 - UVQUAN, 103 - DISTRB self.register_path() # note this registers the path AND stores the object in model_object_cache self.parse_model_props(model_props) - + def handle_deprecated_args(self, name, container, model_props, state): # Handle old deprecated format for Register, Constant and Variable state_path = False @@ -98,7 +96,7 @@ def handle_deprecated_args(self, name, container, model_props, state): print( "WARNING: deprecated 4th argument for ModelObject. Use: [Model class](name, container, model_props, state)" ) - + @staticmethod def required_properties(): # returns a list or minimum properties to create. @@ -107,7 +105,7 @@ def required_properties(): # req_props = super(DataMatrix, DataMatrix).required_properties() req_props = ["name"] return req_props - + @staticmethod def make_op_tokens(num_ops=5000): if ModelObject.ops_data_type == "ndarray": @@ -117,7 +115,7 @@ def make_op_tokens(num_ops=5000): else: op_tokens = Dict.empty(key_type=types.int64, value_type=types.i8[:]) return op_tokens - + @staticmethod def runnable_op_list(op_tokens, meo, debug=False): # only return those objects that do something at runtime @@ -134,7 +132,7 @@ def runnable_op_list(op_tokens, meo, debug=False): rmeo.append(ix) rmeo = asarray(rmeo, dtype="i8") return rmeo - + @staticmethod def model_format_ops(ops): if ModelObject.ops_data_type == "ndarray": @@ -144,12 +142,12 @@ def model_format_ops(ops): else: ops = asarray(ops, dtype="i8") return ops - + def format_ops(self): # this can be sub-classed if needed, but should not be since it is based on the ops_data_type # See ModelObject.model_format_ops() return ModelObject.model_format_ops(self.ops) - + @classmethod def check_properties(cls, model_props): # this is for pre-screening properties for validity in model creation routines @@ -160,13 +158,13 @@ def check_properties(cls, model_props): if len(matching_props) < len(req_props): return False return True - + def handle_path_aliases(self, object_path): if not (self.container == False): object_path = object_path.replace("[parent]", self.container.state_path) object_path = object_path.replace("[self]", self.state_path) return object_path - + def handle_inputs(self, model_props): if "inputs" in model_props.keys(): for i_pair in model_props["inputs"]: @@ -174,7 +172,7 @@ def handle_inputs(self, model_props): i_target = i_pair[1] i_target = handle_path_aliases(i_target) self.add_input(i_name, i_target) - + def handle_prop(self, model_props, prop_name, strict=False, default_value=None): # this checks to see if the prop is in dict with value form, or just a value # strict = True causes an exception if property is missing from model_props dict @@ -197,7 +195,7 @@ def handle_prop(self, model_props, prop_name, strict=False, default_value=None): if (prop_val == None) and not (default_value == None): prop_val = default_value return prop_val - + def parse_model_props(self, model_props, strict=False): # sub-classes will allow an create argument "model_props" and handle them here. # - subclasses should insure that they call super().parse_model_props() or include all code below @@ -207,7 +205,7 @@ def parse_model_props(self, model_props, strict=False): self.handle_inputs(model_props) self.model_props_parsed = model_props return True - + def set_state(self, set_value): var_ix = set_state( self.state_ix, @@ -216,20 +214,20 @@ def set_state(self, set_value): 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_paths = state_paths self.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. # note: "with" statement helps prevent unclosed resources, see: https://www.geeksforgeeks.org/with-statement-in-python/ with HDFStore(hdfname, mode="a") as store: dummy_var = True - + 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 @@ -249,7 +247,7 @@ def make_paths(self, base_path=False): self.state_path = base_path["STATE"] + self.name self.attribute_path = base_path["OBJECTS"] + self.name return self.state_path - + def get_state(self, var_name=False): if var_name == False: return self.state_ix[self.ix] @@ -261,7 +259,7 @@ def get_state(self, var_name=False): if var_ix == False: return False return self.state_ix[var_ix] - + def get_exec_order(self, var_name=False): if var_name == False: var_ix = self.ix @@ -272,7 +270,7 @@ def get_exec_order(self, var_name=False): ) exec_order = get_exec_order(self.self.model_exec_list, var_ix) return exec_order - + def get_tindex(self): timer = self.get_object('timer') tindex = self.state.dict_ix[timer.ix] @@ -284,7 +282,7 @@ def get_object(self, var_name=False): else: var_path = self.find_var_path(var_name) return self.model_object_cache[var_path] - + def find_var_path(self, var_name, local_only=False): # check local inputs for name if type(var_name) == str: @@ -307,7 +305,6 @@ def find_var_path(self, var_name, local_only=False): # return self.state['state_paths'][var_name] return var_name return False - def constant_or_path(self, keyname, keyval, trust=False): if is_float_digit(keyval): # we are given a constant value, not a variable reference @@ -319,7 +316,6 @@ def constant_or_path(self, keyname, keyval, trust=False): else: kix = self.add_input(keyname, keyval, 2, trust) return kix - def register_path(self): # initialize the path variable if not already set # print("register_path called for", self.name, "with state_path", self.state_path) @@ -340,7 +336,6 @@ def register_path(self): # print("Adding", self.name, "as input to", self.container.name) return self.container.add_input(self.name, self.state_path, 1, True) return self.ix - def add_input(self, var_name, var_path, input_type=1, trust=False): # this will add to the inputs, but also insure that this # requested path gets added to the state/exec stack via an input object if it does @@ -358,9 +353,7 @@ def add_input(self, var_name, var_path, input_type=1, trust=False): # 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_ix, self.state_paths, found_path - ) + var_ix = self.state.get_state_ix(found_path) if var_ix == False: if trust == False: raise Exception( @@ -390,14 +383,12 @@ def add_input(self, var_name, var_path, input_type=1, trust=False): # to find the data in /STATE/RCHRES_R001/Qin ??? It is redundant data and writing # but matches a complete data model and prevents stale data? return self.inputs_ix[var_name] - def add_object_input(self, var_name, var_object, link_type=1): # See above for details. # this adds an object as a link to another object self.inputs[var_name] = var_object.state_path self.inputs_ix[var_name] = var_object.ix return self.inputs_ix[var_name] - def create_parent_var(self, parent_var_name, source): # see decision points: https://github.com/HARPgroup/HSPsquared/issues/78 # This is used when an object sets an additional property on its parent @@ -410,7 +401,6 @@ def create_parent_var(self, parent_var_name, source): self.container.add_input(parent_var_name, source, 1, False) elif isinstance(source, ModelObject): self.container.add_object_input(parent_var_name, source, 1) - 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) @@ -419,12 +409,10 @@ def insure_path(self, var_path): self.state_ix, self.state_paths, 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] - def find_paths(self): # Note: every single piece of data used by objects, even constants, are resolved to a PATH in the hdf5 # find_paths() is called to insure that all of these can be found, and then, are added to inputs/inputs_ix @@ -440,7 +428,6 @@ def find_paths(self): # and should also handle deciding if this is a constant, like a numeric value # or a variable data and should handle them accordingly return True - def insure_register( self, var_name, @@ -475,7 +462,6 @@ def insure_register( else: var_register = self.model_object_cache[register_path] return var_register - def tokenize(self): # renders tokens for high speed execution if self.paths_found == False: @@ -488,7 +474,6 @@ def tokenize(self): + "Tokens cannot be generated until method '.find_paths()' is run for all model objects ... process terminated. (see function `model_path_loader(model_object_cache)`)" ) self.ops = [self.optype, self.ix] - 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. @@ -503,7 +488,6 @@ def add_op_tokens(self): + "). " ) self.state.op_tokens[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 @@ -519,7 +503,6 @@ def step(self, step): step, ) # step_model({self.state['op_tokens'][self.ix]}, self.state['state_ix'], self.state['dict_ix'], self.state['ts_ix'], step) - def finish(self): # Do end of model activities here # we do this in the object context if it involves IO and other complex actions @@ -542,7 +525,6 @@ def __init__(self, name, container=False, model_props=None, state=None): var_ix = self.set_state(float(value)) self.paths_found = True # self.state['state_ix'][self.ix] = self.default_value - def required_properties(): req_props = super(ModelVariable, ModelVariable).required_properties() req_props.extend(["value"]) @@ -573,7 +555,6 @@ def __init__(self, name, container=None, model_props=False, state=False): super(ModelRegister, self).__init__(name, container, model_props, state) self.optype = 12 # # self.state['state_ix'][self.ix] = self.default_value - def required_properties(): req_props = super(ModelVariable, ModelVariable).required_properties() req_props.extend(["value"]) From fa5612104744d33aa6d2ebcd701dc381f2dac09f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 14:31:47 -0400 Subject: [PATCH 024/378] fixed setting state at model object level --- src/hsp2/hsp2/om_model_object.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 22719cea..2864bcbf 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -253,9 +253,7 @@ def get_state(self, var_name=False): return self.state_ix[self.ix] else: var_path = self.find_var_path(var_name) - var_ix = get_state_ix( - self.state_ix, self.state_paths, var_path - ) + var_ix = self.state.get_state_ix(var_path) if var_ix == False: return False return self.state_ix[var_ix] @@ -321,12 +319,7 @@ 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_ix, - self.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.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 From 4fbfe8cc78db9c17925cec478743eb2b7476644d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 14:37:38 -0400 Subject: [PATCH 025/378] Need tass cache to model root object creation --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index cb5c6668..50061647 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -168,7 +168,7 @@ 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 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, ...) om_operations["model_root_object"] = model_root_object # set up the timer as the first element From ae6020cd58fc0b8a1dd972e512fba0aefc77ff55 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 14:39:11 -0400 Subject: [PATCH 026/378] simtimer does NOT need state object (must get it from parent) --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 50061647..09cc1577 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -176,7 +176,7 @@ def state_om_model_root_object(state, om_operations, siminfo): 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) + timer = SimTimer("timer", model_root_object, timer_props) # add base object for the HSP2 domains and other things already added to state so they can be influenced for seg_path in state.hsp_segments.items(): if seg_path not in om_operations["model_object_cache"].keys(): From 3469e02fcece533bdffec555f77903d164fb4a07 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 14:42:50 -0400 Subject: [PATCH 027/378] dpes state is nOne work? --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 2864bcbf..21ffeb8e 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -40,7 +40,7 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob 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) == None: + 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( From 82d4141cf69c7cd875642a1223dce7ee45abf534 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 14:50:19 -0400 Subject: [PATCH 028/378] superfluous function removed --- src/hsp2/hsp2/om.py | 13 ------------- src/hsp2/hsp2/om_equation.py | 1 - src/hsp2/hsp2/om_model_object.py | 23 ++--------------------- 3 files changed, 2 insertions(+), 35 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 09cc1577..9e51692b 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -12,19 +12,6 @@ from numba import njit # import the types from hsp2.state.state import append_state, get_ix_path, hydr_init_ix, sedtrn_init_ix, sedmnt_init_ix, rqual_init_ix - -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 - - def init_op_tokens(op_tokens, tops, eq_ix): """ Iinitialize the op_tokens Dict diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index be8a9170..a62b3931 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -14,7 +14,6 @@ # 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 diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 21ffeb8e..b2313b9b 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -6,7 +6,7 @@ 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 hsp2.hsp2.om import is_float_digit from pandas import HDFStore from numpy import pad, asarray, zeros, int32 from numba import njit, types @@ -207,20 +207,12 @@ def parse_model_props(self, model_props, strict=False): return True def set_state(self, set_value): - var_ix = set_state( - self.state_ix, - self.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_paths = state_paths - self.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. @@ -258,17 +250,6 @@ def get_state(self, var_name=False): return False return self.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_ix, self.state_paths, var_path - ) - exec_order = get_exec_order(self.self.model_exec_list, var_ix) - return exec_order - def get_tindex(self): timer = self.get_object('timer') tindex = self.state.dict_ix[timer.ix] From 4d1cebeb19b8c47af39801d8a8aaaf924eac36fc Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 14:52:39 -0400 Subject: [PATCH 029/378] fixed another dangling set_state --- src/hsp2/hsp2/om_model_object.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index b2313b9b..76317e9d 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -276,11 +276,11 @@ def find_var_path(self, var_name, local_only=False): if not (self.container == False): return self.container.find_var_path(var_name) # check for root state vars STATE + var_name - if ("/STATE/" + var_name) in self.state_paths.keys(): + if ("/STATE/" + var_name) in self.state.state_paths.keys(): # return self.state['state_paths'][("/STATE/" + var_name)] return "/STATE/" + var_name # check for full paths - if var_name in self.state_paths.keys(): + if var_name in self.state.state_paths.keys(): # return self.state['state_paths'][var_name] return var_name return False @@ -379,9 +379,7 @@ 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_ix, self.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: From 729abd3439d8df405e655b454cf8f2a042aa0d2b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 14:54:19 -0400 Subject: [PATCH 030/378] search ndarray differently --- src/hsp2/hsp2/om_model_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 76317e9d..7e0ab4bc 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -276,11 +276,11 @@ def find_var_path(self, var_name, local_only=False): if not (self.container == False): 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(): + if ("/STATE/" + var_name) in self.state.state_paths: # return self.state['state_paths'][("/STATE/" + var_name)] return "/STATE/" + var_name # check for full paths - if var_name in self.state.state_paths.keys(): + if var_name in self.state.state_paths: # return self.state['state_paths'][var_name] return var_name return False From c4ac725e412b5439a910ecd0574e4213bd756d46 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 15:03:00 -0400 Subject: [PATCH 031/378] update timer state settings --- src/hsp2/hsp2/om_sim_timer.py | 83 ++++++----------------------------- 1 file changed, 13 insertions(+), 70 deletions(-) diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index cb52d330..d0d4b022 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -28,80 +28,23 @@ def __init__(self, name, container, model_props=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, From 9ce025f07fc3c52a140932d4e19acc25aad9c2b7 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 15:19:51 -0400 Subject: [PATCH 032/378] include dict_ix in new object --- src/hsp2/state/state.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index f89e6183..d1a0afba 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -19,6 +19,7 @@ # TBD: Create a sample tindex for typing tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) tindex_ty = ('tindex', typeof(tindex.to_numpy())) +dict_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:, :]) op_tokens = int32(zeros((1,64))) op_exec_lists = int32(zeros((1,1024))) # note: tested 32-bit key and saw absolutely no improvement, so go with 64 bit @@ -33,6 +34,7 @@ hsp_segments_ty = ('hsp_segments', typeof(hsp_segments)) op_tokens_ty = ('op_tokens', typeof(op_tokens)) state_ix_ty = ('state_ix', typeof(state_ix)) +dict_ix_ty = ('dict_ix', typeof(dict_ix)) ts_ix_ty = ('ts_ix', typeof(ts_ix)) ts_paths_ty = ('ts_paths', typeof(ts_paths)) model_root_name_ty = ('model_root_name', types.unicode_type) @@ -52,12 +54,16 @@ model_root_name_ty, state_step_hydr_ty, hsp2_local_py_ty, hsp_segments_ty, op_tokens_ty, op_exec_lists_ty, model_exec_list_ty, operation_ty, segment_ty, activity_ty, domain_ty, state_step_om_ty, - tindex_ty] + tindex_ty, dict_ix_ty] @jitclass(state_spec) class state_object: def __init__(self, num_ops=5000): self.state_ix = zeros(num_ops) + # 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.empty(key_type=types.int64, value_type=types.float64[:, :]) self.state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64) self.hsp_segments = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) self.ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) From 9543fd72034ccb77d0db9d150355b4cb7709e338 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 15:24:50 -0400 Subject: [PATCH 033/378] adapt to new hsp_segments structure --- src/hsp2/hsp2/om.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 9e51692b..05f30b7e 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -165,7 +165,7 @@ def state_om_model_root_object(state, om_operations, siminfo): timer_props["state_path"] = "/STATE/timer" timer = SimTimer("timer", model_root_object, timer_props) # add base object for the HSP2 domains and other things already added to state so they can be influenced - for seg_path in state.hsp_segments.items(): + 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? @@ -173,7 +173,6 @@ def state_om_model_root_object(state, om_operations, siminfo): # Create an object shell for this # 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 - seg_name = seg_path.rsplit('/',1)[-1] segment = ModelObject(seg_name, model_root_object, {}, state) om_operations["model_object_cache"][segment.state_path] = segment From 184a975a26d86280f2357f7608d51be399690484 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 15:39:53 -0400 Subject: [PATCH 034/378] adapt to new hsp_segments structure --- src/hsp2/hsp2/om.py | 2 +- src/hsp2/hsp2/om_model_object.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 05f30b7e..bcb46802 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -173,7 +173,7 @@ def state_om_model_root_object(state, om_operations, siminfo): # Create an object shell for this # 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, {}, state) + segment = ModelObject(seg_name, model_root_object, om_operations["model_object_cache"], state) om_operations["model_object_cache"][segment.state_path] = segment diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 7e0ab4bc..91da539e 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -34,12 +34,6 @@ class ModelObject: 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 state is None: # we must verify that we have a properly formatted state Dictionary, or that our parent does. if self.container == False: @@ -53,6 +47,12 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob 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.container = container # will be a link to another object + 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" From c6de9c9176eb1125f78f8786bb43672fdf6d92a6 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 15:39:57 -0400 Subject: [PATCH 035/378] adapt to new hsp_segments structure --- src/hsp2/hsp2/om.py | 2 +- src/hsp2/hsp2/om_model_object.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index bcb46802..1c6c4a89 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -173,7 +173,7 @@ def state_om_model_root_object(state, om_operations, siminfo): # Create an object shell for this # 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"], state) + segment = ModelObject(seg_name, model_root_object, {}) om_operations["model_object_cache"][segment.state_path] = segment diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 91da539e..5486ac6d 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -297,11 +297,12 @@ def constant_or_path(self, keyname, keyval, trust=False): return kix def register_path(self): # initialize the path variable if not already set - # print("register_path called for", self.name, "with state_path", self.state_path) + 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 = 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 + 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. From 318ed07fa0dbc10154061d8a44ad0894dc0e8e1b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 15:44:28 -0400 Subject: [PATCH 036/378] adapt to new load container a bit earlier --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 5486ac6d..ecb6d6ef 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -34,6 +34,7 @@ class ModelObject: def __init__(self, name, container=False, model_props=None, state=None, model_object_cache=None): self.name = name + self.container = container # will be a link to another object if state is None: # we must verify that we have a properly formatted state Dictionary, or that our parent does. if self.container == False: @@ -51,7 +52,6 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob # 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) # Local properties self.model_props_parsed = {} # a place to stash parse record for debugging From 8548766ba2962863d754aa8daba436f342d87856 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 16:16:57 -0400 Subject: [PATCH 037/378] load the cache from container separately if state is passed --- src/hsp2/hsp2/om_model_object.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index ecb6d6ef..1effcbf3 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -45,6 +45,15 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob ) 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? From 8ee43c9a9de01d05e443d862766fd204744050b5 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 16:21:53 -0400 Subject: [PATCH 038/378] fix object finder for specl --- src/hsp2/hsp2/om_special_action.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_special_action.py b/src/hsp2/hsp2/om_special_action.py index fa8f4133..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.om_operations["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.om_operations["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 From 2717daca1ce583c7a097a594528ce6a8a74d329d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 16:26:58 -0400 Subject: [PATCH 039/378] advertise fixed num ops for state to use in formatting --- src/hsp2/hsp2/om.py | 2 +- src/hsp2/state/state.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 1c6c4a89..ec2a5ce7 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -200,7 +200,7 @@ def state_om_model_run_prep(state, om_operations, 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 + 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 diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index d1a0afba..aaf0d2e3 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -28,6 +28,7 @@ ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) last_id_ty = ('last_id', types.int64) +num_ops_ty = ('num_ops', types.int64) state_paths_ty = ('state_paths', typeof(state_paths)) model_exec_list_ty = ('model_exec_list', typeof(model_exec_list)) @@ -54,11 +55,12 @@ model_root_name_ty, state_step_hydr_ty, hsp2_local_py_ty, hsp_segments_ty, op_tokens_ty, op_exec_lists_ty, model_exec_list_ty, operation_ty, segment_ty, activity_ty, domain_ty, state_step_om_ty, - tindex_ty, dict_ix_ty] + tindex_ty, dict_ix_ty, num_ops_ty] @jitclass(state_spec) class state_object: def __init__(self, num_ops=5000): + self.num_ops = num_ops self.state_ix = zeros(num_ops) # 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 From 0a3c2e1c1125773e559ae2b73e9a89313b221229 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 21 Oct 2025 16:28:33 -0400 Subject: [PATCH 040/378] do not redundantly set op_tokens --- src/hsp2/hsp2/om.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index ec2a5ce7..de681578 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -199,11 +199,11 @@ def state_om_model_run_prep(state, om_operations, siminfo): 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( - len(model_root_object.state.state_ix) - ) + #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 + #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) @@ -221,9 +221,9 @@ def state_om_model_run_prep(state, om_operations, siminfo): 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? - ) + #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" if len(model_exec_list) > 0: From cab26af5213247cf7da5cc3df4d6268b29d934af Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 14:39:33 -0400 Subject: [PATCH 041/378] more efficient storage and update --- src/hsp2/state/state.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index aaf0d2e3..84c8357d 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -15,11 +15,12 @@ # Define the complex datatypes state_ix = npasarray(zeros(1), dtype="float64") -model_exec_list = npasarray(zeros(1), dtype="int64") +model_exec_list = npasarray(zeros(1), dtype="int32") # TBD: Create a sample tindex for typing tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) tindex_ty = ('tindex', typeof(tindex.to_numpy())) dict_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:, :]) +op_tokens_dict = Dict.empty(key_type=types.int64, value_type=types.int64[:, :]) op_tokens = int32(zeros((1,64))) op_exec_lists = int32(zeros((1,1024))) # note: tested 32-bit key and saw absolutely no improvement, so go with 64 bit @@ -59,9 +60,8 @@ @jitclass(state_spec) class state_object: - def __init__(self, num_ops=5000): - self.num_ops = num_ops - self.state_ix = zeros(num_ops) + def __init__(self): + self.num_ops = 0 # 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 @@ -85,17 +85,23 @@ def __init__(self, num_ops=5000): # form # op_tokens.astype(int32) # to do the type cast - op_tokens = zeros( (num_ops,64) ) + op_tokens = zeros( (self.num_ops,64) ) self.op_tokens = op_tokens.astype(int32) - op_exec_lists = zeros( (num_ops,1024) ) - self.op_exec_lists = op_exec_lists.astype(int32) - model_exec_list = zeros(num_ops) - self.model_exec_list = model_exec_list.astype(types.int64) + op_exec_lists = zeros( (self.num_ops,1024) ) + # TODO: move to individual objects in OM + self.op_exec_lists = op_exec_lists.astype(types.int32) + # TODO: is this even needed? + model_exec_list = zeros(self.num_ops) + self.model_exec_list = model_exec_list.astype(types.int32) return + @property + def size(self): + return self.state_ix.size + def append_state(self, var_value): - val_ix = self.last_id + 1 # next ix value - self.state_ix[val_ix] = var_value + val_ix = self.size + 1 # next ix value + self.state_ix = np.append(self.state_ix, var_value) self.last_id = val_ix return(val_ix) From 0ea7fb0167479d6ec51f0b587c79c2c03b3788d3 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 14:45:00 -0400 Subject: [PATCH 042/378] fix usage --- src/hsp2/hsp2/om.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index de681578..0982dffc 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -509,7 +509,7 @@ 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( @@ -572,7 +572,7 @@ def model_order_recursive( ) return # now after loading input dependencies, add this to list - model_exec_list.append(model_object.ix) + model_exec_list = np.append(model_exec_list, model_object.ix) def model_input_dependencies(state, exec_list, model_object_cache, only_runnable=False): From 200e4d83e3940aab2431c47029494e1215036ffb Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 16:02:52 -0400 Subject: [PATCH 043/378] can now adjust op_token size dynamically --- src/hsp2/state/state.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 84c8357d..9a296e64 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -105,6 +105,27 @@ def append_state(self, var_value): self.last_id = val_ix return(val_ix) + def resize_optokens(self): + num_ops = self.size + print("state_ix has", num_ops, "elements") + #ndims = np.resize(self.op_tokens, (self.size, np.shape(self.op_tokens)[1]) ) + #print("Resized:", ndims) + #self.op_tokens = ndims + ops_needed = num_ops - np.shape(self.op_tokens)[0] + print("op_tokens needs", ops_needed, "slots") + add_ops = 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: + print("Replacing op_tokens with", add_ops) + self.op_tokens = add_ops.astype(types.int32) + else: + print("Need to merge", add_ops) + add_ops = np.append(self.op_tokens, add_ops, 0) + self.op_tokens = add_ops.astype(types.int32) + print("merged add_ops", add_ops) + return + def set_state(self, var_path, var_value=0.0, debug=False): """ Given an hdf5 style path to a variable, set the value From 8c21b94315457408dc71bb1161703f9f54eed03b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:10:49 -0400 Subject: [PATCH 044/378] add set_token method on the state to handle formatting --- src/hsp2/hsp2/om_model_object.py | 2 +- src/hsp2/state/state.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 1effcbf3..878441c9 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -469,7 +469,7 @@ 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 diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 9a296e64..b0cdcb40 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -105,6 +105,18 @@ def append_state(self, var_value): self.last_id = val_ix return(val_ix) + def set_token(self, var_ix, tokens): + if var_ix not in self.state_ix: + print("Undefined index value provided for set_token()") + return False + if var_ix not in self.op_tokens: + self.resize_optokens() + # 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_optokens(self): num_ops = self.size print("state_ix has", num_ops, "elements") From 779c7132b04706e9a524bab7f2ef55b06f40d044 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:17:18 -0400 Subject: [PATCH 045/378] amust use better look up --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index b0cdcb40..22d67979 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -106,7 +106,7 @@ def append_state(self, var_value): return(val_ix) def set_token(self, var_ix, tokens): - if var_ix not in self.state_ix: + if var_ix not in range(len(self.state_ix)): print("Undefined index value provided for set_token()") return False if var_ix not in self.op_tokens: From 097c852c4607e12219a191fec0947884312234ad Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:23:10 -0400 Subject: [PATCH 046/378] info --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 22d67979..df486607 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -107,7 +107,7 @@ def append_state(self, var_value): def set_token(self, var_ix, tokens): if var_ix not in range(len(self.state_ix)): - print("Undefined index value provided for set_token()") + print("Undefined index value," var_ix, " provided for set_token()") return False if var_ix not in self.op_tokens: self.resize_optokens() From b8329723700322163b4059320d3398ed24e4381e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:24:16 -0400 Subject: [PATCH 047/378] info --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index df486607..52f99596 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -107,7 +107,7 @@ def append_state(self, var_value): def set_token(self, var_ix, tokens): if var_ix not in range(len(self.state_ix)): - print("Undefined index value," var_ix, " provided for set_token()") + print("Undefined index value,", var_ix, ", provided for set_token()") return False if var_ix not in self.op_tokens: self.resize_optokens() From c023efa257a5c32ca0712cd05cc1929390985fcb Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:29:01 -0400 Subject: [PATCH 048/378] better resize detection --- src/hsp2/state/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 52f99596..e5a4583f 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -109,7 +109,7 @@ def set_token(self, var_ix, tokens): if var_ix not in range(len(self.state_ix)): print("Undefined index value,", var_ix, ", provided for set_token()") return False - if var_ix not in self.op_tokens: + if var_ix not in range(np.shape(self.op_tokens)[0]): self.resize_optokens() # 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 @@ -123,7 +123,7 @@ def resize_optokens(self): #ndims = np.resize(self.op_tokens, (self.size, np.shape(self.op_tokens)[1]) ) #print("Resized:", ndims) #self.op_tokens = ndims - ops_needed = num_ops - np.shape(self.op_tokens)[0] + ops_needed = num_ops - (np.shape(self.op_tokens)[0] + 1) print("op_tokens needs", ops_needed, "slots") add_ops = zeros( (ops_needed,64) ) print("created add_ops with", ops_needed, "slots") From 73ec596d64e240b51ec388dcebe4baf3dc96c898 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:40:34 -0400 Subject: [PATCH 049/378] better resize math and message --- src/hsp2/state/state.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index e5a4583f..8d5e5240 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -123,8 +123,11 @@ def resize_optokens(self): #ndims = np.resize(self.op_tokens, (self.size, np.shape(self.op_tokens)[1]) ) #print("Resized:", ndims) #self.op_tokens = ndims - ops_needed = num_ops - (np.shape(self.op_tokens)[0] + 1) + ops_needed = num_ops - np.shape(self.op_tokens)[0] print("op_tokens needs", ops_needed, "slots") + if ops_needed == 0: + print("resize_options unneccesary, state has", state.size,"indices and op_tokens has", np.shape(self.op_tokens)[0], "elements") + return add_ops = zeros( (ops_needed,64) ) print("created add_ops with", ops_needed, "slots") # we use the 3rd param "axis=1" to prevent flattening of array From 582e73c683ef50bb31e6233f79c5c7f6e6f62750 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:45:30 -0400 Subject: [PATCH 050/378] better resize math and message --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 8d5e5240..cc97aad4 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -126,7 +126,7 @@ def resize_optokens(self): ops_needed = num_ops - np.shape(self.op_tokens)[0] print("op_tokens needs", ops_needed, "slots") if ops_needed == 0: - print("resize_options unneccesary, state has", state.size,"indices and op_tokens has", np.shape(self.op_tokens)[0], "elements") + print("resize_options unneccesary, state has", self.size,"indices and op_tokens has", np.shape(self.op_tokens)[0], "elements") return add_ops = zeros( (ops_needed,64) ) print("created add_ops with", ops_needed, "slots") From 1fe3cf24def9c63dc81f2887eb85d97bcd3becb2 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:49:06 -0400 Subject: [PATCH 051/378] information --- src/hsp2/state/state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index cc97aad4..fed94730 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -110,6 +110,7 @@ def set_token(self, var_ix, tokens): print("Undefined index value,", var_ix, ", provided for set_token()") return False if var_ix not in range(np.shape(self.op_tokens)[0]): + print("set_token called for ix", var_ix, ", need to expand") self.resize_optokens() # 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 From 564f8d8666d8324d96cd9bac4a3c15d7d3b925dd Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:51:05 -0400 Subject: [PATCH 052/378] etter counting of index values --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index fed94730..869d9b20 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -100,7 +100,7 @@ def size(self): return self.state_ix.size def append_state(self, var_value): - val_ix = self.size + 1 # next ix 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 return(val_ix) From cd75e7ccf2ddf882d34dc74558f2457dcfafbe20 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:56:04 -0400 Subject: [PATCH 053/378] model_exec_list must be formatted correctly --- src/hsp2/hsp2/om.py | 2 +- src/hsp2/state/state.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 0982dffc..2c84861d 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -211,7 +211,7 @@ def state_om_model_run_prep(state, om_operations, siminfo): # the resulting set of objects is returned. state.state_step_om = "disabled" om_operations["model_object_cache"] = model_object_cache - state.model_exec_list = np.asarray(model_exec_list, dtype="i8") + state.model_exec_list = np.asarray(model_exec_list, dtype="int32") if model_root_object.ops_data_type == "ndarray": state_keyvals = np.asarray( zeros(max(model_root_object.state.state_ix.keys()) + 1), dtype="float64" diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 869d9b20..195c1aba 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -5,7 +5,7 @@ from pandas.tseries.offsets import Minute from numba.typed import Dict from numba.experimental import jitclass -from numpy import zeros, int32, asarray as npasarray +from numpy import zeros, int32 from numba import njit, types, typeof # import the types import os import importlib.util @@ -14,8 +14,8 @@ # Define the complex datatypes -state_ix = npasarray(zeros(1), dtype="float64") -model_exec_list = npasarray(zeros(1), dtype="int32") +state_ix = np.asarray(zeros(1), dtype="float64") +model_exec_list = np.asarray(zeros(1), dtype="int32") # TBD: Create a sample tindex for typing tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) tindex_ty = ('tindex', typeof(tindex.to_numpy())) From 9ae5cad772b77fb713d21cc87aab25cf83f1dae4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 18:58:25 -0400 Subject: [PATCH 054/378] no need to reformat state_ix as it is already handled by the state object --- src/hsp2/hsp2/om.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 2c84861d..03875437 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -212,18 +212,6 @@ def state_om_model_run_prep(state, om_operations, siminfo): state.state_step_om = "disabled" om_operations["model_object_cache"] = model_object_cache state.model_exec_list = np.asarray(model_exec_list, dtype="int32") - 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" if len(model_exec_list) > 0: From d5c1edf95e8e45053647651f4fbc3942f923d044 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 23 Oct 2025 19:01:09 -0400 Subject: [PATCH 055/378] use state reference --- src/hsp2/hsp2/om.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 03875437..06705efa 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -212,14 +212,14 @@ def state_om_model_run_prep(state, om_operations, siminfo): state.state_step_om = "disabled" om_operations["model_object_cache"] = model_object_cache state.model_exec_list = np.asarray(model_exec_list, dtype="int32") - if len(op_tokens) > 0: + if len(state.op_tokens) > 0: state.state_step_om = "enabled" - if len(model_exec_list) > 0: + if len(state.model_exec_list) > 0: print( "op_tokens has", - len(op_tokens), + len(state.op_tokens), "elements, with ", - len(model_exec_list), + len(state.model_exec_list), "executable elements", ) # print("Exec list:", model_exec_list) From 3391c558a7bf78abb0b7e01d42b3bdc37edc74fa Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 24 Oct 2025 14:20:34 -0400 Subject: [PATCH 056/378] resize op exec lists too --- src/hsp2/state/state.py | 30 ++++++++++++++------- tests/testcbp/HSP2results/check_equation.py | 11 +------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 195c1aba..ceec307f 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -111,35 +111,45 @@ def set_token(self, var_ix, tokens): return False if var_ix not in range(np.shape(self.op_tokens)[0]): print("set_token called for ix", var_ix, ", need to expand") - self.resize_optokens() + 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_optokens(self): + def resize(self): num_ops = self.size print("state_ix has", num_ops, "elements") - #ndims = np.resize(self.op_tokens, (self.size, np.shape(self.op_tokens)[1]) ) - #print("Resized:", ndims) - #self.op_tokens = ndims ops_needed = num_ops - np.shape(self.op_tokens)[0] print("op_tokens needs", ops_needed, "slots") if ops_needed == 0: - print("resize_options unneccesary, state has", self.size,"indices and op_tokens has", np.shape(self.op_tokens)[0], "elements") + print("resize op_tokens unneccesary, state has", self.size,"indices and op_tokens has", np.shape(self.op_tokens)[0], "elements") return add_ops = zeros( (ops_needed,64) ) - print("created add_ops with", ops_needed, "slots") + 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: - print("Replacing op_tokens with", add_ops) + print("Creating op_tokens") self.op_tokens = add_ops.astype(types.int32) else: - print("Need to merge", add_ops) + print("Merging op_tokens") add_ops = np.append(self.op_tokens, add_ops, 0) self.op_tokens = add_ops.astype(types.int32) - print("merged add_ops", add_ops) + ops_needed = num_ops - np.shape(self.op_exec_lists)[0] + el_width = np.shape(self.op_exec_lists)[1] + 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: + print("Creating op_exec_lists") + self.op_tokens = add_ops.astype(types.int32) + else: + print("Merging op_exec_lists") + add_ops = np.append(self.op_exec_lists, add_ops, 0) + self.op_exec_lists = add_ops.astype(types.int32) return def set_state(self, var_path, var_value=0.0, debug=False): diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index ca36cfe8..0fa84a49 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -50,16 +50,7 @@ # Set up order of execution hsp2_domain_dependencies(state, opseq, activities, om_operations, True) -# 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_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['model_root_object'].find_var_path('RCHRES_R001') # Get the timeseries naked, without an object Rlocal = om_operations["model_object_cache"]["/STATE/RCHRES_R001/Rlocal"] From d9890f8c85d5a42293e5e81515f99ab2170979e0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 24 Oct 2025 14:27:19 -0400 Subject: [PATCH 057/378] actually overwrite op exec lists --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ceec307f..76dd33cb 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -145,7 +145,7 @@ def resize(self): # we use the 3rd param "axis=1" to prevent flattening of array if self.op_exec_lists.size == 0: print("Creating op_exec_lists") - self.op_tokens = add_ops.astype(types.int32) + self.op_exec_lists = add_ops.astype(types.int32) else: print("Merging op_exec_lists") add_ops = np.append(self.op_exec_lists, add_ops, 0) From 4b12de46a58db0580d4b111265f8cd7446100b02 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 24 Oct 2025 15:50:41 -0400 Subject: [PATCH 058/378] resize any time you append --- src/hsp2/state/state.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 76dd33cb..5505f80d 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -103,6 +103,7 @@ 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): @@ -120,12 +121,12 @@ def set_token(self, var_ix, tokens): def resize(self): num_ops = self.size - print("state_ix has", num_ops, "elements") + #print("state_ix has", num_ops, "elements") ops_needed = num_ops - np.shape(self.op_tokens)[0] - print("op_tokens needs", ops_needed, "slots") 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") + #print("resize op_tokens unneccesary, state has", self.size,"indices and op_tokens has", np.shape(self.op_tokens)[0], "elements") return + print("op_tokens needs", ops_needed, "slots") add_ops = zeros( (ops_needed,64) ) print("Created add_ops with", ops_needed, "slots") # we use the 3rd param "axis=1" to prevent flattening of array From 04d6afc72299760792406154db358bb69ba173ae Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 3 Nov 2025 15:49:23 -0500 Subject: [PATCH 059/378] dont replace a list you are trying to modify y reference! also, add a function on state to handle all reformatting for jit --- src/hsp2/hsp2/om.py | 16 ++++++++++++---- src/hsp2/state/state.py | 3 +++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 06705efa..f4f7444d 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -501,7 +501,7 @@ def model_tokenizer_recursive( 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 @@ -515,12 +515,17 @@ 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) @@ -560,7 +565,9 @@ def model_order_recursive( ) return # now after loading input dependencies, add this to list - model_exec_list = np.append(model_exec_list, model_object.ix) + if debug: + print("Adding", model_object.ix, "to element list") + model_exec_list.append(model_object.ix) def model_input_dependencies(state, exec_list, model_object_cache, only_runnable=False): @@ -635,9 +642,10 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals 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.op_exec_lists[activity_id] = np.pad(op_exec_list,(0,state.op_exec_lists.shape[1] - len(op_exec_list))) + state.set_exec_list(activity_id, op_exec_list) def save_object_ts(io_manager, siminfo, op_tokens, ts_ix, ts): diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 5505f80d..286d526c 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -153,6 +153,9 @@ def resize(self): self.op_exec_lists = add_ops.astype(types.int32) return + def set_exec_list(self, ix, op_exec_list): + self.op_exec_lists[ix] = np.pad(op_exec_list,(0,self.op_exec_lists.shape[1] - len(op_exec_list))) + def set_state(self, var_path, var_value=0.0, debug=False): """ Given an hdf5 style path to a variable, set the value From 93ea755b8edde11442261c26705daf047ae5af6b Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 6 Nov 2025 11:16:06 -0500 Subject: [PATCH 060/378] replace plumbing for hydr execution with new state --- src/hsp2/hsp2/HYDR.py | 91 ++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 61 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 1e92b8a2..c1afaa7c 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -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,6 +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"] @@ -140,19 +143,6 @@ 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.state_step_hydr # It appears necessary to load this here, instead of from main.py, otherwise, # _hydr_() does not recognize the function state_step_hydr()? @@ -160,21 +150,11 @@ def hydr(io_manager, siminfo, parameters, ts, ftables, state): 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 + # 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' + activity_id = state.get_state_ix(activity_path) + model_exec_list = state.op_exec_lists[activity_id] ####################################################################################### # Do the simulation with _hydr_ (ie run reaches simulation code) @@ -187,14 +167,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,8 +181,6 @@ 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 @@ -221,14 +194,9 @@ 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) @@ -373,8 +341,9 @@ def _hydr_( ####################################################################################### # 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_ix, state.state_paths, 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"], @@ -408,40 +377,40 @@ 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 + # set state.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 + 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 + state.state_ix[out_ix[oi]] = outdgt[oi] + state.state_ix[vol_ix], state.state_ix[ivol_ix] = vol, IVOL0[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, dict_ix, 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_info, state.state_paths, state.state_ix, dict_ix, ts_ix, hydr_ix, 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 step_model( - model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step + model_exec_list, state.op_tokens, state.state_ix, dict_ix, 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] * VFACT # End dynamic code step() ####################################################################################### From 871851ee6ce32a5007dd2e5d011f801440567724 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 6 Nov 2025 12:15:17 -0500 Subject: [PATCH 061/378] remove unused op_tokens outsie of state --- src/hsp2/hsp2/om.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index f4f7444d..b88ce625 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -129,7 +129,6 @@ def om_init_state(): # Grab globals from state for easy handling op_tokens, model_object_cache = init_om_dicts() 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"] = {} From a8d83d96e5a6ac4f083f6c997546cae5bd4a0522 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 7 Nov 2025 09:13:33 -0500 Subject: [PATCH 062/378] make includes consistent with new naming conventions --- src/hsp2/hsp2/main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 7d7dd8b0..5faab09c 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -23,6 +23,7 @@ state_load_dynamics_hsp2, state_init_hsp2, state_context_hsp2, + state_object ) from hsp2.hsp2.om import ( om_init_state, @@ -30,7 +31,7 @@ state_load_dynamics_om, state_om_model_run_finish, ) -from hsp2.hsp2.SPECL import specl_load_state +from hsp2.hsp2.SPECL import specl_load_om from hsp2.hsp2io.io import IOManager, SupportsReadTS, Category @@ -86,16 +87,16 @@ def main( # 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_object() + 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, om_operations) # - finally stash specactions in state, not domain (segment) dependent so do it once - om_operations = om_init_state() # set up operational model specific containers specl_load_om(om_operations, specactions) # load traditional special actions state_load_dynamics_om( state, io_manager, siminfo, om_operations @@ -106,7 +107,6 @@ def main( # 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 From fcfc5bf4c43be677f7fa5bd8b99e63eb9933cadc Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:16:06 -0500 Subject: [PATCH 063/378] change name of base class --- src/hsp2/hsp2/main.py | 4 ++-- src/hsp2/state/state.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 6 +++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 5faab09c..4d3b47d1 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -23,7 +23,7 @@ state_load_dynamics_hsp2, state_init_hsp2, state_context_hsp2, - state_object + state_class ) from hsp2.hsp2.om import ( om_init_state, @@ -87,7 +87,7 @@ def main( # initialize STATE dicts ####################################################################################### # Set up Things in state that will be used in all modular activities like SPECL - state = state_object() + state = state_class() 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 diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 286d526c..dd67e63f 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -59,7 +59,7 @@ tindex_ty, dict_ix_ty, num_ops_ty] @jitclass(state_spec) -class state_object: +class state_class: def __init__(self): self.num_ops = 0 # this dict_ix approach is inherently slow, and should be replaced by some other np table type diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 0fa84a49..f4d02815 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -29,7 +29,7 @@ # - 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 = state_object() +state = state_class() om_operations = om_init_state() state_siminfo_hsp2(state, uci_obj, siminfo, io_manager) @@ -50,6 +50,10 @@ # Set up order of execution hsp2_domain_dependencies(state, opseq, activities, om_operations, True) +# debug loading: +# mtl = [] +# mel = [] +# model_order_recursive(endpoint, om_operations["model_object_cache"], mel, mtl, True) # state['model_root_object'].find_var_path('RCHRES_R001') # Get the timeseries naked, without an object From daa989ce36bd192fb398e34549c84c3fc0abf49d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:24:47 -0500 Subject: [PATCH 064/378] io_manager unused in hydr() so do not pass as argument --- src/hsp2/hsp2/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 4d3b47d1..08ab8bfb 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -397,7 +397,7 @@ 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, state ) elif activity == "SEDTRN" or activity == "SEDMNT": errors, errmessages = function( From 881f7598718851006a4c773fb2a7edfeb8e9e25b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:27:44 -0500 Subject: [PATCH 065/378] fix bad name --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index c1afaa7c..6d453429 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -143,7 +143,7 @@ def hydr(siminfo, parameters, ts, ftables, state): ####################################################################################### # the following section (1 of 3) added to HYDR by rb to handle dynamic code and special actions ####################################################################################### - hsp2_local_py = state.state_step_hydr + 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 1ac2ae3df028038cddb44c41ae28bdab7fa4cd2a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:29:50 -0500 Subject: [PATCH 066/378] add object references for dicts --- src/hsp2/hsp2/HYDR.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 6d453429..73f229e3 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -388,17 +388,17 @@ def _hydr_( # - these if statements may be irrelevant if default functions simply return # when no objects are defined. if state.state_step_om == "enabled": - pre_step_model(model_exec_list, state.op_tokens, state.state_ix, dict_ix, ts_ix, step) + 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.state_paths, state.state_ix, dict_ix, ts_ix, hydr_ix, step + state_info, state.state_paths, state.state_ix, state.dict_ix, state.ts_ix, hydr_ix, step ) 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 step_model( - model_exec_list, state.op_tokens, state.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.state_step_hydr == "enabled") or ( state.state_step_om == "enabled" From 1b1b88c2e36280978a4a698eab29bee351fa2b58 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:33:32 -0500 Subject: [PATCH 067/378] refine custom framework for dynamic python in state --- src/hsp2/hsp2/HYDR.py | 2 +- src/hsp2/state/state_fn_defaults.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 73f229e3..054fc147 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -391,7 +391,7 @@ def _hydr_( 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.state_paths, state.state_ix, state.dict_ix, state.ts_ix, hydr_ix, step + state, step ) if state.state_step_om == "enabled": # print("trying to execute state_step_om()") diff --git a/src/hsp2/state/state_fn_defaults.py b/src/hsp2/state/state_fn_defaults.py index 45c7a0c0..c2e158d4 100644 --- a/src/hsp2/state/state_fn_defaults.py +++ b/src/hsp2/state/state_fn_defaults.py @@ -3,5 +3,7 @@ @njit -def state_step_hydr(state_info, state_paths, state_ix, dict_ix, ts_ix, hydr_ix, step): +def state_step_hydr(state, step): + # TODO: return + From cbf7a06bcb5fc409a9b5ce808bb143460c46e689 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:35:04 -0500 Subject: [PATCH 068/378] debug --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 054fc147..8fadd968 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -184,7 +184,7 @@ def hydr(siminfo, parameters, ts, ftables, state): return errors, ERRMSGS -@njit(cache=True) +#@njit(cache=True) def _hydr_( ui, ts, From b1dea4e4ce0a9c17a91f72132e8624a240820c3a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:36:55 -0500 Subject: [PATCH 069/378] debug --- src/hsp2/state/state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index dd67e63f..fde8f71b 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -497,6 +497,7 @@ def hydr_get_ix(state_ix, state_paths, domain): for i in hydr_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i + print("looking for:", var_path) hydr_ix[i] = state_paths[var_path] return hydr_ix From 6921a3948c9cda25ccb1074ded8f744f071e5ee9 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:41:13 -0500 Subject: [PATCH 070/378] debug --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index fde8f71b..fbf336c6 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -472,7 +472,7 @@ def rqual_init_ix(state, domain): return rqual_ix -@njit +#@njit def hydr_get_ix(state_ix, state_paths, domain): # get a list of keys for all hydr state variables hydr_state = [ From fe03ec98c38d90bbd6f766bd69b1b851f66bd5c6 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:52:00 -0500 Subject: [PATCH 071/378] debug --- src/hsp2/state/state.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index fbf336c6..ddde0312 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -473,7 +473,7 @@ def rqual_init_ix(state, domain): #@njit -def hydr_get_ix(state_ix, state_paths, domain): +def hydr_get_ix(state, domain): # get a list of keys for all hydr state variables hydr_state = [ "DEP", @@ -493,12 +493,13 @@ def hydr_get_ix(state_ix, state_paths, domain): "VOL", "VOLEV", ] + print(state.state_paths) hydr_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) for i in hydr_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i print("looking for:", var_path) - hydr_ix[i] = state_paths[var_path] + hydr_ix[i] = state.get_state_ix(var_path) return hydr_ix From beadc3feab066f241fb5f810f30b65404cd1663d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:54:18 -0500 Subject: [PATCH 072/378] fix pos args --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 8fadd968..4e847f5c 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -341,7 +341,7 @@ def _hydr_( ####################################################################################### # 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.state_ix, state.state_paths, state.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 = ( From 5f01a1a0882710b2a7f92ce2485bd851d8b76292 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 09:58:16 -0500 Subject: [PATCH 073/378] debug --- src/hsp2/state/state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ddde0312..f6355a89 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -410,6 +410,7 @@ def hydr_init_ix(state, domain): for i in hydr_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i + print("initializing", var_path) hydr_ix[i] = state.set_state(var_path, 0.0) return hydr_ix From 3d05065673034d7a998992ebff01cd25dbdc9e1e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 10:24:42 -0500 Subject: [PATCH 074/378] debug --- src/hsp2/hsp2/main.py | 3 +++ src/hsp2/state/state.py | 1 + 2 files changed, 4 insertions(+) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 08ab8bfb..fb02a277 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -30,6 +30,7 @@ state_om_model_run_prep, state_load_dynamics_om, state_om_model_run_finish, + hsp2_domain_dependencies ) from hsp2.hsp2.SPECL import specl_load_om @@ -96,6 +97,8 @@ def main( # Iterate through all segments and add crucial paths to state # before loading dynamic components that may reference them state_init_hsp2(state, opseq, activities, om_operations) + # now initialize all state variables for mutable variables + hsp2_domain_dependencies(state, opseq, activities, om_operations, True) # - finally stash specactions in state, not domain (segment) dependent so do it once specl_load_om(om_operations, specactions) # load traditional special actions state_load_dynamics_om( diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index f6355a89..436c6ad3 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -325,6 +325,7 @@ def state_init_hsp2(state, opseq, activities, om_operations): state_context_hsp2(state, operation, segment, activity) + 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 From ad9e794916d85547ca8c8fd46d7ebf4bad6fed00 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 10:33:33 -0500 Subject: [PATCH 075/378] use iteration to save op_exec_list --- src/hsp2/state/state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 436c6ad3..b0e7dcd2 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -154,7 +154,8 @@ def resize(self): return def set_exec_list(self, ix, op_exec_list): - self.op_exec_lists[ix] = np.pad(op_exec_list,(0,self.op_exec_lists.shape[1] - len(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): """ From a22db35712b99462eae1ca0ee85f1b546d4db111 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 7 Nov 2025 10:35:56 -0500 Subject: [PATCH 076/378] debug off, njit re-enabled --- src/hsp2/hsp2/HYDR.py | 2 +- src/hsp2/state/state.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 4e847f5c..d3667dd3 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -184,7 +184,7 @@ def hydr(siminfo, parameters, ts, ftables, state): return errors, ERRMSGS -#@njit(cache=True) +@njit(cache=True) def _hydr_( ui, ts, diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index b0e7dcd2..560962be 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -475,7 +475,7 @@ def rqual_init_ix(state, domain): return rqual_ix -#@njit +@njit def hydr_get_ix(state, domain): # get a list of keys for all hydr state variables hydr_state = [ @@ -496,12 +496,12 @@ def hydr_get_ix(state, domain): "VOL", "VOLEV", ] - print(state.state_paths) + #print(state.state_paths) hydr_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) for i in hydr_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i - print("looking for:", var_path) + #print("looking for:", var_path) hydr_ix[i] = state.get_state_ix(var_path) return hydr_ix From d1b06b55e64271103d95cf628476ad1b1674c5a7 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 10 Nov 2025 11:29:01 -0500 Subject: [PATCH 077/378] debug --- src/hsp2/hsp2/om.py | 3 +++ src/hsp2/hsp2/om_model_object.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 11 +++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index b88ce625..6040d0e6 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -129,6 +129,7 @@ def om_init_state(): # Grab globals from state for easy handling op_tokens, model_object_cache = init_om_dicts() 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"] = {} @@ -222,6 +223,8 @@ def state_om_model_run_prep(state, om_operations, siminfo): "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, True) return diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 878441c9..04e89118 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -230,7 +230,7 @@ def save_object_hdf(self, hdfname, overwrite=False): dummy_var = True def make_paths(self, base_path=False): - # print("calling make_paths from", self.name, "with base path", base_path) + 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): self.state_path = self.container.state_path + "/" + str(self.name) diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index f4d02815..390d5836 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -10,6 +10,9 @@ 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" ucipath = "./tests/testcbp/HSP2results/PL3_5250_0001.uci" @@ -17,11 +20,13 @@ # 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_parameters() siminfo = uci_obj.siminfo opseq = uci_obj.opseq @@ -91,3 +96,9 @@ end - start, "seconds", ) + + +# try also: +run(fpath, saveall=True, compress=False) +dstore_hydr = pd.HDFStore(str(fpath), mode='r') +hsp2_specl_hydr1 = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') From 510a91c678f10429d6e7bf71bf7c098444e14de0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 11:34:10 -0500 Subject: [PATCH 078/378] debug --- src/hsp2/hsp2/om_model_object.py | 1 + tests/testcbp/HSP2results/check_endpoint_ts.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 04e89118..598206de 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -233,6 +233,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) diff --git a/tests/testcbp/HSP2results/check_endpoint_ts.py b/tests/testcbp/HSP2results/check_endpoint_ts.py index e768573d..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: From 0940e0af7296f9f5379e95ac9db80cccf1479ae5 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 11:37:19 -0500 Subject: [PATCH 079/378] state default must be None not False --- src/hsp2/hsp2/om_model_linkage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index f69b813f..c8782f73 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -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 From b9a169b02c21fe85200e945b036d475f2cd3fe52 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 11:53:15 -0500 Subject: [PATCH 080/378] sdebug --- src/hsp2/hsp2/om_model_object.py | 1 + tests/testcbp/HSP2results/check_equation.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 598206de..c67ec4f8 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -255,6 +255,7 @@ def get_state(self, var_name=False): return self.state_ix[self.ix] else: var_path = self.find_var_path(var_name) + print("Looking for state ix of:", var_path) var_ix = self.state.get_state_ix(var_path) if var_ix == False: return False diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 390d5836..28a71b52 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -99,6 +99,22 @@ # 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 + +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.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" run(fpath, saveall=True, compress=False) dstore_hydr = pd.HDFStore(str(fpath), mode='r') hsp2_specl_hydr1 = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') From ca10607e5ed067ebf9bdb76e478ba7d3f9e20aca Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 11:55:51 -0500 Subject: [PATCH 081/378] sdebug --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index c67ec4f8..526af880 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -338,7 +338,7 @@ 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) + print("Searched", var_name, "with path", var_path,"found", found_path) var_ix = self.state.get_state_ix(found_path) if var_ix == False: if trust == False: From c99b369363e945ba923a896e65ddb76f3530e011 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 12:04:06 -0500 Subject: [PATCH 082/378] try relative path for wd_cfs --- tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd b/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd index 3a4a0439..637b7290 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd @@ -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": "RCHRES_R001/O2", + "right_path": "RCHRES_R001/wd_cfs", "link_type": 5 } } From d0a2a3cc551bd83f2d988439a97531b6bde8b556 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 12:12:32 -0500 Subject: [PATCH 083/378] use model_root_object as state base --- src/hsp2/hsp2/om_model_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 526af880..837d0333 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -287,9 +287,9 @@ def find_var_path(self, var_name, local_only=False): if not (self.container == False): 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: + if (state.model_root_object + "/" + var_name) in self.state.state_paths: # return self.state['state_paths'][("/STATE/" + var_name)] - return "/STATE/" + var_name + return state.model_root_object + "/" + var_name # check for full paths if var_name in self.state.state_paths: # return self.state['state_paths'][var_name] From 4079863aaa6915ec02e20ef1fa070e66886492c4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 12:12:36 -0500 Subject: [PATCH 084/378] use model_root_object as state base --- src/hsp2/hsp2/om_model_object.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 837d0333..6e703dbc 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -286,10 +286,12 @@ def find_var_path(self, var_name, local_only=False): # check parent for name if not (self.container == False): return self.container.find_var_path(var_name) - # check for root state vars STATE + var_name + # check for model_root_object state vars model_root_object + var_name if (state.model_root_object + "/" + var_name) in self.state.state_paths: - # return self.state['state_paths'][("/STATE/" + var_name)] return state.model_root_object + "/" + var_name + # check for root state vars 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: # return self.state['state_paths'][var_name] From 25729bd6124d778caa87e45f431d26c28a93df4a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 12:14:18 -0500 Subject: [PATCH 085/378] oops use object notation --- src/hsp2/hsp2/om_model_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 6e703dbc..1f0a64f6 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -287,8 +287,8 @@ def find_var_path(self, var_name, local_only=False): if not (self.container == False): return self.container.find_var_path(var_name) # check for model_root_object state vars model_root_object + var_name - if (state.model_root_object + "/" + var_name) in self.state.state_paths: - return state.model_root_object + "/" + var_name + if (self.state.model_root_object + "/" + var_name) in self.state.state_paths: + return self.state.model_root_object + "/" + var_name # check for root state vars STATE + var_name if ("/STATE/" + var_name) in self.state.state_paths: return "/STATE/" + var_name From 8a9d27c67e9aee5e546f03476ddf693da70e9723 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 12:18:28 -0500 Subject: [PATCH 086/378] try in object path and undo guesing from root object --- src/hsp2/hsp2/om_model_object.py | 3 --- tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 1f0a64f6..7b8fbe15 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -286,9 +286,6 @@ def find_var_path(self, var_name, local_only=False): # check parent for name if not (self.container == False): return self.container.find_var_path(var_name) - # check for model_root_object state vars model_root_object + var_name - if (self.state.model_root_object + "/" + var_name) in self.state.state_paths: - return self.state.model_root_object + "/" + var_name # check for root state vars STATE + var_name if ("/STATE/" + var_name) in self.state.state_paths: return "/STATE/" + var_name diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd b/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd index 637b7290..bbbd2070 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.constant_wd @@ -11,8 +11,8 @@ "IVOLwrite": { "name": "IVOLwrite", "object_class": "ModelLinkage", - "left_path": "RCHRES_R001/O2", - "right_path": "RCHRES_R001/wd_cfs", + "left_path": "/STATE/PL3_5250_0001/RCHRES_R001/O2", + "right_path": "/STATE/PL3_5250_0001/RCHRES_R001/wd_cfs", "link_type": 5 } } From 0c7b78d6bb092372ac4f0c1a659c01a18bee046a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 13:38:49 -0500 Subject: [PATCH 087/378] why were there commas there? --- src/hsp2/hsp2/om_model_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 7b8fbe15..f645211a 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -49,9 +49,9 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob # 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. ", + "Error: model_object_cache object must be available on to root object. " + name - + " cannot be created. See state::init_state_dicts()", + + " cannot be created. See state::init_state_dicts()" ) else: model_object_cache = self.container.model_object_cache From 457863685f68d7aa557f163401dd376eaabdda3c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 13:43:21 -0500 Subject: [PATCH 088/378] debug --- src/hsp2/hsp2/om_model_linkage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index c8782f73..08debcd9 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -96,6 +96,7 @@ 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): + print("ModelLinkage", self.name, "insuring register with path", self.left_path) self.insure_path(self.left_path) push_pieces = self.left_path.split("/") push_name = push_pieces[len(push_pieces) - 1] From a37a7f1d7ccef8e3625e53878fa345ce30161398 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 14:25:58 -0500 Subject: [PATCH 089/378] better handling of push registers --- src/hsp2/hsp2/om_model_linkage.py | 32 ++++++++++++++++++++----------- src/hsp2/hsp2/om_model_object.py | 5 ++++- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index 08debcd9..78eeed9d 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -97,19 +97,29 @@ def find_paths(self): # 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): print("ModelLinkage", self.name, "insuring register with path", self.left_path) - self.insure_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.find_object(self.left_path) + if left_object == False: + # 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 left_parent_object == False: + 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: diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index f645211a..45f83414 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -271,7 +271,10 @@ def get_object(self, var_name=False): return self.model_object_cache[self.state_path] else: var_path = self.find_var_path(var_name) - return self.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 From c5055efafd8bf35d9b67c75bce02833db20b9a05 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 14:28:20 -0500 Subject: [PATCH 090/378] fix parent clean up syntax --- src/hsp2/hsp2/om_model_linkage.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index 78eeed9d..dc37ae71 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -100,16 +100,17 @@ def find_paths(self): push_pieces = self.left_path.split("/") push_name = push_pieces[len(push_pieces) - 1] left_object = self.find_object(self.left_path) - if left_object == False: + 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 left_parent_object == False: + 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 ) From 770214c63a35bb856c37d3ca6c61607a69dfcf2f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 14:29:39 -0500 Subject: [PATCH 091/378] wrong function --- src/hsp2/hsp2/om_model_linkage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index dc37ae71..a4c500cd 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -99,7 +99,7 @@ def find_paths(self): 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] - left_object = self.find_object(self.left_path) + 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]) From da368ea1addc4ab5b0c5b12ad4be661b4a745c57 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 14:33:51 -0500 Subject: [PATCH 092/378] need to pass in opseq --- src/hsp2/hsp2/main.py | 2 +- src/hsp2/hsp2/om.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index fb02a277..7dc66939 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -105,7 +105,7 @@ def main( 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, om_operations, siminfo) + state_om_model_run_prep(opseq, state, om_operations, siminfo) ####################################################################################### # main processing loop diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 6040d0e6..6e9f2ba0 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -177,7 +177,7 @@ def state_om_model_root_object(state, om_operations, siminfo): om_operations["model_object_cache"][segment.state_path] = segment -def state_om_model_run_prep(state, om_operations, siminfo): +def state_om_model_run_prep(op_seq, state, om_operations, siminfo): # insure model base is set state_om_model_root_object(state, om_operations, siminfo) # now instantiate and link objects From 066d4670958cca3390d3f06d76c38c863c926c63 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 14:36:40 -0500 Subject: [PATCH 093/378] correct name --- src/hsp2/hsp2/om.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 6e9f2ba0..09ed940c 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -177,7 +177,7 @@ def state_om_model_root_object(state, om_operations, siminfo): om_operations["model_object_cache"][segment.state_path] = segment -def state_om_model_run_prep(op_seq, state, om_operations, siminfo): +def state_om_model_run_prep(opseq, state, om_operations, siminfo): # insure model base is set state_om_model_root_object(state, om_operations, siminfo) # now instantiate and link objects diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 28a71b52..e22cbf29 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -51,9 +51,8 @@ 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, om_operations, siminfo) +state_om_model_run_prep(opseq, state, om_operations, siminfo) # Set up order of execution -hsp2_domain_dependencies(state, opseq, activities, om_operations, True) # debug loading: # mtl = [] From dc437b599ae0f1a4456f903e59ab6decdcc2cc99 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 14:39:01 -0500 Subject: [PATCH 094/378] activities also passed in --- src/hsp2/hsp2/main.py | 2 +- src/hsp2/hsp2/om.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 7dc66939..560704fe 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -105,7 +105,7 @@ def main( 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(opseq, state, om_operations, siminfo) + state_om_model_run_prep(opseq, activities, state, om_operations, siminfo) ####################################################################################### # main processing loop diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 09ed940c..9fb0248b 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -177,7 +177,7 @@ def state_om_model_root_object(state, om_operations, siminfo): om_operations["model_object_cache"][segment.state_path] = segment -def state_om_model_run_prep(opseq, state, om_operations, siminfo): +def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): # insure model base is set state_om_model_root_object(state, om_operations, siminfo) # now instantiate and link objects From cf8cf11148dd59be10f2a1e73682be700f569eb6 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 14:46:55 -0500 Subject: [PATCH 095/378] one lingering state object reference fixed --- src/hsp2/hsp2/om_model_object.py | 4 ++-- tests/testcbp/HSP2results/check_equation.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 45f83414..3782aeee 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -259,7 +259,7 @@ def get_state(self, var_name=False): var_ix = self.state.get_state_ix(var_path) if var_ix == False: return False - return self.state_ix[var_ix] + return self.state.state_ix[var_ix] def get_tindex(self): timer = self.get_object('timer') @@ -482,7 +482,7 @@ def step(self, step): step_one( self.state.op_tokens, self.state.op_tokens[self.ix], - self.state_ix, + self.state.state_ix, self.state.dict_ix, self.state.state_ix, self.state.ts_ix, diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index e22cbf29..0a75569d 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -10,6 +10,7 @@ from hsp2.hsp2io.hdf import HDF5 from hsp2.hsp2io.io import IOManager from hsp2.hsp2tools.readUCI import * +from hsp2.hsp2.configuration import activities from src.hsp2.hsp2tools.commands import import_uci, run from pandas import read_hdf @@ -51,7 +52,7 @@ 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(opseq, state, om_operations, siminfo) +state_om_model_run_prep(opseq, activities, state, om_operations, siminfo) # Set up order of execution # debug loading: From 7ce534ec805c56a5b77894e2ae1bce4d74ea7d42 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 14:49:07 -0500 Subject: [PATCH 096/378] another lingering state object reference fixed --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 3782aeee..3d1511e4 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -252,7 +252,7 @@ def make_paths(self, base_path=False): def get_state(self, var_name=False): if var_name == False: - return self.state_ix[self.ix] + return self.state.state_ix[var_ix] else: var_path = self.find_var_path(var_name) print("Looking for state ix of:", var_path) From 98dfea6b8da2e54f20f1f58ca58927c37ebe966d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 14:49:57 -0500 Subject: [PATCH 097/378] another lingering state object reference fixed --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 3d1511e4..bc90cce9 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -252,7 +252,7 @@ def make_paths(self, base_path=False): def get_state(self, var_name=False): if var_name == False: - return self.state.state_ix[var_ix] + return self.state.state_ix[self.ix] else: var_path = self.find_var_path(var_name) print("Looking for state ix of:", var_path) From 2f9a93c5b06650d91919687f896d921966308964 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 15:04:36 -0500 Subject: [PATCH 098/378] more quiet --- src/hsp2/state/state.py | 30 +++++++++++++-------- tests/testcbp/HSP2results/check_equation.py | 3 +++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 560962be..9969cbb3 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -106,12 +106,14 @@ def append_state(self, var_value): self.resize() return(val_ix) - def set_token(self, var_ix, tokens): + def set_token(self, var_ix, tokens, debug=False): if var_ix not in range(len(self.state_ix)): - print("Undefined index value,", var_ix, ", provided for set_token()") + 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]): - print("set_token called for ix", var_ix, ", need to expand") + 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 @@ -119,36 +121,42 @@ def set_token(self, var_ix, tokens): # length limit described by ModelObject.max_token_length (64) which must match self.op_tokens[var_ix] = tokens - def resize(self): + 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 - print("op_tokens needs", ops_needed, "slots") + if debug: + print("op_tokens needs", ops_needed, "slots") add_ops = zeros( (ops_needed,64) ) - print("Created add_ops with", ops_needed, "slots") + #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: - print("Creating op_tokens") + if debug: + print("Creating op_tokens") self.op_tokens = add_ops.astype(types.int32) else: - print("Merging op_tokens") + if debug: + print("Merging op_tokens") add_ops = np.append(self.op_tokens, add_ops, 0) self.op_tokens = add_ops.astype(types.int32) ops_needed = num_ops - np.shape(self.op_exec_lists)[0] el_width = np.shape(self.op_exec_lists)[1] - print("op_exec_lists needs", ops_needed, "slots") + 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: - print("Creating op_exec_lists") + if debug: + print("Creating op_exec_lists") self.op_exec_lists = add_ops.astype(types.int32) else: - print("Merging op_exec_lists") + 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(types.int32) return diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 0a75569d..83dbe4db 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -118,3 +118,6 @@ run(fpath, saveall=True, compress=False) dstore_hydr = pd.HDFStore(str(fpath), mode='r') hsp2_specl_hydr1 = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') +np.quantile(hsp2_specl_hydr1[:]['O2'], [0,0.25,0.5,0.75,1.0]) +# To re-run: +dstore_hydr.close() From 98fb8859d685f3447dbef8e7ebcb0b03d1916c45 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 10 Nov 2025 15:07:34 -0500 Subject: [PATCH 099/378] more quieter still --- src/hsp2/hsp2/om.py | 2 +- src/hsp2/hsp2/om_model_object.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 9fb0248b..dc530d85 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -224,7 +224,7 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): ) # 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, True) + hsp2_domain_dependencies(state, opseq, activities, om_operations, False) return diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index bc90cce9..04a4c01c 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -230,10 +230,10 @@ def save_object_hdf(self, hdfname, overwrite=False): dummy_var = True def make_paths(self, base_path=False): - print("calling make_paths from", self.name, "with base path", base_path) + #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)) + #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) @@ -255,7 +255,7 @@ def get_state(self, var_name=False): return self.state.state_ix[self.ix] else: var_path = self.find_var_path(var_name) - print("Looking for state ix of:", 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 @@ -310,12 +310,12 @@ def constant_or_path(self, keyname, keyval, trust=False): return kix def register_path(self): # initialize the path variable if not already set - print("register_path called for", self.name, "with state_path", self.state_path) + #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 = 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 - print("Adding ", self.name, "with state_path", self.state_path, "to model_object_cache") + #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. @@ -340,7 +340,7 @@ 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) + #print("Searched", var_name, "with path", var_path,"found", found_path) var_ix = self.state.get_state_ix(found_path) if var_ix == False: if trust == False: From e2fbd843fd11a63b555c7a50466c9a08325f137b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 12 Nov 2025 11:43:00 -0500 Subject: [PATCH 100/378] withdraw 10% not 90% --- .../PL3_5250_0001.json.dynamic_wd.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001.json.dynamic_wd.json 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..ae9c3973 --- /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" + }, + "IVOLwrite": { + "name": "IVOLwrite", + "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 + } + } +} From ea359d62edad949b7ca35d109ef9cd0e394ead90 Mon Sep 17 00:00:00 2001 From: Rob Date: Mon, 1 Dec 2025 16:22:12 +0000 Subject: [PATCH 101/378] updated json to run dynamic withdrawal --- tests/testcbp/HSP2results/PL3_5250_0001.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001.json diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json b/tests/testcbp/HSP2results/PL3_5250_0001.json new file mode 100644 index 00000000..ae9c3973 --- /dev/null +++ b/tests/testcbp/HSP2results/PL3_5250_0001.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" + }, + "IVOLwrite": { + "name": "IVOLwrite", + "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 + } + } +} From ce1081059aff0011b607f12a25ca8f0f1d33cc70 Mon Sep 17 00:00:00 2001 From: Rob Date: Mon, 1 Dec 2025 19:35:23 +0000 Subject: [PATCH 102/378] mo changes --- src/hsp2/hsp2/om.py | 90 ++++--- src/hsp2/hsp2/om_equation.py | 45 ++-- src/hsp2/hsp2/om_model_object.py | 140 ++++++----- src/hsp2/state/state.py | 171 +++++++------ tests/testcbp/HSP2results/PL3_5250_0001.uci | 7 - ...L3_5250_0001.json => PL3_5250_0001eq.json} | 4 +- tests/testcbp/HSP2results/PL3_5250_0001eq.uci | 228 ++++++++++++++++++ ....json.constant_wd => PL3_5250_0001wd.json} | 4 +- tests/testcbp/HSP2results/PL3_5250_0001wd.uci | 227 +++++++++++++++++ 9 files changed, 721 insertions(+), 195 deletions(-) rename tests/testcbp/HSP2results/{PL3_5250_0001.json => PL3_5250_0001eq.json} (71%) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001eq.uci rename tests/testcbp/HSP2results/{PL3_5250_0001.json.constant_wd => PL3_5250_0001wd.json} (73%) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001wd.uci diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index dc530d85..5d468af0 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -5,12 +5,22 @@ # 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 + +import numpy as np +import pandas as pd from numba import njit # import the types -from hsp2.state.state import append_state, get_ix_path, hydr_init_ix, sedtrn_init_ix, sedmnt_init_ix, rqual_init_ix +from numpy import zeros + +from hsp2.state.state import ( + append_state, + get_ix_path, + hydr_init_ix, + rqual_init_ix, + sedmnt_init_ix, + sedtrn_init_ix, +) + def init_op_tokens(op_tokens, tops, eq_ix): """ @@ -51,11 +61,12 @@ def model_element_paths(mel, state): # 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 * @@ -133,7 +144,7 @@ def om_init_state(): om_operations["model_object_cache"] = model_object_cache om_operations["model_exec_list"] = [] om_operations["model_data"] = {} - return(om_operations) + return om_operations def state_load_dynamics_om(state, io_manager, siminfo, om_operations): @@ -155,7 +166,7 @@ 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 om_operations.keys(): model_root_object = ModelObject( - state.model_root_name, False, {}, state, om_operations['model_object_cache'] + 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, ...) om_operations["model_root_object"] = model_root_object # set up the timer as the first element @@ -171,7 +182,7 @@ def state_om_model_root_object(state, om_operations, siminfo): # later when adding from json? # Can we simply check the model_object_cache during load step? # Create an object shell for this - # just get the end of the path, which should be fine since we + # 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 @@ -184,7 +195,9 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): # 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) + model_loader_recursive( + om_operations["model_data"], model_root_object, state, model_object_cache + ) # 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? @@ -199,11 +212,11 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): 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( + # 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 + # 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) @@ -483,7 +496,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. @@ -503,7 +516,11 @@ def model_tokenizer_recursive( def model_order_recursive( - model_object, model_object_cache, model_exec_list, model_touch_list=None, debug=False + 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 @@ -518,16 +535,27 @@ def model_order_recursive( - 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) + 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.") + print(model_object.name, "already added to model_exec_list. Returning.") return if model_object.ix in model_touch_list: if debug: - print("Already touched", model_object.name, model_object.ix, model_object.state_path, ". Returning.") + 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) @@ -553,7 +581,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. @@ -584,9 +612,7 @@ def model_input_dependencies(state, exec_list, model_object_cache, only_runnable 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, 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) @@ -594,7 +620,9 @@ def model_input_dependencies(state, exec_list, model_object_cache, only_runnable return mello -def model_domain_dependencies(om_operations, state, domain, ep_list, only_runnable=False, debug=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 @@ -605,14 +633,16 @@ def model_domain_dependencies(om_operations, state, domain, ep_list, only_runnab mel = [] mtl = [] if debug: - print("Searching for", (domain + "/" + ep), "in state_paths" ) + 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.keys(): if (domain + "/" + ep) in om_operations["model_object_cache"].keys(): if debug: - print("Found", (domain + "/" + ep), "in om_operations" ) + 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) + 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) @@ -643,7 +673,9 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals 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 = 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 @@ -691,7 +723,9 @@ def step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): def finish_model(state, io_manager, siminfo): # 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"][get_ix_path(state.state_paths, i)] + model_object = om_operations["model_object_cache"][ + get_ix_path(state.state_paths, i) + ] if "io_manager" in dir(model_object): model_object.io_manager = io_manager model_object.finish() diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index a62b3931..e7dd3159 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -6,25 +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 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 @@ -136,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]), ) @@ -146,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 ", @@ -158,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 @@ -177,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 = [] diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 04a4c01c..1fbc1a69 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 is_float_digit +from numpy import asarray, int32, 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 get_state_ix, set_state class ModelObject: @@ -31,8 +32,15 @@ class ModelObject: 100, ] # 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, model_object_cache=None): + + def __init__( + self, + name, + container=False, + model_props=None, + state=None, + model_object_cache=None, + ): self.name = name self.container = container # will be a link to another object if state is None: @@ -40,8 +48,7 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob if self.container == False: raise Exception( "Error: State object must be passed to root object. ", - + name - + " cannot be created. See state::init_state_dicts()", + +name + " cannot be created. See state::init_state_dicts()", ) else: state = self.container.state @@ -56,7 +63,9 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob 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.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: @@ -87,7 +96,7 @@ def __init__(self, name, container=False, model_props=None, state=None, model_ob # 100 - SpecialAction, 101 - UVNAME, 102 - UVQUAN, 103 - DISTRB self.register_path() # note this registers the path AND stores the object in model_object_cache self.parse_model_props(model_props) - + def handle_deprecated_args(self, name, container, model_props, state): # Handle old deprecated format for Register, Constant and Variable state_path = False @@ -105,7 +114,7 @@ def handle_deprecated_args(self, name, container, model_props, state): print( "WARNING: deprecated 4th argument for ModelObject. Use: [Model class](name, container, model_props, state)" ) - + @staticmethod def required_properties(): # returns a list or minimum properties to create. @@ -114,7 +123,7 @@ def required_properties(): # req_props = super(DataMatrix, DataMatrix).required_properties() req_props = ["name"] return req_props - + @staticmethod def make_op_tokens(num_ops=5000): if ModelObject.ops_data_type == "ndarray": @@ -124,7 +133,7 @@ def make_op_tokens(num_ops=5000): else: op_tokens = Dict.empty(key_type=types.int64, value_type=types.i8[:]) return op_tokens - + @staticmethod def runnable_op_list(op_tokens, meo, debug=False): # only return those objects that do something at runtime @@ -141,7 +150,7 @@ def runnable_op_list(op_tokens, meo, debug=False): rmeo.append(ix) rmeo = asarray(rmeo, dtype="i8") return rmeo - + @staticmethod def model_format_ops(ops): if ModelObject.ops_data_type == "ndarray": @@ -151,12 +160,12 @@ def model_format_ops(ops): else: ops = asarray(ops, dtype="i8") return ops - + def format_ops(self): # this can be sub-classed if needed, but should not be since it is based on the ops_data_type # See ModelObject.model_format_ops() return ModelObject.model_format_ops(self.ops) - + @classmethod def check_properties(cls, model_props): # this is for pre-screening properties for validity in model creation routines @@ -167,13 +176,13 @@ def check_properties(cls, model_props): if len(matching_props) < len(req_props): return False return True - + def handle_path_aliases(self, object_path): if not (self.container == False): object_path = object_path.replace("[parent]", self.container.state_path) object_path = object_path.replace("[self]", self.state_path) return object_path - + def handle_inputs(self, model_props): if "inputs" in model_props.keys(): for i_pair in model_props["inputs"]: @@ -181,7 +190,7 @@ def handle_inputs(self, model_props): i_target = i_pair[1] i_target = handle_path_aliases(i_target) self.add_input(i_name, i_target) - + def handle_prop(self, model_props, prop_name, strict=False, default_value=None): # this checks to see if the prop is in dict with value form, or just a value # strict = True causes an exception if property is missing from model_props dict @@ -200,11 +209,13 @@ 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 return prop_val - + def parse_model_props(self, model_props, strict=False): # sub-classes will allow an create argument "model_props" and handle them here. # - subclasses should insure that they call super().parse_model_props() or include all code below @@ -214,26 +225,26 @@ def parse_model_props(self, model_props, strict=False): self.handle_inputs(model_props) self.model_props_parsed = model_props return True - + def set_state(self, set_value): var_ix = self.state.set_state( self.state_path, set_value, ) return var_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. # note: "with" statement helps prevent unclosed resources, see: https://www.geeksforgeeks.org/with-statement-in-python/ with HDFStore(hdfname, mode="a") as store: dummy_var = True - + def make_paths(self, base_path=False): - #print("calling make_paths from", self.name, "with base path", base_path) + # 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)) + # 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) @@ -249,23 +260,23 @@ def make_paths(self, base_path=False): self.state_path = base_path["STATE"] + self.name self.attribute_path = base_path["OBJECTS"] + self.name return self.state_path - + def get_state(self, var_name=False): if var_name == False: return self.state.state_ix[self.ix] else: var_path = self.find_var_path(var_name) - #print("Looking for state ix of:", 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] - + def get_tindex(self): - timer = self.get_object('timer') + timer = self.get_object("timer") tindex = self.state.dict_ix[timer.ix] - return(tindex) - + return tindex + def get_object(self, var_name=False): if var_name == False: return self.model_object_cache[self.state_path] @@ -273,9 +284,9 @@ def get_object(self, var_name=False): var_path = self.find_var_path(var_name) if var_path in self.model_object_cache: return self.model_object_cache[var_path] - else: + else: return False - + def find_var_path(self, var_name, local_only=False): # check local inputs for name if type(var_name) == str: @@ -284,10 +295,15 @@ def find_var_path(self, var_name, local_only=False): # 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 (self.state_path + "/" + var_name) in self.state.state_paths: + return self.state_path + "/" + var_name if local_only: + print("Cannot find var in local scope", var_name) return False # we are limiting the scope, so just return # check parent for name if not (self.container == False): + print("Searching for var in container scope", var_name) 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: @@ -296,7 +312,9 @@ def find_var_path(self, var_name, local_only=False): if var_name in self.state.state_paths: # 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): if is_float_digit(keyval): # we are given a constant value, not a variable reference @@ -308,14 +326,15 @@ def constant_or_path(self, keyname, keyval, trust=False): else: kix = self.add_input(keyname, keyval, 2, trust) return kix + def register_path(self): # initialize the path variable if not already set - #print("register_path called for", self.name, "with state_path", self.state_path) + # 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 = 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 - #print("Adding ", self.name, "with state_path", self.state_path, "to model_object_cache") + # 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. @@ -324,6 +343,7 @@ def register_path(self): # print("Adding", self.name, "as input to", self.container.name) return self.container.add_input(self.name, self.state_path, 1, True) return self.ix + def add_input(self, var_name, var_path, input_type=1, trust=False): # this will add to the inputs, but also insure that this # requested path gets added to the state/exec stack via an input object if it does @@ -340,8 +360,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 = self.state.get_state_ix(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( @@ -353,6 +375,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: @@ -371,12 +397,14 @@ def add_input(self, var_name, var_path, input_type=1, trust=False): # to find the data in /STATE/RCHRES_R001/Qin ??? It is redundant data and writing # but matches a complete data model and prevents stale data? return self.inputs_ix[var_name] + def add_object_input(self, var_name, var_object, link_type=1): # See above for details. # this adds an object as a link to another object self.inputs[var_name] = var_object.state_path self.inputs_ix[var_name] = var_object.ix return self.inputs_ix[var_name] + def create_parent_var(self, parent_var_name, source): # see decision points: https://github.com/HARPgroup/HSPsquared/issues/78 # This is used when an object sets an additional property on its parent @@ -389,16 +417,19 @@ def create_parent_var(self, parent_var_name, source): self.container.add_input(parent_var_name, source, 1, False) elif isinstance(source, ModelObject): self.container.add_object_input(parent_var_name, source, 1) + 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 = 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] + def find_paths(self): # Note: every single piece of data used by objects, even constants, are resolved to a PATH in the hdf5 # find_paths() is called to insure that all of these can be found, and then, are added to inputs/inputs_ix @@ -414,6 +445,7 @@ def find_paths(self): # and should also handle deciding if this is a constant, like a numeric value # or a variable data and should handle them accordingly return True + def insure_register( self, var_name, @@ -448,6 +480,7 @@ def insure_register( else: var_register = self.model_object_cache[register_path] return var_register + def tokenize(self): # renders tokens for high speed execution if self.paths_found == False: @@ -460,6 +493,7 @@ def tokenize(self): + "Tokens cannot be generated until method '.find_paths()' is run for all model objects ... process terminated. (see function `model_path_loader(model_object_cache)`)" ) self.ops = [self.optype, self.ix] + 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. @@ -474,6 +508,7 @@ def add_op_tokens(self): + "). " ) 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 @@ -489,20 +524,17 @@ def step(self, step): step, ) # step_model({self.state['op_tokens'][self.ix]}, self.state['state_ix'], self.state['dict_ix'], self.state['ts_ix'], step) + def finish(self): # Do end of model activities here # we do this in the object context if it involves IO and other complex actions 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) @@ -511,36 +543,30 @@ def __init__(self, name, container=False, model_props=None, state=None): var_ix = self.set_state(float(value)) self.paths_found = True # self.state['state_ix'][self.ix] = self.default_value + def required_properties(): req_props = super(ModelVariable, ModelVariable).required_properties() req_props.extend(["value"]) 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 + def required_properties(): req_props = super(ModelVariable, ModelVariable).required_properties() req_props.extend(["value"]) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 9969cbb3..5de85f46 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -1,16 +1,18 @@ """General routines for SPECL""" +import importlib.util +import os +import sys + import numpy as np +from numba import njit, typeof, types # import the types +from numba.experimental import jitclass +from numba.typed import Dict +from numpy import int32, zeros from pandas import date_range from pandas.tseries.offsets import Minute -from numba.typed import Dict -from numba.experimental import jitclass -from numpy import zeros, int32 -from numba import njit, types, typeof # import the types -import os -import importlib.util -import sys -#from hsp2.hsp2.utilities import make_class_spec + +# from hsp2.hsp2.utilities import make_class_spec # Define the complex datatypes @@ -18,45 +20,63 @@ model_exec_list = np.asarray(zeros(1), dtype="int32") # TBD: Create a sample tindex for typing tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) -tindex_ty = ('tindex', typeof(tindex.to_numpy())) +tindex_ty = ("tindex", typeof(tindex.to_numpy())) dict_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:, :]) op_tokens_dict = Dict.empty(key_type=types.int64, value_type=types.int64[:, :]) -op_tokens = int32(zeros((1,64))) -op_exec_lists = int32(zeros((1,1024))) +op_tokens = int32(zeros((1, 64))) +op_exec_lists = int32(zeros((1, 1024))) # note: tested 32-bit key and saw absolutely no improvement, so go with 64 bit state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64) hsp_segments = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) -last_id_ty = ('last_id', types.int64) -num_ops_ty = ('num_ops', types.int64) - -state_paths_ty = ('state_paths', typeof(state_paths)) -model_exec_list_ty = ('model_exec_list', typeof(model_exec_list)) -hsp_segments_ty = ('hsp_segments', typeof(hsp_segments)) -op_tokens_ty = ('op_tokens', typeof(op_tokens)) -state_ix_ty = ('state_ix', typeof(state_ix)) -dict_ix_ty = ('dict_ix', typeof(dict_ix)) -ts_ix_ty = ('ts_ix', typeof(ts_ix)) -ts_paths_ty = ('ts_paths', typeof(ts_paths)) -model_root_name_ty = ('model_root_name', types.unicode_type) -# these are likely to be located in model objects when we go fully to that level. +last_id_ty = ("last_id", types.int64) +num_ops_ty = ("num_ops", types.int64) + +state_paths_ty = ("state_paths", typeof(state_paths)) +model_exec_list_ty = ("model_exec_list", typeof(model_exec_list)) +hsp_segments_ty = ("hsp_segments", typeof(hsp_segments)) +op_tokens_ty = ("op_tokens", typeof(op_tokens)) +state_ix_ty = ("state_ix", typeof(state_ix)) +dict_ix_ty = ("dict_ix", typeof(dict_ix)) +ts_ix_ty = ("ts_ix", typeof(ts_ix)) +ts_paths_ty = ("ts_paths", typeof(ts_paths)) +model_root_name_ty = ("model_root_name", types.unicode_type) +# 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 -state_step_hydr_ty = ('state_step_hydr', types.unicode_type) -state_step_om_ty = ('state_step_om', types.unicode_type) -operation_ty = ('operation', types.unicode_type) -segment_ty = ('segment', types.unicode_type) -activity_ty = ('activity', types.unicode_type) -domain_ty = ('domain', types.unicode_type) -hsp2_local_py_ty = ('hsp2_local_py', types.boolean) -op_exec_lists_ty = ('op_exec_lists', typeof(op_exec_lists)) +state_step_hydr_ty = ("state_step_hydr", types.unicode_type) +state_step_om_ty = ("state_step_om", types.unicode_type) +operation_ty = ("operation", types.unicode_type) +segment_ty = ("segment", types.unicode_type) +activity_ty = ("activity", types.unicode_type) +domain_ty = ("domain", types.unicode_type) +hsp2_local_py_ty = ("hsp2_local_py", types.boolean) +op_exec_lists_ty = ("op_exec_lists", typeof(op_exec_lists)) # Combine these into a spec to create the class -state_spec = [state_paths_ty, state_ix_ty, ts_paths_ty, ts_ix_ty, last_id_ty, - model_root_name_ty, state_step_hydr_ty, hsp2_local_py_ty, - hsp_segments_ty, op_tokens_ty, op_exec_lists_ty, model_exec_list_ty, - operation_ty, segment_ty, activity_ty, domain_ty, state_step_om_ty, - tindex_ty, dict_ix_ty, num_ops_ty] +state_spec = [ + state_paths_ty, + state_ix_ty, + ts_paths_ty, + ts_ix_ty, + last_id_ty, + model_root_name_ty, + state_step_hydr_ty, + hsp2_local_py_ty, + hsp_segments_ty, + op_tokens_ty, + op_exec_lists_ty, + model_exec_list_ty, + operation_ty, + segment_ty, + activity_ty, + domain_ty, + state_step_om_ty, + tindex_ty, + dict_ix_ty, + num_ops_ty, +] + @jitclass(state_spec) class state_class: @@ -66,9 +86,15 @@ def __init__(self): # 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.empty(key_type=types.int64, value_type=types.float64[:, :]) - self.state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64) - self.hsp_segments = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) - self.ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) + self.state_paths = Dict.empty( + key_type=types.unicode_type, value_type=types.int64 + ) + self.hsp_segments = Dict.empty( + key_type=types.unicode_type, value_type=types.unicode_type + ) + self.ts_paths = Dict.empty( + key_type=types.unicode_type, value_type=types.float64[:] + ) self.ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) self.state_step_om = "disabled" self.state_step_hydr = "disabled" @@ -81,31 +107,31 @@ def __init__(self): self.hsp2_local_py = False # Note: in the type declaration above we are alloweed to use the shortened form # op_tokens = int32(zeros((1,64))) - # but in jited class that throws an error and we have to use the - # form - # op_tokens.astype(int32) + # but in jited class that throws an error and we have to use the + # form + # op_tokens.astype(int32) # to do the type cast - op_tokens = zeros( (self.num_ops,64) ) + op_tokens = zeros((self.num_ops, 64)) self.op_tokens = op_tokens.astype(int32) - op_exec_lists = zeros( (self.num_ops,1024) ) + op_exec_lists = zeros((self.num_ops, 1024)) # TODO: move to individual objects in OM self.op_exec_lists = op_exec_lists.astype(types.int32) # TODO: is this even needed? model_exec_list = zeros(self.num_ops) self.model_exec_list = model_exec_list.astype(types.int32) 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) - + return val_ix + def set_token(self, var_ix, tokens, debug=False): if var_ix not in range(len(self.state_ix)): if debug: @@ -117,21 +143,21 @@ def set_token(self, var_ix, tokens, debug=False): 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 + # 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") + # 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") + # 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 = zeros( (ops_needed,64) ) - #print("Created add_ops with", ops_needed, "slots") + add_ops = 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: @@ -148,7 +174,7 @@ def resize(self, debug=False): print("op_exec_lists needs", ops_needed, "slots") if ops_needed == 0: return - add_ops = zeros( (ops_needed,el_width) ) + 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: @@ -160,7 +186,7 @@ def resize(self, debug=False): add_ops = np.append(self.op_exec_lists, add_ops, 0) self.op_exec_lists = add_ops.astype(types.int32) 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] @@ -180,19 +206,20 @@ def set_state(self, var_path, var_value=0.0, debug=False): self.state_ix[var_ix] = var_value if debug: print("Setting state_ix[", var_ix, "], to", var_value) - return(var_ix) - + 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) - - + return var_ix def op_path_name(operation, id): @@ -314,6 +341,7 @@ def state_context_hsp2(state, operation, segment, activity): state.hsp_segments[seg_name] = seg_path state.domain = seg_path # + "/" + activity # may want to comment out activity? + def state_init_hsp2(state, opseq, activities, om_operations): # This sets up the state entries for all state compatible HSP2 model variables # print("STATE initializing contexts.") @@ -334,12 +362,14 @@ def state_init_hsp2(state, opseq, activities, om_operations): state_context_hsp2(state, operation, segment, activity) - 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 + 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( io_manager, @@ -355,7 +385,6 @@ def state_load_hdf5_components( return - @njit def get_domain_state(state_paths, state_ix, domain, varkeys): # get values for a set of variables in a domain @@ -504,12 +533,12 @@ def hydr_get_ix(state, domain): "VOL", "VOLEV", ] - #print(state.state_paths) + # print(state.state_paths) hydr_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) for i in hydr_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i - #print("looking for:", var_path) + # print("looking for:", var_path) hydr_ix[i] = state.get_state_ix(var_path) return hydr_ix @@ -594,9 +623,9 @@ def load_dynamics(io_manager, siminfo): # see if there is a code module with custom python # print("Looking for SPECL with custom python code ", (fbase + ".py")) hsp2_local_py = dynamic_module_import(fbase, fbase + ".py", "hsp2_local_py") - siminfo['state_step_hydr'] = "disabled" + siminfo["state_step_hydr"] = "disabled" if "state_step_hydr" in dir(hsp2_local_py): - siminfo['state_step_hydr'] = "enabled" + siminfo["state_step_hydr"] = "enabled" print("state_step_hydr function defined, using custom python code") else: # print("state_step_hydr function not defined. Using default") diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.uci b/tests/testcbp/HSP2results/PL3_5250_0001.uci index ba530527..25d7a004 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.uci +++ b/tests/testcbp/HSP2results/PL3_5250_0001.uci @@ -224,11 +224,4 @@ PLTGEN 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 b/tests/testcbp/HSP2results/PL3_5250_0001eq.json similarity index 71% rename from tests/testcbp/HSP2results/PL3_5250_0001.json rename to tests/testcbp/HSP2results/PL3_5250_0001eq.json index ae9c3973..b7a94a97 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json +++ b/tests/testcbp/HSP2results/PL3_5250_0001eq.json @@ -11,8 +11,8 @@ "IVOLwrite": { "name": "IVOLwrite", "object_class": "ModelLinkage", - "left_path": "/STATE/PL3_5250_0001/RCHRES_R001/O2", - "right_path": "/STATE/PL3_5250_0001/RCHRES_R001/wd_cfs", + "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_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 bbbd2070..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/PL3_5250_0001/RCHRES_R001/O2", - "right_path": "/STATE/PL3_5250_0001/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 From 1497d1ec11e34366539cd5e64351002681cd5f21 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 1 Dec 2025 14:55:51 -0500 Subject: [PATCH 103/378] more testing cases --- .../testcbp/HSP2results/PL3_5250_0001spec.uci | 236 ++++++++++++++++++ tests/testcbp/HSP2results/check_equation.py | 26 +- 2 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001spec.uci 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/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 83dbe4db..39cc0355 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -101,9 +101,12 @@ # 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 * @@ -117,7 +120,24 @@ fpath = "./tests/testcbp/HSP2results/PL3_5250_0001.h5" run(fpath, saveall=True, compress=False) dstore_hydr = pd.HDFStore(str(fpath), mode='r') -hsp2_specl_hydr1 = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') -np.quantile(hsp2_specl_hydr1[:]['O2'], [0,0.25,0.5,0.75,1.0]) +hsp2_hydr = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') +np.quantile(hsp2_hydr[:]['O3'], [0,0.25,0.5,0.75,1.0]) +# To re-run: +dstore_hydr.close() + +fpath = "./tests/testcbp/HSP2results/PL3_5250_0001wd.h5" +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" +run(fpath, saveall=True, compress=False) +dstore_hydr = pd.HDFStore(str(fpath), mode='r') +hsp2_eq_hydr = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') +np.quantile(hsp2_eq_hydr[:]['O2'], [0,0.25,0.5,0.75,1.0]) # To re-run: dstore_hydr.close() From 4182dc7b89456ad6e18b34202edaf925a6d8da3d Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 10 Dec 2025 09:40:37 -0500 Subject: [PATCH 104/378] debug --- src/hsp2/hsp2/om.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 5d468af0..32f7efb0 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -741,6 +741,10 @@ def step_one(op_tokens, ops, state_ix, dict_ix, ts_ix, step, debug=0): print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) print("DEBUG: ops: ", ops) if ops[0] == 1: + if step < 2: + print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) + print("DEBUG: ops: ", ops) + print("DEBUG: calling: step_equation()", ops,state_ix) step_equation(ops, state_ix) elif ops[0] == 2: # todo: this should be moved into a single function, From 5f4fa6024d572e04655c28c9e2b6301fd5ba4572 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 10 Dec 2025 09:50:59 -0500 Subject: [PATCH 105/378] debug --- src/hsp2/hsp2/om.py | 2 +- src/hsp2/hsp2/om_equation.py | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 32f7efb0..7ae796a3 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -745,7 +745,7 @@ def step_one(op_tokens, ops, state_ix, dict_ix, ts_ix, step, debug=0): print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) print("DEBUG: ops: ", ops) print("DEBUG: calling: step_equation()", ops,state_ix) - 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 e7dd3159..851ea56d 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -442,7 +442,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 @@ -454,7 +454,8 @@ def step_equation(op_token, state_ix): 4 ] # this index is equal to the number of ops common to all classes + 1. See om_model_object for base ops and adjust op_loc = 5 # where do the operators and operands start in op_token - # print(num_ops, " operations") + if step < 2: + 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( @@ -482,8 +483,11 @@ def step_equation(op_token, state_ix): s_ix -= 1 else: val2 = state_ix[t2] - # print(s_ix, op, val1, val2) + if step < 2: + print("Ops to eval", s_ix, op, val1, val2) result = evaluate_eq_ops(op, val1, val2) + if step < 2: + print("result = ", result) s_ix += 1 if s_ix >= s_len: s = append(s, 0) From 51748ff459370e0e0e28578fcd4f98c8aec4bbd8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 10 Dec 2025 09:55:11 -0500 Subject: [PATCH 106/378] debug --- src/hsp2/hsp2/om_equation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index 851ea56d..5e713336 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -470,6 +470,7 @@ def step_equation(op_token, state_ix, step): op = op_token[op_loc + 3 * i] t1 = op_token[op_loc + 3 * i + 1] t2 = op_token[op_loc + 3 * i + 2] + print("op tokens", op, t1, t2) # if val1 or val2 are < 0 this means they are to come from the stack # if token is negative, means we need to use a stack value # print("s", s) From a7cc7a65f15814ee93280561214632e06e3975f0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 10 Dec 2025 09:59:32 -0500 Subject: [PATCH 107/378] debug --- src/hsp2/hsp2/om_equation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index 5e713336..ea0a81fe 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -458,11 +458,16 @@ def step_equation(op_token, state_ix, step): 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: + print("op tokens", op_token[op_loc], op_token[op_loc + 1], op_token[op_loc + 2]) + if step < 2: + print("Ops to eval", op_token[op_loc], state_ix[op_token[op_loc + 1]], state_ix[op_token[op_loc + 2]]) result = evaluate_eq_ops( op_token[op_loc], state_ix[op_token[op_loc + 1]], state_ix[op_token[op_loc + 2]], ) + if step < 2: + print("result = ", result) else: for i in range(num_ops): # the number of ops common to all classes + 1 (the counter for math operators) is offset for this @@ -470,7 +475,6 @@ def step_equation(op_token, state_ix, step): op = op_token[op_loc + 3 * i] t1 = op_token[op_loc + 3 * i + 1] t2 = op_token[op_loc + 3 * i + 2] - print("op tokens", op, t1, t2) # if val1 or val2 are < 0 this means they are to come from the stack # if token is negative, means we need to use a stack value # print("s", s) @@ -484,11 +488,7 @@ def step_equation(op_token, state_ix, step): s_ix -= 1 else: val2 = state_ix[t2] - if step < 2: - print("Ops to eval", s_ix, op, val1, val2) result = evaluate_eq_ops(op, val1, val2) - if step < 2: - print("result = ", result) s_ix += 1 if s_ix >= s_len: s = append(s, 0) From ab100b6a482f8a3b0b19d5641a781b3cd3c0b311 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 10 Dec 2025 10:00:50 -0500 Subject: [PATCH 108/378] debug --- src/hsp2/hsp2/om_equation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index ea0a81fe..1fd08d03 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -458,8 +458,8 @@ def step_equation(op_token, state_ix, step): 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: - print("op tokens", op_token[op_loc], op_token[op_loc + 1], op_token[op_loc + 2]) if step < 2: + print("op tokens", op_token[op_loc], op_token[op_loc + 1], op_token[op_loc + 2]) print("Ops to eval", op_token[op_loc], state_ix[op_token[op_loc + 1]], state_ix[op_token[op_loc + 2]]) result = evaluate_eq_ops( op_token[op_loc], From ff6163ac78312c5c5b45ae99cfc420932ed686fb Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 10:02:48 -0500 Subject: [PATCH 109/378] debug --- src/hsp2/hsp2/om_model_object.py | 4 ++-- tests/testcbp/HSP2results/check_equation.py | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 1fbc1a69..5c2e074c 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -299,11 +299,11 @@ def find_var_path(self, var_name, local_only=False): if (self.state_path + "/" + var_name) in self.state.state_paths: return self.state_path + "/" + var_name if local_only: - print("Cannot find var in local scope", var_name) + 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 in container scope", var_name) + 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: diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 39cc0355..8dec970a 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -15,8 +15,8 @@ from pandas import read_hdf -fpath = "./tests/testcbp/HSP2results/PL3_5250_0001.h5" -ucipath = "./tests/testcbp/HSP2results/PL3_5250_0001.uci" +fpath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.h5" +ucipath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.uci" uci = readUCI(ucipath, fpath) # try also: @@ -59,6 +59,8 @@ # mtl = [] # mel = [] # model_order_recursive(endpoint, om_operations["model_object_cache"], mel, mtl, True) +O3 = om_operations["model_object_cache"]["/STATE/RCHRES_R001/O3"] +wd_cfs = om_operations["model_object_cache"]["/STATE/PL3_5250_0001eq/RCHRES_R001/wd_cfs"] # state['model_root_object'].find_var_path('RCHRES_R001') # Get the timeseries naked, without an object @@ -138,6 +140,6 @@ run(fpath, saveall=True, compress=False) dstore_hydr = pd.HDFStore(str(fpath), mode='r') hsp2_eq_hydr = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') +dstore_hydr.close() np.quantile(hsp2_eq_hydr[:]['O2'], [0,0.25,0.5,0.75,1.0]) # To re-run: -dstore_hydr.close() From 6a318d42abf9ac9e9be90f442e792ddc4a61de23 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:08:25 -0500 Subject: [PATCH 110/378] debug --- src/hsp2/hsp2/HYDR.py | 3 +++ tests/testcbp/HSP2results/check_equation.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index d3667dd3..066d01e9 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -382,7 +382,10 @@ def _hydr_( state.state_ix[ro_ix], state.state_ix[rovol_ix] = ro, rovol di = 0 for oi in range(nexits): + if step <= 2: + print("Setting O var", oi, "to", outdgt[oi]) state.state_ix[out_ix[oi]] = outdgt[oi] + state.state_ix[vol_ix], state.state_ix[ivol_ix] = vol, IVOL0[step] state.state_ix[volev_ix] = volev # - these if statements may be irrelevant if default functions simply return diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 8dec970a..0bc6d875 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -39,6 +39,8 @@ om_operations = om_init_state() state_siminfo_hsp2(state, uci_obj, siminfo, io_manager) +# now initialize all state variables for mutable variables +hsp2_domain_dependencies(state, opseq, activities, om_operations, True) # 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) @@ -61,6 +63,7 @@ # model_order_recursive(endpoint, om_operations["model_object_cache"], mel, mtl, True) O3 = om_operations["model_object_cache"]["/STATE/RCHRES_R001/O3"] wd_cfs = om_operations["model_object_cache"]["/STATE/PL3_5250_0001eq/RCHRES_R001/wd_cfs"] +wd_cfs.find_var_path("O3") # state['model_root_object'].find_var_path('RCHRES_R001') # Get the timeseries naked, without an object From f9ca6da7c3ce3d08e38d3459f523384b9bacd293 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:12:51 -0500 Subject: [PATCH 111/378] debug --- src/hsp2/hsp2/HYDR.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 066d01e9..c3dbfa26 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -381,6 +381,8 @@ def _hydr_( # Note: we pass IVOL0, not IVOL here since IVOL has been converted to different units state.state_ix[ro_ix], state.state_ix[rovol_ix] = ro, rovol di = 0 + if step <= 2: + print("Number of exits nexits = ",nexits) for oi in range(nexits): if step <= 2: print("Setting O var", oi, "to", outdgt[oi]) From 1996bca05adc23e23fafef827b9b862a06416256 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:16:22 -0500 Subject: [PATCH 112/378] debug --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index c3dbfa26..e263e42c 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -385,7 +385,7 @@ def _hydr_( print("Number of exits nexits = ",nexits) for oi in range(nexits): if step <= 2: - print("Setting O var", oi, "to", outdgt[oi]) + print("Setting O var", oi, "with state index", out_ix[oi], "to", outdgt[oi]) state.state_ix[out_ix[oi]] = outdgt[oi] state.state_ix[vol_ix], state.state_ix[ivol_ix] = vol, IVOL0[step] From be1e938d532d97d4f1b18ff968d78f681058223c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:18:37 -0500 Subject: [PATCH 113/378] debug --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index e263e42c..b127ece4 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -385,7 +385,7 @@ def _hydr_( print("Number of exits nexits = ",nexits) for oi in range(nexits): if step <= 2: - print("Setting O var", oi, "with state index", out_ix[oi], "to", outdgt[oi]) + print("Setting O var", oi, "with state index", out_ix[oi], "and path", get_ix_path(state.state_paths, out_ix[oi]), "to", outdgt[oi]) state.state_ix[out_ix[oi]] = outdgt[oi] state.state_ix[vol_ix], state.state_ix[ivol_ix] = vol, IVOL0[step] From fc78f4ad8355b8d8fc75f42e75f58aca060c8afb Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:19:52 -0500 Subject: [PATCH 114/378] debug --- src/hsp2/state/state.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 5de85f46..7057d6b9 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -220,6 +220,16 @@ def get_state_ix(self, var_path): return False # should throw an error var_ix = self.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 op_path_name(operation, id): @@ -242,17 +252,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 From 8881a27d90e39f9abdb2315ac35cef9ac40a0c95 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:23:40 -0500 Subject: [PATCH 115/378] debug --- src/hsp2/hsp2/HYDR.py | 2 +- src/hsp2/hsp2/om.py | 5 ++--- tests/testcbp/HSP2results/check_equation.py | 5 ++++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index b127ece4..0f2bf7f0 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -385,7 +385,7 @@ def _hydr_( print("Number of exits nexits = ",nexits) for oi in range(nexits): if step <= 2: - print("Setting O var", oi, "with state index", out_ix[oi], "and path", get_ix_path(state.state_paths, out_ix[oi]), "to", outdgt[oi]) + print("Setting O var", oi, "with state index", out_ix[oi], "and path", state.get_ix_path(out_ix[oi]), "to", outdgt[oi]) state.state_ix[out_ix[oi]] = outdgt[oi] state.state_ix[vol_ix], state.state_ix[ivol_ix] = vol, IVOL0[step] diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 7ae796a3..a8364e9a 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -14,7 +14,6 @@ from hsp2.state.state import ( append_state, - get_ix_path, hydr_init_ix, rqual_init_ix, sedmnt_init_ix, @@ -53,7 +52,7 @@ def model_element_paths(mel, state): """ ixn = 1 for ix in mel: - ip = get_ix_path(state.state_paths, ix) + 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 @@ -724,7 +723,7 @@ def finish_model(state, io_manager, siminfo): # 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"][ - get_ix_path(state.state_paths, i) + state.get_ix_path(i) ] if "io_manager" in dir(model_object): model_object.io_manager = io_manager diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 0bc6d875..b1570941 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -63,6 +63,9 @@ # model_order_recursive(endpoint, om_operations["model_object_cache"], mel, mtl, True) O3 = om_operations["model_object_cache"]["/STATE/RCHRES_R001/O3"] 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("O3") # state['model_root_object'].find_var_path('RCHRES_R001') @@ -140,7 +143,7 @@ fpath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.h5" -run(fpath, saveall=True, compress=False) +#run(fpath, saveall=True, compress=False) dstore_hydr = pd.HDFStore(str(fpath), mode='r') hsp2_eq_hydr = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') dstore_hydr.close() From 009759452efb25a64a015a79e99e654cbf5d7312 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:27:30 -0500 Subject: [PATCH 116/378] Move get_ix_path to state object and use numpy array tuple handler to iterate --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 7057d6b9..9bbd9118 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -225,7 +225,7 @@ 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(): + for spath, ix in np.ndenumerate(state_paths): if var_ix == ix: # we need to add this to the state return spath From 953376cbc7ea00cc5c84a91cee22a573c3d93596 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:32:28 -0500 Subject: [PATCH 117/378] items are a dictionary must refer to state also --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 9bbd9118..d0c5c1ad 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -225,7 +225,7 @@ def get_ix_path(state_paths, var_ix): """ Find the path of a variable with integer key in state_ix """ - for spath, ix in np.ndenumerate(state_paths): + for spath, ix in self.state_paths.items(): if var_ix == ix: # we need to add this to the state return spath From 4050a29928a58d95500e9b932dc2eac1406ad904 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:32:50 -0500 Subject: [PATCH 118/378] use correct method syntac --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index d0c5c1ad..db1fc1d6 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -221,7 +221,7 @@ def get_state_ix(self, var_path): var_ix = self.state_paths[var_path] return var_ix - def get_ix_path(state_paths, var_ix): + def get_ix_path(self, var_ix): """ Find the path of a variable with integer key in state_ix """ From 2e27c2dd0d60e7fe2dd870166e0d92d701325de7 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 12 Dec 2025 11:37:33 -0500 Subject: [PATCH 119/378] can we return unicode or None? --- src/hsp2/state/state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index db1fc1d6..2ec1ee22 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -225,11 +225,12 @@ 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 False + return spath def op_path_name(operation, id): From 704e6fbd5aace065f255bd2e4b387b41814b1b4f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 17 Dec 2025 16:52:27 -0500 Subject: [PATCH 120/378] more debug --- src/hsp2/hsp2/HYDR.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 0f2bf7f0..eab436e8 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -384,7 +384,7 @@ def _hydr_( if step <= 2: print("Number of exits nexits = ",nexits) for oi in range(nexits): - if step <= 2: + if step <= 5: print("Setting O var", oi, "with state index", out_ix[oi], "and path", state.get_ix_path(out_ix[oi]), "to", outdgt[oi]) state.state_ix[out_ix[oi]] = outdgt[oi] diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index b1570941..6d27e7b8 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -61,7 +61,7 @@ # mtl = [] # mel = [] # model_order_recursive(endpoint, om_operations["model_object_cache"], mel, mtl, True) -O3 = om_operations["model_object_cache"]["/STATE/RCHRES_R001/O3"] +O3 = om_operations["model_object_cache"]["/STATE/PL3_5250_0001eq/RCHRES_R001/O3"] 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]) From d816181ea8cacc9cf580226168ee336b1870c397 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 17 Dec 2025 17:23:09 -0500 Subject: [PATCH 121/378] provide OVOL to state for use in specl --- src/hsp2/hsp2/HYDR.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index eab436e8..a63024ae 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -350,6 +350,11 @@ def _hydr_( 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"], @@ -358,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) @@ -387,6 +396,8 @@ def _hydr_( if step <= 5: print("Setting O var", oi, "with state index", out_ix[oi], "and path", state.get_ix_path(out_ix[oi]), "to", outdgt[oi]) state.state_ix[out_ix[oi]] = outdgt[oi] + # 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, IVOL0[step] state.state_ix[volev_ix] = volev @@ -408,6 +419,10 @@ def _hydr_( if (state.state_step_hydr == "enabled") or ( state.state_step_om == "enabled" ): + for oi in range(nexits): + if step <= 5: + print("Copying O var", oi, "with state index", out_ix[oi], "from state to outdgt", outdgt[oi]) + state.state_ix[out_ix[oi]] = outdgt[oi] # Do write-backs for editable STATE variables # OUTDGT is writeable for oi in range(nexits): From 7cd18af8c5ed56aea1a9c034e5df0129f7cf4cbc Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 17 Dec 2025 17:23:54 -0500 Subject: [PATCH 122/378] ref ovol3 in equation for withdrawal --- tests/testcbp/HSP2results/PL3_5250_0001eq.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eq.json b/tests/testcbp/HSP2results/PL3_5250_0001eq.json index b7a94a97..c0eef21d 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001eq.json +++ b/tests/testcbp/HSP2results/PL3_5250_0001eq.json @@ -6,7 +6,7 @@ "wd_cfs": { "name": "wd_cfs", "object_class": "Equation", - "value": "0.1 * O3" + "value": "0.1 * OVOL3" }, "IVOLwrite": { "name": "IVOLwrite", From e0a07b0bea07dd614404c59ea340e91d34b89e43 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 18 Dec 2025 07:31:15 -0500 Subject: [PATCH 123/378] corrected bad overwrite of demand o1,... and set test flow to ivol --- src/hsp2/hsp2/HYDR.py | 4 ---- tests/testcbp/HSP2results/PL3_5250_0001eq.json | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index a63024ae..825b27f6 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -419,10 +419,6 @@ def _hydr_( if (state.state_step_hydr == "enabled") or ( state.state_step_om == "enabled" ): - for oi in range(nexits): - if step <= 5: - print("Copying O var", oi, "with state index", out_ix[oi], "from state to outdgt", outdgt[oi]) - state.state_ix[out_ix[oi]] = outdgt[oi] # Do write-backs for editable STATE variables # OUTDGT is writeable for oi in range(nexits): diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eq.json b/tests/testcbp/HSP2results/PL3_5250_0001eq.json index c0eef21d..e79edcc1 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001eq.json +++ b/tests/testcbp/HSP2results/PL3_5250_0001eq.json @@ -6,7 +6,7 @@ "wd_cfs": { "name": "wd_cfs", "object_class": "Equation", - "value": "0.1 * OVOL3" + "value": "0.1 * IVOL" }, "IVOLwrite": { "name": "IVOLwrite", From 08ca68e4830d6ce00e886575802a3a77ed04dae4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 19 Dec 2025 09:56:36 -0500 Subject: [PATCH 124/378] debug --- src/hsp2/hsp2/om_model_linkage.py | 7 ++++--- tests/testcbp/HSP2results/check_equation.py | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index a4c500cd..d24312c0 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -232,12 +232,13 @@ def finish(self): # Function for use during model simulations of tokenized objects @njit 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 step <= 2: + 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: + if step <= 2: + print("Copying op id", op_token[2], "with value", state_ix[op_token[2]], "to id", op_token[1]) state_ix[op_token[1]] = state_ix[op_token[2]] return True elif op_token[3] == 3: diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 6d27e7b8..5843a01f 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -129,7 +129,7 @@ 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[:]['O3'], [0,0.25,0.5,0.75,1.0]) +np.quantile(hsp2_hydr[:]['O2'], [0,0.25,0.5,0.75,1.0]) # To re-run: dstore_hydr.close() @@ -143,9 +143,9 @@ fpath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.h5" -#run(fpath, saveall=True, compress=False) -dstore_hydr = pd.HDFStore(str(fpath), mode='r') -hsp2_eq_hydr = read_hdf(dstore_hydr, '/RESULTS/RCHRES_R001/HYDR') -dstore_hydr.close() +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: From 5d5891dbc8ce3add9e07b9020524b1da0d67668c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 19 Dec 2025 10:00:01 -0500 Subject: [PATCH 125/378] debug --- src/hsp2/hsp2/om_model_linkage.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index d24312c0..4bf9ace1 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -251,6 +251,8 @@ def step_model_link(op_token, state_ix, ts_ix, step): return True elif op_token[3] == 5: # overwrite remote variable state with value in another paths state + if step <= 2: + print("Copying op id", op_token[4], "with value", state_ix[op_token[4]], "to id", op_token[2]) state_ix[op_token[2]] = state_ix[op_token[4]] return True elif op_token[3] == 6: From 167a62a9c8212b758907ebed040f60ee8f003f1c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 19 Dec 2025 10:11:08 -0500 Subject: [PATCH 126/378] debug --- src/hsp2/hsp2/HYDR.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 825b27f6..69f7e4e1 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -390,12 +390,7 @@ def _hydr_( # Note: we pass IVOL0, not IVOL here since IVOL has been converted to different units state.state_ix[ro_ix], state.state_ix[rovol_ix] = ro, rovol di = 0 - if step <= 2: - print("Number of exits nexits = ",nexits) for oi in range(nexits): - if step <= 5: - print("Setting O var", oi, "with state index", out_ix[oi], "and path", state.get_ix_path(out_ix[oi]), "to", outdgt[oi]) - state.state_ix[out_ix[oi]] = outdgt[oi] # Write OVOL for use in equations/specacts. Note: this must be improved! too much code... state.state_ix[ovol_ix[oi]] = ovol[oi] @@ -422,6 +417,8 @@ def _hydr_( # Do write-backs for editable STATE variables # OUTDGT is writeable for oi in range(nexits): + if step <= 5: + print("Getting O var", oi, "with state index", out_ix[oi], "and path", state.get_ix_path(out_ix[oi]), "from state ix", out_ix[oi],"val=", state.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_ From 37c5b0faba6f1e817d73169a8b54367b716cc31d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 19 Dec 2025 10:11:44 -0500 Subject: [PATCH 127/378] debug --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 69f7e4e1..97a224ae 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -418,7 +418,7 @@ def _hydr_( # OUTDGT is writeable for oi in range(nexits): if step <= 5: - print("Getting O var", oi, "with state index", out_ix[oi], "and path", state.get_ix_path(out_ix[oi]), "from state ix", out_ix[oi],"val=", state.state_ix[out_ix[oi]] + print("Getting O var", oi, "with state index", out_ix[oi], "and path", state.get_ix_path(out_ix[oi]), "from state ix", out_ix[oi],"val=", state.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_ From 1fb6e64018d487a026977455af1758c23676c07c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 19 Dec 2025 10:33:20 -0500 Subject: [PATCH 128/378] do not convert ivol in state transactions, if ops need conversions they should handle it themselves --- src/hsp2/hsp2/HYDR.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 97a224ae..17508ab9 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -394,7 +394,7 @@ def _hydr_( # 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, IVOL0[step] + 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. @@ -423,7 +423,7 @@ def _hydr_( # 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.state_ix[ivol_ix] * VFACT + IVOL[step] = state.state_ix[ivol_ix] # End dynamic code step() ####################################################################################### From 2ae811ae0faff85b404be51f6950424dd2a56d91 Mon Sep 17 00:00:00 2001 From: Rob Date: Mon, 29 Dec 2025 19:41:41 +0000 Subject: [PATCH 129/378] added an extra equation --- tests/testcbp/HSP2results/PL3_5250_0001eq.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eq.json b/tests/testcbp/HSP2results/PL3_5250_0001eq.json index e79edcc1..82aaec29 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001eq.json +++ b/tests/testcbp/HSP2results/PL3_5250_0001eq.json @@ -8,6 +8,11 @@ "object_class": "Equation", "value": "0.1 * IVOL" }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "value": "OVOL3 * 12.1" + }, "IVOLwrite": { "name": "IVOLwrite", "object_class": "ModelLinkage", From 21cef61e319e5afa2ce6455bf41c4c072f5f975a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 29 Dec 2025 15:09:34 -0500 Subject: [PATCH 130/378] removed deprecated column --- src/hsp2/hsp2/HYDR.py | 2 -- tests/testcbp/HSP2results/check_equation.py | 9 ++++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 17508ab9..8650a838 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -336,7 +336,6 @@ 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 @@ -387,7 +386,6 @@ def _hydr_( # the following section (3 of 3) added by rb to accommodate dynamic code, operations models, and special actions ####################################################################################### # set state.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.state_ix[ro_ix], state.state_ix[rovol_ix] = ro, rovol di = 0 for oi in range(nexits): diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 5843a01f..addc1e99 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -126,7 +126,8 @@ from pandas import read_hdf fpath = "./tests/testcbp/HSP2results/PL3_5250_0001.h5" -run(fpath, saveall=True, compress=False) +# 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]) @@ -134,7 +135,8 @@ dstore_hydr.close() fpath = "./tests/testcbp/HSP2results/PL3_5250_0001wd.h5" -run(fpath, saveall=True, compress=False) +# 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() @@ -143,7 +145,8 @@ fpath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.h5" -run(fpath, saveall=True, compress=False) +# 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() From a3ce2fc2c3a7dc29d34da22bad4193973de920e4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 29 Dec 2025 15:46:38 -0500 Subject: [PATCH 131/378] madapt sedtrn to new state object --- src/hsp2/hsp2/SEDTRN.py | 67 ++++++++++++----------------------------- src/hsp2/state/state.py | 4 +-- 2 files changed, 21 insertions(+), 50 deletions(-) diff --git a/src/hsp2/hsp2/SEDTRN.py b/src/hsp2/hsp2/SEDTRN.py index 4b0debe0..997dadb9 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, sedtrn_init_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()? @@ -114,29 +101,17 @@ def sedtrn(io_manager, siminfo, parameters, ts, state): # 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 = state.get_state_ix(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 +140,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 +373,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_info.domain) # these are integer placeholders faster than calling the array look each timestep rsed4_ix, rsed5_ix, rsed6_ix = ( sedtrn_ix["RSED4"], @@ -417,24 +387,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 ) # (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/state/state.py b/src/hsp2/state/state.py index 2ec1ee22..05f44962 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -544,13 +544,13 @@ def hydr_get_ix(state, domain): @njit -def sedtrn_get_ix(state_ix, state_paths, domain): +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) for i in sedtrn_state: var_path = domain + "/" + i - sedtrn_ix[i] = state_paths[var_path] + sedtrn_ix[i] = state.get_state_ix(var_path) return sedtrn_ix From 92b7fca2bc8016a57452161a0cddb2aba7719515 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 29 Dec 2025 15:53:01 -0500 Subject: [PATCH 132/378] io_manager was no longer used --- src/hsp2/hsp2/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 560704fe..374a6b55 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -404,7 +404,7 @@ def main( ) elif activity == "SEDTRN" or activity == "SEDMNT": errors, errmessages = function( - io_manager, siminfo, ui, ts, state + siminfo, ui, ts, state ) elif activity != "RQUAL": errors, errmessages = function(io_manager, siminfo, ui, ts) From 0be33d4743bbd36e19c68ed1a42aae7688bba07f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 29 Dec 2025 15:57:04 -0500 Subject: [PATCH 133/378] io_manager was no longer used --- src/hsp2/hsp2/SEDTRN.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/SEDTRN.py b/src/hsp2/hsp2/SEDTRN.py index 997dadb9..b7078ecb 100644 --- a/src/hsp2/hsp2/SEDTRN.py +++ b/src/hsp2/hsp2/SEDTRN.py @@ -373,7 +373,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, 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"], From d499de31bea85903c9d86914b156244dc79b23ed Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 29 Dec 2025 16:01:05 -0500 Subject: [PATCH 134/378] one more state migration fix --- src/hsp2/hsp2/SEDTRN.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/SEDTRN.py b/src/hsp2/hsp2/SEDTRN.py index b7078ecb..56d9da19 100644 --- a/src/hsp2/hsp2/SEDTRN.py +++ b/src/hsp2/hsp2/SEDTRN.py @@ -392,7 +392,7 @@ def _sedtrn_( 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 From 89c003fe348916eac2f8e37a001a7c6aa03128cf Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 30 Dec 2025 11:14:17 -0500 Subject: [PATCH 135/378] migrate RQUAL to new format --- src/hsp2/hsp2/RQUAL.py | 36 ++++----------------- src/hsp2/hsp2/RQUAL_Class.py | 62 +++++++++++++++++------------------- src/hsp2/state/state.py | 8 ++--- 3 files changed, 40 insertions(+), 66 deletions(-) diff --git a/src/hsp2/hsp2/RQUAL.py b/src/hsp2/hsp2/RQUAL.py index b69e3911..382a883d 100644 --- a/src/hsp2/hsp2/RQUAL.py +++ b/src/hsp2/hsp2/RQUAL.py @@ -267,17 +267,10 @@ def rqual( # 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 = state.get_state_ix(activity_path) + model_exec_list = state.op_exec_lists[activity_id] ####################################################################################### # --------------------------------------------------------------------- @@ -292,12 +285,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 +352,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 +365,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/state/state.py b/src/hsp2/state/state.py index 05f44962..47c88519 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -555,18 +555,18 @@ def sedtrn_get_ix(state, domain): @njit -def sedmnt_get_ix(state_ix, state_paths, domain): +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) for i in sedmnt_state: var_path = domain + "/" + i - sedmnt_ix[i] = state_paths[var_path] + sedmnt_ix[i] = state.get_state_ix(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", @@ -584,7 +584,7 @@ def rqual_get_ix(state_ix, state_paths, domain): rqual_ix = Dict.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] = state.get_state_ix(var_path) return rqual_ix From c7ccff7549ce2a72ec1938024fce0fff50ff444e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 30 Dec 2025 14:45:56 -0500 Subject: [PATCH 136/378] debug off --- src/hsp2/hsp2/HYDR.py | 2 -- src/hsp2/hsp2/om.py | 3 ++- src/hsp2/state/state.py | 5 +++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 8650a838..7b4f1abf 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -415,8 +415,6 @@ def _hydr_( # Do write-backs for editable STATE variables # OUTDGT is writeable for oi in range(nexits): - if step <= 5: - print("Getting O var", oi, "with state index", out_ix[oi], "and path", state.get_ix_path(out_ix[oi]), "from state ix", out_ix[oi],"val=", state.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_ diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index a8364e9a..aebb4087 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -662,7 +662,8 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals activity_path = seg_path + "/" + activity activity_id = state.set_state(activity_path, 0.0) ep_list = [] - print("Getting init_ix for", seg_path, activity) + if debug: + print("Getting init_ix for", seg_path, activity) if activity == "HYDR": ep_list = hydr_init_ix(state, seg_path) elif activity == "SEDTRN": diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 47c88519..d420ed72 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -442,14 +442,15 @@ 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) for i in hydr_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i - print("initializing", var_path) + if debug: + print("initializing", var_path) hydr_ix[i] = state.set_state(var_path, 0.0) return hydr_ix From 7916fec530e8ba5bf454e368599e78fc76852f89 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 30 Dec 2025 14:47:40 -0500 Subject: [PATCH 137/378] debug off --- src/hsp2/hsp2/om_equation.py | 7 ------- src/hsp2/hsp2/om_model_object.py | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index 1fd08d03..1319ce1e 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -454,20 +454,13 @@ def step_equation(op_token, state_ix, step): 4 ] # this index is equal to the number of ops common to all classes + 1. See om_model_object for base ops and adjust op_loc = 5 # where do the operators and operands start in op_token - if step < 2: - 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: - if step < 2: - print("op tokens", op_token[op_loc], op_token[op_loc + 1], op_token[op_loc + 2]) - print("Ops to eval", op_token[op_loc], state_ix[op_token[op_loc + 1]], state_ix[op_token[op_loc + 2]]) result = evaluate_eq_ops( op_token[op_loc], state_ix[op_token[op_loc + 1]], state_ix[op_token[op_loc + 2]], ) - if step < 2: - print("result = ", result) else: for i in range(num_ops): # the number of ops common to all classes + 1 (the counter for math operators) is offset for this diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 5c2e074c..c683e2f0 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -303,7 +303,7 @@ def find_var_path(self, var_name, local_only=False): 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) + #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: From f59f92c63bc3abe77bad87c551000cde9f64850e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 30 Dec 2025 15:01:02 -0500 Subject: [PATCH 138/378] debug off --- src/hsp2/hsp2/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 374a6b55..88cb5e36 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -98,7 +98,7 @@ def main( # before loading dynamic components that may reference them state_init_hsp2(state, opseq, activities, om_operations) # now initialize all state variables for mutable variables - hsp2_domain_dependencies(state, opseq, activities, om_operations, True) + hsp2_domain_dependencies(state, opseq, activities, om_operations, False) # - finally stash specactions in state, not domain (segment) dependent so do it once specl_load_om(om_operations, specactions) # load traditional special actions state_load_dynamics_om( From 705f355544fb357f7646315a90d1333043d02adf Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 30 Dec 2025 15:25:24 -0500 Subject: [PATCH 139/378] test no om --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index aebb4087..8680341e 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -225,7 +225,7 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): om_operations["model_object_cache"] = model_object_cache state.model_exec_list = np.asarray(model_exec_list, dtype="int32") if len(state.op_tokens) > 0: - state.state_step_om = "enabled" + state.state_step_om = "disabled" if len(state.model_exec_list) > 0: print( "op_tokens has", From 5702caf886f538e4c00c6a1f05d7f306e8444d21 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 30 Dec 2025 15:54:12 -0500 Subject: [PATCH 140/378] reenable om --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 8680341e..aebb4087 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -225,7 +225,7 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): om_operations["model_object_cache"] = model_object_cache state.model_exec_list = np.asarray(model_exec_list, dtype="int32") if len(state.op_tokens) > 0: - state.state_step_om = "disabled" + state.state_step_om = "enabled" if len(state.model_exec_list) > 0: print( "op_tokens has", From 95b5f704585a96663b854cb2d8b85ce4efbb7ba0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 30 Dec 2025 18:11:02 -0500 Subject: [PATCH 141/378] debug off --- src/hsp2/hsp2/om_model_linkage.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index 4bf9ace1..f837afdc 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -232,13 +232,9 @@ def finish(self): # Function for use during model simulations of tokenized objects @njit 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) if op_token[3] == 1: return True elif op_token[3] == 2: - if step <= 2: - print("Copying op id", op_token[2], "with value", state_ix[op_token[2]], "to id", op_token[1]) state_ix[op_token[1]] = state_ix[op_token[2]] return True elif op_token[3] == 3: @@ -251,21 +247,10 @@ def step_model_link(op_token, state_ix, ts_ix, step): return True elif op_token[3] == 5: # overwrite remote variable state with value in another paths state - if step <= 2: - print("Copying op id", op_token[4], "with value", state_ix[op_token[4]], "to id", op_token[2]) state_ix[op_token[2]] = state_ix[op_token[4]] 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 From 9cd4d7c0c43801ddc75d539cc90af5f14d8916ac Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 30 Dec 2025 18:47:34 -0500 Subject: [PATCH 142/378] debug off --- src/hsp2/hsp2/om.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index aebb4087..775da20e 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -741,10 +741,6 @@ def step_one(op_tokens, ops, state_ix, dict_ix, ts_ix, step, debug=0): print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) print("DEBUG: ops: ", ops) if ops[0] == 1: - if step < 2: - print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) - print("DEBUG: ops: ", ops) - print("DEBUG: calling: step_equation()", ops,state_ix) step_equation(ops, state_ix, step) elif ops[0] == 2: # todo: this should be moved into a single function, From d034b0531185a0eb58418c51e06cf19ba761bed0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 31 Dec 2025 14:01:59 -0500 Subject: [PATCH 143/378] added refresh for uci only command --- src/hsp2/hsp2tools/HSP2_CLI.py | 3 ++- src/hsp2/hsp2tools/commands.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) 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..623b2574 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -57,3 +57,28 @@ 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. + """ + + readUCI(ucifile, h5file) + + with open(ucifile) as fp: + uci = [] + for line in fp.readlines(): + if "***" in line[:81]: + continue + if not line[:81].strip(): + continue + uci.append(line[:81].rstrip()) From 53b077a2894738e9eafb4bb8f154b6fdd308ac74 Mon Sep 17 00:00:00 2001 From: Rob Date: Wed, 31 Dec 2025 18:55:31 +0000 Subject: [PATCH 144/378] added a long running version of UCI --- .../HSP2results/PL3_5250_0001eqlong.uci. | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci. diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci. b/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci. new file mode 100644 index 00000000..27f93f16 --- /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 2001/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 From f8915290ee6c0141869faf7d2d883e9a154a76e9 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 31 Dec 2025 14:07:31 -0500 Subject: [PATCH 145/378] dont remove existing h5 --- src/hsp2/hsp2tools/commands.py | 4 +- .../HSP2results/PL3_5250_0001eqlong.uci | 228 ++++++++++++++++++ 2 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci diff --git a/src/hsp2/hsp2tools/commands.py b/src/hsp2/hsp2tools/commands.py index 623b2574..b83d8ece 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -71,8 +71,8 @@ def update_uci(ucifile, h5file): h5file: str The destination HDF5 file. """ - - readUCI(ucifile, h5file) + # we send False here to prevent deleting and recreating the UCI + readUCI(ucifile, h5file, False) with open(ucifile) as fp: uci = [] diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci b/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci new file mode 100644 index 00000000..27f93f16 --- /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 2001/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 From 1760357b2dbd5e96707b5e5d57dbc2708f58d395 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 31 Dec 2025 14:14:32 -0500 Subject: [PATCH 146/378] add info --- src/hsp2/hsp2tools/commands.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2tools/commands.py b/src/hsp2/hsp2tools/commands.py index b83d8ece..d27ffc1b 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -73,7 +73,9 @@ def update_uci(ucifile, h5file): """ # we send False here to prevent deleting and recreating the UCI readUCI(ucifile, h5file, False) - + 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 ...' ") with open(ucifile) as fp: uci = [] for line in fp.readlines(): From 70ba943691a2d362ed3c85d4be68048fdd8298d8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 31 Dec 2025 14:26:15 -0500 Subject: [PATCH 147/378] add info --- src/hsp2/hsp2tools/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2tools/commands.py b/src/hsp2/hsp2tools/commands.py index d27ffc1b..73519703 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -72,10 +72,10 @@ def update_uci(ucifile, h5file): The destination HDF5 file. """ # we send False here to prevent deleting and recreating the UCI - readUCI(ucifile, h5file, False) 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) with open(ucifile) as fp: uci = [] for line in fp.readlines(): From f1103a929f96c6f77c0dc112878a77bcdeb46a74 Mon Sep 17 00:00:00 2001 From: Rob Date: Wed, 31 Dec 2025 19:26:37 +0000 Subject: [PATCH 148/378] update uci test --- .../HSP2results/PL3_5250_0001eqlong.uci | 2 +- .../HSP2results/PL3_5250_0001eqlong.uci. | 228 ------------------ 2 files changed, 1 insertion(+), 229 deletions(-) delete mode 100644 tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci. diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci b/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci index 27f93f16..5cc08fab 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci +++ b/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci @@ -3,7 +3,7 @@ RUN GLOBAL PL3_5250_0 riv | P5 | hsp2_2022 | Occoquan - START 2001/01/01 END 2019/12/31 + START 1984/01/01 END 2019/12/31 RUN INTERP OUTPUT LEVEL 1 1 RESUME 0 RUN 1 UNIT SYSTEM 1 END GLOBAL diff --git a/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci. b/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci. deleted file mode 100644 index 27f93f16..00000000 --- a/tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci. +++ /dev/null @@ -1,228 +0,0 @@ -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 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 From 07938cf760dac4beb8a9d33ff7b31c9e9ae9ac16 Mon Sep 17 00:00:00 2001 From: "Robert W. Burgholzer" Date: Fri, 2 Jan 2026 21:14:07 +0000 Subject: [PATCH 149/378] Add update_uci mode in CLI and test UCI files --- src/hsp2/hsp2tools/HSP2_CLI.py | 3 +- src/hsp2/hsp2tools/commands.py | 27 +++ tests/testcbp/HSP2results/PL3_5250_0001eq.uci | 228 ++++++++++++++++++ .../HSP2results/PL3_5250_0001eqlong.uci | 228 ++++++++++++++++++ 4 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001eq.uci create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001eqlong.uci 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..73519703 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -57,3 +57,30 @@ 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) + with open(ucifile) as fp: + uci = [] + for line in fp.readlines(): + if "***" in line[:81]: + continue + if not line[:81].strip(): + continue + uci.append(line[:81].rstrip()) 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 From da443d1e562b86edf856063f01af5cf8f0780731 Mon Sep 17 00:00:00 2001 From: "Robert W. Burgholzer" Date: Mon, 5 Jan 2026 15:52:30 +0000 Subject: [PATCH 150/378] Removed extraneous coe that reads FILES blocks since no FILES updates are done. --- src/hsp2/hsp2tools/commands.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/hsp2/hsp2tools/commands.py b/src/hsp2/hsp2tools/commands.py index 73519703..e2b8e740 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -1,4 +1,4 @@ -from pathlib import Path +https://github.com/HARPgroup/HSPsquared/blob/develop-state-class/src/hsp2/hsp2tools/data/rename.csvfrom pathlib import Path from hsp2.hsp2.main import main from hsp2.hsp2io.hdf import HDF5 @@ -76,11 +76,3 @@ def update_uci(ucifile, h5file): 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) - with open(ucifile) as fp: - uci = [] - for line in fp.readlines(): - if "***" in line[:81]: - continue - if not line[:81].strip(): - continue - uci.append(line[:81].rstrip()) From f530fc625f2b9b4d191081d6c8465ce3b1350e13 Mon Sep 17 00:00:00 2001 From: "Robert W. Burgholzer" Date: Mon, 5 Jan 2026 16:01:49 +0000 Subject: [PATCH 151/378] Removed accidental paste --- src/hsp2/hsp2tools/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2tools/commands.py b/src/hsp2/hsp2tools/commands.py index e2b8e740..057670e2 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -1,4 +1,4 @@ -https://github.com/HARPgroup/HSPsquared/blob/develop-state-class/src/hsp2/hsp2tools/data/rename.csvfrom pathlib import Path +from pathlib import Path from hsp2.hsp2.main import main from hsp2.hsp2io.hdf import HDF5 From 5f8a6d6bcf505d2cc1e753a7ef750732a31162bb Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 13:10:45 -0500 Subject: [PATCH 152/378] replace Dict to make explicit reference that hopefully numba will run OK in NUMBA_DISABLE_JIT=1 mode --- src/hsp2/hsp2/om_sim_timer.py | 4 ++-- src/hsp2/hsp2tools/commands.py | 8 ------- src/hsp2/state/state.py | 40 +++++++++++++++++----------------- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index d0d4b022..eeb36b95 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -13,11 +13,11 @@ class SimTimer(ModelObject): - def __init__(self, name, container, model_props=None): + 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 diff --git a/src/hsp2/hsp2tools/commands.py b/src/hsp2/hsp2tools/commands.py index 73519703..057670e2 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -76,11 +76,3 @@ def update_uci(ucifile, h5file): 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) - with open(ucifile) as fp: - uci = [] - for line in fp.readlines(): - if "***" in line[:81]: - continue - if not line[:81].strip(): - continue - uci.append(line[:81].rstrip()) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index d420ed72..cb0aaf7b 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -7,7 +7,7 @@ import numpy as np from numba import njit, typeof, types # import the types from numba.experimental import jitclass -from numba.typed import Dict +from numba.typed import Dict as ntdict from numpy import int32, zeros from pandas import date_range from pandas.tseries.offsets import Minute @@ -21,15 +21,15 @@ # TBD: Create a sample tindex for typing tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) tindex_ty = ("tindex", typeof(tindex.to_numpy())) -dict_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:, :]) -op_tokens_dict = Dict.empty(key_type=types.int64, value_type=types.int64[:, :]) +dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) +op_tokens_dict = ntdict.empty(key_type=types.int64, value_type=types.int64[:, :]) op_tokens = int32(zeros((1, 64))) op_exec_lists = int32(zeros((1, 1024))) # note: tested 32-bit key and saw absolutely no improvement, so go with 64 bit -state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64) -hsp_segments = Dict.empty(key_type=types.unicode_type, value_type=types.unicode_type) -ts_paths = Dict.empty(key_type=types.unicode_type, value_type=types.float64[:]) -ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) +state_paths = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) +hsp_segments = ntdict.empty(key_type=types.unicode_type, value_type=types.unicode_type) +ts_paths = ntdict.empty(key_type=types.unicode_type, value_type=types.float64[:]) +ts_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:]) last_id_ty = ("last_id", types.int64) num_ops_ty = ("num_ops", types.int64) @@ -85,17 +85,17 @@ def __init__(self): # 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.empty(key_type=types.int64, value_type=types.float64[:, :]) - self.state_paths = Dict.empty( + self.dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) + self.state_paths = ntdict.empty( key_type=types.unicode_type, value_type=types.int64 ) - self.hsp_segments = Dict.empty( + self.hsp_segments = ntdict.empty( key_type=types.unicode_type, value_type=types.unicode_type ) - self.ts_paths = Dict.empty( + self.ts_paths = ntdict.empty( key_type=types.unicode_type, value_type=types.float64[:] ) - self.ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:]) + self.ts_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:]) self.state_step_om = "disabled" self.state_step_hydr = "disabled" self.model_root_name = "" @@ -445,7 +445,7 @@ def hydr_state_vars(): 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 = 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 @@ -463,7 +463,7 @@ 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 = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) for i in sedtrn_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i @@ -479,7 +479,7 @@ 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 = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) for i in sedmnt_state: var_path = domain + "/" + i sedmnt_ix[i] = state.set_state(var_path, 0.0) @@ -506,7 +506,7 @@ def rqual_state_vars(): 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 = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) for i in rqual_state: var_path = domain + "/" + i rqual_ix[i] = state.set_state(var_path, 0.0) @@ -535,7 +535,7 @@ def hydr_get_ix(state, domain): "VOLEV", ] # print(state.state_paths) - hydr_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64) + 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 @@ -548,7 +548,7 @@ def hydr_get_ix(state, domain): 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.get_state_ix(var_path) @@ -559,7 +559,7 @@ def sedtrn_get_ix(state, domain): 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.get_state_ix(var_path) @@ -582,7 +582,7 @@ def rqual_get_ix(state, 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.get_state_ix(var_path) From 7ea20fe3118b573137922c67943138f2d658d2df Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 13:24:45 -0500 Subject: [PATCH 153/378] test different declaration style --- src/hsp2/state/state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index cb0aaf7b..48e32b8d 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -33,7 +33,7 @@ last_id_ty = ("last_id", types.int64) num_ops_ty = ("num_ops", types.int64) -state_paths_ty = ("state_paths", typeof(state_paths)) +state_paths_ty = ("state_paths", types.DictType(types.unicode_type, value_type=types.int64)) model_exec_list_ty = ("model_exec_list", typeof(model_exec_list)) hsp_segments_ty = ("hsp_segments", typeof(hsp_segments)) op_tokens_ty = ("op_tokens", typeof(op_tokens)) @@ -55,6 +55,7 @@ # Combine these into a spec to create the class state_spec = [ + # ("state_paths", types.DictType(types.unicode_type, value_type=types.int64)), state_paths_ty, state_ix_ty, ts_paths_ty, From 42826d808f9e22e47e60486d8fb9f127237a2c37 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 13:26:30 -0500 Subject: [PATCH 154/378] test different declaration style - fixe --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 48e32b8d..9bf2fc5b 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -33,7 +33,7 @@ last_id_ty = ("last_id", types.int64) num_ops_ty = ("num_ops", types.int64) -state_paths_ty = ("state_paths", types.DictType(types.unicode_type, value_type=types.int64)) +state_paths_ty = ("state_paths", types.DictType(types.unicode_type, types.int64)) model_exec_list_ty = ("model_exec_list", typeof(model_exec_list)) hsp_segments_ty = ("hsp_segments", typeof(hsp_segments)) op_tokens_ty = ("op_tokens", typeof(op_tokens)) From ed13ec76ff7438dfe2a82fc58b3117b50756f7ae Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 15:36:29 -0500 Subject: [PATCH 155/378] new declarations ready for model run testin --- src/hsp2/state/state.py | 128 +++++++++++++++------------------------- 1 file changed, 47 insertions(+), 81 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 9bf2fc5b..7e0ee5f7 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -5,77 +5,42 @@ import sys import numpy as np -from numba import njit, typeof, types # import the types +from numba import njit, types, typeof # import the types from numba.experimental import jitclass from numba.typed import Dict as ntdict -from numpy import int32, zeros +from numpy import int64, zeros from pandas import date_range from pandas.tseries.offsets import Minute -# from hsp2.hsp2.utilities import make_class_spec - - -# Define the complex datatypes -state_ix = np.asarray(zeros(1), dtype="float64") -model_exec_list = np.asarray(zeros(1), dtype="int32") -# TBD: Create a sample tindex for typing -tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) -tindex_ty = ("tindex", typeof(tindex.to_numpy())) -dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) -op_tokens_dict = ntdict.empty(key_type=types.int64, value_type=types.int64[:, :]) -op_tokens = int32(zeros((1, 64))) -op_exec_lists = int32(zeros((1, 1024))) -# note: tested 32-bit key and saw absolutely no improvement, so go with 64 bit -state_paths = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) -hsp_segments = ntdict.empty(key_type=types.unicode_type, value_type=types.unicode_type) -ts_paths = ntdict.empty(key_type=types.unicode_type, value_type=types.float64[:]) -ts_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:]) -last_id_ty = ("last_id", types.int64) -num_ops_ty = ("num_ops", types.int64) - -state_paths_ty = ("state_paths", types.DictType(types.unicode_type, types.int64)) -model_exec_list_ty = ("model_exec_list", typeof(model_exec_list)) -hsp_segments_ty = ("hsp_segments", typeof(hsp_segments)) -op_tokens_ty = ("op_tokens", typeof(op_tokens)) -state_ix_ty = ("state_ix", typeof(state_ix)) -dict_ix_ty = ("dict_ix", typeof(dict_ix)) -ts_ix_ty = ("ts_ix", typeof(ts_ix)) -ts_paths_ty = ("ts_paths", typeof(ts_paths)) -model_root_name_ty = ("model_root_name", types.unicode_type) -# these are likely to be located in model objects when we go fully to that level. +# 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 -state_step_hydr_ty = ("state_step_hydr", types.unicode_type) -state_step_om_ty = ("state_step_om", types.unicode_type) -operation_ty = ("operation", types.unicode_type) -segment_ty = ("segment", types.unicode_type) -activity_ty = ("activity", types.unicode_type) -domain_ty = ("domain", types.unicode_type) -hsp2_local_py_ty = ("hsp2_local_py", types.boolean) -op_exec_lists_ty = ("op_exec_lists", typeof(op_exec_lists)) - # Combine these into a spec to create the class +tindex = date_range("1984-01-01", "2020-12-31", freq=Minute(60)) + state_spec = [ - # ("state_paths", types.DictType(types.unicode_type, value_type=types.int64)), - state_paths_ty, - state_ix_ty, - ts_paths_ty, - ts_ix_ty, - last_id_ty, - model_root_name_ty, - state_step_hydr_ty, - hsp2_local_py_ty, - hsp_segments_ty, - op_tokens_ty, - op_exec_lists_ty, - model_exec_list_ty, - operation_ty, - segment_ty, - activity_ty, - domain_ty, - state_step_om_ty, - tindex_ty, - dict_ix_ty, - num_ops_ty, + # the first entries here are NP arrays, fixed dimenstions, and fast + ("state_ix", typeof(np.asarray(zeros(1), dtype="float64")) ), + ("op_tokens", typeof(int64(zeros((1, 64)))) ), + ("op_exec_lists", typeof(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), + ("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) ) ] @@ -107,32 +72,33 @@ def __init__(self): self.last_id = 0 self.hsp2_local_py = False # Note: in the type declaration above we are alloweed to use the shortened form - # op_tokens = int32(zeros((1,64))) + # op_tokens = int64(zeros((1,64))) # but in jited class that throws an error and we have to use the # form - # op_tokens.astype(int32) + # op_tokens.astype(int64) # to do the type cast + # Also - IT IS IMPORTANT that these are handled as nparray as numba Dict would be super slow. op_tokens = zeros((self.num_ops, 64)) - self.op_tokens = op_tokens.astype(int32) + self.op_tokens = op_tokens.astype(int64) + # TODO: move to individual objects in OM/RCHRES/PERLND/... op_exec_lists = zeros((self.num_ops, 1024)) - # TODO: move to individual objects in OM - self.op_exec_lists = op_exec_lists.astype(types.int32) - # TODO: is this even needed? + self.op_exec_lists = op_exec_lists.astype(int64) + # 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(types.int32) + self.model_exec_list = model_exec_list.astype(types.int64) 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: @@ -147,7 +113,7 @@ def set_token(self, var_ix, tokens, debug=False): # 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") @@ -163,12 +129,12 @@ def resize(self, debug=False): if self.op_tokens.size == 0: if debug: print("Creating op_tokens") - self.op_tokens = add_ops.astype(types.int32) + self.op_tokens = add_ops.astype(types.int64) else: if debug: print("Merging op_tokens") add_ops = np.append(self.op_tokens, add_ops, 0) - self.op_tokens = add_ops.astype(types.int32) + self.op_tokens = add_ops.astype(types.int64) ops_needed = num_ops - np.shape(self.op_exec_lists)[0] el_width = np.shape(self.op_exec_lists)[1] if debug: @@ -180,18 +146,18 @@ def resize(self, debug=False): if self.op_exec_lists.size == 0: if debug: print("Creating op_exec_lists") - self.op_exec_lists = add_ops.astype(types.int32) + self.op_exec_lists = add_ops.astype(types.int64) 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(types.int32) + self.op_exec_lists = add_ops.astype(types.int64) 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 @@ -208,7 +174,7 @@ def set_state(self, var_path, var_value=0.0, debug=False): 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 From aa787deb896637ccaa9b0ef5fe00a61b00f2e40e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 15:42:55 -0500 Subject: [PATCH 156/378] removed extraneous package indicator since it is aliased --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 7e0ee5f7..ba21cbc9 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -85,7 +85,7 @@ def __init__(self): self.op_exec_lists = op_exec_lists.astype(int64) # 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(types.int64) + self.model_exec_list = model_exec_list.astype(int64) return @property From 2b2bd27219591bdbcc532a138698548867fa912d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 15:49:27 -0500 Subject: [PATCH 157/378] add state_ix initialization --- src/hsp2/state/state.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ba21cbc9..3c583cf5 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -8,7 +8,7 @@ from numba import njit, types, typeof # import the types from numba.experimental import jitclass from numba.typed import Dict as ntdict -from numpy import int64, zeros +from numpy import int64, zeros, float64 from pandas import date_range from pandas.tseries.offsets import Minute @@ -48,6 +48,21 @@ class state_class: def __init__(self): 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 + state_ix = zeros(self.num_ops) + self.state_ix = state_ix.astype(float64) + op_tokens = zeros((self.num_ops, 64)) + self.op_tokens = op_tokens.astype(int64) + # 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(int64) + # 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(int64) + # 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 @@ -71,21 +86,6 @@ def __init__(self): self.domain = "" self.last_id = 0 self.hsp2_local_py = False - # 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 - # Also - IT IS IMPORTANT that these are handled as nparray as numba Dict would be super slow. - op_tokens = zeros((self.num_ops, 64)) - self.op_tokens = op_tokens.astype(int64) - # 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(int64) - # 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(int64) return @property From 2225002bbbc0688e3fc97c9a78f8e40a260556e2 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 15:54:10 -0500 Subject: [PATCH 158/378] go to all numba types for number arrays --- src/hsp2/state/state.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 3c583cf5..a88c81de 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -5,10 +5,10 @@ import sys import numpy as np -from numba import njit, types, typeof # import the types +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 int64, zeros, float64 +from numpy import zeros from pandas import date_range from pandas.tseries.offsets import Minute @@ -20,8 +20,8 @@ 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(int64(zeros((1, 64)))) ), - ("op_exec_lists", typeof(int64(zeros((1, 1024)))) ), + ("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 @@ -53,15 +53,15 @@ def __init__(self): # but in jited class that throws an error and we have to use the form op_tokens.astype(int64) # to do the type cast state_ix = zeros(self.num_ops) - self.state_ix = state_ix.astype(float64) + self.state_ix = state_ix.astype(types.float64) op_tokens = zeros((self.num_ops, 64)) - self.op_tokens = op_tokens.astype(int64) + self.op_tokens = op_tokens.astype(types.int64) # 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(int64) + self.op_exec_lists = op_exec_lists.astype(types.int64) # 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(int64) + self.model_exec_list = model_exec_list.astype(types.int64) # 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 From 550874ec4d6d7c4af830eb968104ef64d967c7f9 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 15:59:26 -0500 Subject: [PATCH 159/378] muste use numpy types when casting to numba arrays? --- src/hsp2/state/state.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index a88c81de..d86fa3fe 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -8,7 +8,7 @@ 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 +from numpy import zeros, float64 as npfloat64, int64 as npint64 from pandas import date_range from pandas.tseries.offsets import Minute @@ -53,15 +53,15 @@ def __init__(self): # but in jited class that throws an error and we have to use the form op_tokens.astype(int64) # to do the type cast state_ix = zeros(self.num_ops) - self.state_ix = state_ix.astype(types.float64) + self.state_ix = state_ix.astype(npfloat64) op_tokens = zeros((self.num_ops, 64)) - self.op_tokens = op_tokens.astype(types.int64) + 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(types.int64) + 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(types.int64) + 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 From 39ce8f7105a827b05a4d87174405d47b09020d82 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 16:01:31 -0500 Subject: [PATCH 160/378] use numpy types during resize too --- src/hsp2/state/state.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index d86fa3fe..acd854df 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -129,12 +129,12 @@ def resize(self, debug=False): if self.op_tokens.size == 0: if debug: print("Creating op_tokens") - self.op_tokens = add_ops.astype(types.int64) + 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(types.int64) + 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: @@ -146,12 +146,12 @@ def resize(self, debug=False): if self.op_exec_lists.size == 0: if debug: print("Creating op_exec_lists") - self.op_exec_lists = add_ops.astype(types.int64) + 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(types.int64) + self.op_exec_lists = add_ops.astype(npint64) return def set_exec_list(self, ix, op_exec_list): From 0d50083951109c4834828bcb7842abc3db03994e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 16:07:30 -0500 Subject: [PATCH 161/378] change all OM indices to 64 bit --- src/hsp2/hsp2/om.py | 2 +- src/hsp2/hsp2/om_model_object.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 775da20e..30b01a1c 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -223,7 +223,7 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): # the resulting set of objects is returned. state.state_step_om = "disabled" om_operations["model_object_cache"] = model_object_cache - state.model_exec_list = np.asarray(model_exec_list, dtype="int32") + 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.model_exec_list) > 0: diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index c683e2f0..0c745ad3 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -6,7 +6,7 @@ from numba import njit, types from numba.typed import Dict -from numpy import asarray, int32, pad, zeros +from numpy import asarray, int64, pad, zeros from pandas import HDFStore from hsp2.hsp2.om import is_float_digit @@ -127,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: From a0393645d59d7575e4844b278a61196e931f6406 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 12:11:55 -0500 Subject: [PATCH 162/378] timer debugging added --- src/hsp2/hsp2/main.py | 8 ++++ src/hsp2/hsp2/om_sim_timer.py | 47 ++++++++++++++++++--- tests/testcbp/HSP2results/check_equation.py | 11 +++-- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 88cb5e36..a5e14936 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -32,6 +32,7 @@ state_om_model_run_finish, hsp2_domain_dependencies ) +from hsp2.hsp2.om_sim_timer import timer_class from hsp2.hsp2.SPECL import specl_load_om from hsp2.hsp2io.io import IOManager, SupportsReadTS, Category @@ -56,6 +57,10 @@ def main( None """ + + timer = timer_class() + print("main() call", timer.split(), "seconds") + if isinstance(io_manager, str): hdf5_instance = HDF5(io_manager) io_manager = IOManager(hdf5_instance) @@ -68,6 +73,7 @@ def main( # read user control, parameters, states, and flags parameters and map to local variables parameter_obj = io_manager.read_parameters() + print("Load io_manager parameters", timer.split(), "seconds") opseq = parameter_obj.opseq ddlinks = parameter_obj.ddlinks ddmasslinks = parameter_obj.ddmasslinks @@ -106,6 +112,7 @@ def main( ) # operational model for custom python # finalize all dynamically loaded components and prepare to run the model state_om_model_run_prep(opseq, activities, state, om_operations, siminfo) + print("Load all state + om", timer.split(), "seconds") ####################################################################################### # main processing loop @@ -519,6 +526,7 @@ def main( jupyterlab, outstep_phcarb, ) + print(operation, segment, timer.split(), 'seconds') msglist = msg(1, "Done", final=True) diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index eeb36b95..19a2ca54 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -4,13 +4,15 @@ during a model simulation. """ -from hsp2.state.state import set_state +from hsp2.state.state import state from hsp2.hsp2.om import ModelObject from hsp2.hsp2.om_model_object import ModelObject from pandas import DataFrame -from numba import njit -from numpy import int64 - +from numba import njit, types +from numpy import int64, float64 +from numba.experimental import jitclass +import ctypes +import time class SimTimer(ModelObject): def __init__(self, name, container, model_props=None, state=None): @@ -67,7 +69,7 @@ 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. @@ -118,3 +120,38 @@ 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 + +# 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(): + 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 diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index addc1e99..4f2e571f 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -1,7 +1,7 @@ # 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 * @@ -61,12 +61,12 @@ # mtl = [] # mel = [] # model_order_recursive(endpoint, om_operations["model_object_cache"], mel, mtl, True) -O3 = om_operations["model_object_cache"]["/STATE/PL3_5250_0001eq/RCHRES_R001/O3"] +O2 = om_operations["model_object_cache"]["/STATE/PL3_5250_0001eq/RCHRES_R001/O2"] 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("O3") +wd_cfs.find_var_path("O2") # state['model_root_object'].find_var_path('RCHRES_R001') # Get the timeseries naked, without an object @@ -152,3 +152,8 @@ 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']) From 17dde1d1bb3b805eaa7bf9d8735dd72a4b94d8ef Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 12:13:37 -0500 Subject: [PATCH 163/378] remove unused import --- src/hsp2/hsp2/om_sim_timer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index 19a2ca54..a062bf9c 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -4,7 +4,6 @@ during a model simulation. """ -from hsp2.state.state import state from hsp2.hsp2.om import ModelObject from hsp2.hsp2.om_model_object import ModelObject from pandas import DataFrame From 5670b61e653a97968a2686f56b30cef28792dc4e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 12:16:23 -0500 Subject: [PATCH 164/378] detailed state tracking 1 --- src/hsp2/hsp2/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index a5e14936..915b06b8 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -103,6 +103,7 @@ def main( # Iterate through all segments and add crucial paths to state # before loading dynamic components that may reference them state_init_hsp2(state, opseq, activities, om_operations) + print("state_class() to state_init_hsp2() call", timer.split(), "seconds") # 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 From 372431a84240508e66159208adfd8342ab2bc332 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 12:17:55 -0500 Subject: [PATCH 165/378] detailed state tracking 2 --- src/hsp2/hsp2/main.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 915b06b8..56f845c2 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -95,11 +95,15 @@ def main( ####################################################################################### # Set up Things in state that will be used in all modular activities like SPECL state = state_class() + print("state_class() call", timer.split(), "seconds") om_operations = om_init_state() # set up operational model specific containers + print("om_init_state() call", timer.split(), "seconds") state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) + print("state_siminfo_hsp2() call", timer.split(), "seconds") # 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", 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, om_operations) From 7b26504d4d99ebfd718447e7bb52091f1068b511 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 12:36:17 -0500 Subject: [PATCH 166/378] test caching objecdt in function --- src/hsp2/hsp2/main.py | 6 +++--- src/hsp2/hsp2/om_model_linkage.py | 2 +- src/hsp2/state/state.py | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 56f845c2..177b9715 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -23,7 +23,7 @@ state_load_dynamics_hsp2, state_init_hsp2, state_context_hsp2, - state_class + make_state_class ) from hsp2.hsp2.om import ( om_init_state, @@ -94,7 +94,7 @@ def main( # initialize STATE dicts ####################################################################################### # Set up Things in state that will be used in all modular activities like SPECL - state = state_class() + state = make_state_class() print("state_class() call", timer.split(), "seconds") om_operations = om_init_state() # set up operational model specific containers print("om_init_state() call", timer.split(), "seconds") @@ -107,7 +107,7 @@ def main( # Iterate through all segments and add crucial paths to state # before loading dynamic components that may reference them state_init_hsp2(state, opseq, activities, om_operations) - print("state_class() to state_init_hsp2() call", timer.split(), "seconds") + print("state_init_hsp2() call", timer.split(), "seconds") # 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 diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index f837afdc..2f984b7a 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -230,7 +230,7 @@ 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 op_token[3] == 1: return True diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index acd854df..4288dd14 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -67,6 +67,7 @@ def __init__(self): # 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 = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) + self.dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) self.state_paths = ntdict.empty( key_type=types.unicode_type, value_type=types.int64 ) @@ -199,6 +200,9 @@ def get_ix_path(self, var_ix): return spath return spath +@njit(cache=True) +def make_state_class(): + return(state_class()) def op_path_name(operation, id): """ From fa645cc55f55c3c1174e2bfa2c5b77715ba0ccc9 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 12:42:06 -0500 Subject: [PATCH 167/378] different reference will work? --- src/hsp2/state/state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 4288dd14..e187b70c 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -202,7 +202,8 @@ def get_ix_path(self, var_ix): @njit(cache=True) def make_state_class(): - return(state_class()) + sc = state_class() + return(sc) def op_path_name(operation, id): """ From 3adaad0dc1c47ef0546359a3de859997d78f281c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 12:47:46 -0500 Subject: [PATCH 168/378] set initial values externally --- src/hsp2/hsp2/main.py | 4 ++- src/hsp2/state/state.py | 73 +++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 177b9715..598f9eac 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -23,7 +23,8 @@ state_load_dynamics_hsp2, state_init_hsp2, state_context_hsp2, - make_state_class + make_state_class, + init_state ) from hsp2.hsp2.om import ( om_init_state, @@ -95,6 +96,7 @@ def main( ####################################################################################### # Set up Things in state that will be used in all modular activities like SPECL state = make_state_class() + init_state(state) print("state_class() call", timer.split(), "seconds") om_operations = om_init_state() # set up operational model specific containers print("om_init_state() call", timer.split(), "seconds") diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index e187b70c..ae08f3f2 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -52,41 +52,6 @@ def __init__(self): # 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 - 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) - # 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 = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) - self.dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) - self.state_paths = ntdict.empty( - key_type=types.unicode_type, value_type=types.int64 - ) - self.hsp_segments = ntdict.empty( - key_type=types.unicode_type, value_type=types.unicode_type - ) - self.ts_paths = ntdict.empty( - key_type=types.unicode_type, value_type=types.float64[:] - ) - self.ts_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:]) - 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 return @property @@ -200,6 +165,44 @@ def get_ix_path(self, var_ix): return spath return spath +def init_state(state_class): + state_ix = zeros(state_class.num_ops) + state_class.state_ix = state_ix.astype(npfloat64) + op_tokens = zeros((state_class.num_ops, 64)) + state_class.op_tokens = op_tokens.astype(npint64) + # TODO: move to individual objects in OM/RCHRES/PERLND/... + op_exec_lists = zeros((state_class.num_ops, 1024)) + state_class.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(state_class.num_ops) + state_class.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 + state_class.dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) + state_class.dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) + state_class.state_paths = ntdict.empty( + key_type=types.unicode_type, value_type=types.int64 + ) + state_class.hsp_segments = ntdict.empty( + key_type=types.unicode_type, value_type=types.unicode_type + ) + state_class.ts_paths = ntdict.empty( + key_type=types.unicode_type, value_type=types.float64[:] + ) + state_class.ts_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:]) + state_class.state_step_om = "disabled" + state_class.state_step_hydr = "disabled" + state_class.model_root_name = "" + state_class.operation = "" + state_class.segment = "" + state_class.activity = "" + state_class.domain = "" + state_class.last_id = 0 + state_class.hsp2_local_py = False + + @njit(cache=True) def make_state_class(): sc = state_class() From 9468566d5420daaec21dad5b8042060f86f577c8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:14:42 -0500 Subject: [PATCH 169/378] test simpler implementation --- src/hsp2/hsp2/main.py | 7 +-- src/hsp2/state/state.py | 109 ++++++++++++++++++++++++---------------- 2 files changed, 69 insertions(+), 47 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 598f9eac..d6ac4011 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -22,9 +22,7 @@ state_siminfo_hsp2, state_load_dynamics_hsp2, state_init_hsp2, - state_context_hsp2, - make_state_class, - init_state + state_context_hsp2 ) from hsp2.hsp2.om import ( om_init_state, @@ -95,8 +93,7 @@ def main( # initialize STATE dicts ####################################################################################### # Set up Things in state that will be used in all modular activities like SPECL - state = make_state_class() - init_state(state) + state = state_class() print("state_class() call", timer.split(), "seconds") om_operations = om_init_state() # set up operational model specific containers print("om_init_state() call", timer.split(), "seconds") diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ae08f3f2..e6a0a6a2 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -44,6 +44,38 @@ ] +state_lite = [ + # 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[:, :]) ), + #("ts_ix", types.DictType(types.int64, types.float64[:]) ) +] + +@jitclass(state_lite) +class state_class_lite: + def __init__(self): + self.num_ops = 0 + 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) + +@njit(cache=True) +def make_state_lite(): + sc = state_class_lite() + return sc + @jitclass(state_spec) class state_class: def __init__(self): @@ -52,6 +84,41 @@ def __init__(self): # 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 + 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) + # 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 = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) + self.dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) + self.state_paths = ntdict.empty( + key_type=types.unicode_type, value_type=types.int64 + ) + self.hsp_segments = ntdict.empty( + key_type=types.unicode_type, value_type=types.unicode_type + ) + self.ts_paths = ntdict.empty( + key_type=types.unicode_type, value_type=types.float64[:] + ) + self.ts_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:]) + 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 return @property @@ -165,48 +232,6 @@ def get_ix_path(self, var_ix): return spath return spath -def init_state(state_class): - state_ix = zeros(state_class.num_ops) - state_class.state_ix = state_ix.astype(npfloat64) - op_tokens = zeros((state_class.num_ops, 64)) - state_class.op_tokens = op_tokens.astype(npint64) - # TODO: move to individual objects in OM/RCHRES/PERLND/... - op_exec_lists = zeros((state_class.num_ops, 1024)) - state_class.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(state_class.num_ops) - state_class.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 - state_class.dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) - state_class.dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) - state_class.state_paths = ntdict.empty( - key_type=types.unicode_type, value_type=types.int64 - ) - state_class.hsp_segments = ntdict.empty( - key_type=types.unicode_type, value_type=types.unicode_type - ) - state_class.ts_paths = ntdict.empty( - key_type=types.unicode_type, value_type=types.float64[:] - ) - state_class.ts_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:]) - state_class.state_step_om = "disabled" - state_class.state_step_hydr = "disabled" - state_class.model_root_name = "" - state_class.operation = "" - state_class.segment = "" - state_class.activity = "" - state_class.domain = "" - state_class.last_id = 0 - state_class.hsp2_local_py = False - - -@njit(cache=True) -def make_state_class(): - sc = state_class() - return(sc) def op_path_name(operation, id): """ From 7e44c7752584fe15d10156d0d05b29812accf54d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:16:51 -0500 Subject: [PATCH 170/378] test simpler implementation --- src/hsp2/hsp2/main.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index d6ac4011..cf5913b0 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -22,7 +22,10 @@ state_siminfo_hsp2, state_load_dynamics_hsp2, state_init_hsp2, - state_context_hsp2 + state_context_hsp2, + state_class, + make_state_lite + ) from hsp2.hsp2.om import ( om_init_state, @@ -94,6 +97,8 @@ def main( ####################################################################################### # Set up Things in state that will be used in all modular activities like SPECL state = state_class() + scl = make_state_lite() + print("Made state_class_lite", scl.num_ops) print("state_class() call", timer.split(), "seconds") om_operations = om_init_state() # set up operational model specific containers print("om_init_state() call", timer.split(), "seconds") From f019206f492e6b3a74b20e6ce5fb346453f25469 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:19:37 -0500 Subject: [PATCH 171/378] add num_ops --- src/hsp2/state/state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index e6a0a6a2..9b04fd9a 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -45,6 +45,7 @@ state_lite = [ + ("num_ops", types.int64), # 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)))) ), From 7f2042c8798cda546fad40388782e35439d77c29 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:24:04 -0500 Subject: [PATCH 172/378] simpler spec --- src/hsp2/state/state.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 9b04fd9a..3972f9ee 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -48,10 +48,10 @@ ("num_ops", types.int64), # 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()) ), + #("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[:]) ) From 61ac91340a61c3b40ef94988a61f63b2cd71e203 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:25:26 -0500 Subject: [PATCH 173/378] simpler spec --- src/hsp2/state/state.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 3972f9ee..daa45384 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -63,14 +63,14 @@ def __init__(self): self.num_ops = 0 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) + #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) + #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.model_exec_list = model_exec_list.astype(npint64) @njit(cache=True) def make_state_lite(): From fb713148031fdeaf91097941ab1969db1d56118f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:29:50 -0500 Subject: [PATCH 174/378] no complex setting in init --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index daa45384..ea3649d5 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -62,7 +62,7 @@ class state_class_lite: def __init__(self): self.num_ops = 0 state_ix = zeros(self.num_ops) - self.state_ix = state_ix.astype(npfloat64) + #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/... From ffddc6420b84673c24a765da811fa350fbb4fd26 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:30:46 -0500 Subject: [PATCH 175/378] no complex setting in init --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ea3649d5..2cf5f308 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -69,7 +69,7 @@ def __init__(self): #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) + #model_exec_list = zeros(self.num_ops) #self.model_exec_list = model_exec_list.astype(npint64) @njit(cache=True) From 33ac79e41fc16990f171760f4d1d496cb34e2e90 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:35:23 -0500 Subject: [PATCH 176/378] no complex setting in init --- src/hsp2/state/state.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 2cf5f308..7b0c8054 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -5,6 +5,7 @@ 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 @@ -46,8 +47,9 @@ state_lite = [ ("num_ops", types.int64), + ("state_ix", nb.float64[:]), # the first entries here are NP arrays, fixed dimenstions, and fast - ("state_ix", typeof(np.asarray(zeros(1), dtype="float64")) ), + #("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")) ), From d9001b7d8d457a0addba167d40cc8e311ef21296 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:36:38 -0500 Subject: [PATCH 177/378] no complex setting in init --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 7b0c8054..6f58baeb 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -63,7 +63,7 @@ class state_class_lite: def __init__(self): self.num_ops = 0 - state_ix = zeros(self.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) From e728ae765572d08955807ddfaacb24dd6035693e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:40:21 -0500 Subject: [PATCH 178/378] what happens if we dont return it? --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 6f58baeb..b09a5092 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -77,7 +77,7 @@ def __init__(self): @njit(cache=True) def make_state_lite(): sc = state_class_lite() - return sc +# return sc @jitclass(state_spec) class state_class: From fb36864ba802c3e1e948b1b8bfc2ef97ddd81aa6 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:43:43 -0500 Subject: [PATCH 179/378] numba as source not types --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index b09a5092..d2aec7cc 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -46,7 +46,7 @@ state_lite = [ - ("num_ops", types.int64), + ("num_ops", nb.int64), ("state_ix", nb.float64[:]), # the first entries here are NP arrays, fixed dimenstions, and fast #("state_ix", typeof(np.asarray(zeros(1), dtype="float64")) ), From 175aed440f349946ba96309f4d80106f451bc0be Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:44:54 -0500 Subject: [PATCH 180/378] numba as source not types --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index d2aec7cc..53e18845 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -77,7 +77,7 @@ def __init__(self): @njit(cache=True) def make_state_lite(): sc = state_class_lite() -# return sc + return sc @jitclass(state_spec) class state_class: From ea925015cc035742d20033ae4aed520e83f25f25 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 13:58:29 -0500 Subject: [PATCH 181/378] return nothing --- src/hsp2/hsp2/main.py | 2 +- src/hsp2/state/state.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index cf5913b0..c1f0465f 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -98,7 +98,7 @@ def main( # Set up Things in state that will be used in all modular activities like SPECL state = state_class() scl = make_state_lite() - print("Made state_class_lite", scl.num_ops) + print("Made state_class_lite", scl) print("state_class() call", timer.split(), "seconds") om_operations = om_init_state() # set up operational model specific containers print("om_init_state() call", timer.split(), "seconds") diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 53e18845..d2aec7cc 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -77,7 +77,7 @@ def __init__(self): @njit(cache=True) def make_state_lite(): sc = state_class_lite() - return sc +# return sc @jitclass(state_spec) class state_class: From 9d6e7da1c2547ebbf7010a713c6003ff8048bb6b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 14:03:37 -0500 Subject: [PATCH 182/378] pass atts --- src/hsp2/hsp2/main.py | 2 +- src/hsp2/state/state.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index c1f0465f..b3f6f232 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -97,7 +97,7 @@ def main( ####################################################################################### # Set up Things in state that will be used in all modular activities like SPECL state = state_class() - scl = make_state_lite() + scl = make_state_lite(0) print("Made state_class_lite", scl) print("state_class() call", timer.split(), "seconds") om_operations = om_init_state() # set up operational model specific containers diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index d2aec7cc..f1d5320d 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -61,8 +61,8 @@ @jitclass(state_lite) class state_class_lite: - def __init__(self): - self.num_ops = 0 + 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)) From a6cdeb18095d9acd6d1e1762ee4adf2fd6f2b032 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 14:05:24 -0500 Subject: [PATCH 183/378] pass atts --- src/hsp2/state/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index f1d5320d..0ea1f6f3 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -75,8 +75,8 @@ def __init__(self, num_ops): #self.model_exec_list = model_exec_list.astype(npint64) @njit(cache=True) -def make_state_lite(): - sc = state_class_lite() +def make_state_lite(num_ops): + sc = state_class_lite(num_ops) # return sc @jitclass(state_spec) From 75e31f9e0a379fca424c822cbb0b0b6fca3e83a1 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 14:06:45 -0500 Subject: [PATCH 184/378] pass atts and return --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 0ea1f6f3..7a20da12 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -77,7 +77,7 @@ def __init__(self, num_ops): @njit(cache=True) def make_state_lite(num_ops): sc = state_class_lite(num_ops) -# return sc + return sc @jitclass(state_spec) class state_class: From 8bad920223d159de9e4f5f67dd8d5cbee3dc9cbd Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 14:09:21 -0500 Subject: [PATCH 185/378] pass atts and return --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 7a20da12..0751bbca 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -77,7 +77,7 @@ def __init__(self, num_ops): @njit(cache=True) def make_state_lite(num_ops): sc = state_class_lite(num_ops) - return sc + #return sc @jitclass(state_spec) class state_class: From 9361030833fd623bf1394c8dde8064025c8fb4e5 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 15:41:45 -0500 Subject: [PATCH 186/378] try to use cache=true cause the google AI said it should work even though all human say it shouldnt --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 0751bbca..a88abb11 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -79,7 +79,7 @@ def make_state_lite(num_ops): sc = state_class_lite(num_ops) #return sc -@jitclass(state_spec) +@jitclass(state_spec, cache=True) class state_class: def __init__(self): self.num_ops = 0 From 075d8b3b20234c5f70a898880e2f2c6f7e2d98e1 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:00:32 -0500 Subject: [PATCH 187/378] this is why you dont trust the silly AI --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index a88abb11..0751bbca 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -79,7 +79,7 @@ def make_state_lite(num_ops): sc = state_class_lite(num_ops) #return sc -@jitclass(state_spec, cache=True) +@jitclass(state_spec) class state_class: def __init__(self): self.num_ops = 0 From 92e9abff5b2be66093685cce37d21d5739a353fc Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:06:04 -0500 Subject: [PATCH 188/378] can compile state_init_true? --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 0751bbca..6722ecea 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -344,7 +344,7 @@ def state_context_hsp2(state, operation, segment, activity): state.hsp_segments[seg_name] = seg_path state.domain = seg_path # + "/" + activity # may want to comment out activity? - +@njit(cache=True) def state_init_hsp2(state, opseq, activities, om_operations): # This sets up the state entries for all state compatible HSP2 model variables # print("STATE initializing contexts.") From b60d263698034c014e84b7370997c6d184d64965 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:07:11 -0500 Subject: [PATCH 189/378] can compile state_init_true? --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 6722ecea..516b38f5 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -330,7 +330,7 @@ def state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager): (fbase, fext) = os.path.splitext(hdf5_path) 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 From aeb3c7e7adb7886630419992b173d19599f3a1fe Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:12:32 -0500 Subject: [PATCH 190/378] can compile state_init_true? --- src/hsp2/state/state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 516b38f5..89c65beb 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -340,7 +340,8 @@ def state_context_hsp2(state, operation, segment, activity): # insure that there is a model object container seg_name = operation + "_" + segment seg_path = "/STATE/" + state.model_root_name + "/" + seg_name - if seg_name not in state.hsp_segments.keys(): + #if seg_name not in state.hsp_segments.keys(): + if seg_name not in state.hsp_segments: # test this for njit state.hsp_segments[seg_name] = seg_path state.domain = seg_path # + "/" + activity # may want to comment out activity? From 1a8789371cac0fcd28a6ff8cf01f8f522bbdec57 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:14:00 -0500 Subject: [PATCH 191/378] can compile state_context_hsp2 --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 89c65beb..9ab190e0 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -345,7 +345,7 @@ def state_context_hsp2(state, operation, segment, activity): state.hsp_segments[seg_name] = seg_path state.domain = seg_path # + "/" + activity # may want to comment out activity? -@njit(cache=True) +#@njit(cache=True) def state_init_hsp2(state, opseq, activities, om_operations): # This sets up the state entries for all state compatible HSP2 model variables # print("STATE initializing contexts.") From e6b466238586a7ee94c6388f58b55d5b134c63b2 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:16:52 -0500 Subject: [PATCH 192/378] more info --- src/hsp2/hsp2/main.py | 7 +++++-- src/hsp2/state/state.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index b3f6f232..af09006f 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -110,18 +110,21 @@ def main( print("state_load_dynamics_hsp2() call", 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, om_operations) + state_init_hsp2(state, opseq, activities) print("state_init_hsp2() call", timer.split(), "seconds") # now initialize all state variables for mutable variables hsp2_domain_dependencies(state, opseq, activities, om_operations, False) + print("hsp2_domain_dependencies", timer.split(), "seconds") # - finally stash specactions in state, not domain (segment) dependent so do it once specl_load_om(om_operations, specactions) # load traditional special actions + print("specl_load_om", timer.split(), "seconds") state_load_dynamics_om( state, io_manager, siminfo, om_operations ) # operational model for custom python + print("state_load_dynamics_om", 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("Load all state + om", timer.split(), "seconds") + print("state_om_model_run_prep", timer.split(), "seconds") ####################################################################################### # main processing loop diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 9ab190e0..e7acd4a2 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -346,7 +346,7 @@ def state_context_hsp2(state, operation, segment, activity): state.domain = seg_path # + "/" + activity # may want to comment out activity? #@njit(cache=True) -def state_init_hsp2(state, opseq, activities, om_operations): +def state_init_hsp2(state, opseq, activities): # This sets up the state entries for all state compatible HSP2 model variables # print("STATE initializing contexts.") for _, operation, segment, delt in opseq.itertuples(): From f31ef357b4c043f71d2effb05bfab3536d89e497 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:18:18 -0500 Subject: [PATCH 193/378] no njit --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index e7acd4a2..0effb904 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -330,7 +330,7 @@ def state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager): (fbase, fext) = os.path.splitext(hdf5_path) state.model_root_name = os.path.split(fbase)[1] # takes the text before .h5 -@njit(cache=True) +#@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 From 01b4da9d596864e5fe08f4b008d2ef91e17668ed Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:22:55 -0500 Subject: [PATCH 194/378] remove redundant path creation --- src/hsp2/state/state.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 0effb904..112bfdae 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -350,12 +350,13 @@ def state_init_hsp2(state, opseq, activities): # This sets up the state entries for all state compatible HSP2 model variables # 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) + #print("adding", seg_path) 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 - state.set_state(seg_path, 0.0) if activity == "HYDR": state_context_hsp2(state, operation, segment, activity) elif activity == "SEDTRN": From b4f8293bd01f11850a4bc03bfb5a08ca6a3c7393 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:24:25 -0500 Subject: [PATCH 195/378] info --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 112bfdae..1c697ae5 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -354,7 +354,7 @@ def state_init_hsp2(state, opseq, activities): seg_path = "/STATE/" + state.model_root_name + "/" + seg_name # set up named paths for model operations state.set_state(seg_path, 0.0) - #print("adding", seg_path) + print("adding", seg_path) if operation != "GENER" and operation != "COPY": for activity, function in activities[operation].items(): if activity == "HYDR": From c414585d32d61e0f8b1bcf8211f0b2ed6cb21e88 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:26:44 -0500 Subject: [PATCH 196/378] info --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 1c697ae5..7ae710ac 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -348,7 +348,7 @@ def state_context_hsp2(state, operation, segment, activity): #@njit(cache=True) def state_init_hsp2(state, opseq, activities): # 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 From c40c0aa0cd17106a94abaf0e528e4b3ff37cbf0d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:36:10 -0500 Subject: [PATCH 197/378] eval prep with state as non jit --- src/hsp2/state/state.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 7ae710ac..ccbbbac3 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -79,7 +79,7 @@ def make_state_lite(num_ops): sc = state_class_lite(num_ops) #return sc -@jitclass(state_spec) +#@jitclass(state_spec) class state_class: def __init__(self): self.num_ops = 0 diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 4f2e571f..3f843d74 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -47,7 +47,7 @@ # Iterate through all segments and add crucial paths to state # before loading dynamic components that may reference them -state_init_hsp2(state, opseq, activities, om_operations) +state_init_hsp2(state, opseq, activities) # - finally stash specactions in state, not domain (segment) dependent so do it once specl_load_om(om_operations, uci_obj.specactions) # load traditional special actions state_load_dynamics_om( From a2db292fba9e2458c76f3c78b4a185af8731a6cb Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:39:08 -0500 Subject: [PATCH 198/378] eval prep with state as non jit --- src/hsp2/hsp2/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index af09006f..723442f3 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -97,9 +97,9 @@ def main( ####################################################################################### # Set up Things in state that will be used in all modular activities like SPECL state = state_class() - scl = make_state_lite(0) - print("Made state_class_lite", scl) print("state_class() call", timer.split(), "seconds") + scl = make_state_lite(0) + print("Made state_class_lite", timer.split()) om_operations = om_init_state() # set up operational model specific containers print("om_init_state() call", timer.split(), "seconds") state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) From 10da314a9d18799c260b8413b83038335c591d3c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:42:31 -0500 Subject: [PATCH 199/378] state class lite compiled and returned what is time impact? --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ccbbbac3..bb5acd7b 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -77,7 +77,7 @@ def __init__(self, num_ops): @njit(cache=True) def make_state_lite(num_ops): sc = state_class_lite(num_ops) - #return sc + return sc #@jitclass(state_spec) class state_class: From fb22f7513953273aa1f22f9ad9b9a2feddc9d6c6 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:43:42 -0500 Subject: [PATCH 200/378] also must compile state_class --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index bb5acd7b..45f0ae1b 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -79,7 +79,7 @@ def make_state_lite(num_ops): sc = state_class_lite(num_ops) return sc -#@jitclass(state_spec) +@jitclass(state_spec) class state_class: def __init__(self): self.num_ops = 0 From 2b09ca8c4450f4dc6cad3441b888710df8d25e08 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:45:34 -0500 Subject: [PATCH 201/378] add field to lite --- src/hsp2/state/state.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 45f0ae1b..d6dce155 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -47,9 +47,8 @@ state_lite = [ ("num_ops", nb.int64), - ("state_ix", nb.float64[:]), # the first entries here are NP arrays, fixed dimenstions, and fast - #("state_ix", typeof(np.asarray(zeros(1), dtype="float64")) ), + ("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")) ), @@ -63,8 +62,8 @@ 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) + 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/... From f3176c22649485035e96da79bfd97da15ea45b91 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:46:48 -0500 Subject: [PATCH 202/378] add field to lite --- src/hsp2/state/state.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index d6dce155..daa1460f 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -49,7 +49,7 @@ ("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_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()) ), @@ -64,8 +64,8 @@ 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) + 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) From cfe0b7b4d75aa160ba732d10f5877ef08ef7b567 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:47:33 -0500 Subject: [PATCH 203/378] add field to lite --- src/hsp2/state/state.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index daa1460f..8c038ac2 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -50,7 +50,7 @@ # 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)))) ), + ("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 @@ -67,8 +67,8 @@ def __init__(self, num_ops): 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) + 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) From 0a8f3d821fe59fb22288cb3a7694e1820b2733e5 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:48:31 -0500 Subject: [PATCH 204/378] add field to lite --- src/hsp2/state/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 8c038ac2..4bec91c7 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -70,8 +70,8 @@ def __init__(self, num_ops): 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) + model_exec_list = zeros(self.num_ops) + self.model_exec_list = model_exec_list.astype(npint64) @njit(cache=True) def make_state_lite(num_ops): From 19d01b5e138ad34888e786bccd9e5a60e414e131 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:49:48 -0500 Subject: [PATCH 205/378] add field to lite --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 4bec91c7..c2d62da7 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -51,7 +51,7 @@ ("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")) ), + ("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[:, :]) ), From abd0bbe3effaa58030a2cc41dab4ba77c75a6146 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:51:01 -0500 Subject: [PATCH 206/378] add remaining needed fields to lite --- src/hsp2/state/state.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index c2d62da7..0609f1f1 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -52,10 +52,10 @@ ("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()) ), + ("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[:]) ) + ("dict_ix", types.DictType(types.int64, types.float64[:, :]) ), + ("ts_ix", types.DictType(types.int64, types.float64[:]) ) ] @jitclass(state_lite) From 5674ce09408f7d972cec95e6d87f6ea51147b118 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:57:17 -0500 Subject: [PATCH 207/378] add contextual fields to lite --- src/hsp2/state/state.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 0609f1f1..dd083fba 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -55,7 +55,17 @@ ("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[:]) ) + ("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), + ("operation", types.unicode_type), + ("segment", types.unicode_type), + ("activity", types.unicode_type), + ("domain", types.unicode_type), + ("state_step_om", types.unicode_type), ] @jitclass(state_lite) From 4f0fc2f327da31c80e0604cffcc1dd93f116fe28 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 16:59:41 -0500 Subject: [PATCH 208/378] where is lite --- src/hsp2/hsp2/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 723442f3..cc6456be 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -98,8 +98,6 @@ def main( # Set up Things in state that will be used in all modular activities like SPECL state = state_class() print("state_class() call", timer.split(), "seconds") - scl = make_state_lite(0) - print("Made state_class_lite", timer.split()) om_operations = om_init_state() # set up operational model specific containers print("om_init_state() call", timer.split(), "seconds") state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) @@ -125,6 +123,8 @@ def main( # 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", timer.split(), "seconds") + scl = make_state_lite(0) + print("make_state_lite", timer.split()) ####################################################################################### # main processing loop From 2ac85a9042bb4df65071f682874c7c321f9fde54 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:13:55 -0500 Subject: [PATCH 209/378] now use lite with copier at start --- src/hsp2/hsp2/RQUAL.py | 14 -------------- src/hsp2/hsp2/main.py | 17 +++++++++++------ src/hsp2/state/state.py | 8 ++++++++ 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/hsp2/hsp2/RQUAL.py b/src/hsp2/hsp2/RQUAL.py index 382a883d..2d285e26 100644 --- a/src/hsp2/hsp2/RQUAL.py +++ b/src/hsp2/hsp2/RQUAL.py @@ -251,20 +251,6 @@ 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) # Aggregate the list of all SEDTRN end point dependencies diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index cc6456be..da37f49f 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -24,7 +24,8 @@ state_init_hsp2, state_context_hsp2, state_class, - make_state_lite + state_class_lite, + state_copy ) from hsp2.hsp2.om import ( @@ -123,7 +124,8 @@ def main( # 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", timer.split(), "seconds") - scl = make_state_lite(0) + statenb = state_class_lite(0) + state_copy(state, statenb) print("make_state_lite", timer.split()) ####################################################################################### @@ -225,7 +227,7 @@ def main( msg(3, f"{activity}") # Set context for dynamic executables and special actions - state_context_hsp2(state, operation, segment, activity) + state_context_hsp2(statenb, operation, segment, activity) ui = model[(operation, activity, segment)] # ui is a dictionary if operation == "PERLND" and activity == "SEDMNT": @@ -419,11 +421,11 @@ def main( if operation not in ["COPY", "GENER"]: if activity == "HYDR": errors, errmessages = function( - siminfo, ui, ts, ftables, state + siminfo, ui, ts, ftables, statenb ) elif activity == "SEDTRN" or activity == "SEDMNT": errors, errmessages = function( - siminfo, ui, ts, state + siminfo, ui, ts, statenb ) elif activity != "RQUAL": errors, errmessages = function(io_manager, siminfo, ui, ts) @@ -438,7 +440,7 @@ def main( ui_phcarb, ts, monthdata, - state, + statenb ) ############################################################### @@ -543,6 +545,9 @@ def main( msglist = msg(1, "Done", final=True) # Finish operational models + (state.num_ops, state.state_ix, state.op_tokens, state.op_exec_lists, state.model_exec_list) = ( + statenb.num_ops, statenb.state_ix, statenb.op_tokens, statenb.op_exec_lists, statenb.model_exec_list + ) state_om_model_run_finish(state, io_manager, siminfo) df = DataFrame(msglist, columns=["logfile"]) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index dd083fba..00cff291 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -88,6 +88,14 @@ 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.numops + statedest.state_ix = statesrc.state_ix + statedest.op_tokens = statesrc.op_tokens + statedest.op_exec_lists = statesrc.op_exec_lists + statedest.model_exec_list = statesrc.model_exec_list + @jitclass(state_spec) class state_class: def __init__(self): From 500933acd4d61e26ad19f92dccc6b070095e039d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:15:15 -0500 Subject: [PATCH 210/378] typo --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 00cff291..13b89062 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -90,7 +90,7 @@ def make_state_lite(num_ops): def state_copy(statesrc, statedest): # copies from a non-jit to a jit or vice versa - statedest.num_ops = statesrc.numops + statedest.num_ops = statesrc.num_ops statedest.state_ix = statesrc.state_ix statedest.op_tokens = statesrc.op_tokens statedest.op_exec_lists = statesrc.op_exec_lists From e27a1539a98995a8c755d305469880b2a19e2964 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:18:55 -0500 Subject: [PATCH 211/378] typo --- src/hsp2/state/state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 13b89062..6a3734f7 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -56,6 +56,7 @@ # 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), @@ -262,7 +263,7 @@ def op_path_name(operation, id): return path_name -def get_state_ix(state_ix, state_paths, var_path): +def get_state_ix(state_paths, var_path): """ Find the integer key of a variable name in state_ix """ From 4ce465cfd3594e61f984d49a0c825978fa222925 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:20:38 -0500 Subject: [PATCH 212/378] use non method function --- src/hsp2/hsp2/HYDR.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 7b4f1abf..790feb41 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 @@ -153,7 +153,7 @@ def hydr(siminfo, parameters, ts, ftables, state): # 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' - activity_id = state.get_state_ix(activity_path) + activity_id = get_state_ix(state.state_paths, activity_path) model_exec_list = state.op_exec_lists[activity_id] ####################################################################################### From 6cf1552ff804596d64ce807aa971bbe8da11041e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:22:54 -0500 Subject: [PATCH 213/378] dont forget to copy all needed --- src/hsp2/state/state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 6a3734f7..427ea69b 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -96,6 +96,7 @@ def state_copy(statesrc, statedest): 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 @jitclass(state_spec) class state_class: From efc3f1b7091acefa1ac11324834f670cad12f437 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:27:21 -0500 Subject: [PATCH 214/378] de ubg and copy hsp active or not --- src/hsp2/hsp2/HYDR.py | 3 ++- src/hsp2/state/state.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 790feb41..575c2f2e 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -153,6 +153,7 @@ def hydr(siminfo, parameters, ts, ftables, state): # 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("Getting activity id from", activity_path) activity_id = get_state_ix(state.state_paths, activity_path) model_exec_list = state.op_exec_lists[activity_id] ####################################################################################### @@ -199,7 +200,7 @@ def _hydr_( model_exec_list ): errors = zeros(int(ui["errlen"])).astype(int64) - + print("DEBUG: _hydr_ Called with:", model_exec_list) steps = int(ui["steps"]) # number of simulation steps delts = ui["delt"] * 60.0 # seconds in simulation interval uunits = ui["uunits"] diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 427ea69b..3beb4cef 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -97,6 +97,7 @@ def state_copy(statesrc, statedest): 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 @jitclass(state_spec) class state_class: From 162725e4e5c46a9e8d5b5c23ba69a777d6f1a3ce Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:29:10 -0500 Subject: [PATCH 215/378] jit off --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 575c2f2e..e4af3ab4 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -185,7 +185,7 @@ def hydr(siminfo, parameters, ts, ftables, state): return errors, ERRMSGS -@njit(cache=True) +#@njit(cache=True) def _hydr_( ui, ts, From 923f9b3f90503a265b5b6345d350a8586f061f6f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:30:35 -0500 Subject: [PATCH 216/378] debug --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index e4af3ab4..9b568511 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -51,7 +51,7 @@ def hydr(siminfo, parameters, ts, ftables, state): # 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. - + print("Running hydr()") steps = siminfo["steps"] # number of simulation points uunits = siminfo["units"] nexits = int(parameters["PARAMETERS"]["NEXITS"]) From bf5bbe5f37472a46c0c2ea892eff907c78bc830c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:47:07 -0500 Subject: [PATCH 217/378] jit on, removed context call since that is a double function that is not needed here --- src/hsp2/hsp2/main.py | 9 ++++----- src/hsp2/state/state.py | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index da37f49f..034f6344 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -22,11 +22,10 @@ state_siminfo_hsp2, state_load_dynamics_hsp2, state_init_hsp2, - state_context_hsp2, state_class, state_class_lite, - state_copy - + state_copy, + state_domain ) from hsp2.hsp2.om import ( om_init_state, @@ -227,8 +226,8 @@ def main( msg(3, f"{activity}") # Set context for dynamic executables and special actions - state_context_hsp2(statenb, operation, segment, activity) - + state.domain = state_domain(statenb, operation, segment, activity) + (state.operation, state.segment, state.activity) = (operation, segment, activity) ui = model[(operation, activity, segment)] # ui is a dictionary if operation == "PERLND" and activity == "SEDMNT": # special exception here to make CSNOFG available diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 3beb4cef..c377e0ce 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -358,12 +358,22 @@ def state_context_hsp2(state, operation, segment, activity): 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 + (seg_name, seg_path) = state_segname(state, operation, segment, activity) #if seg_name not in state.hsp_segments.keys(): if seg_name not in state.hsp_segments: # test this for njit state.hsp_segments[seg_name] = seg_path - state.domain = seg_path # + "/" + activity # may want to comment out activity? + 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) #@njit(cache=True) def state_init_hsp2(state, opseq, activities): From fc112df749dbb26d537a2a6adeca8aff80b32d9c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:51:11 -0500 Subject: [PATCH 218/378] info --- src/hsp2/hsp2/HYDR.py | 2 +- src/hsp2/hsp2/main.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 9b568511..d1f9ca07 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -185,7 +185,7 @@ def hydr(siminfo, parameters, ts, ftables, state): return errors, ERRMSGS -#@njit(cache=True) +@njit(cache=True) def _hydr_( ui, ts, diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 034f6344..d4575536 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -226,8 +226,10 @@ def main( msg(3, f"{activity}") # Set context for dynamic executables and special actions - state.domain = state_domain(statenb, operation, segment, activity) - (state.operation, state.segment, state.activity) = (operation, segment, activity) + statenb.domain = state_domain(statenb, operation, segment, activity) + print("set domain to", statenb.domain) + (statenb.operation, statenb.segment, statenb.activity) = (operation, segment, activity) + print("set dostatenb op seg zct", operation, segment, activity) ui = model[(operation, activity, segment)] # ui is a dictionary if operation == "PERLND" and activity == "SEDMNT": # special exception here to make CSNOFG available From 332380491aa8f66aa5447610893e2a5e4f72194b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:53:01 -0500 Subject: [PATCH 219/378] info --- src/hsp2/hsp2/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index d4575536..623c32ca 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -226,6 +226,7 @@ def main( msg(3, f"{activity}") # Set context for dynamic executables and special actions + print("trying state_domain()") statenb.domain = state_domain(statenb, operation, segment, activity) print("set domain to", statenb.domain) (statenb.operation, statenb.segment, statenb.activity) = (operation, segment, activity) From 7016e7e8a4513f9b2fd23e167daf94fb94fba1b6 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:56:09 -0500 Subject: [PATCH 220/378] add actual defaults --- src/hsp2/state/state.py | 4 ++++ tests/testcbp/HSP2results/check_equation.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index c377e0ce..3122c50f 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -83,6 +83,10 @@ def __init__(self, num_ops): # 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 = "" @njit(cache=True) def make_state_lite(num_ops): diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 3f843d74..c34ae98c 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -56,6 +56,8 @@ # finalize all dynamically loaded components and prepare to run the model state_om_model_run_prep(opseq, activities, state, om_operations, siminfo) # Set up order of execution +statenb = state_class_lite(0) +state_copy(state, statenb) # debug loading: # mtl = [] From 84d10b21a66286ab70b4439c9bdb8f9ea462a8d0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 17:59:05 -0500 Subject: [PATCH 221/378] add model_root_name! --- src/hsp2/state/state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 3122c50f..84a82c72 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -87,6 +87,7 @@ def __init__(self, num_ops): self.segment = "" self.operation = "" self.domain = "" + self.model_root_name = "" @njit(cache=True) def make_state_lite(num_ops): From 75131dc03b2f02858532d5083dbb07df2e952fe8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 18:05:23 -0500 Subject: [PATCH 222/378] use old function --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 84a82c72..13249414 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -580,7 +580,7 @@ def hydr_get_ix(state, domain): # var_path = f'{domain}/{i}' var_path = domain + "/" + i # print("looking for:", var_path) - hydr_ix[i] = state.get_state_ix(var_path) + hydr_ix[i] = get_state_ix(state.state_paths, var_path) return hydr_ix From eed2c1207010f241a794553112f80c2f7cfc88da Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 18:08:56 -0500 Subject: [PATCH 223/378] copy root name --- src/hsp2/state/state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 13249414..fa2eb1e9 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -103,6 +103,7 @@ def state_copy(statesrc, statedest): 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 @jitclass(state_spec) class state_class: From f365fcd1105ac6a09e32ad00eb334f1ee5a18201 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 18:11:17 -0500 Subject: [PATCH 224/378] numbaize old support function --- src/hsp2/state/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index fa2eb1e9..387959ac 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -270,7 +270,7 @@ def op_path_name(operation, id): path_name = f"{operation}_{operation[0]}{tid}" return path_name - +@njit(cache=True) def get_state_ix(state_paths, var_path): """ Find the integer key of a variable name in state_ix @@ -554,7 +554,7 @@ def rqual_init_ix(state, domain): return rqual_ix -@njit +@njit(cache=True) def hydr_get_ix(state, domain): # get a list of keys for all hydr state variables hydr_state = [ From cb32862ecf7bb74c2532c0a6f107d7739f14836f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 18:14:14 -0500 Subject: [PATCH 225/378] no jit on base state class to speed up --- src/hsp2/hsp2/HYDR.py | 5 +---- src/hsp2/hsp2/main.py | 3 --- src/hsp2/state/state.py | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index d1f9ca07..4ad0d64f 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -51,7 +51,6 @@ def hydr(siminfo, parameters, ts, ftables, state): # 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. - print("Running hydr()") steps = siminfo["steps"] # number of simulation points uunits = siminfo["units"] nexits = int(parameters["PARAMETERS"]["NEXITS"]) @@ -153,7 +152,6 @@ def hydr(siminfo, parameters, ts, ftables, state): # 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("Getting activity id from", activity_path) activity_id = get_state_ix(state.state_paths, activity_path) model_exec_list = state.op_exec_lists[activity_id] ####################################################################################### @@ -200,7 +198,6 @@ def _hydr_( model_exec_list ): errors = zeros(int(ui["errlen"])).astype(int64) - print("DEBUG: _hydr_ Called with:", model_exec_list) steps = int(ui["steps"]) # number of simulation steps delts = ui["delt"] * 60.0 # seconds in simulation interval uunits = ui["uunits"] @@ -341,7 +338,7 @@ def _hydr_( ####################################################################################### # 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, state.domain) + hydr_ix = hydr_get_ix(state.state_paths, 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 = ( diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 623c32ca..b4aec778 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -226,11 +226,8 @@ def main( msg(3, f"{activity}") # Set context for dynamic executables and special actions - print("trying state_domain()") statenb.domain = state_domain(statenb, operation, segment, activity) - print("set domain to", statenb.domain) (statenb.operation, statenb.segment, statenb.activity) = (operation, segment, activity) - print("set dostatenb op seg zct", operation, segment, activity) ui = model[(operation, activity, segment)] # ui is a dictionary if operation == "PERLND" and activity == "SEDMNT": # special exception here to make CSNOFG available diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 387959ac..f3643a83 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -105,7 +105,6 @@ def state_copy(statesrc, statedest): statedest.hsp2_local_py = statesrc.hsp2_local_py statedest.model_root_name = statesrc.model_root_name -@jitclass(state_spec) class state_class: def __init__(self): self.num_ops = 0 From 17e21cc2439e2b6de7b8ccb4a961d4fc1c4f5890 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 6 Jan 2026 18:20:29 -0500 Subject: [PATCH 226/378] use correct term --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 4ad0d64f..420d7ea3 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -338,7 +338,7 @@ def _hydr_( ####################################################################################### # 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.state_paths, state.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 = ( From 97baab99a843b7c7b8bdb8b09e376e5a6a58fd60 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 09:18:18 -0500 Subject: [PATCH 227/378] cleaned up imports --- src/hsp2/hsp2/RQUAL.py | 9 +++------ src/hsp2/hsp2/SEDTRN.py | 4 +--- src/hsp2/hsp2/om_sim_timer.py | 3 +-- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/hsp2/hsp2/RQUAL.py b/src/hsp2/hsp2/RQUAL.py index 2d285e26..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,11 +250,9 @@ def rqual( ####################################################################################### # the following section (1 of 3) added to RQUAL by pbd to handle special actions ####################################################################################### - # initialize the rqual paths in case they don't already reside here - rqual_init_ix(state, state.domain) # Aggregate the list of all SEDTRN end point dependencies activity_path = state.domain + "/" + 'SEDTRN' - activity_id = state.get_state_ix(activity_path) + activity_id = get_state_ix(state.state_paths, activity_path) model_exec_list = state.op_exec_lists[activity_id] ####################################################################################### diff --git a/src/hsp2/hsp2/SEDTRN.py b/src/hsp2/hsp2/SEDTRN.py index 56d9da19..a353e9d8 100644 --- a/src/hsp2/hsp2/SEDTRN.py +++ b/src/hsp2/hsp2/SEDTRN.py @@ -99,11 +99,9 @@ def sedtrn(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) # Aggregate the list of all SEDTRN end point dependencies activity_path = state.domain + "/" + 'SEDTRN' - activity_id = state.get_state_ix(activity_path) + activity_id = get_state_ix(state.state_paths, activity_path) model_exec_list = state.op_exec_lists[activity_id] ####################################################################################### diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index a062bf9c..b40ebb61 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -8,10 +8,9 @@ from hsp2.hsp2.om_model_object import ModelObject from pandas import DataFrame from numba import njit, types -from numpy import int64, float64 +from numpy import int64 from numba.experimental import jitclass import ctypes -import time class SimTimer(ModelObject): def __init__(self, name, container, model_props=None, state=None): From 12035570369f7ccdca35baa1a60b17b16ea295c3 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 11:44:55 -0500 Subject: [PATCH 228/378] better memory handling --- src/hsp2/hsp2/main.py | 71 +++++++++++++---------------- src/hsp2/state/state.py | 22 ++------- src/hsp2/state/state_definitions.py | 30 ++++++++++++ src/hsp2/state/state_fn_defaults.py | 9 ---- 4 files changed, 66 insertions(+), 66 deletions(-) create mode 100644 src/hsp2/state/state_definitions.py delete mode 100644 src/hsp2/state/state_fn_defaults.py diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index b4aec778..3b7aa201 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -18,24 +18,22 @@ get_gener_timeseries, ) from hsp2.hsp2.configuration import activities, noop, expand_masslinks +from hsp2.state.state_definitions import state_empty from hsp2.state.state import ( state_siminfo_hsp2, state_load_dynamics_hsp2, state_init_hsp2, - state_class, - state_class_lite, - state_copy, - state_domain + state_context_hsp2, + state_class ) 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_sim_timer import timer_class -from hsp2.hsp2.SPECL import specl_load_om from hsp2.hsp2io.io import IOManager, SupportsReadTS, Category @@ -59,10 +57,8 @@ def main( None """ - timer = timer_class() print("main() call", timer.split(), "seconds") - if isinstance(io_manager, str): hdf5_instance = HDF5(io_manager) io_manager = IOManager(hdf5_instance) @@ -75,7 +71,6 @@ def main( # read user control, parameters, states, and flags parameters and map to local variables parameter_obj = io_manager.read_parameters() - print("Load io_manager parameters", timer.split(), "seconds") opseq = parameter_obj.opseq ddlinks = parameter_obj.ddlinks ddmasslinks = parameter_obj.ddmasslinks @@ -91,45 +86,45 @@ def main( 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() - print("state_class() call", timer.split(), "seconds") - om_operations = om_init_state() # set up operational model specific containers - print("om_init_state() call", timer.split(), "seconds") - state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) - print("state_siminfo_hsp2() call", timer.split(), "seconds") + 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"] + ) + state = state_empty # init_state_dicts() # automatically imported from state_fn_defaults + print("init_state_dicts()", timer.split(), "seconds") + state_siminfo_hsp2(parameter_obj, siminfo, io_manager, state) # 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", timer.split(), "seconds") + 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) - print("state_init_hsp2() call", timer.split(), "seconds") - # now initialize all state variables for mutable variables - hsp2_domain_dependencies(state, opseq, activities, om_operations, False) - print("hsp2_domain_dependencies", timer.split(), "seconds") + state_init_hsp2(state, opseq, activities, timer) + print("state_init_hsp2() call and config", timer.split(), "seconds") # - finally stash specactions in state, not domain (segment) dependent so do it once - specl_load_om(om_operations, specactions) # load traditional special actions - print("specl_load_om", timer.split(), "seconds") + state["specactions"] = specactions # stash the specaction dict in state + om_init_state(state) # set up operational model specific state entries + print("om_init_state() call and config", timer.split(), "seconds") + specl_load_state(state, io_manager, siminfo) # traditional special actions + print("specl_load_state() call and config", timer.split(), "seconds") state_load_dynamics_om( - state, io_manager, siminfo, om_operations + state, io_manager, siminfo ) # operational model for custom python - print("state_load_dynamics_om", timer.split(), "seconds") + 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", timer.split(), "seconds") - statenb = state_class_lite(0) - state_copy(state, statenb) - print("make_state_lite", timer.split()) + state_om_model_run_prep(state, io_manager, siminfo) + print("state_om_model_run_prep() call and config", timer.split(), "seconds") ####################################################################################### # 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 @@ -226,8 +221,8 @@ def main( msg(3, f"{activity}") # Set context for dynamic executables and special actions - statenb.domain = state_domain(statenb, operation, segment, activity) - (statenb.operation, statenb.segment, statenb.activity) = (operation, segment, activity) + state_context_hsp2(state, operation, segment, activity) + ui = model[(operation, activity, segment)] # ui is a dictionary if operation == "PERLND" and activity == "SEDMNT": # special exception here to make CSNOFG available @@ -420,11 +415,11 @@ def main( if operation not in ["COPY", "GENER"]: if activity == "HYDR": errors, errmessages = function( - siminfo, ui, ts, ftables, statenb + io_manager, siminfo, ui, ts, ftables, state ) elif activity == "SEDTRN" or activity == "SEDMNT": errors, errmessages = function( - siminfo, ui, ts, statenb + io_manager, siminfo, ui, ts, state ) elif activity != "RQUAL": errors, errmessages = function(io_manager, siminfo, ui, ts) @@ -439,7 +434,7 @@ def main( ui_phcarb, ts, monthdata, - statenb + state, ) ############################################################### @@ -539,14 +534,10 @@ def main( jupyterlab, outstep_phcarb, ) - print(operation, segment, timer.split(), 'seconds') msglist = msg(1, "Done", final=True) # Finish operational models - (state.num_ops, state.state_ix, state.op_tokens, state.op_exec_lists, state.model_exec_list) = ( - statenb.num_ops, statenb.state_ix, statenb.op_tokens, statenb.op_exec_lists, statenb.model_exec_list - ) state_om_model_run_finish(state, io_manager, siminfo) df = DataFrame(msglist, columns=["logfile"]) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index f3643a83..444c9ad3 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -106,38 +106,26 @@ def state_copy(statesrc, statedest): statedest.model_root_name = statesrc.model_root_name class state_class: - def __init__(self): + 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 - 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) # 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 = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) - self.dict_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:, :]) - self.state_paths = ntdict.empty( - key_type=types.unicode_type, value_type=types.int64 - ) - self.hsp_segments = ntdict.empty( - key_type=types.unicode_type, value_type=types.unicode_type - ) - self.ts_paths = ntdict.empty( - key_type=types.unicode_type, value_type=types.float64[:] - ) - self.ts_ix = ntdict.empty(key_type=types.int64, value_type=types.float64[:]) + 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 = "" diff --git a/src/hsp2/state/state_definitions.py b/src/hsp2/state/state_definitions.py new file mode 100644 index 00000000..f373af58 --- /dev/null +++ b/src/hsp2/state/state_definitions.py @@ -0,0 +1,30 @@ +# 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 + +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"] = 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_info, state_paths, state_ix, dict_ix, ts_ix, hydr_ix, 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 c2e158d4..00000000 --- a/src/hsp2/state/state_fn_defaults.py +++ /dev/null @@ -1,9 +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, step): - # TODO: - return - From 1170c648a0e884448f3b16d501d8e0c658ae23e9 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 11:48:25 -0500 Subject: [PATCH 229/378] missing import --- src/hsp2/state/state_definitions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state_definitions.py b/src/hsp2/state/state_definitions.py index f373af58..80929c4a 100644 --- a/src/hsp2/state/state_definitions.py +++ b/src/hsp2/state/state_definitions.py @@ -7,7 +7,7 @@ state_empty["state_paths"] = Dict.empty( key_type=types.unicode_type, value_type=types.int64 ) -state_empty["state_ix"] = float64(zeros(0)) +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) From 1dc000171ed81174ce0dbc3365a1d8fe3f9e91a5 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 11:49:31 -0500 Subject: [PATCH 230/378] missing import --- src/hsp2/state/state_definitions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/state/state_definitions.py b/src/hsp2/state/state_definitions.py index 80929c4a..bf0587de 100644 --- a/src/hsp2/state/state_definitions.py +++ b/src/hsp2/state/state_definitions.py @@ -2,6 +2,7 @@ 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( From ea180cd4a059e753c1ddb79a35af705610c787b4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 12:00:24 -0500 Subject: [PATCH 231/378] timer --- src/hsp2/hsp2/om_sim_timer.py | 16 +++++- tests/testcbp/HSP2results/check_equation.py | 63 +++++++++++++++------ 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index b40ebb61..c85507dd 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -11,6 +11,7 @@ from numpy import int64 from numba.experimental import jitclass import ctypes +import time class SimTimer(ModelObject): def __init__(self, name, container, model_props=None, state=None): @@ -141,7 +142,7 @@ def jitime(): return current_time @jitclass(timer_spec) -class timer_class(): +class timer_class_jit(): def __init__(self): self.tstart = jitime() @@ -153,3 +154,16 @@ def split(self): 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/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index c34ae98c..4dbcac22 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -13,6 +13,7 @@ from hsp2.hsp2.configuration import activities from src.hsp2.hsp2tools.commands import import_uci, run from pandas import read_hdf +import time fpath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.h5" @@ -28,33 +29,59 @@ hdf5_instance = HDF5(fpath) io_manager = IOManager(hdf5_instance) -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: -# - 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 = state_class() -om_operations = om_init_state() - -state_siminfo_hsp2(state, uci_obj, siminfo, io_manager) -# now initialize all state variables for mutable variables -hsp2_domain_dependencies(state, opseq, activities, om_operations, True) +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"] +) +state = state_empty # init_state_dicts() # automatically imported from state_fn_defaults +print("init_state_dicts()", timer.split(), "seconds") +state_siminfo_hsp2(parameter_obj, siminfo, io_manager, state) # 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_init_hsp2(state, opseq, activities, timer) +print("state_init_hsp2() call and config", timer.split(), "seconds") # - finally stash specactions in state, not domain (segment) dependent so do it once -specl_load_om(om_operations, uci_obj.specactions) # load traditional special actions +state["specactions"] = specactions # stash the specaction dict in state +om_init_state(state) # set up operational model specific state entries +print("om_init_state() call and config", timer.split(), "seconds") +specl_load_state(state, io_manager, siminfo) # traditional special actions +print("specl_load_state() call and config", timer.split(), "seconds") state_load_dynamics_om( - state, io_manager, siminfo, om_operations + state, io_manager, siminfo ) # 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) +state_om_model_run_prep(state, io_manager, siminfo) +print("state_om_model_run_prep() call and config", timer.split(), "seconds") +####################################################################################### + + # Set up order of execution statenb = state_class_lite(0) state_copy(state, statenb) From a8f0103ca6656ff604b1c522c335019f0c468e90 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 12:14:24 -0500 Subject: [PATCH 232/378] need to pass state --- src/hsp2/hsp2/main.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 3b7aa201..661a5a7a 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -98,7 +98,7 @@ def main( ) state = state_empty # init_state_dicts() # automatically imported from state_fn_defaults print("init_state_dicts()", timer.split(), "seconds") - state_siminfo_hsp2(parameter_obj, siminfo, io_manager, state) + state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager, state) # 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) diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 4dbcac22..872999b8 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -13,13 +13,11 @@ from hsp2.hsp2.configuration import activities from src.hsp2.hsp2tools.commands import import_uci, run from pandas import read_hdf -import time +from hsp2.hsp2.om_sim_timer import timer_class +timer = timer_class() fpath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.h5" -ucipath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.uci" -uci = readUCI(ucipath, fpath) - # try also: # fpath = './tests/testcbp/HSP2results/JL1_6562_6560.h5' From 70fdba582d0500d74d15c81d9743b3196c4b2579 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 12:17:37 -0500 Subject: [PATCH 233/378] nreposition --- src/hsp2/hsp2/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 661a5a7a..a4c6e359 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -98,7 +98,7 @@ def main( ) state = state_empty # init_state_dicts() # automatically imported from state_fn_defaults print("init_state_dicts()", timer.split(), "seconds") - state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager, state) + 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) From 9205c5727d6d1077cecd791663d4e3aa5fa46ec5 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 12:21:38 -0500 Subject: [PATCH 234/378] oops overwrote state --- src/hsp2/hsp2/main.py | 1 - tests/testcbp/HSP2results/check_equation.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index a4c6e359..0082eafc 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -96,7 +96,6 @@ def main( state_empty["op_exec_lists"], state_empty["model_exec_list"], state_empty["dict_ix"], state_empty["ts_ix"], state_empty["hsp_segments"] ) - state = state_empty # init_state_dicts() # automatically imported from state_fn_defaults print("init_state_dicts()", timer.split(), "seconds") state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) # Add support for dynamic functions to operate on STATE diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 872999b8..848222eb 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -17,7 +17,7 @@ timer = timer_class() -fpath = "./tests/testcbp/HSP2results/PL3_5250_0001eq.h5" +fpath = "./tests/testcbp/HSP2results/PL3_5250_0001.h5" # try also: # fpath = './tests/testcbp/HSP2results/JL1_6562_6560.h5' @@ -55,7 +55,7 @@ ) state = state_empty # init_state_dicts() # automatically imported from state_fn_defaults print("init_state_dicts()", timer.split(), "seconds") -state_siminfo_hsp2(parameter_obj, siminfo, io_manager, state) +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) From 4eebe6a48ced1585a94fd7753ff3dd7a1d93f67c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 12:23:16 -0500 Subject: [PATCH 235/378] dont pass timer --- src/hsp2/hsp2/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 0082eafc..f7a84d93 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -104,7 +104,7 @@ def main( 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, timer) + state_init_hsp2(state, opseq, activities) print("state_init_hsp2() call and config", timer.split(), "seconds") # - finally stash specactions in state, not domain (segment) dependent so do it once state["specactions"] = specactions # stash the specaction dict in state From 480fa0936421e6770090efd5250d74f1fbcc11c7 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 14:17:37 -0500 Subject: [PATCH 236/378] restore main.py and add timing alerts --- src/hsp2/hsp2/main.py | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index f7a84d93..096e0781 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -18,7 +18,6 @@ get_gener_timeseries, ) from hsp2.hsp2.configuration import activities, noop, expand_masslinks -from hsp2.state.state_definitions import state_empty from hsp2.state.state import ( state_siminfo_hsp2, state_load_dynamics_hsp2, @@ -31,9 +30,10 @@ 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_sim_timer import timer_class +from hsp2.hsp2.SPECL import specl_load_om from hsp2.hsp2io.io import IOManager, SupportsReadTS, Category @@ -57,8 +57,6 @@ def main( None """ - timer = timer_class() - print("main() call", timer.split(), "seconds") if isinstance(io_manager, str): hdf5_instance = HDF5(io_manager) io_manager = IOManager(hdf5_instance) @@ -86,6 +84,7 @@ def main( copy_instances = {} gener_instances = {} + print("io_manager.read_parameters() call and config", timer.split(), "seconds") ####################################################################################### # initialize STATE dicts @@ -96,34 +95,30 @@ def main( 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") + print("state_class()", timer.split(), "seconds") + om_operations = om_init_state() # set up operational model specific containers + print("om_operations()", timer.split(), "seconds") state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) + print("state_siminfo_hsp2()", timer.split(), "seconds") # 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) - print("state_init_hsp2() call and config", timer.split(), "seconds") + state_init_hsp2(state, opseq, activities, om_operations) + # 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 - print("om_init_state() call and config", timer.split(), "seconds") - specl_load_state(state, io_manager, siminfo) # traditional special actions - print("specl_load_state() call and config", timer.split(), "seconds") + 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 - 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(state, io_manager, siminfo) - print("state_om_model_run_prep() call and config", timer.split(), "seconds") + state_om_model_run_prep(opseq, activities, state, om_operations, siminfo) ####################################################################################### # 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 @@ -414,11 +409,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, state ) elif activity == "SEDTRN" or activity == "SEDMNT": errors, errmessages = function( - io_manager, siminfo, ui, ts, state + siminfo, ui, ts, state ) elif activity != "RQUAL": errors, errmessages = function(io_manager, siminfo, ui, ts) From 1c6ab623df966c5b0794fb79444555f01e3f290d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 14:19:39 -0500 Subject: [PATCH 237/378] create timer --- src/hsp2/hsp2/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 096e0781..56b7f135 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -57,6 +57,7 @@ def main( None """ + timer = timer_class() if isinstance(io_manager, str): hdf5_instance = HDF5(io_manager) io_manager = IOManager(hdf5_instance) From 9f9ab0f251c8aa9526235ecc05c29c2f6666c5be Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 14:21:19 -0500 Subject: [PATCH 238/378] import def --- src/hsp2/hsp2/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 56b7f135..262afa9f 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -34,7 +34,7 @@ ) from hsp2.hsp2.om_sim_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 From c4d976b80108063eefa55e655872b094b84dfe1b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 14:24:26 -0500 Subject: [PATCH 239/378] fix args --- src/hsp2/hsp2/main.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 262afa9f..9ca20937 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -104,18 +104,24 @@ def main( # 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()", 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, om_operations) + state_init_hsp2(state, opseq, activities) + print("state_init_hsp2()", timer.split(), "seconds") # now initialize all state variables for mutable variables hsp2_domain_dependencies(state, opseq, activities, om_operations, False) + print("hsp2_domain_dependencies()", timer.split(), "seconds") # - finally stash specactions in state, not domain (segment) dependent so do it once specl_load_om(om_operations, specactions) # load traditional special actions + print("specl_load_om()", timer.split(), "seconds") state_load_dynamics_om( state, io_manager, siminfo, om_operations ) # operational model for custom python + print("state_load_dynamics_om()", 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()", timer.split(), "seconds") ####################################################################################### # main processing loop From dbb51d40a632a07b33f1241fcc9770d67a0c54d8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 14:33:12 -0500 Subject: [PATCH 240/378] add numba compatible small state --- src/hsp2/hsp2/main.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 9ca20937..60e4b848 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -23,7 +23,9 @@ state_load_dynamics_hsp2, state_init_hsp2, state_context_hsp2, - state_class + state_class, + state_class_lite, + state_copy ) from hsp2.hsp2.om import ( om_init_state, @@ -122,6 +124,8 @@ def main( # 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()", timer.split(), "seconds") + statenb = state_class_lite(0) + state_copy(state, statenb) ####################################################################################### # main processing loop @@ -222,7 +226,7 @@ def main( msg(3, f"{activity}") # Set context for dynamic executables and special actions - state_context_hsp2(state, operation, segment, activity) + state_context_hsp2(statenb, operation, segment, activity) ui = model[(operation, activity, segment)] # ui is a dictionary if operation == "PERLND" and activity == "SEDMNT": @@ -416,11 +420,11 @@ def main( if operation not in ["COPY", "GENER"]: if activity == "HYDR": errors, errmessages = function( - siminfo, ui, ts, ftables, state + siminfo, ui, ts, ftables, statenb ) elif activity == "SEDTRN" or activity == "SEDMNT": errors, errmessages = function( - siminfo, ui, ts, state + siminfo, ui, ts, statenb ) elif activity != "RQUAL": errors, errmessages = function(io_manager, siminfo, ui, ts) @@ -435,7 +439,7 @@ def main( ui_phcarb, ts, monthdata, - state, + statenb, ) ############################################################### @@ -539,7 +543,7 @@ def main( 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) From 2a1844be4cd29773697802232d750e50af172444 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 14:48:16 -0500 Subject: [PATCH 241/378] add segments --- src/hsp2/state/state.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 444c9ad3..ffed94bb 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -67,6 +67,7 @@ ("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) @@ -104,6 +105,7 @@ def state_copy(statesrc, statedest): 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 class state_class: def __init__(self, state_ix, op_tokens, state_paths, op_exec_lists, model_exec_list, dict_ix, ts_ix, hsp_segments): From 8f5d9b489447450cd3fc6b9232744382078ecfb9 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 14:53:46 -0500 Subject: [PATCH 242/378] reduce args for this empty function --- src/hsp2/state/state_definitions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state_definitions.py b/src/hsp2/state/state_definitions.py index bf0587de..cf563b0b 100644 --- a/src/hsp2/state/state_definitions.py +++ b/src/hsp2/state/state_definitions.py @@ -27,5 +27,5 @@ ] @njit -def state_step_hydr(state_info, state_paths, state_ix, dict_ix, ts_ix, hydr_ix, step): +def state_step_hydr(state, step): return From 8c37013082a8e75042529f2d4a7f4e5d36d8f092 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 14:57:21 -0500 Subject: [PATCH 243/378] isable jit for debug --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 420d7ea3..5eca458e 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -183,7 +183,7 @@ def hydr(siminfo, parameters, ts, ftables, state): return errors, ERRMSGS -@njit(cache=True) +#@njit(cache=True) def _hydr_( ui, ts, From 74c2ec4ed4ac3bdce1a1f591754422bca4624633 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 15:03:46 -0500 Subject: [PATCH 244/378] isable jit for debug --- src/hsp2/hsp2/HYDR.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 5eca458e..a67bc8de 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -394,12 +394,18 @@ def _hydr_( state.state_ix[volev_ix] = volev # - these if statements may be irrelevant if default functions simply return # when no objects are defined. + if step < 3: + print("Calling pre_step_model") 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 step < 3: + print("Calling state_step_hydr") if state.state_step_hydr == "enabled": state_step_hydr( state, step ) + if step < 3: + print("Calling step_model") if state.state_step_om == "enabled": # print("trying to execute state_step_om()") # model_exec_list contains the model exec list in dependency order From 563c858681ef16b78c15bb81d437eaf3510be711 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 15:10:16 -0500 Subject: [PATCH 245/378] debug --- src/hsp2/hsp2/om.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 30b01a1c..0775be99 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -709,6 +709,9 @@ 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: # register type data (like broadcast accumulators) + if step < 3: + print("Calling pre_step_register") + pre_step_register(op_tokens[i], state_ix) return From a92d57ddf08bc84649784385fd516dce89235aa9 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 15:20:21 -0500 Subject: [PATCH 246/378] debug --- src/hsp2/hsp2/HYDR.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index a67bc8de..677dfe6d 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -394,10 +394,12 @@ def _hydr_( state.state_ix[volev_ix] = volev # - these if statements may be irrelevant if default functions simply return # when no objects are defined. - if step < 3: - print("Calling pre_step_model") if state.state_step_om == "enabled": + if step < 3: + print("Calling pre_step_model") pre_step_model(model_exec_list, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step) + if step < 3: + print("Calling pre_step_model") if step < 3: print("Calling state_step_hydr") if state.state_step_hydr == "enabled": From 005aa9b529038bc3a21797e8606691d097561137 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 15:22:46 -0500 Subject: [PATCH 247/378] need to include other pointer --- src/hsp2/state/state.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ffed94bb..395aef9e 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -106,6 +106,8 @@ def state_copy(statesrc, statedest): 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 class state_class: def __init__(self, state_ix, op_tokens, state_paths, op_exec_lists, model_exec_list, dict_ix, ts_ix, hsp_segments): From b7c6942b01ba313828c64e0f3d2c39ba461407ae Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 15:26:29 -0500 Subject: [PATCH 248/378] need to include other pointer --- src/hsp2/state/state.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 395aef9e..0b239166 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -99,6 +99,8 @@ 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 From 57640e9e7ec01b59efedaa32cafb88cc281155d2 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 15:27:56 -0500 Subject: [PATCH 249/378] debug off --- src/hsp2/hsp2/HYDR.py | 10 ++-------- src/hsp2/hsp2/om.py | 3 --- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 677dfe6d..1daeee27 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -395,19 +395,13 @@ def _hydr_( # - these if statements may be irrelevant if default functions simply return # when no objects are defined. if state.state_step_om == "enabled": - if step < 3: - print("Calling pre_step_model") pre_step_model(model_exec_list, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step) - if step < 3: - print("Calling pre_step_model") - if step < 3: - print("Calling state_step_hydr") + if state.state_step_hydr == "enabled": state_step_hydr( state, step ) - if step < 3: - print("Calling step_model") + if state.state_step_om == "enabled": # print("trying to execute state_step_om()") # model_exec_list contains the model exec list in dependency order diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 0775be99..30b01a1c 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -709,9 +709,6 @@ 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: # register type data (like broadcast accumulators) - if step < 3: - print("Calling pre_step_register") - pre_step_register(op_tokens[i], state_ix) return From 9008810dd86eeadf71d4902b4d614ee6295a86f4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 15:28:14 -0500 Subject: [PATCH 250/378] njiton --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 1daeee27..9056ef59 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -183,7 +183,7 @@ def hydr(siminfo, parameters, ts, ftables, state): return errors, ERRMSGS -#@njit(cache=True) +@njit(cache=True) def _hydr_( ui, ts, From c826e9f6acc5206376cff95e3e8f0c4b93d62564 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 16:19:18 -0500 Subject: [PATCH 251/378] debug --- src/hsp2/hsp2/HYDR.py | 2 +- src/hsp2/hsp2/om.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 9056ef59..1daeee27 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -183,7 +183,7 @@ def hydr(siminfo, parameters, ts, ftables, state): return errors, ERRMSGS -@njit(cache=True) +#@njit(cache=True) def _hydr_( ui, ts, diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 30b01a1c..8463aba6 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -704,10 +704,14 @@ def iterate_models( return checksum -@njit +#@njit def pre_step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): + if step < 3: + print("pre_step_model()") for i in model_exec_list: if op_tokens[i][0] == 12: + if step < 3: + print("pre_step_register() element", i) # register type data (like broadcast accumulators) pre_step_register(op_tokens[i], state_ix) return From 251761b288e02bd3cf15ff37c9c58ce35d2397f0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 16:21:59 -0500 Subject: [PATCH 252/378] jit on --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 8463aba6..f2e6fa94 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -704,7 +704,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): if step < 3: print("pre_step_model()") From 0afb066e7062b962b44f15f9dcb7a30fb6909312 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 16:23:13 -0500 Subject: [PATCH 253/378] debug less --- src/hsp2/hsp2/om.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index f2e6fa94..c1273641 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -706,12 +706,8 @@ def iterate_models( @njit(cache=True) def pre_step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): - if step < 3: - print("pre_step_model()") for i in model_exec_list: if op_tokens[i][0] == 12: - if step < 3: - print("pre_step_register() element", i) # register type data (like broadcast accumulators) pre_step_register(op_tokens[i], state_ix) return From 8a87929f9f2e727face44e06168b354a053b0922 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 16:27:54 -0500 Subject: [PATCH 254/378] debug less --- src/hsp2/hsp2/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 60e4b848..bf52d715 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -226,8 +226,8 @@ def main( msg(3, f"{activity}") # Set context for dynamic executables and special actions - state_context_hsp2(statenb, operation, segment, activity) - + 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 From 42fdb4c911371e5082efa30155117a2ce08712cf Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 16:33:13 -0500 Subject: [PATCH 255/378] debug --- src/hsp2/state/state.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 0b239166..fc482f9a 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -375,7 +375,7 @@ def state_segname(state, operation, segment, activity): return (seg_name, seg_path) #@njit(cache=True) -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.") for _, operation, segment, delt in opseq.itertuples(): @@ -387,12 +387,16 @@ def state_init_hsp2(state, opseq, activities): if operation != "GENER" and operation != "COPY": for activity, function in activities[operation].items(): if activity == "HYDR": + print("HYDR state_init_hsp2()", timer.split(), "seconds") state_context_hsp2(state, operation, segment, activity) elif activity == "SEDTRN": + print("SEDTRN state_init_hsp2()", timer.split(), "seconds") state_context_hsp2(state, operation, segment, activity) elif activity == "SEDMNT": + print("SEDMNT state_init_hsp2()", timer.split(), "seconds") state_context_hsp2(state, operation, segment, activity) elif activity == "RQUAL": + print("RQUAL state_init_hsp2()", timer.split(), "seconds") state_context_hsp2(state, operation, segment, activity) From 77e6a740679bbaef7063840db30c3482171d57ab Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 16:34:02 -0500 Subject: [PATCH 256/378] debug --- src/hsp2/hsp2/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index bf52d715..012afae5 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -109,7 +109,7 @@ def main( print("state_load_dynamics_hsp2()", 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_init_hsp2(state, opseq, activities, timer) print("state_init_hsp2()", timer.split(), "seconds") # now initialize all state variables for mutable variables hsp2_domain_dependencies(state, opseq, activities, om_operations, False) From fe0b1bd5a5d1d1a4bc087b7f1cc9ecf7ec681688 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 16:35:45 -0500 Subject: [PATCH 257/378] debug --- src/hsp2/state/state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index fc482f9a..881b753b 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -383,6 +383,7 @@ def state_init_hsp2(state, opseq, activities, timer): seg_path = "/STATE/" + state.model_root_name + "/" + seg_name # set up named paths for model operations state.set_state(seg_path, 0.0) + print("set_state()", seg_path, timer.split(), "seconds") print("adding", seg_path) if operation != "GENER" and operation != "COPY": for activity, function in activities[operation].items(): From 6dd19b6bd54dbf6a02033a2cdaca46cc6f3abd56 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 16:56:50 -0500 Subject: [PATCH 258/378] debug --- src/hsp2/state/state.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 881b753b..4746f7e8 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -111,6 +111,11 @@ def state_copy(statesrc, statedest): statedest.state_step_hydr = statesrc.state_step_hydr statedest.state_step_om = statesrc.state_step_om +@njit(cache=True) +def append_state_path(state_paths, var_path, var_ix): + state_paths[var_path] = var_ix + return state_paths + 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 @@ -222,7 +227,8 @@ def set_state(self, var_path, var_value=0.0, debug=False): 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[var_path] = var_ix + self.state_paths = append_state_path(self.state_paths, var_path, var_ix) + else: var_ix = self.get_state_ix(var_path) self.state_ix[var_ix] = var_value From 417cfd82cf986e26cab0df864452933524380a98 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 17:06:56 -0500 Subject: [PATCH 259/378] handle other dict append too --- src/hsp2/state/state.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 4746f7e8..744388d2 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -111,10 +111,17 @@ def state_copy(statesrc, statedest): statedest.state_step_hydr = statesrc.state_step_hydr statedest.state_step_om = statesrc.state_step_om +""" +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_state_path(state_paths, var_path, var_ix): - state_paths[var_path] = var_ix - return state_paths +def append_numba_dict(var_dict, var_key, var_val): + var_dict[var_key] = var_val + return 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): @@ -227,7 +234,7 @@ def set_state(self, var_path, var_value=0.0, debug=False): 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_state_path(self.state_paths, var_path, var_ix) + self.state_paths = append_numba_dict(self.state_paths, var_path, var_ix) else: var_ix = self.get_state_ix(var_path) @@ -366,7 +373,7 @@ def state_context_hsp2(state, operation, segment, activity): (seg_name, seg_path) = state_segname(state, operation, segment, activity) #if seg_name not in state.hsp_segments.keys(): if seg_name not in state.hsp_segments: # test this for njit - state.hsp_segments[seg_name] = seg_path + state.hsp_segments[seg_name] = append_numba_dict(state.hsp_segments, seg_path) state.domain = state_domain(state, operation, segment, activity) def state_domain(state, operation, segment, activity): @@ -380,7 +387,6 @@ def state_segname(state, operation, segment, activity): seg_path = "/STATE/" + state.model_root_name + "/" + seg_name return (seg_name, seg_path) -#@njit(cache=True) 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.") From f6680f8e9506a8eb5ee76798d4e6b30750aaa5fc Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 17:08:42 -0500 Subject: [PATCH 260/378] oops missing arg --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 744388d2..31cf5b62 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -373,7 +373,7 @@ def state_context_hsp2(state, operation, segment, activity): (seg_name, seg_path) = state_segname(state, operation, segment, activity) #if seg_name not in state.hsp_segments.keys(): if seg_name not in state.hsp_segments: # test this for njit - state.hsp_segments[seg_name] = append_numba_dict(state.hsp_segments, seg_path) + state.hsp_segments[seg_name] = append_numba_dict(state.hsp_segments[seg_name], state.hsp_segments, seg_path) state.domain = state_domain(state, operation, segment, activity) def state_domain(state, operation, segment, activity): From 9dfaa64404c5d5dc4142971555e33476472b9a92 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 17:10:23 -0500 Subject: [PATCH 261/378] oops missing arg --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 31cf5b62..cd9606bc 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -373,7 +373,7 @@ def state_context_hsp2(state, operation, segment, activity): (seg_name, seg_path) = state_segname(state, operation, segment, activity) #if seg_name not in state.hsp_segments.keys(): if seg_name not in state.hsp_segments: # test this for njit - state.hsp_segments[seg_name] = append_numba_dict(state.hsp_segments[seg_name], state.hsp_segments, seg_path) + state.hsp_segments[seg_name] = 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): From cffa44ec968b8de36aad45a66cbf69ee14096fcb Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 17:16:17 -0500 Subject: [PATCH 262/378] wrong target --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index cd9606bc..82a26236 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -373,7 +373,7 @@ def state_context_hsp2(state, operation, segment, activity): (seg_name, seg_path) = state_segname(state, operation, segment, activity) #if seg_name not in state.hsp_segments.keys(): if seg_name not in state.hsp_segments: # test this for njit - state.hsp_segments[seg_name] = append_numba_dict(state.hsp_segments, seg_name, seg_path) + 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): From 39b9df9a14dc1183197ea469aa8f8676b4baf573 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 17:19:24 -0500 Subject: [PATCH 263/378] wrong target --- src/hsp2/state/state.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 82a26236..424329dc 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -400,17 +400,17 @@ def state_init_hsp2(state, opseq, activities, timer): if operation != "GENER" and operation != "COPY": for activity, function in activities[operation].items(): if activity == "HYDR": - print("HYDR state_init_hsp2()", timer.split(), "seconds") state_context_hsp2(state, operation, segment, activity) + print("HYDR state_init_hsp2()", timer.split(), "seconds") elif activity == "SEDTRN": - print("SEDTRN state_init_hsp2()", timer.split(), "seconds") state_context_hsp2(state, operation, segment, activity) + print("SEDTRN state_init_hsp2()", timer.split(), "seconds") elif activity == "SEDMNT": - print("SEDMNT state_init_hsp2()", timer.split(), "seconds") state_context_hsp2(state, operation, segment, activity) + print("SEDMNT state_init_hsp2()", timer.split(), "seconds") elif activity == "RQUAL": - print("RQUAL state_init_hsp2()", timer.split(), "seconds") state_context_hsp2(state, operation, segment, activity) + print("RQUAL state_init_hsp2()", timer.split(), "seconds") def state_load_dynamics_hsp2(state, io_manager, siminfo): From e101c8dce6d8e3720b95d6bb814d605b88f7af7f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 7 Jan 2026 17:21:55 -0500 Subject: [PATCH 264/378] less debug --- src/hsp2/state/state.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 424329dc..5719e29a 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -396,7 +396,6 @@ def state_init_hsp2(state, opseq, activities, timer): # set up named paths for model operations state.set_state(seg_path, 0.0) print("set_state()", seg_path, timer.split(), "seconds") - print("adding", seg_path) if operation != "GENER" and operation != "COPY": for activity, function in activities[operation].items(): if activity == "HYDR": From bb3eebdc87f19ccaf3b9ed4d9615c39f75000771 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 10:31:59 -0500 Subject: [PATCH 265/378] jit fn to see if key exists in state --- src/hsp2/state/state.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 5719e29a..6395d1dd 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -123,6 +123,10 @@ def append_numba_dict(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 @@ -372,7 +376,7 @@ def state_context_hsp2(state, operation, segment, activity): # 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 seg_name not in state.hsp_segments: # test this for njit + 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) From 4eef404b2cc0684b288e206d406945ec162f1f0a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 10:38:58 -0500 Subject: [PATCH 266/378] jit part of fn to measure speed --- src/hsp2/state/state.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 6395d1dd..868070e4 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -235,11 +235,10 @@ def set_state(self, var_path, var_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 self.state_paths: + if not nkey_exists(self.state_paths, var_path): # 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 @@ -399,21 +398,16 @@ def state_init_hsp2(state, opseq, activities, timer): seg_path = "/STATE/" + state.model_root_name + "/" + seg_name # set up named paths for model operations state.set_state(seg_path, 0.0) - print("set_state()", seg_path, timer.split(), "seconds") if operation != "GENER" and operation != "COPY": for activity, function in activities[operation].items(): if activity == "HYDR": state_context_hsp2(state, operation, segment, activity) - print("HYDR state_init_hsp2()", timer.split(), "seconds") elif activity == "SEDTRN": state_context_hsp2(state, operation, segment, activity) - print("SEDTRN state_init_hsp2()", timer.split(), "seconds") elif activity == "SEDMNT": state_context_hsp2(state, operation, segment, activity) - print("SEDMNT state_init_hsp2()", timer.split(), "seconds") elif activity == "RQUAL": state_context_hsp2(state, operation, segment, activity) - print("RQUAL state_init_hsp2()", timer.split(), "seconds") def state_load_dynamics_hsp2(state, io_manager, siminfo): From 54d1b4a78b7e1c55c97d41790aa720173d901488 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 10:42:05 -0500 Subject: [PATCH 267/378] jit part of fn to measure speed --- src/hsp2/state/state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 868070e4..ed955df6 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -235,7 +235,8 @@ def set_state(self, var_path, var_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 not nkey_exists(self.state_paths, var_path): + #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) From a40161547aedc9af427cfdc79bef9f614248e7fa Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 10:44:46 -0500 Subject: [PATCH 268/378] jit part of fn to measure speed --- src/hsp2/state/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ed955df6..dcc2fe3d 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -235,8 +235,8 @@ def set_state(self, var_path, var_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 not nkey_exists(self.state_paths, var_path): - if var_path not in self.state_paths: + 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) From 6c9806a918a72ab3a61098dcba7fdaff2ec3fec1 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 10:48:30 -0500 Subject: [PATCH 269/378] jit set value --- src/hsp2/state/state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index dcc2fe3d..5a57698e 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -242,7 +242,8 @@ def set_state(self, var_path, var_value=0.0, debug=False): 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[var_ix] = var_value + append_numba_dict(self.state_ix, var_value) if debug: print("Setting state_ix[", var_ix, "], to", var_value) return var_ix From b6c67a7cda4e5cd69885ba2eaa2c3ef1e3fbabd3 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 10:51:21 -0500 Subject: [PATCH 270/378] jit set value not append --- src/hsp2/state/state.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 5a57698e..9f485469 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -123,6 +123,11 @@ 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 + @njit(cache=True) def nkey_exists(var_dict, var_key): return (var_key in var_dict) @@ -243,7 +248,8 @@ def set_state(self, var_path, var_value=0.0, debug=False): else: var_ix = self.get_state_ix(var_path) #self.state_ix[var_ix] = var_value - append_numba_dict(self.state_ix, var_value) + set_numba_value(self.state_ix, var_value, var_ix) + #append_numba_dict(self.state_ix, var_value, var_ix) if debug: print("Setting state_ix[", var_ix, "], to", var_value) return var_ix From ffc4bba03fd9783d57f04704d9857590f7e77342 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 10:52:18 -0500 Subject: [PATCH 271/378] jit set value not append --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 9f485469..eedcdde5 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -248,7 +248,7 @@ def set_state(self, var_path, var_value=0.0, debug=False): else: var_ix = self.get_state_ix(var_path) #self.state_ix[var_ix] = var_value - set_numba_value(self.state_ix, var_value, var_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) From 5859220010b51af951dbfbc62e54e528e0eb0c48 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 10:54:59 -0500 Subject: [PATCH 272/378] return not set in ref --- src/hsp2/state/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index eedcdde5..61a0a9a0 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -126,7 +126,7 @@ def append_numba_dict(var_dict, var_key, var_val): @njit(cache=True) def set_numba_value(var_dict, var_key, var_val): var_dict[var_key] = var_val - return + return var_dict @njit(cache=True) def nkey_exists(var_dict, var_key): @@ -248,7 +248,7 @@ def set_state(self, var_path, var_value=0.0, debug=False): else: var_ix = self.get_state_ix(var_path) #self.state_ix[var_ix] = var_value - set_numba_value(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) From 091186472abc9eed97bd2cf82fd4bfa2d0f597de Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 11:00:54 -0500 Subject: [PATCH 273/378] use np array --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 61a0a9a0..2f9a8db0 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -501,7 +501,7 @@ def hydr_state_vars(): 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 = ntdict.empty(key_type=types.unicode_type, value_type=types.int64) + hydr_ix = np.asarray(zeros(1), dtype="int64") #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 From 16cd73f62b6e619955e71d757439b77842be4596 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 11:10:00 -0500 Subject: [PATCH 274/378] use DataFrame to as_nparray --- src/hsp2/hsp2/om.py | 1 + src/hsp2/state/state.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index c1273641..fa36380d 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -666,6 +666,7 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals print("Getting init_ix for", seg_path, activity) if activity == "HYDR": ep_list = hydr_init_ix(state, seg_path) + ep_list - ep_list.to_numpy() elif activity == "SEDTRN": ep_list = sedtrn_init_ix(state, seg_path) elif activity == "SEDMNT": diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 2f9a8db0..0682e9ed 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -10,7 +10,7 @@ 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 +from pandas import date_range, DataFrame from pandas.tseries.offsets import Minute # Beginning in operation these are likely to be located in model objects when we go fully to that level. @@ -501,7 +501,7 @@ def hydr_state_vars(): 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 = np.asarray(zeros(1), dtype="int64") #ntdict.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 From 66962c448bab86d41c37a28a3f3c97f39eda069b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 11:11:09 -0500 Subject: [PATCH 275/378] must call as function --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 0682e9ed..3f83c83c 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -501,7 +501,7 @@ def hydr_state_vars(): 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 = DataFrame + hydr_ix = DataFrame() for i in hydr_state: # var_path = f'{domain}/{i}' var_path = domain + "/" + i From 1cde96aea521b67d4e0dc7608dd48ebfc2ca0c5f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 11:14:19 -0500 Subject: [PATCH 276/378] make all ixs as df then convert --- src/hsp2/hsp2/om.py | 2 +- src/hsp2/state/state.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index fa36380d..cb21fd3d 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -666,7 +666,6 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals print("Getting init_ix for", seg_path, activity) if activity == "HYDR": ep_list = hydr_init_ix(state, seg_path) - ep_list - ep_list.to_numpy() elif activity == "SEDTRN": ep_list = sedtrn_init_ix(state, seg_path) elif activity == "SEDMNT": @@ -674,6 +673,7 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals elif activity == "RQUAL": ep_list = rqual_init_ix(state, seg_path) # Register list of elements to execute if any + ep_list = ep_list.to_numpy() op_exec_list = model_domain_dependencies( om_operations, state, seg_path, ep_list, True, debug ) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 3f83c83c..fcf895f4 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -519,7 +519,7 @@ 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 = ntdict.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 @@ -535,7 +535,7 @@ 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 = ntdict.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] = state.set_state(var_path, 0.0) From 30502e941d55c9aeef1a9724cede96e2e99df1f2 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 11:17:10 -0500 Subject: [PATCH 277/378] import df --- src/hsp2/hsp2/om.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index cb21fd3d..98a8e51c 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -8,7 +8,7 @@ import time import numpy as np -import pandas as pd +from pandas import Series, DataFrame from numba import njit # import the types from numpy import zeros @@ -615,7 +615,7 @@ def model_input_dependencies(state, exec_list, model_object_cache, only_runnable mello = mello + mel if only_runnable == True: mello = ModelObject.runnable_op_list(state.op_tokens, mello) - mello = pd.Series(mello).drop_duplicates().tolist() + mello = Series(mello).drop_duplicates().tolist() return mello @@ -661,7 +661,7 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals 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 = [] + ep_list = DataFrame() if debug: print("Getting init_ix for", seg_path, activity) if activity == "HYDR": @@ -687,7 +687,7 @@ 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 From 278de3892e3f30f21cc0b599fa1442b7f9fca922 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 11:20:20 -0500 Subject: [PATCH 278/378] convert all to df --- src/hsp2/state/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index fcf895f4..8ec29c32 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -562,7 +562,7 @@ def rqual_state_vars(): def rqual_init_ix(state, domain): # get a list of keys for all rqual state variables rqual_state = rqual_state_vars() - rqual_ix = ntdict.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] = state.set_state(var_path, 0.0) From 4f311c2ff00ee68863a8c6194c365bb3db49e7d0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 11:37:01 -0500 Subject: [PATCH 279/378] add a timer to single section --- src/hsp2/hsp2/om.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 98a8e51c..dfaae20e 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -11,6 +11,7 @@ from pandas import Series, DataFrame from numba import njit # import the types from numpy import zeros +from hsp2.hsp2.om_sim_timer import timer_class from hsp2.state.state import ( append_state, @@ -653,6 +654,7 @@ def model_domain_dependencies( 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.") + timer = timer_class() for _, operation, segment, delt in opseq.itertuples(): if operation != "GENER" and operation != "COPY": for activity, function in activities[operation].items(): @@ -681,6 +683,7 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals # 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) + print(seg_name, timer.split(), 'seconds') def save_object_ts(io_manager, siminfo, op_tokens, ts_ix, ts): From 15d32e2bd248c96f4a9a209f125aebee50a1c7e0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 11:40:13 -0500 Subject: [PATCH 280/378] make timer a separate function file --- src/hsp2/hsp2/main.py | 2 +- src/hsp2/hsp2/om.py | 2 +- src/hsp2/hsp2/om_sim_timer.py | 50 -------------------------------- src/hsp2/hsp2/om_timer.py | 54 +++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 52 deletions(-) create mode 100644 src/hsp2/hsp2/om_timer.py diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 012afae5..47c37c56 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -34,7 +34,7 @@ state_om_model_run_finish, hsp2_domain_dependencies ) -from hsp2.hsp2.om_sim_timer import timer_class +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 diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index dfaae20e..0246cf7f 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -11,7 +11,7 @@ from pandas import Series, DataFrame from numba import njit # import the types from numpy import zeros -from hsp2.hsp2.om_sim_timer import timer_class +from hsp2.hsp2.om_timer import timer_class from hsp2.state.state import ( append_state, diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index c85507dd..b9b1a7ca 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -9,9 +9,6 @@ from pandas import DataFrame from numba import njit, types from numpy import int64 -from numba.experimental import jitclass -import ctypes -import time class SimTimer(ModelObject): def __init__(self, name, container, model_props=None, state=None): @@ -120,50 +117,3 @@ def step_sim_timer(op_token, state_ix, dict_ix, ts_ix, step): state_ix[op_token[12]] = dict_ix[op_token[1]][step][11] # dts return -# 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/hsp2/om_timer.py b/src/hsp2/hsp2/om_timer.py new file mode 100644 index 00000000..3f6612ed --- /dev/null +++ b/src/hsp2/hsp2/om_timer.py @@ -0,0 +1,54 @@ +""" +The class timer_class/timer_class_jit is used for benchmarking and peformance inquiry. +""" + +from numba.experimental import jitclass +import ctypes +import time +# 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 From 667d7fa0b79f6fba3c4947a7d1a7fb0b1cf87958 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 11:41:59 -0500 Subject: [PATCH 281/378] missing import --- src/hsp2/hsp2/om_sim_timer.py | 2 +- src/hsp2/hsp2/om_timer.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index b9b1a7ca..84b78a3d 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -7,7 +7,7 @@ from hsp2.hsp2.om import ModelObject from hsp2.hsp2.om_model_object import ModelObject from pandas import DataFrame -from numba import njit, types +from numba import njit from numpy import int64 class SimTimer(ModelObject): diff --git a/src/hsp2/hsp2/om_timer.py b/src/hsp2/hsp2/om_timer.py index 3f6612ed..48ddaa3e 100644 --- a/src/hsp2/hsp2/om_timer.py +++ b/src/hsp2/hsp2/om_timer.py @@ -5,6 +5,8 @@ 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 From d3cc126645af96259350589ab68fbf50b7c3d435 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 13:57:18 -0500 Subject: [PATCH 282/378] debug --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 0246cf7f..ddf149d7 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -683,7 +683,7 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals # 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) - print(seg_name, timer.split(), 'seconds') + print("hsp2_domain_dependencies:", seg_name, timer.split(), 'seconds') def save_object_ts(io_manager, siminfo, op_tokens, ts_ix, ts): From c575a78c1a6bdfe4f1472f312ad5fbab621d9ab8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 14:02:31 -0500 Subject: [PATCH 283/378] debug timing --- src/hsp2/hsp2/om.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index ddf149d7..d7c88a63 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -190,7 +190,9 @@ def state_om_model_root_object(state, om_operations, siminfo): def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): # insure model base is set + timer = timer_class() state_om_model_root_object(state, om_operations, siminfo) + print("state_om_model_root_object", timer.split()) # now instantiate and link objects # om_operations['model_data'] has alread been prepopulated from json, .py files, hdf5, etc. model_root_object = om_operations["model_root_object"] @@ -198,12 +200,14 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): 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_path_loader(model_object_cache) + print("model_path_loader", timer.split()) # 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 # put all objects in token form for fast runtime execution and sort according to dependency order @@ -216,6 +220,7 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): # len(model_root_object.state.state_ix) # ) model_tokenizer_recursive(model_root_object, model_object_cache, model_exec_list) + 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 @@ -237,7 +242,9 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): ) # print("Exec list:", model_exec_list) # Now make sure that all HSP2 vars that can be affected by state have + print("remaining hsp2 settings", timer.split()) hsp2_domain_dependencies(state, opseq, activities, om_operations, False) + print("hsp2_domain_dependencies", timer.split()) return @@ -654,7 +661,6 @@ def model_domain_dependencies( 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.") - timer = timer_class() for _, operation, segment, delt in opseq.itertuples(): if operation != "GENER" and operation != "COPY": for activity, function in activities[operation].items(): @@ -683,7 +689,6 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals # 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) - print("hsp2_domain_dependencies:", seg_name, timer.split(), 'seconds') def save_object_ts(io_manager, siminfo, op_tokens, ts_ix, ts): From dfe6b317bb645829a30af24274d2200a1aba0a63 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 14:09:52 -0500 Subject: [PATCH 284/378] debug timing --- src/hsp2/hsp2/om.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index d7c88a63..5056cf04 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -164,17 +164,21 @@ def state_load_dynamics_om(state, io_manager, siminfo, om_operations): 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. + timer = timer_class() if "model_root_object" not in om_operations.keys(): model_root_object = ModelObject( 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, ...) om_operations["model_root_object"] = model_root_object # set up the timer as the first element - model_root_object = om_operations["model_root_object"] + 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) + 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 om_operations["model_object_cache"].keys(): @@ -186,6 +190,7 @@ def state_om_model_root_object(state, om_operations, siminfo): # 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 + print("Segment Objects", timer.split()) def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): From 1df85cd763fa15c1400e0d2775b05b9a8b49b9d8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 14:11:39 -0500 Subject: [PATCH 285/378] disambiguate --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 5056cf04..4fd5f33e 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -177,7 +177,7 @@ def state_om_model_root_object(state, om_operations, siminfo): 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) + 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(): From d11cd069c4e3db98c7aa4456be8e33df9bc340e7 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 14:16:41 -0500 Subject: [PATCH 286/378] use faster state path check --- src/hsp2/hsp2/om_model_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 0c745ad3..14cba362 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -296,7 +296,7 @@ def 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 (self.state_path + "/" + var_name) in self.state.state_paths: + 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) @@ -309,7 +309,7 @@ def find_var_path(self, var_name, local_only=False): 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: + 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) From 321a91797afd021a93df553007349b4f394c1384 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 14:17:31 -0500 Subject: [PATCH 287/378] include fn --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 14cba362..d150e169 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -10,7 +10,7 @@ from pandas import HDFStore from hsp2.hsp2.om import is_float_digit -from hsp2.state.state import get_state_ix, set_state +from hsp2.state.state import nkey_exists class ModelObject: From 469343f948c37b3c6de9c4ba1508a7de2375ddab Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 14:26:59 -0500 Subject: [PATCH 288/378] debug less --- src/hsp2/hsp2/main.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 47c37c56..d41d2955 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -87,8 +87,9 @@ def main( copy_instances = {} gener_instances = {} + section_timing = {} - print("io_manager.read_parameters() call and config", timer.split(), "seconds") + section_timing["io_manager.read_parameters() call and config"] = str(timer.split()) + "seconds" ####################################################################################### # initialize STATE dicts ####################################################################################### @@ -98,32 +99,24 @@ def main( state_empty["op_exec_lists"], state_empty["model_exec_list"], state_empty["dict_ix"], state_empty["ts_ix"], state_empty["hsp_segments"] ) - print("state_class()", timer.split(), "seconds") om_operations = om_init_state() # set up operational model specific containers - print("om_operations()", timer.split(), "seconds") state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) - print("state_siminfo_hsp2()", timer.split(), "seconds") # 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()", 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, timer) - print("state_init_hsp2()", timer.split(), "seconds") # now initialize all state variables for mutable variables hsp2_domain_dependencies(state, opseq, activities, om_operations, False) - print("hsp2_domain_dependencies()", timer.split(), "seconds") # - finally stash specactions in state, not domain (segment) dependent so do it once specl_load_om(om_operations, specactions) # load traditional special actions - print("specl_load_om()", timer.split(), "seconds") state_load_dynamics_om( state, io_manager, siminfo, om_operations ) # operational model for custom python - print("state_load_dynamics_om()", 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()", timer.split(), "seconds") + section_timing["state om initialization()"] = str(timer.split()) + "seconds" statenb = state_class_lite(0) state_copy(state, statenb) ####################################################################################### @@ -539,6 +532,7 @@ def main( jupyterlab, outstep_phcarb, ) + section_timing[operation + segment] = str(timer.split()) + "seconds" msglist = msg(1, "Done", final=True) From 46150bf8c84095ee23f3c392bbdc427ce270a723 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 14:39:43 -0500 Subject: [PATCH 289/378] use fn in sim timer --- src/hsp2/hsp2/om_sim_timer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_sim_timer.py b/src/hsp2/hsp2/om_sim_timer.py index 84b78a3d..5b4f9e96 100644 --- a/src/hsp2/hsp2/om_sim_timer.py +++ b/src/hsp2/hsp2/om_sim_timer.py @@ -6,6 +6,7 @@ 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 @@ -56,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 @@ -70,7 +71,7 @@ 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"] From 2633f71bb74e196922f378836101bccf74b8527c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 15:01:08 -0500 Subject: [PATCH 290/378] debugless --- src/hsp2/hsp2/om.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 4fd5f33e..148f94d5 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -173,12 +173,12 @@ def state_om_model_root_object(state, om_operations, siminfo): # set up the timer as the first element else: model_root_object = om_operations["model_root_object"] - print("model_root_object", timer.split()) + #print("model_root_object", timer.split()) if "/STATE/timer" not in state.state_paths.keys(): timer_props = siminfo timer_props["state_path"] = "/STATE/timer" sim_timer = SimTimer("timer", model_root_object, timer_props) - print("timer", timer.split()) + #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 om_operations["model_object_cache"].keys(): @@ -190,14 +190,12 @@ def state_om_model_root_object(state, om_operations, siminfo): # 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 - print("Segment Objects", timer.split()) def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): # insure model base is set timer = timer_class() state_om_model_root_object(state, om_operations, siminfo) - print("state_om_model_root_object", timer.split()) # now instantiate and link objects # om_operations['model_data'] has alread been prepopulated from json, .py files, hdf5, etc. model_root_object = om_operations["model_root_object"] @@ -205,14 +203,13 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): model_loader_recursive( om_operations["model_data"], model_root_object, state, model_object_cache ) - print("model_loader_recursive", timer.split()) + #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_path_loader(model_object_cache) - print("model_path_loader", timer.split()) # 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 # put all objects in token form for fast runtime execution and sort according to dependency order @@ -225,7 +222,7 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): # len(model_root_object.state.state_ix) # ) model_tokenizer_recursive(model_root_object, model_object_cache, model_exec_list) - print("model_tokenizer_recursive", timer.split()) + #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 @@ -247,9 +244,7 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): ) # print("Exec list:", model_exec_list) # Now make sure that all HSP2 vars that can be affected by state have - print("remaining hsp2 settings", timer.split()) hsp2_domain_dependencies(state, opseq, activities, om_operations, False) - print("hsp2_domain_dependencies", timer.split()) return From dafe3197128777c7f6345323ae05804a3b998af0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 15:04:03 -0500 Subject: [PATCH 291/378] less verbose --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index d150e169..f1a3c270 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -299,7 +299,7 @@ def find_var_path(self, var_name, local_only=False): 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) + #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): From 639b6e677a1fb29419b6852cfd3a72e478f717ca Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 15:04:38 -0500 Subject: [PATCH 292/378] less verbose --- src/hsp2/hsp2/om_model_linkage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index 2f984b7a..668d5e6d 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -96,7 +96,7 @@ 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): - print("ModelLinkage", self.name, "insuring register with 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] left_object = self.get_object(self.left_path) From b37f90d552d9a66d678d51fd2353f56dbf30e8e3 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 15:06:25 -0500 Subject: [PATCH 293/378] less verbose --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index f1a3c270..4b47526a 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -312,7 +312,7 @@ def find_var_path(self, var_name, local_only=False): 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) + #print("Cannot find var in global scope", self.state_path, "var", var_name) return False def constant_or_path(self, keyname, keyval, trust=False): From 15f5dc894ac81ea3ec172a85f5fc66ceefb461ef Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 15:08:02 -0500 Subject: [PATCH 294/378] less verbose --- src/hsp2/hsp2/om_model_linkage.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/hsp2/hsp2/om_model_linkage.py b/src/hsp2/hsp2/om_model_linkage.py index 668d5e6d..f318556f 100644 --- a/src/hsp2/hsp2/om_model_linkage.py +++ b/src/hsp2/hsp2/om_model_linkage.py @@ -114,12 +114,7 @@ def find_paths(self): 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, - ) + #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 From 6f7bfd4c34769091d176a94697b37294db686e5f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 20:04:32 -0500 Subject: [PATCH 295/378] ad big test data set --- .../PL3_5250_0001.json.mechtest.json | 1312 +++++++++++++++++ 1 file changed, 1312 insertions(+) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json b/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json new file mode 100644 index 00000000..692ccafb --- /dev/null +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json @@ -0,0 +1,1312 @@ +{ + "RCHRES_R001": { + "name": "RCHRES_R001", + "description": "This is a test setup only with data from another watershed Mechums River to test performance with large json arrays", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.2689586532 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8566933": { + "name": "nhd_8566933", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 2.8744521696 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567297": { + "name": "nhd_8567297", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.217182375 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + }, + "nhd_8566941": { + "name": "nhd_8566941", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 1.3493106594 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8566975": { + "name": "nhd_8566975", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.8364127626 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8566977": { + "name": "nhd_8566977", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.2150974242 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8566973": { + "name": "nhd_8566973", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567299": { + "name": "nhd_8567299", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.286680735 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + }, + "nhd_8567153": { + "name": "nhd_8567153", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 2.4814389438 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567007": { + "name": "nhd_8567007", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.1018150974 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + } + }, + "nhd_8567001": { + "name": "nhd_8567001", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.15637131 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567049": { + "name": "nhd_8567049", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.4041329634 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567253": { + "name": "nhd_8567253", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.0827030484 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8568339": { + "name": "nhd_8568339", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.0656759502 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8568365": { + "name": "nhd_8568365", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567591": { + "name": "nhd_8567591", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.7033234032 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567615": { + "name": "nhd_8567615", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.3071827512 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + } + } + } + } + }, + "nhd_8567307": { + "name": "nhd_8567307", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 1.8177296058 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567053": { + "name": "nhd_8567053", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.2731285548 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567055": { + "name": "nhd_8567055", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.0003474918 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567617": { + "name": "nhd_8567617", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 1.3896197082 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8568285": { + "name": "nhd_8568285", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 2.2972682898 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567679": { + "name": "nhd_8567679", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.1080699498 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + }, + "nhd_8568287": { + "name": "nhd_8568287", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.0736682616 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567687": { + "name": "nhd_8567687", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.7613545338 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567703": { + "name": "nhd_8567703", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.9861817284 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567717": { + "name": "nhd_8567717", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.3356770788 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + }, + "nhd_8567759": { + "name": "nhd_8567759", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 1.1887694478 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567797": { + "name": "nhd_8567797", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.7724742714 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + } + }, + "nhd_8568293": { + "name": "nhd_8568293", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.4416620778 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567719": { + "name": "nhd_8567719", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.0962552286 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + } + } + } + }, + "nhd_8567057": { + "name": "nhd_8567057", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.0597685896 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8569665": { + "name": "nhd_8569665", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.0097297704 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8568281": { + "name": "nhd_8568281", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.6626668626 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567577": { + "name": "nhd_8567577", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.1105023924 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567059": { + "name": "nhd_8567059", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.3245573412 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + }, + "nhd_8567585": { + "name": "nhd_8567585", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.2700011286 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567587": { + "name": "nhd_8567587", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.2234372274 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567061": { + "name": "nhd_8567061", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.8649070902 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + }, + "nhd_8567597": { + "name": "nhd_8567597", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 1.1088463338 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8569667": { + "name": "nhd_8569667", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.0232819506 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567063": { + "name": "nhd_8567063", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 1.3215113154 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + } + } + } + } + } + } + }, + "nhd_8567315": { + "name": "nhd_8567315", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.005212377 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567581": { + "name": "nhd_8567581", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.1855606212 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567599": { + "name": "nhd_8567599", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.1800007524 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567605": { + "name": "nhd_8567605", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.1515064248 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8568389": { + "name": "nhd_8568389", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.4878784872 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + }, + "nhd_8567727": { + "name": "nhd_8567727", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 1.7569185408 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8568391": { + "name": "nhd_8568391", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.8934014178 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + } + }, + "nhd_8567667": { + "name": "nhd_8567667", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 1.1922443658 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567701": { + "name": "nhd_8567701", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.4927433724 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + }, + "nhd_8567777": { + "name": "nhd_8567777", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.9983439414 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + }, + "nhd_8567803": { + "name": "nhd_8567803", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 0.2178773586 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + } + } + } + } + } + } + }, + "nhd_8567013": { + "name": "nhd_8567013", + "object_class": "ModelObject", + "local_area_sqmi": { + "name": "local_area_sqmi", + "object_class": "ModelConstant", + "value": 2.4001258626 + }, + "Qlocal": { + "name": "Qlocal", + "object_class": "Equation", + "value": "local_area_sqmi * Runit" + }, + "Qin": { + "name": "Qin", + "object_class": "Equation", + "equation": "Qlocal + 0" + }, + "Qout": { + "name": "Qout", + "object_class": "Equation", + "equation": "Qin * 1.0" + } + } + }, + "value": "0", + "IVOLin": { + "name": "IVOLin", + "object_class": "ModelLinkage", + "right_path": "/STATE/JL1_6560_6440/RCHRES_R001/IVOL", + "link_type": 2 + }, + "Runit": { + "name": "Runit", + "object_class": "Equation", + "value": "IVOLin / drainage_area_sqmi" + } + } +} + From fc0b362bbbaaf7f87fbdda375815f1f136951ad1 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 20:14:06 -0500 Subject: [PATCH 296/378] debug --- src/hsp2/hsp2/om_model_object.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 4b47526a..a5b8d959 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -289,6 +289,8 @@ def get_object(self, var_name=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 From d868f2837a573dcaa9984d170d3653a4c7b9c952 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 20:17:05 -0500 Subject: [PATCH 297/378] replace nuneeded link --- .../testcbp/HSP2results/PL3_5250_0001.json.mechtest.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json b/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json index 692ccafb..6db7f045 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json @@ -1296,16 +1296,10 @@ } }, "value": "0", - "IVOLin": { - "name": "IVOLin", - "object_class": "ModelLinkage", - "right_path": "/STATE/JL1_6560_6440/RCHRES_R001/IVOL", - "link_type": 2 - }, "Runit": { "name": "Runit", "object_class": "Equation", - "value": "IVOLin / drainage_area_sqmi" + "value": "IVOL / drainage_area_sqmi" } } } From f0d49a5ab08676c6e341372551a5ea770ce6113e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 20:31:45 -0500 Subject: [PATCH 298/378] debug --- src/hsp2/hsp2/om.py | 2 +- src/hsp2/hsp2/om_equation.py | 2 ++ tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 148f94d5..799c6960 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -234,7 +234,7 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): 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.model_exec_list) > 0: + if len(state.op_tokens) > 0: print( "op_tokens has", len(state.op_tokens), diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index 1319ce1e..fecdf9fe 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -490,5 +490,7 @@ def step_equation(op_token, state_ix, step): 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/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json b/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json index 6db7f045..6b666abc 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json @@ -8,6 +8,11 @@ "object_class": "ModelConstant", "value": 0.2689586532 }, + "drainage_area_sqmi": { + "name": "drainage_area_sqmi", + "object_class": "Constant", + "value": null + }, "Qlocal": { "name": "Qlocal", "object_class": "Equation", From d5784b76fcc304290e5e320901ad74943aee0544 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 21:36:02 -0500 Subject: [PATCH 299/378] good WD test --- src/hsp2/hsp2/om.py | 9 +- .../PL3_5250_0001.json.dynamic_wd.json | 4 +- .../HSP2results/PL3_5250_0001.json.manyeq | 2515 +++++++++++++++++ .../PL3_5250_0001.json.mechtest.json | 1311 --------- 4 files changed, 2523 insertions(+), 1316 deletions(-) create mode 100644 tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq delete mode 100644 tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 799c6960..8ce45e61 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -238,10 +238,13 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): print( "op_tokens has", len(state.op_tokens), - "elements, with ", - len(state.model_exec_list), - "executable elements", + "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) diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.dynamic_wd.json b/tests/testcbp/HSP2results/PL3_5250_0001.json.dynamic_wd.json index ae9c3973..a61c54a4 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json.dynamic_wd.json +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.dynamic_wd.json @@ -8,8 +8,8 @@ "object_class": "Equation", "value": "0.1 * O3" }, - "IVOLwrite": { - "name": "IVOLwrite", + "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", 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..3c47ade9 --- /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.0 + 0.0" + }, + "wd_2": { + "name": "wd_2", + "object_class": "Equation", + "value": "0.0 + wd_1" + }, + "wd_3": { + "name": "wd_3", + "object_class": "Equation", + "value": "0.0 + wd_2" + }, + "wd_4": { + "name": "wd_4", + "object_class": "Equation", + "value": "0.0 + wd_3" + }, + "wd_5": { + "name": "wd_5", + "object_class": "Equation", + "value": "0.0 + wd_4" + }, + "wd_6": { + "name": "wd_6", + "object_class": "Equation", + "value": "0.0 + wd_5" + }, + "wd_7": { + "name": "wd_7", + "object_class": "Equation", + "value": "0.0 + wd_6" + }, + "wd_8": { + "name": "wd_8", + "object_class": "Equation", + "value": "0.0 + wd_7" + }, + "wd_9": { + "name": "wd_9", + "object_class": "Equation", + "value": "0.0 + wd_8" + }, + "wd_10": { + "name": "wd_10", + "object_class": "Equation", + "value": "0.0 + wd_9" + }, + "wd_11": { + "name": "wd_11", + "object_class": "Equation", + "value": "0.0 + wd_10" + }, + "wd_12": { + "name": "wd_12", + "object_class": "Equation", + "value": "0.0 + wd_11" + }, + "wd_13": { + "name": "wd_13", + "object_class": "Equation", + "value": "0.0 + wd_12" + }, + "wd_14": { + "name": "wd_14", + "object_class": "Equation", + "value": "0.0 + wd_13" + }, + "wd_15": { + "name": "wd_15", + "object_class": "Equation", + "value": "0.0 + wd_14" + }, + "wd_16": { + "name": "wd_16", + "object_class": "Equation", + "value": "0.0 + wd_15" + }, + "wd_17": { + "name": "wd_17", + "object_class": "Equation", + "value": "0.0 + wd_16" + }, + "wd_18": { + "name": "wd_18", + "object_class": "Equation", + "value": "0.0 + wd_17" + }, + "wd_19": { + "name": "wd_19", + "object_class": "Equation", + "value": "0.0 + wd_18" + }, + "wd_20": { + "name": "wd_20", + "object_class": "Equation", + "value": "0.0 + wd_19" + }, + "wd_21": { + "name": "wd_21", + "object_class": "Equation", + "value": "0.0 + wd_20" + }, + "wd_22": { + "name": "wd_22", + "object_class": "Equation", + "value": "0.0 + wd_21" + }, + "wd_23": { + "name": "wd_23", + "object_class": "Equation", + "value": "0.0 + wd_22" + }, + "wd_24": { + "name": "wd_24", + "object_class": "Equation", + "value": "0.0 + wd_23" + }, + "wd_25": { + "name": "wd_25", + "object_class": "Equation", + "value": "0.0 + wd_24" + }, + "wd_26": { + "name": "wd_26", + "object_class": "Equation", + "value": "0.0 + wd_25" + }, + "wd_27": { + "name": "wd_27", + "object_class": "Equation", + "value": "0.0 + wd_26" + }, + "wd_28": { + "name": "wd_28", + "object_class": "Equation", + "value": "0.0 + wd_27" + }, + "wd_29": { + "name": "wd_29", + "object_class": "Equation", + "value": "0.0 + wd_28" + }, + "wd_30": { + "name": "wd_30", + "object_class": "Equation", + "value": "0.0 + wd_29" + }, + "wd_31": { + "name": "wd_31", + "object_class": "Equation", + "value": "0.0 + wd_30" + }, + "wd_32": { + "name": "wd_32", + "object_class": "Equation", + "value": "0.0 + wd_31" + }, + "wd_33": { + "name": "wd_33", + "object_class": "Equation", + "value": "0.0 + wd_32" + }, + "wd_34": { + "name": "wd_34", + "object_class": "Equation", + "value": "0.0 + wd_33" + }, + "wd_35": { + "name": "wd_35", + "object_class": "Equation", + "value": "0.0 + wd_34" + }, + "wd_36": { + "name": "wd_36", + "object_class": "Equation", + "value": "0.0 + wd_35" + }, + "wd_37": { + "name": "wd_37", + "object_class": "Equation", + "value": "0.0 + wd_36" + }, + "wd_38": { + "name": "wd_38", + "object_class": "Equation", + "value": "0.0 + wd_37" + }, + "wd_39": { + "name": "wd_39", + "object_class": "Equation", + "value": "0.0 + wd_38" + }, + "wd_40": { + "name": "wd_40", + "object_class": "Equation", + "value": "0.0 + wd_39" + }, + "wd_41": { + "name": "wd_41", + "object_class": "Equation", + "value": "0.0 + wd_40" + }, + "wd_42": { + "name": "wd_42", + "object_class": "Equation", + "value": "0.0 + wd_41" + }, + "wd_43": { + "name": "wd_43", + "object_class": "Equation", + "value": "0.0 + wd_42" + }, + "wd_44": { + "name": "wd_44", + "object_class": "Equation", + "value": "0.0 + wd_43" + }, + "wd_45": { + "name": "wd_45", + "object_class": "Equation", + "value": "0.0 + wd_44" + }, + "wd_46": { + "name": "wd_46", + "object_class": "Equation", + "value": "0.0 + wd_45" + }, + "wd_47": { + "name": "wd_47", + "object_class": "Equation", + "value": "0.0 + wd_46" + }, + "wd_48": { + "name": "wd_48", + "object_class": "Equation", + "value": "0.0 + wd_47" + }, + "wd_49": { + "name": "wd_49", + "object_class": "Equation", + "value": "0.0 + wd_48" + }, + "wd_50": { + "name": "wd_50", + "object_class": "Equation", + "value": "0.0 + wd_49" + }, + "wd_51": { + "name": "wd_51", + "object_class": "Equation", + "value": "0.0 + wd_50" + }, + "wd_52": { + "name": "wd_52", + "object_class": "Equation", + "value": "0.0 + wd_51" + }, + "wd_53": { + "name": "wd_53", + "object_class": "Equation", + "value": "0.0 + wd_52" + }, + "wd_54": { + "name": "wd_54", + "object_class": "Equation", + "value": "0.0 + wd_53" + }, + "wd_55": { + "name": "wd_55", + "object_class": "Equation", + "value": "0.0 + wd_54" + }, + "wd_56": { + "name": "wd_56", + "object_class": "Equation", + "value": "0.0 + wd_55" + }, + "wd_57": { + "name": "wd_57", + "object_class": "Equation", + "value": "0.0 + wd_56" + }, + "wd_58": { + "name": "wd_58", + "object_class": "Equation", + "value": "0.0 + wd_57" + }, + "wd_59": { + "name": "wd_59", + "object_class": "Equation", + "value": "0.0 + wd_58" + }, + "wd_60": { + "name": "wd_60", + "object_class": "Equation", + "value": "0.0 + wd_59" + }, + "wd_61": { + "name": "wd_61", + "object_class": "Equation", + "value": "0.0 + wd_60" + }, + "wd_62": { + "name": "wd_62", + "object_class": "Equation", + "value": "0.0 + wd_61" + }, + "wd_63": { + "name": "wd_63", + "object_class": "Equation", + "value": "0.0 + wd_62" + }, + "wd_64": { + "name": "wd_64", + "object_class": "Equation", + "value": "0.0 + wd_63" + }, + "wd_65": { + "name": "wd_65", + "object_class": "Equation", + "value": "0.0 + wd_64" + }, + "wd_66": { + "name": "wd_66", + "object_class": "Equation", + "value": "0.0 + wd_65" + }, + "wd_67": { + "name": "wd_67", + "object_class": "Equation", + "value": "0.0 + wd_66" + }, + "wd_68": { + "name": "wd_68", + "object_class": "Equation", + "value": "0.0 + wd_67" + }, + "wd_69": { + "name": "wd_69", + "object_class": "Equation", + "value": "0.0 + wd_68" + }, + "wd_70": { + "name": "wd_70", + "object_class": "Equation", + "value": "0.0 + wd_69" + }, + "wd_71": { + "name": "wd_71", + "object_class": "Equation", + "value": "0.0 + wd_70" + }, + "wd_72": { + "name": "wd_72", + "object_class": "Equation", + "value": "0.0 + wd_71" + }, + "wd_73": { + "name": "wd_73", + "object_class": "Equation", + "value": "0.0 + wd_72" + }, + "wd_74": { + "name": "wd_74", + "object_class": "Equation", + "value": "0.0 + wd_73" + }, + "wd_75": { + "name": "wd_75", + "object_class": "Equation", + "value": "0.0 + wd_74" + }, + "wd_76": { + "name": "wd_76", + "object_class": "Equation", + "value": "0.0 + wd_75" + }, + "wd_77": { + "name": "wd_77", + "object_class": "Equation", + "value": "0.0 + wd_76" + }, + "wd_78": { + "name": "wd_78", + "object_class": "Equation", + "value": "0.0 + wd_77" + }, + "wd_79": { + "name": "wd_79", + "object_class": "Equation", + "value": "0.0 + wd_78" + }, + "wd_80": { + "name": "wd_80", + "object_class": "Equation", + "value": "0.0 + wd_79" + }, + "wd_81": { + "name": "wd_81", + "object_class": "Equation", + "value": "0.0 + wd_80" + }, + "wd_82": { + "name": "wd_82", + "object_class": "Equation", + "value": "0.0 + wd_81" + }, + "wd_83": { + "name": "wd_83", + "object_class": "Equation", + "value": "0.0 + wd_82" + }, + "wd_84": { + "name": "wd_84", + "object_class": "Equation", + "value": "0.0 + wd_83" + }, + "wd_85": { + "name": "wd_85", + "object_class": "Equation", + "value": "0.0 + wd_84" + }, + "wd_86": { + "name": "wd_86", + "object_class": "Equation", + "value": "0.0 + wd_85" + }, + "wd_87": { + "name": "wd_87", + "object_class": "Equation", + "value": "0.0 + wd_86" + }, + "wd_88": { + "name": "wd_88", + "object_class": "Equation", + "value": "0.0 + wd_87" + }, + "wd_89": { + "name": "wd_89", + "object_class": "Equation", + "value": "0.0 + wd_88" + }, + "wd_90": { + "name": "wd_90", + "object_class": "Equation", + "value": "0.0 + wd_89" + }, + "wd_91": { + "name": "wd_91", + "object_class": "Equation", + "value": "0.0 + wd_90" + }, + "wd_92": { + "name": "wd_92", + "object_class": "Equation", + "value": "0.0 + wd_91" + }, + "wd_93": { + "name": "wd_93", + "object_class": "Equation", + "value": "0.0 + wd_92" + }, + "wd_94": { + "name": "wd_94", + "object_class": "Equation", + "value": "0.0 + wd_93" + }, + "wd_95": { + "name": "wd_95", + "object_class": "Equation", + "value": "0.0 + wd_94" + }, + "wd_96": { + "name": "wd_96", + "object_class": "Equation", + "value": "0.0 + wd_95" + }, + "wd_97": { + "name": "wd_97", + "object_class": "Equation", + "value": "0.0 + wd_96" + }, + "wd_98": { + "name": "wd_98", + "object_class": "Equation", + "value": "0.0 + wd_97" + }, + "wd_99": { + "name": "wd_99", + "object_class": "Equation", + "value": "0.0 + wd_98" + }, + "wd_100": { + "name": "wd_100", + "object_class": "Equation", + "value": "0.0 + wd_99" + }, + "wd_101": { + "name": "wd_101", + "object_class": "Equation", + "value": "0.0 + wd_100" + }, + "wd_102": { + "name": "wd_102", + "object_class": "Equation", + "value": "0.0 + wd_101" + }, + "wd_103": { + "name": "wd_103", + "object_class": "Equation", + "value": "0.0 + wd_102" + }, + "wd_104": { + "name": "wd_104", + "object_class": "Equation", + "value": "0.0 + wd_103" + }, + "wd_105": { + "name": "wd_105", + "object_class": "Equation", + "value": "0.0 + wd_104" + }, + "wd_106": { + "name": "wd_106", + "object_class": "Equation", + "value": "0.0 + wd_105" + }, + "wd_107": { + "name": "wd_107", + "object_class": "Equation", + "value": "0.0 + wd_106" + }, + "wd_108": { + "name": "wd_108", + "object_class": "Equation", + "value": "0.0 + wd_107" + }, + "wd_109": { + "name": "wd_109", + "object_class": "Equation", + "value": "0.0 + wd_108" + }, + "wd_110": { + "name": "wd_110", + "object_class": "Equation", + "value": "0.0 + wd_109" + }, + "wd_111": { + "name": "wd_111", + "object_class": "Equation", + "value": "0.0 + wd_110" + }, + "wd_112": { + "name": "wd_112", + "object_class": "Equation", + "value": "0.0 + wd_111" + }, + "wd_113": { + "name": "wd_113", + "object_class": "Equation", + "value": "0.0 + wd_112" + }, + "wd_114": { + "name": "wd_114", + "object_class": "Equation", + "value": "0.0 + wd_113" + }, + "wd_115": { + "name": "wd_115", + "object_class": "Equation", + "value": "0.0 + wd_114" + }, + "wd_116": { + "name": "wd_116", + "object_class": "Equation", + "value": "0.0 + wd_115" + }, + "wd_117": { + "name": "wd_117", + "object_class": "Equation", + "value": "0.0 + wd_116" + }, + "wd_118": { + "name": "wd_118", + "object_class": "Equation", + "value": "0.0 + wd_117" + }, + "wd_119": { + "name": "wd_119", + "object_class": "Equation", + "value": "0.0 + wd_118" + }, + "wd_120": { + "name": "wd_120", + "object_class": "Equation", + "value": "0.0 + wd_119" + }, + "wd_121": { + "name": "wd_121", + "object_class": "Equation", + "value": "0.0 + wd_120" + }, + "wd_122": { + "name": "wd_122", + "object_class": "Equation", + "value": "0.0 + wd_121" + }, + "wd_123": { + "name": "wd_123", + "object_class": "Equation", + "value": "0.0 + wd_122" + }, + "wd_124": { + "name": "wd_124", + "object_class": "Equation", + "value": "0.0 + wd_123" + }, + "wd_125": { + "name": "wd_125", + "object_class": "Equation", + "value": "0.0 + wd_124" + }, + "wd_126": { + "name": "wd_126", + "object_class": "Equation", + "value": "0.0 + wd_125" + }, + "wd_127": { + "name": "wd_127", + "object_class": "Equation", + "value": "0.0 + wd_126" + }, + "wd_128": { + "name": "wd_128", + "object_class": "Equation", + "value": "0.0 + wd_127" + }, + "wd_129": { + "name": "wd_129", + "object_class": "Equation", + "value": "0.0 + wd_128" + }, + "wd_130": { + "name": "wd_130", + "object_class": "Equation", + "value": "0.0 + wd_129" + }, + "wd_131": { + "name": "wd_131", + "object_class": "Equation", + "value": "0.0 + wd_130" + }, + "wd_132": { + "name": "wd_132", + "object_class": "Equation", + "value": "0.0 + wd_131" + }, + "wd_133": { + "name": "wd_133", + "object_class": "Equation", + "value": "0.0 + wd_132" + }, + "wd_134": { + "name": "wd_134", + "object_class": "Equation", + "value": "0.0 + wd_133" + }, + "wd_135": { + "name": "wd_135", + "object_class": "Equation", + "value": "0.0 + wd_134" + }, + "wd_136": { + "name": "wd_136", + "object_class": "Equation", + "value": "0.0 + wd_135" + }, + "wd_137": { + "name": "wd_137", + "object_class": "Equation", + "value": "0.0 + wd_136" + }, + "wd_138": { + "name": "wd_138", + "object_class": "Equation", + "value": "0.0 + wd_137" + }, + "wd_139": { + "name": "wd_139", + "object_class": "Equation", + "value": "0.0 + wd_138" + }, + "wd_140": { + "name": "wd_140", + "object_class": "Equation", + "value": "0.0 + wd_139" + }, + "wd_141": { + "name": "wd_141", + "object_class": "Equation", + "value": "0.0 + wd_140" + }, + "wd_142": { + "name": "wd_142", + "object_class": "Equation", + "value": "0.0 + wd_141" + }, + "wd_143": { + "name": "wd_143", + "object_class": "Equation", + "value": "0.0 + wd_142" + }, + "wd_144": { + "name": "wd_144", + "object_class": "Equation", + "value": "0.0 + wd_143" + }, + "wd_145": { + "name": "wd_145", + "object_class": "Equation", + "value": "0.0 + wd_144" + }, + "wd_146": { + "name": "wd_146", + "object_class": "Equation", + "value": "0.0 + wd_145" + }, + "wd_147": { + "name": "wd_147", + "object_class": "Equation", + "value": "0.0 + wd_146" + }, + "wd_148": { + "name": "wd_148", + "object_class": "Equation", + "value": "0.0 + wd_147" + }, + "wd_149": { + "name": "wd_149", + "object_class": "Equation", + "value": "0.0 + wd_148" + }, + "wd_150": { + "name": "wd_150", + "object_class": "Equation", + "value": "0.0 + wd_149" + }, + "wd_151": { + "name": "wd_151", + "object_class": "Equation", + "value": "0.0 + wd_150" + }, + "wd_152": { + "name": "wd_152", + "object_class": "Equation", + "value": "0.0 + wd_151" + }, + "wd_153": { + "name": "wd_153", + "object_class": "Equation", + "value": "0.0 + wd_152" + }, + "wd_154": { + "name": "wd_154", + "object_class": "Equation", + "value": "0.0 + wd_153" + }, + "wd_155": { + "name": "wd_155", + "object_class": "Equation", + "value": "0.0 + wd_154" + }, + "wd_156": { + "name": "wd_156", + "object_class": "Equation", + "value": "0.0 + wd_155" + }, + "wd_157": { + "name": "wd_157", + "object_class": "Equation", + "value": "0.0 + wd_156" + }, + "wd_158": { + "name": "wd_158", + "object_class": "Equation", + "value": "0.0 + wd_157" + }, + "wd_159": { + "name": "wd_159", + "object_class": "Equation", + "value": "0.0 + wd_158" + }, + "wd_160": { + "name": "wd_160", + "object_class": "Equation", + "value": "0.0 + wd_159" + }, + "wd_161": { + "name": "wd_161", + "object_class": "Equation", + "value": "0.0 + wd_160" + }, + "wd_162": { + "name": "wd_162", + "object_class": "Equation", + "value": "0.0 + wd_161" + }, + "wd_163": { + "name": "wd_163", + "object_class": "Equation", + "value": "0.0 + wd_162" + }, + "wd_164": { + "name": "wd_164", + "object_class": "Equation", + "value": "0.0 + wd_163" + }, + "wd_165": { + "name": "wd_165", + "object_class": "Equation", + "value": "0.0 + wd_164" + }, + "wd_166": { + "name": "wd_166", + "object_class": "Equation", + "value": "0.0 + wd_165" + }, + "wd_167": { + "name": "wd_167", + "object_class": "Equation", + "value": "0.0 + wd_166" + }, + "wd_168": { + "name": "wd_168", + "object_class": "Equation", + "value": "0.0 + wd_167" + }, + "wd_169": { + "name": "wd_169", + "object_class": "Equation", + "value": "0.0 + wd_168" + }, + "wd_170": { + "name": "wd_170", + "object_class": "Equation", + "value": "0.0 + wd_169" + }, + "wd_171": { + "name": "wd_171", + "object_class": "Equation", + "value": "0.0 + wd_170" + }, + "wd_172": { + "name": "wd_172", + "object_class": "Equation", + "value": "0.0 + wd_171" + }, + "wd_173": { + "name": "wd_173", + "object_class": "Equation", + "value": "0.0 + wd_172" + }, + "wd_174": { + "name": "wd_174", + "object_class": "Equation", + "value": "0.0 + wd_173" + }, + "wd_175": { + "name": "wd_175", + "object_class": "Equation", + "value": "0.0 + wd_174" + }, + "wd_176": { + "name": "wd_176", + "object_class": "Equation", + "value": "0.0 + wd_175" + }, + "wd_177": { + "name": "wd_177", + "object_class": "Equation", + "value": "0.0 + wd_176" + }, + "wd_178": { + "name": "wd_178", + "object_class": "Equation", + "value": "0.0 + wd_177" + }, + "wd_179": { + "name": "wd_179", + "object_class": "Equation", + "value": "0.0 + wd_178" + }, + "wd_180": { + "name": "wd_180", + "object_class": "Equation", + "value": "0.0 + wd_179" + }, + "wd_181": { + "name": "wd_181", + "object_class": "Equation", + "value": "0.0 + wd_180" + }, + "wd_182": { + "name": "wd_182", + "object_class": "Equation", + "value": "0.0 + wd_181" + }, + "wd_183": { + "name": "wd_183", + "object_class": "Equation", + "value": "0.0 + wd_182" + }, + "wd_184": { + "name": "wd_184", + "object_class": "Equation", + "value": "0.0 + wd_183" + }, + "wd_185": { + "name": "wd_185", + "object_class": "Equation", + "value": "0.0 + wd_184" + }, + "wd_186": { + "name": "wd_186", + "object_class": "Equation", + "value": "0.0 + wd_185" + }, + "wd_187": { + "name": "wd_187", + "object_class": "Equation", + "value": "0.0 + wd_186" + }, + "wd_188": { + "name": "wd_188", + "object_class": "Equation", + "value": "0.0 + wd_187" + }, + "wd_189": { + "name": "wd_189", + "object_class": "Equation", + "value": "0.0 + wd_188" + }, + "wd_190": { + "name": "wd_190", + "object_class": "Equation", + "value": "0.0 + wd_189" + }, + "wd_191": { + "name": "wd_191", + "object_class": "Equation", + "value": "0.0 + wd_190" + }, + "wd_192": { + "name": "wd_192", + "object_class": "Equation", + "value": "0.0 + wd_191" + }, + "wd_193": { + "name": "wd_193", + "object_class": "Equation", + "value": "0.0 + wd_192" + }, + "wd_194": { + "name": "wd_194", + "object_class": "Equation", + "value": "0.0 + wd_193" + }, + "wd_195": { + "name": "wd_195", + "object_class": "Equation", + "value": "0.0 + wd_194" + }, + "wd_196": { + "name": "wd_196", + "object_class": "Equation", + "value": "0.0 + wd_195" + }, + "wd_197": { + "name": "wd_197", + "object_class": "Equation", + "value": "0.0 + wd_196" + }, + "wd_198": { + "name": "wd_198", + "object_class": "Equation", + "value": "0.0 + wd_197" + }, + "wd_199": { + "name": "wd_199", + "object_class": "Equation", + "value": "0.0 + wd_198" + }, + "wd_200": { + "name": "wd_200", + "object_class": "Equation", + "value": "0.0 + wd_199" + }, + "wd_201": { + "name": "wd_201", + "object_class": "Equation", + "value": "0.0 + wd_200" + }, + "wd_202": { + "name": "wd_202", + "object_class": "Equation", + "value": "0.0 + wd_201" + }, + "wd_203": { + "name": "wd_203", + "object_class": "Equation", + "value": "0.0 + wd_202" + }, + "wd_204": { + "name": "wd_204", + "object_class": "Equation", + "value": "0.0 + wd_203" + }, + "wd_205": { + "name": "wd_205", + "object_class": "Equation", + "value": "0.0 + wd_204" + }, + "wd_206": { + "name": "wd_206", + "object_class": "Equation", + "value": "0.0 + wd_205" + }, + "wd_207": { + "name": "wd_207", + "object_class": "Equation", + "value": "0.0 + wd_206" + }, + "wd_208": { + "name": "wd_208", + "object_class": "Equation", + "value": "0.0 + wd_207" + }, + "wd_209": { + "name": "wd_209", + "object_class": "Equation", + "value": "0.0 + wd_208" + }, + "wd_210": { + "name": "wd_210", + "object_class": "Equation", + "value": "0.0 + wd_209" + }, + "wd_211": { + "name": "wd_211", + "object_class": "Equation", + "value": "0.0 + wd_210" + }, + "wd_212": { + "name": "wd_212", + "object_class": "Equation", + "value": "0.0 + wd_211" + }, + "wd_213": { + "name": "wd_213", + "object_class": "Equation", + "value": "0.0 + wd_212" + }, + "wd_214": { + "name": "wd_214", + "object_class": "Equation", + "value": "0.0 + wd_213" + }, + "wd_215": { + "name": "wd_215", + "object_class": "Equation", + "value": "0.0 + wd_214" + }, + "wd_216": { + "name": "wd_216", + "object_class": "Equation", + "value": "0.0 + wd_215" + }, + "wd_217": { + "name": "wd_217", + "object_class": "Equation", + "value": "0.0 + wd_216" + }, + "wd_218": { + "name": "wd_218", + "object_class": "Equation", + "value": "0.0 + wd_217" + }, + "wd_219": { + "name": "wd_219", + "object_class": "Equation", + "value": "0.0 + wd_218" + }, + "wd_220": { + "name": "wd_220", + "object_class": "Equation", + "value": "0.0 + wd_219" + }, + "wd_221": { + "name": "wd_221", + "object_class": "Equation", + "value": "0.0 + wd_220" + }, + "wd_222": { + "name": "wd_222", + "object_class": "Equation", + "value": "0.0 + wd_221" + }, + "wd_223": { + "name": "wd_223", + "object_class": "Equation", + "value": "0.0 + wd_222" + }, + "wd_224": { + "name": "wd_224", + "object_class": "Equation", + "value": "0.0 + wd_223" + }, + "wd_225": { + "name": "wd_225", + "object_class": "Equation", + "value": "0.0 + wd_224" + }, + "wd_226": { + "name": "wd_226", + "object_class": "Equation", + "value": "0.0 + wd_225" + }, + "wd_227": { + "name": "wd_227", + "object_class": "Equation", + "value": "0.0 + wd_226" + }, + "wd_228": { + "name": "wd_228", + "object_class": "Equation", + "value": "0.0 + wd_227" + }, + "wd_229": { + "name": "wd_229", + "object_class": "Equation", + "value": "0.0 + wd_228" + }, + "wd_230": { + "name": "wd_230", + "object_class": "Equation", + "value": "0.0 + wd_229" + }, + "wd_231": { + "name": "wd_231", + "object_class": "Equation", + "value": "0.0 + wd_230" + }, + "wd_232": { + "name": "wd_232", + "object_class": "Equation", + "value": "0.0 + wd_231" + }, + "wd_233": { + "name": "wd_233", + "object_class": "Equation", + "value": "0.0 + wd_232" + }, + "wd_234": { + "name": "wd_234", + "object_class": "Equation", + "value": "0.0 + wd_233" + }, + "wd_235": { + "name": "wd_235", + "object_class": "Equation", + "value": "0.0 + wd_234" + }, + "wd_236": { + "name": "wd_236", + "object_class": "Equation", + "value": "0.0 + wd_235" + }, + "wd_237": { + "name": "wd_237", + "object_class": "Equation", + "value": "0.0 + wd_236" + }, + "wd_238": { + "name": "wd_238", + "object_class": "Equation", + "value": "0.0 + wd_237" + }, + "wd_239": { + "name": "wd_239", + "object_class": "Equation", + "value": "0.0 + wd_238" + }, + "wd_240": { + "name": "wd_240", + "object_class": "Equation", + "value": "0.0 + wd_239" + }, + "wd_241": { + "name": "wd_241", + "object_class": "Equation", + "value": "0.0 + wd_240" + }, + "wd_242": { + "name": "wd_242", + "object_class": "Equation", + "value": "0.0 + wd_241" + }, + "wd_243": { + "name": "wd_243", + "object_class": "Equation", + "value": "0.0 + wd_242" + }, + "wd_244": { + "name": "wd_244", + "object_class": "Equation", + "value": "0.0 + wd_243" + }, + "wd_245": { + "name": "wd_245", + "object_class": "Equation", + "value": "0.0 + wd_244" + }, + "wd_246": { + "name": "wd_246", + "object_class": "Equation", + "value": "0.0 + wd_245" + }, + "wd_247": { + "name": "wd_247", + "object_class": "Equation", + "value": "0.0 + wd_246" + }, + "wd_248": { + "name": "wd_248", + "object_class": "Equation", + "value": "0.0 + wd_247" + }, + "wd_249": { + "name": "wd_249", + "object_class": "Equation", + "value": "0.0 + wd_248" + }, + "wd_250": { + "name": "wd_250", + "object_class": "Equation", + "value": "0.0 + wd_249" + }, + "wd_251": { + "name": "wd_251", + "object_class": "Equation", + "value": "0.0 + wd_250" + }, + "wd_252": { + "name": "wd_252", + "object_class": "Equation", + "value": "0.0 + wd_251" + }, + "wd_253": { + "name": "wd_253", + "object_class": "Equation", + "value": "0.0 + wd_252" + }, + "wd_254": { + "name": "wd_254", + "object_class": "Equation", + "value": "0.0 + wd_253" + }, + "wd_255": { + "name": "wd_255", + "object_class": "Equation", + "value": "0.0 + wd_254" + }, + "wd_256": { + "name": "wd_256", + "object_class": "Equation", + "value": "0.0 + wd_255" + }, + "wd_257": { + "name": "wd_257", + "object_class": "Equation", + "value": "0.0 + wd_256" + }, + "wd_258": { + "name": "wd_258", + "object_class": "Equation", + "value": "0.0 + wd_257" + }, + "wd_259": { + "name": "wd_259", + "object_class": "Equation", + "value": "0.0 + wd_258" + }, + "wd_260": { + "name": "wd_260", + "object_class": "Equation", + "value": "0.0 + wd_259" + }, + "wd_261": { + "name": "wd_261", + "object_class": "Equation", + "value": "0.0 + wd_260" + }, + "wd_262": { + "name": "wd_262", + "object_class": "Equation", + "value": "0.0 + wd_261" + }, + "wd_263": { + "name": "wd_263", + "object_class": "Equation", + "value": "0.0 + wd_262" + }, + "wd_264": { + "name": "wd_264", + "object_class": "Equation", + "value": "0.0 + wd_263" + }, + "wd_265": { + "name": "wd_265", + "object_class": "Equation", + "value": "0.0 + wd_264" + }, + "wd_266": { + "name": "wd_266", + "object_class": "Equation", + "value": "0.0 + wd_265" + }, + "wd_267": { + "name": "wd_267", + "object_class": "Equation", + "value": "0.0 + wd_266" + }, + "wd_268": { + "name": "wd_268", + "object_class": "Equation", + "value": "0.0 + wd_267" + }, + "wd_269": { + "name": "wd_269", + "object_class": "Equation", + "value": "0.0 + wd_268" + }, + "wd_270": { + "name": "wd_270", + "object_class": "Equation", + "value": "0.0 + wd_269" + }, + "wd_271": { + "name": "wd_271", + "object_class": "Equation", + "value": "0.0 + wd_270" + }, + "wd_272": { + "name": "wd_272", + "object_class": "Equation", + "value": "0.0 + wd_271" + }, + "wd_273": { + "name": "wd_273", + "object_class": "Equation", + "value": "0.0 + wd_272" + }, + "wd_274": { + "name": "wd_274", + "object_class": "Equation", + "value": "0.0 + wd_273" + }, + "wd_275": { + "name": "wd_275", + "object_class": "Equation", + "value": "0.0 + wd_274" + }, + "wd_276": { + "name": "wd_276", + "object_class": "Equation", + "value": "0.0 + wd_275" + }, + "wd_277": { + "name": "wd_277", + "object_class": "Equation", + "value": "0.0 + wd_276" + }, + "wd_278": { + "name": "wd_278", + "object_class": "Equation", + "value": "0.0 + wd_277" + }, + "wd_279": { + "name": "wd_279", + "object_class": "Equation", + "value": "0.0 + wd_278" + }, + "wd_280": { + "name": "wd_280", + "object_class": "Equation", + "value": "0.0 + wd_279" + }, + "wd_281": { + "name": "wd_281", + "object_class": "Equation", + "value": "0.0 + wd_280" + }, + "wd_282": { + "name": "wd_282", + "object_class": "Equation", + "value": "0.0 + wd_281" + }, + "wd_283": { + "name": "wd_283", + "object_class": "Equation", + "value": "0.0 + wd_282" + }, + "wd_284": { + "name": "wd_284", + "object_class": "Equation", + "value": "0.0 + wd_283" + }, + "wd_285": { + "name": "wd_285", + "object_class": "Equation", + "value": "0.0 + wd_284" + }, + "wd_286": { + "name": "wd_286", + "object_class": "Equation", + "value": "0.0 + wd_285" + }, + "wd_287": { + "name": "wd_287", + "object_class": "Equation", + "value": "0.0 + wd_286" + }, + "wd_288": { + "name": "wd_288", + "object_class": "Equation", + "value": "0.0 + wd_287" + }, + "wd_289": { + "name": "wd_289", + "object_class": "Equation", + "value": "0.0 + wd_288" + }, + "wd_290": { + "name": "wd_290", + "object_class": "Equation", + "value": "0.0 + wd_289" + }, + "wd_291": { + "name": "wd_291", + "object_class": "Equation", + "value": "0.0 + wd_290" + }, + "wd_292": { + "name": "wd_292", + "object_class": "Equation", + "value": "0.0 + wd_291" + }, + "wd_293": { + "name": "wd_293", + "object_class": "Equation", + "value": "0.0 + wd_292" + }, + "wd_294": { + "name": "wd_294", + "object_class": "Equation", + "value": "0.0 + wd_293" + }, + "wd_295": { + "name": "wd_295", + "object_class": "Equation", + "value": "0.0 + wd_294" + }, + "wd_296": { + "name": "wd_296", + "object_class": "Equation", + "value": "0.0 + wd_295" + }, + "wd_297": { + "name": "wd_297", + "object_class": "Equation", + "value": "0.0 + wd_296" + }, + "wd_298": { + "name": "wd_298", + "object_class": "Equation", + "value": "0.0 + wd_297" + }, + "wd_299": { + "name": "wd_299", + "object_class": "Equation", + "value": "0.0 + wd_298" + }, + "wd_300": { + "name": "wd_300", + "object_class": "Equation", + "value": "0.0 + wd_299" + }, + "wd_301": { + "name": "wd_301", + "object_class": "Equation", + "value": "0.0 + wd_300" + }, + "wd_302": { + "name": "wd_302", + "object_class": "Equation", + "value": "0.0 + wd_301" + }, + "wd_303": { + "name": "wd_303", + "object_class": "Equation", + "value": "0.0 + wd_302" + }, + "wd_304": { + "name": "wd_304", + "object_class": "Equation", + "value": "0.0 + wd_303" + }, + "wd_305": { + "name": "wd_305", + "object_class": "Equation", + "value": "0.0 + wd_304" + }, + "wd_306": { + "name": "wd_306", + "object_class": "Equation", + "value": "0.0 + wd_305" + }, + "wd_307": { + "name": "wd_307", + "object_class": "Equation", + "value": "0.0 + wd_306" + }, + "wd_308": { + "name": "wd_308", + "object_class": "Equation", + "value": "0.0 + wd_307" + }, + "wd_309": { + "name": "wd_309", + "object_class": "Equation", + "value": "0.0 + wd_308" + }, + "wd_310": { + "name": "wd_310", + "object_class": "Equation", + "value": "0.0 + wd_309" + }, + "wd_311": { + "name": "wd_311", + "object_class": "Equation", + "value": "0.0 + wd_310" + }, + "wd_312": { + "name": "wd_312", + "object_class": "Equation", + "value": "0.0 + wd_311" + }, + "wd_313": { + "name": "wd_313", + "object_class": "Equation", + "value": "0.0 + wd_312" + }, + "wd_314": { + "name": "wd_314", + "object_class": "Equation", + "value": "0.0 + wd_313" + }, + "wd_315": { + "name": "wd_315", + "object_class": "Equation", + "value": "0.0 + wd_314" + }, + "wd_316": { + "name": "wd_316", + "object_class": "Equation", + "value": "0.0 + wd_315" + }, + "wd_317": { + "name": "wd_317", + "object_class": "Equation", + "value": "0.0 + wd_316" + }, + "wd_318": { + "name": "wd_318", + "object_class": "Equation", + "value": "0.0 + wd_317" + }, + "wd_319": { + "name": "wd_319", + "object_class": "Equation", + "value": "0.0 + wd_318" + }, + "wd_320": { + "name": "wd_320", + "object_class": "Equation", + "value": "0.0 + wd_319" + }, + "wd_321": { + "name": "wd_321", + "object_class": "Equation", + "value": "0.0 + wd_320" + }, + "wd_322": { + "name": "wd_322", + "object_class": "Equation", + "value": "0.0 + wd_321" + }, + "wd_323": { + "name": "wd_323", + "object_class": "Equation", + "value": "0.0 + wd_322" + }, + "wd_324": { + "name": "wd_324", + "object_class": "Equation", + "value": "0.0 + wd_323" + }, + "wd_325": { + "name": "wd_325", + "object_class": "Equation", + "value": "0.0 + wd_324" + }, + "wd_326": { + "name": "wd_326", + "object_class": "Equation", + "value": "0.0 + wd_325" + }, + "wd_327": { + "name": "wd_327", + "object_class": "Equation", + "value": "0.0 + wd_326" + }, + "wd_328": { + "name": "wd_328", + "object_class": "Equation", + "value": "0.0 + wd_327" + }, + "wd_329": { + "name": "wd_329", + "object_class": "Equation", + "value": "0.0 + wd_328" + }, + "wd_330": { + "name": "wd_330", + "object_class": "Equation", + "value": "0.0 + wd_329" + }, + "wd_331": { + "name": "wd_331", + "object_class": "Equation", + "value": "0.0 + wd_330" + }, + "wd_332": { + "name": "wd_332", + "object_class": "Equation", + "value": "0.0 + wd_331" + }, + "wd_333": { + "name": "wd_333", + "object_class": "Equation", + "value": "0.0 + wd_332" + }, + "wd_334": { + "name": "wd_334", + "object_class": "Equation", + "value": "0.0 + wd_333" + }, + "wd_335": { + "name": "wd_335", + "object_class": "Equation", + "value": "0.0 + wd_334" + }, + "wd_336": { + "name": "wd_336", + "object_class": "Equation", + "value": "0.0 + wd_335" + }, + "wd_337": { + "name": "wd_337", + "object_class": "Equation", + "value": "0.0 + wd_336" + }, + "wd_338": { + "name": "wd_338", + "object_class": "Equation", + "value": "0.0 + wd_337" + }, + "wd_339": { + "name": "wd_339", + "object_class": "Equation", + "value": "0.0 + wd_338" + }, + "wd_340": { + "name": "wd_340", + "object_class": "Equation", + "value": "0.0 + wd_339" + }, + "wd_341": { + "name": "wd_341", + "object_class": "Equation", + "value": "0.0 + wd_340" + }, + "wd_342": { + "name": "wd_342", + "object_class": "Equation", + "value": "0.0 + wd_341" + }, + "wd_343": { + "name": "wd_343", + "object_class": "Equation", + "value": "0.0 + wd_342" + }, + "wd_344": { + "name": "wd_344", + "object_class": "Equation", + "value": "0.0 + wd_343" + }, + "wd_345": { + "name": "wd_345", + "object_class": "Equation", + "value": "0.0 + wd_344" + }, + "wd_346": { + "name": "wd_346", + "object_class": "Equation", + "value": "0.0 + wd_345" + }, + "wd_347": { + "name": "wd_347", + "object_class": "Equation", + "value": "0.0 + wd_346" + }, + "wd_348": { + "name": "wd_348", + "object_class": "Equation", + "value": "0.0 + wd_347" + }, + "wd_349": { + "name": "wd_349", + "object_class": "Equation", + "value": "0.0 + wd_348" + }, + "wd_350": { + "name": "wd_350", + "object_class": "Equation", + "value": "0.0 + wd_349" + }, + "wd_351": { + "name": "wd_351", + "object_class": "Equation", + "value": "0.0 + wd_350" + }, + "wd_352": { + "name": "wd_352", + "object_class": "Equation", + "value": "0.0 + wd_351" + }, + "wd_353": { + "name": "wd_353", + "object_class": "Equation", + "value": "0.0 + wd_352" + }, + "wd_354": { + "name": "wd_354", + "object_class": "Equation", + "value": "0.0 + wd_353" + }, + "wd_355": { + "name": "wd_355", + "object_class": "Equation", + "value": "0.0 + wd_354" + }, + "wd_356": { + "name": "wd_356", + "object_class": "Equation", + "value": "0.0 + wd_355" + }, + "wd_357": { + "name": "wd_357", + "object_class": "Equation", + "value": "0.0 + wd_356" + }, + "wd_358": { + "name": "wd_358", + "object_class": "Equation", + "value": "0.0 + wd_357" + }, + "wd_359": { + "name": "wd_359", + "object_class": "Equation", + "value": "0.0 + wd_358" + }, + "wd_360": { + "name": "wd_360", + "object_class": "Equation", + "value": "0.0 + wd_359" + }, + "wd_361": { + "name": "wd_361", + "object_class": "Equation", + "value": "0.0 + wd_360" + }, + "wd_362": { + "name": "wd_362", + "object_class": "Equation", + "value": "0.0 + wd_361" + }, + "wd_363": { + "name": "wd_363", + "object_class": "Equation", + "value": "0.0 + wd_362" + }, + "wd_364": { + "name": "wd_364", + "object_class": "Equation", + "value": "0.0 + wd_363" + }, + "wd_365": { + "name": "wd_365", + "object_class": "Equation", + "value": "0.0 + wd_364" + }, + "wd_366": { + "name": "wd_366", + "object_class": "Equation", + "value": "0.0 + wd_365" + }, + "wd_367": { + "name": "wd_367", + "object_class": "Equation", + "value": "0.0 + wd_366" + }, + "wd_368": { + "name": "wd_368", + "object_class": "Equation", + "value": "0.0 + wd_367" + }, + "wd_369": { + "name": "wd_369", + "object_class": "Equation", + "value": "0.0 + wd_368" + }, + "wd_370": { + "name": "wd_370", + "object_class": "Equation", + "value": "0.0 + wd_369" + }, + "wd_371": { + "name": "wd_371", + "object_class": "Equation", + "value": "0.0 + wd_370" + }, + "wd_372": { + "name": "wd_372", + "object_class": "Equation", + "value": "0.0 + wd_371" + }, + "wd_373": { + "name": "wd_373", + "object_class": "Equation", + "value": "0.0 + wd_372" + }, + "wd_374": { + "name": "wd_374", + "object_class": "Equation", + "value": "0.0 + wd_373" + }, + "wd_375": { + "name": "wd_375", + "object_class": "Equation", + "value": "0.0 + wd_374" + }, + "wd_376": { + "name": "wd_376", + "object_class": "Equation", + "value": "0.0 + wd_375" + }, + "wd_377": { + "name": "wd_377", + "object_class": "Equation", + "value": "0.0 + wd_376" + }, + "wd_378": { + "name": "wd_378", + "object_class": "Equation", + "value": "0.0 + wd_377" + }, + "wd_379": { + "name": "wd_379", + "object_class": "Equation", + "value": "0.0 + wd_378" + }, + "wd_380": { + "name": "wd_380", + "object_class": "Equation", + "value": "0.0 + wd_379" + }, + "wd_381": { + "name": "wd_381", + "object_class": "Equation", + "value": "0.0 + wd_380" + }, + "wd_382": { + "name": "wd_382", + "object_class": "Equation", + "value": "0.0 + wd_381" + }, + "wd_383": { + "name": "wd_383", + "object_class": "Equation", + "value": "0.0 + wd_382" + }, + "wd_384": { + "name": "wd_384", + "object_class": "Equation", + "value": "0.0 + wd_383" + }, + "wd_385": { + "name": "wd_385", + "object_class": "Equation", + "value": "0.0 + wd_384" + }, + "wd_386": { + "name": "wd_386", + "object_class": "Equation", + "value": "0.0 + wd_385" + }, + "wd_387": { + "name": "wd_387", + "object_class": "Equation", + "value": "0.0 + wd_386" + }, + "wd_388": { + "name": "wd_388", + "object_class": "Equation", + "value": "0.0 + wd_387" + }, + "wd_389": { + "name": "wd_389", + "object_class": "Equation", + "value": "0.0 + wd_388" + }, + "wd_390": { + "name": "wd_390", + "object_class": "Equation", + "value": "0.0 + wd_389" + }, + "wd_391": { + "name": "wd_391", + "object_class": "Equation", + "value": "0.0 + wd_390" + }, + "wd_392": { + "name": "wd_392", + "object_class": "Equation", + "value": "0.0 + wd_391" + }, + "wd_393": { + "name": "wd_393", + "object_class": "Equation", + "value": "0.0 + wd_392" + }, + "wd_394": { + "name": "wd_394", + "object_class": "Equation", + "value": "0.0 + wd_393" + }, + "wd_395": { + "name": "wd_395", + "object_class": "Equation", + "value": "0.0 + wd_394" + }, + "wd_396": { + "name": "wd_396", + "object_class": "Equation", + "value": "0.0 + wd_395" + }, + "wd_397": { + "name": "wd_397", + "object_class": "Equation", + "value": "0.0 + wd_396" + }, + "wd_398": { + "name": "wd_398", + "object_class": "Equation", + "value": "0.0 + wd_397" + }, + "wd_399": { + "name": "wd_399", + "object_class": "Equation", + "value": "0.0 + wd_398" + }, + "wd_400": { + "name": "wd_400", + "object_class": "Equation", + "value": "0.0 + wd_399" + }, + "wd_401": { + "name": "wd_401", + "object_class": "Equation", + "value": "0.0 + wd_400" + }, + "wd_402": { + "name": "wd_402", + "object_class": "Equation", + "value": "0.0 + wd_401" + }, + "wd_403": { + "name": "wd_403", + "object_class": "Equation", + "value": "0.0 + wd_402" + }, + "wd_404": { + "name": "wd_404", + "object_class": "Equation", + "value": "0.0 + wd_403" + }, + "wd_405": { + "name": "wd_405", + "object_class": "Equation", + "value": "0.0 + wd_404" + }, + "wd_406": { + "name": "wd_406", + "object_class": "Equation", + "value": "0.0 + wd_405" + }, + "wd_407": { + "name": "wd_407", + "object_class": "Equation", + "value": "0.0 + wd_406" + }, + "wd_408": { + "name": "wd_408", + "object_class": "Equation", + "value": "0.0 + wd_407" + }, + "wd_409": { + "name": "wd_409", + "object_class": "Equation", + "value": "0.0 + wd_408" + }, + "wd_410": { + "name": "wd_410", + "object_class": "Equation", + "value": "0.0 + wd_409" + }, + "wd_411": { + "name": "wd_411", + "object_class": "Equation", + "value": "0.0 + wd_410" + }, + "wd_412": { + "name": "wd_412", + "object_class": "Equation", + "value": "0.0 + wd_411" + }, + "wd_413": { + "name": "wd_413", + "object_class": "Equation", + "value": "0.0 + wd_412" + }, + "wd_414": { + "name": "wd_414", + "object_class": "Equation", + "value": "0.0 + wd_413" + }, + "wd_415": { + "name": "wd_415", + "object_class": "Equation", + "value": "0.0 + wd_414" + }, + "wd_416": { + "name": "wd_416", + "object_class": "Equation", + "value": "0.0 + wd_415" + }, + "wd_417": { + "name": "wd_417", + "object_class": "Equation", + "value": "0.0 + wd_416" + }, + "wd_418": { + "name": "wd_418", + "object_class": "Equation", + "value": "0.0 + wd_417" + }, + "wd_419": { + "name": "wd_419", + "object_class": "Equation", + "value": "0.0 + wd_418" + }, + "wd_420": { + "name": "wd_420", + "object_class": "Equation", + "value": "0.0 + wd_419" + }, + "wd_421": { + "name": "wd_421", + "object_class": "Equation", + "value": "0.0 + wd_420" + }, + "wd_422": { + "name": "wd_422", + "object_class": "Equation", + "value": "0.0 + wd_421" + }, + "wd_423": { + "name": "wd_423", + "object_class": "Equation", + "value": "0.0 + wd_422" + }, + "wd_424": { + "name": "wd_424", + "object_class": "Equation", + "value": "0.0 + wd_423" + }, + "wd_425": { + "name": "wd_425", + "object_class": "Equation", + "value": "0.0 + wd_424" + }, + "wd_426": { + "name": "wd_426", + "object_class": "Equation", + "value": "0.0 + wd_425" + }, + "wd_427": { + "name": "wd_427", + "object_class": "Equation", + "value": "0.0 + wd_426" + }, + "wd_428": { + "name": "wd_428", + "object_class": "Equation", + "value": "0.0 + wd_427" + }, + "wd_429": { + "name": "wd_429", + "object_class": "Equation", + "value": "0.0 + wd_428" + }, + "wd_430": { + "name": "wd_430", + "object_class": "Equation", + "value": "0.0 + wd_429" + }, + "wd_431": { + "name": "wd_431", + "object_class": "Equation", + "value": "0.0 + wd_430" + }, + "wd_432": { + "name": "wd_432", + "object_class": "Equation", + "value": "0.0 + wd_431" + }, + "wd_433": { + "name": "wd_433", + "object_class": "Equation", + "value": "0.0 + wd_432" + }, + "wd_434": { + "name": "wd_434", + "object_class": "Equation", + "value": "0.0 + wd_433" + }, + "wd_435": { + "name": "wd_435", + "object_class": "Equation", + "value": "0.0 + wd_434" + }, + "wd_436": { + "name": "wd_436", + "object_class": "Equation", + "value": "0.0 + wd_435" + }, + "wd_437": { + "name": "wd_437", + "object_class": "Equation", + "value": "0.0 + wd_436" + }, + "wd_438": { + "name": "wd_438", + "object_class": "Equation", + "value": "0.0 + wd_437" + }, + "wd_439": { + "name": "wd_439", + "object_class": "Equation", + "value": "0.0 + wd_438" + }, + "wd_440": { + "name": "wd_440", + "object_class": "Equation", + "value": "0.0 + wd_439" + }, + "wd_441": { + "name": "wd_441", + "object_class": "Equation", + "value": "0.0 + wd_440" + }, + "wd_442": { + "name": "wd_442", + "object_class": "Equation", + "value": "0.0 + wd_441" + }, + "wd_443": { + "name": "wd_443", + "object_class": "Equation", + "value": "0.0 + wd_442" + }, + "wd_444": { + "name": "wd_444", + "object_class": "Equation", + "value": "0.0 + wd_443" + }, + "wd_445": { + "name": "wd_445", + "object_class": "Equation", + "value": "0.0 + wd_444" + }, + "wd_446": { + "name": "wd_446", + "object_class": "Equation", + "value": "0.0 + wd_445" + }, + "wd_447": { + "name": "wd_447", + "object_class": "Equation", + "value": "0.0 + wd_446" + }, + "wd_448": { + "name": "wd_448", + "object_class": "Equation", + "value": "0.0 + wd_447" + }, + "wd_449": { + "name": "wd_449", + "object_class": "Equation", + "value": "0.0 + wd_448" + }, + "wd_450": { + "name": "wd_450", + "object_class": "Equation", + "value": "0.0 + wd_449" + }, + "wd_451": { + "name": "wd_451", + "object_class": "Equation", + "value": "0.0 + wd_450" + }, + "wd_452": { + "name": "wd_452", + "object_class": "Equation", + "value": "0.0 + wd_451" + }, + "wd_453": { + "name": "wd_453", + "object_class": "Equation", + "value": "0.0 + wd_452" + }, + "wd_454": { + "name": "wd_454", + "object_class": "Equation", + "value": "0.0 + wd_453" + }, + "wd_455": { + "name": "wd_455", + "object_class": "Equation", + "value": "0.0 + wd_454" + }, + "wd_456": { + "name": "wd_456", + "object_class": "Equation", + "value": "0.0 + wd_455" + }, + "wd_457": { + "name": "wd_457", + "object_class": "Equation", + "value": "0.0 + wd_456" + }, + "wd_458": { + "name": "wd_458", + "object_class": "Equation", + "value": "0.0 + wd_457" + }, + "wd_459": { + "name": "wd_459", + "object_class": "Equation", + "value": "0.0 + wd_458" + }, + "wd_460": { + "name": "wd_460", + "object_class": "Equation", + "value": "0.0 + wd_459" + }, + "wd_461": { + "name": "wd_461", + "object_class": "Equation", + "value": "0.0 + wd_460" + }, + "wd_462": { + "name": "wd_462", + "object_class": "Equation", + "value": "0.0 + wd_461" + }, + "wd_463": { + "name": "wd_463", + "object_class": "Equation", + "value": "0.0 + wd_462" + }, + "wd_464": { + "name": "wd_464", + "object_class": "Equation", + "value": "0.0 + wd_463" + }, + "wd_465": { + "name": "wd_465", + "object_class": "Equation", + "value": "0.0 + wd_464" + }, + "wd_466": { + "name": "wd_466", + "object_class": "Equation", + "value": "0.0 + wd_465" + }, + "wd_467": { + "name": "wd_467", + "object_class": "Equation", + "value": "0.0 + wd_466" + }, + "wd_468": { + "name": "wd_468", + "object_class": "Equation", + "value": "0.0 + wd_467" + }, + "wd_469": { + "name": "wd_469", + "object_class": "Equation", + "value": "0.0 + wd_468" + }, + "wd_470": { + "name": "wd_470", + "object_class": "Equation", + "value": "0.0 + wd_469" + }, + "wd_471": { + "name": "wd_471", + "object_class": "Equation", + "value": "0.0 + wd_470" + }, + "wd_472": { + "name": "wd_472", + "object_class": "Equation", + "value": "0.0 + wd_471" + }, + "wd_473": { + "name": "wd_473", + "object_class": "Equation", + "value": "0.0 + wd_472" + }, + "wd_474": { + "name": "wd_474", + "object_class": "Equation", + "value": "0.0 + wd_473" + }, + "wd_475": { + "name": "wd_475", + "object_class": "Equation", + "value": "0.0 + wd_474" + }, + "wd_476": { + "name": "wd_476", + "object_class": "Equation", + "value": "0.0 + wd_475" + }, + "wd_477": { + "name": "wd_477", + "object_class": "Equation", + "value": "0.0 + wd_476" + }, + "wd_478": { + "name": "wd_478", + "object_class": "Equation", + "value": "0.0 + wd_477" + }, + "wd_479": { + "name": "wd_479", + "object_class": "Equation", + "value": "0.0 + wd_478" + }, + "wd_480": { + "name": "wd_480", + "object_class": "Equation", + "value": "0.0 + wd_479" + }, + "wd_481": { + "name": "wd_481", + "object_class": "Equation", + "value": "0.0 + wd_480" + }, + "wd_482": { + "name": "wd_482", + "object_class": "Equation", + "value": "0.0 + wd_481" + }, + "wd_483": { + "name": "wd_483", + "object_class": "Equation", + "value": "0.0 + wd_482" + }, + "wd_484": { + "name": "wd_484", + "object_class": "Equation", + "value": "0.0 + wd_483" + }, + "wd_485": { + "name": "wd_485", + "object_class": "Equation", + "value": "0.0 + wd_484" + }, + "wd_486": { + "name": "wd_486", + "object_class": "Equation", + "value": "0.0 + wd_485" + }, + "wd_487": { + "name": "wd_487", + "object_class": "Equation", + "value": "0.0 + wd_486" + }, + "wd_488": { + "name": "wd_488", + "object_class": "Equation", + "value": "0.0 + wd_487" + }, + "wd_489": { + "name": "wd_489", + "object_class": "Equation", + "value": "0.0 + wd_488" + }, + "wd_490": { + "name": "wd_490", + "object_class": "Equation", + "value": "0.0 + wd_489" + }, + "wd_491": { + "name": "wd_491", + "object_class": "Equation", + "value": "0.0 + wd_490" + }, + "wd_492": { + "name": "wd_492", + "object_class": "Equation", + "value": "0.0 + wd_491" + }, + "wd_493": { + "name": "wd_493", + "object_class": "Equation", + "value": "0.0 + wd_492" + }, + "wd_494": { + "name": "wd_494", + "object_class": "Equation", + "value": "0.0 + wd_493" + }, + "wd_495": { + "name": "wd_495", + "object_class": "Equation", + "value": "0.0 + wd_494" + }, + "wd_496": { + "name": "wd_496", + "object_class": "Equation", + "value": "0.0 + wd_495" + }, + "wd_497": { + "name": "wd_497", + "object_class": "Equation", + "value": "0.0 + wd_496" + }, + "wd_498": { + "name": "wd_498", + "object_class": "Equation", + "value": "0.0 + wd_497" + }, + "wd_499": { + "name": "wd_499", + "object_class": "Equation", + "value": "0.0 + wd_498" + }, + "wd_500": { + "name": "wd_500", + "object_class": "Equation", + "value": "0.0 + wd_499" + }, + "O2write": { + "name": "O2write", + "object_class": "ModelLinkage", + "left_path": "/STATE/JL1_6560_6440/RCHRES_R001/O2", + "right_path": "/STATE/JL1_6560_6440/RCHRES_R001/wd_500", + "link_type": 5 + } + } +} + diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json b/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json deleted file mode 100644 index 6b666abc..00000000 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json.mechtest.json +++ /dev/null @@ -1,1311 +0,0 @@ -{ - "RCHRES_R001": { - "name": "RCHRES_R001", - "description": "This is a test setup only with data from another watershed Mechums River to test performance with large json arrays", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.2689586532 - }, - "drainage_area_sqmi": { - "name": "drainage_area_sqmi", - "object_class": "Constant", - "value": null - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8566933": { - "name": "nhd_8566933", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 2.8744521696 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567297": { - "name": "nhd_8567297", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.217182375 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - }, - "nhd_8566941": { - "name": "nhd_8566941", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 1.3493106594 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8566975": { - "name": "nhd_8566975", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.8364127626 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8566977": { - "name": "nhd_8566977", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.2150974242 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8566973": { - "name": "nhd_8566973", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567299": { - "name": "nhd_8567299", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.286680735 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - }, - "nhd_8567153": { - "name": "nhd_8567153", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 2.4814389438 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567007": { - "name": "nhd_8567007", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.1018150974 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - } - }, - "nhd_8567001": { - "name": "nhd_8567001", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.15637131 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567049": { - "name": "nhd_8567049", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.4041329634 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567253": { - "name": "nhd_8567253", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.0827030484 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8568339": { - "name": "nhd_8568339", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.0656759502 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8568365": { - "name": "nhd_8568365", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567591": { - "name": "nhd_8567591", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.7033234032 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567615": { - "name": "nhd_8567615", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.3071827512 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - } - } - } - } - }, - "nhd_8567307": { - "name": "nhd_8567307", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 1.8177296058 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567053": { - "name": "nhd_8567053", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.2731285548 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567055": { - "name": "nhd_8567055", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.0003474918 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567617": { - "name": "nhd_8567617", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 1.3896197082 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8568285": { - "name": "nhd_8568285", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 2.2972682898 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567679": { - "name": "nhd_8567679", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.1080699498 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - }, - "nhd_8568287": { - "name": "nhd_8568287", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.0736682616 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567687": { - "name": "nhd_8567687", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.7613545338 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567703": { - "name": "nhd_8567703", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.9861817284 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567717": { - "name": "nhd_8567717", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.3356770788 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - }, - "nhd_8567759": { - "name": "nhd_8567759", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 1.1887694478 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567797": { - "name": "nhd_8567797", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.7724742714 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - } - }, - "nhd_8568293": { - "name": "nhd_8568293", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.4416620778 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567719": { - "name": "nhd_8567719", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.0962552286 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - } - } - } - }, - "nhd_8567057": { - "name": "nhd_8567057", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.0597685896 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8569665": { - "name": "nhd_8569665", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.0097297704 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8568281": { - "name": "nhd_8568281", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.6626668626 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567577": { - "name": "nhd_8567577", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.1105023924 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567059": { - "name": "nhd_8567059", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.3245573412 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - }, - "nhd_8567585": { - "name": "nhd_8567585", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.2700011286 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567587": { - "name": "nhd_8567587", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.2234372274 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567061": { - "name": "nhd_8567061", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.8649070902 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - }, - "nhd_8567597": { - "name": "nhd_8567597", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 1.1088463338 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8569667": { - "name": "nhd_8569667", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.0232819506 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567063": { - "name": "nhd_8567063", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 1.3215113154 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - } - } - } - } - } - } - }, - "nhd_8567315": { - "name": "nhd_8567315", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.005212377 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567581": { - "name": "nhd_8567581", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.1855606212 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567599": { - "name": "nhd_8567599", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.1800007524 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567605": { - "name": "nhd_8567605", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.1515064248 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8568389": { - "name": "nhd_8568389", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.4878784872 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - }, - "nhd_8567727": { - "name": "nhd_8567727", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 1.7569185408 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8568391": { - "name": "nhd_8568391", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.8934014178 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - } - }, - "nhd_8567667": { - "name": "nhd_8567667", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 1.1922443658 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567701": { - "name": "nhd_8567701", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.4927433724 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - }, - "nhd_8567777": { - "name": "nhd_8567777", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.9983439414 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - }, - "nhd_8567803": { - "name": "nhd_8567803", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 0.2178773586 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - } - } - } - } - } - } - }, - "nhd_8567013": { - "name": "nhd_8567013", - "object_class": "ModelObject", - "local_area_sqmi": { - "name": "local_area_sqmi", - "object_class": "ModelConstant", - "value": 2.4001258626 - }, - "Qlocal": { - "name": "Qlocal", - "object_class": "Equation", - "value": "local_area_sqmi * Runit" - }, - "Qin": { - "name": "Qin", - "object_class": "Equation", - "equation": "Qlocal + 0" - }, - "Qout": { - "name": "Qout", - "object_class": "Equation", - "equation": "Qin * 1.0" - } - } - }, - "value": "0", - "Runit": { - "name": "Runit", - "object_class": "Equation", - "value": "IVOL / drainage_area_sqmi" - } - } -} - From b851d5b7908d8ffe087af811dd0997267e39bfe4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 21:39:03 -0500 Subject: [PATCH 300/378] good WD test --- tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq b/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq index 3c47ade9..f6d4b249 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq @@ -2506,8 +2506,8 @@ "O2write": { "name": "O2write", "object_class": "ModelLinkage", - "left_path": "/STATE/JL1_6560_6440/RCHRES_R001/O2", - "right_path": "/STATE/JL1_6560_6440/RCHRES_R001/wd_500", + "left_path": "/STATE/PL3_5250_0001/RCHRES_R001/O2", + "right_path": "/STATE/PL3_5250_0001/RCHRES_R001/wd_500", "link_type": 5 } } From e8134bbe3d79dd310d801717dc6421803b6d9298 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 21:44:24 -0500 Subject: [PATCH 301/378] info --- src/hsp2/hsp2/HYDR.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 1daeee27..8c689430 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -154,6 +154,7 @@ def hydr(siminfo, parameters, ts, ftables, state): activity_path = state.domain + "/" + 'HYDR' activity_id = get_state_ix(state.state_paths, activity_path) model_exec_list = state.op_exec_lists[activity_id] + print(state.domain, "HYDR called with", state.domain, len(model_exec_list), "op elements.") ####################################################################################### # Do the simulation with _hydr_ (ie run reaches simulation code) From 8158666429bd491bd6e9fcb8f0a4d85ffc1edfce Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 21:49:36 -0500 Subject: [PATCH 302/378] info --- src/hsp2/hsp2/om_equation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index fecdf9fe..0f99c495 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -450,9 +450,9 @@ def step_equation(op_token, state_ix, step): # 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 # is the below faster since it avoids a brief loop and a couple ifs for 2 op equations? if num_ops == 1: From 8fd53a09408ebcc0e94a57dfd3c265efd222f674 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 22:00:00 -0500 Subject: [PATCH 303/378] debug --- src/hsp2/hsp2/HYDR.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 8c689430..42d26a12 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -407,6 +407,8 @@ def _hydr_( # 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, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step ) # traditional 'ACTIONS' done in here From d791160b37799359c7adc7d165f3a214d67b8782 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 8 Jan 2026 22:01:39 -0500 Subject: [PATCH 304/378] debug --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 8ce45e61..a24b3ca6 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -749,7 +749,7 @@ 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 step < 2: print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) print("DEBUG: ops: ", ops) if ops[0] == 1: From f89c64a8afcc38e2d2f5b502515086ebf278b72c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 10:20:45 -0500 Subject: [PATCH 305/378] do not conert ep_list to numpy cuz it is text! --- src/hsp2/hsp2/HYDR.py | 6 +++--- src/hsp2/hsp2/om.py | 3 +-- tests/testcbp/HSP2results/check_equation.py | 20 +++++++++----------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 42d26a12..b936861b 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -154,7 +154,7 @@ def hydr(siminfo, parameters, ts, ftables, state): activity_path = state.domain + "/" + 'HYDR' activity_id = get_state_ix(state.state_paths, activity_path) model_exec_list = state.op_exec_lists[activity_id] - print(state.domain, "HYDR called with", state.domain, len(model_exec_list), "op elements.") + #print(state.domain, "HYDR called with", state.domain, len(model_exec_list), "op elements.") ####################################################################################### # Do the simulation with _hydr_ (ie run reaches simulation code) @@ -407,8 +407,8 @@ def _hydr_( # 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") + #if step < 2: + # print("Calling step_model with", len(model_exec_list), "out of", len(state.op_tokens), "tokens") step_model( model_exec_list, state.op_tokens, state.state_ix, state.dict_ix, state.ts_ix, step ) # traditional 'ACTIONS' done in here diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index a24b3ca6..15707e1f 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -684,7 +684,6 @@ def hsp2_domain_dependencies(state, opseq, activities, om_operations, debug=Fals elif activity == "RQUAL": ep_list = rqual_init_ix(state, seg_path) # Register list of elements to execute if any - ep_list = ep_list.to_numpy() op_exec_list = model_domain_dependencies( om_operations, state, seg_path, ep_list, True, debug ) @@ -749,7 +748,7 @@ 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 step < 2: + if debug > 0: print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) print("DEBUG: ops: ", ops) if ops[0] == 1: diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 848222eb..4d414016 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -13,7 +13,7 @@ from hsp2.hsp2.configuration import activities from src.hsp2.hsp2tools.commands import import_uci, run from pandas import read_hdf -from hsp2.hsp2.om_sim_timer import timer_class +from hsp2.hsp2.om_timer import timer_class timer = timer_class() @@ -53,8 +53,8 @@ state_empty["op_exec_lists"], state_empty["model_exec_list"], state_empty["dict_ix"], state_empty["ts_ix"], state_empty["hsp_segments"] ) -state = state_empty # init_state_dicts() # automatically imported from state_fn_defaults 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 @@ -64,18 +64,16 @@ # before loading dynamic components that may reference them state_init_hsp2(state, opseq, activities, timer) print("state_init_hsp2() call and config", timer.split(), "seconds") -# - 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 -print("om_init_state() call and config", timer.split(), "seconds") -specl_load_state(state, io_manager, siminfo) # traditional special actions -print("specl_load_state() 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, 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(state, io_manager, siminfo) +state_om_model_run_prep(opseq, activities, state, om_operations, siminfo) print("state_om_model_run_prep() call and config", timer.split(), "seconds") ####################################################################################### From ea37f2305adca806323040d425b2e3590979e4c9 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 10:36:00 -0500 Subject: [PATCH 306/378] debug --- src/hsp2/hsp2/om.py | 2 +- tests/testcbp/HSP2results/check_equation.py | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 15707e1f..22c97a61 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -748,7 +748,7 @@ 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 step < 2: print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) print("DEBUG: ops: ", ops) if ops[0] == 1: diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 4d414016..f178fee7 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -77,22 +77,30 @@ print("state_om_model_run_prep() call and config", timer.split(), "seconds") ####################################################################################### - -# Set up order of execution -statenb = state_class_lite(0) -state_copy(state, statenb) - # 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 = om_operations["model_object_cache"]["/STATE/RCHRES_R001/Rlocal"] From 167543424f853bdef0a1c427d71b33c696256686 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 10:45:43 -0500 Subject: [PATCH 307/378] debug --- src/hsp2/hsp2/HYDR.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index b936861b..9f1428ae 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -152,8 +152,10 @@ def hydr(siminfo, parameters, ts, ftables, state): # 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.") ####################################################################################### From e5194a88116e7b981fe18d7f22df216211d316f1 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 10:49:51 -0500 Subject: [PATCH 308/378] debug --- src/hsp2/hsp2/om.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 22c97a61..60ed4e26 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -726,8 +726,12 @@ 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): + m = 0 for i in model_exec_list: + if n < 20 and step < 2: + print op_tokens[i] step_one(op_tokens, op_tokens[i], state_ix, dict_ix, ts_ix, step, 0) + n = n + 1 return @@ -748,7 +752,7 @@ 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 step < 2: + if debug: print("DEBUG: Operator ID", ops[1], "is op type", ops[0]) print("DEBUG: ops: ", ops) if ops[0] == 1: From 82d4a39cdabdb5fdfb04838755b161cf6fb6bd82 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 10:50:34 -0500 Subject: [PATCH 309/378] debug --- src/hsp2/hsp2/om.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 60ed4e26..54f6c01e 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -726,10 +726,10 @@ 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): - m = 0 + n = 0 for i in model_exec_list: if n < 20 and step < 2: - print op_tokens[i] + print(op_tokens[i]) step_one(op_tokens, op_tokens[i], state_ix, dict_ix, ts_ix, step, 0) n = n + 1 return From 89b9d339d0d9f361774443d1dc05126ac5728670 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 10:54:45 -0500 Subject: [PATCH 310/378] copy domain too! --- src/hsp2/hsp2/om.py | 4 ++++ src/hsp2/state/state.py | 1 + 2 files changed, 5 insertions(+) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 54f6c01e..b9c48cc9 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -728,6 +728,10 @@ def pre_step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): 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 zero item is the end of the active components + if op_tokens[i][0] == 0: + continue if n < 20 and step < 2: print(op_tokens[i]) step_one(op_tokens, op_tokens[i], state_ix, dict_ix, ts_ix, step, 0) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 8ec29c32..3b9363fc 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -110,6 +110,7 @@ def state_copy(statesrc, statedest): 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 From 4eb17077dc4e44d66ec179e93ab19f127c236e0c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 10:56:18 -0500 Subject: [PATCH 311/378] debug off --- src/hsp2/hsp2/om.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index b9c48cc9..4556b317 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -732,8 +732,6 @@ def step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): # that the first zero item is the end of the active components if op_tokens[i][0] == 0: continue - if n < 20 and step < 2: - print(op_tokens[i]) step_one(op_tokens, op_tokens[i], state_ix, dict_ix, ts_ix, step, 0) n = n + 1 return From 9b996ddc4b9223bfb2e0d272d9641d9f3672d622 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 10:58:33 -0500 Subject: [PATCH 312/378] debug off --- src/hsp2/hsp2/om_equation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_equation.py b/src/hsp2/hsp2/om_equation.py index 0f99c495..4316e90c 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -490,7 +490,7 @@ def step_equation(op_token, state_ix, step): 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) + #if step < 2: + # print("Eq:", op_token[1], result) state_ix[op_token[1]] = result return True From 189b77f84e9a98d3fed9d67a2c58b0706566bb6b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 11:06:45 -0500 Subject: [PATCH 313/378] debug off --- src/hsp2/hsp2/HYDR.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 9f1428ae..5b97e581 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -152,10 +152,10 @@ def hydr(siminfo, parameters, ts, ftables, state): # 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) + #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("model_exec_list", model_exec_list) #print(state.domain, "HYDR called with", state.domain, len(model_exec_list), "op elements.") ####################################################################################### From 4d57370978b3c7006ee6cccb9a2e18f18644d3c4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 11:11:56 -0500 Subject: [PATCH 314/378] return on zero op type --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 4556b317..4ec145d9 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -731,7 +731,7 @@ def step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): # skip these - we could optimize performance and return assuming # that the first zero item is the end of the active components if op_tokens[i][0] == 0: - continue + return step_one(op_tokens, op_tokens[i], state_ix, dict_ix, ts_ix, step, 0) n = n + 1 return From 74701bd29217fe2a5448ff4d2a6ffc492ba042f6 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 11:22:35 -0500 Subject: [PATCH 315/378] return on -1 initialize op_lists as such --- src/hsp2/hsp2/om.py | 4 ++-- src/hsp2/state/state.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 4ec145d9..3a4e9016 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -729,8 +729,8 @@ 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 zero item is the end of the active components - if op_tokens[i][0] == 0: + # that the first -1 item is the end of the active components + if op_tokens[i][0] < 0: return step_one(op_tokens, op_tokens[i], state_ix, dict_ix, ts_ix, step, 0) n = n + 1 diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 3b9363fc..ae86b2a5 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -36,6 +36,7 @@ ("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), @@ -163,6 +164,7 @@ def __init__(self, state_ix, op_tokens, state_paths, op_exec_lists, model_exec_l self.domain = "" self.last_id = 0 self.hsp2_local_py = False + self.op_len = 64 # how wide is an op list array return @property @@ -200,7 +202,7 @@ def resize(self, debug=False): return if debug: print("op_tokens needs", ops_needed, "slots") - add_ops = zeros((ops_needed, 64)) + add_ops = np.full(self.op_len,-1) # fill with -1 # 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: From 46fb0af2b9ef908f780a14972b6153a8b7fc17b2 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 11:28:24 -0500 Subject: [PATCH 316/378] debug --- src/hsp2/hsp2/om_model_object.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index a5b8d959..fed4c2b9 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -141,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: From df32f757321d581b146ab5a373716c01bd517cf3 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 11:36:50 -0500 Subject: [PATCH 317/378] multi dim not scalar --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index fed4c2b9..b0c549d1 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -141,7 +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) + #print("Handling ops", ops) if ops[0] in ModelObject.runnables: run_ops[ops[1]] = ops if debug == True: From 35adb5fd922988bee3d43625f8ecb18c307ce237 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 11:37:50 -0500 Subject: [PATCH 318/378] multi dim not scalar --- src/hsp2/state/state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index ae86b2a5..4c24c881 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -202,7 +202,8 @@ def resize(self, debug=False): return if debug: print("op_tokens needs", ops_needed, "slots") - add_ops = np.full(self.op_len,-1) # fill with -1 + 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: From 058937f4a26e840aacb0ad1282987d73fcea2e54 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 11:39:38 -0500 Subject: [PATCH 319/378] check comparator efficiency --- src/hsp2/hsp2/om.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index 3a4e9016..ed8f9d53 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -730,7 +730,7 @@ def step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): 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] < 0: + 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 From 10254be4af2d4988cc0ae2983f78de20aeeb56fc Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 11:50:19 -0500 Subject: [PATCH 320/378] tiny withdrawal --- .../HSP2results/PL3_5250_0001.json.manyeq | 1000 ++++++++--------- 1 file changed, 500 insertions(+), 500 deletions(-) diff --git a/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq b/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq index f6d4b249..4eb8a9a0 100644 --- a/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq +++ b/tests/testcbp/HSP2results/PL3_5250_0001.json.manyeq @@ -6,2502 +6,2502 @@ "wd_1": { "name": "wd_1", "object_class": "Equation", - "value": "0.0 + 0.0" + "value": "0.02 + 0.0" }, "wd_2": { "name": "wd_2", "object_class": "Equation", - "value": "0.0 + wd_1" + "value": "0.02 + wd_1" }, "wd_3": { "name": "wd_3", "object_class": "Equation", - "value": "0.0 + wd_2" + "value": "0.02 + wd_2" }, "wd_4": { "name": "wd_4", "object_class": "Equation", - "value": "0.0 + wd_3" + "value": "0.02 + wd_3" }, "wd_5": { "name": "wd_5", "object_class": "Equation", - "value": "0.0 + wd_4" + "value": "0.02 + wd_4" }, "wd_6": { "name": "wd_6", "object_class": "Equation", - "value": "0.0 + wd_5" + "value": "0.02 + wd_5" }, "wd_7": { "name": "wd_7", "object_class": "Equation", - "value": "0.0 + wd_6" + "value": "0.02 + wd_6" }, "wd_8": { "name": "wd_8", "object_class": "Equation", - "value": "0.0 + wd_7" + "value": "0.02 + wd_7" }, "wd_9": { "name": "wd_9", "object_class": "Equation", - "value": "0.0 + wd_8" + "value": "0.02 + wd_8" }, "wd_10": { "name": "wd_10", "object_class": "Equation", - "value": "0.0 + wd_9" + "value": "0.02 + wd_9" }, "wd_11": { "name": "wd_11", "object_class": "Equation", - "value": "0.0 + wd_10" + "value": "0.02 + wd_10" }, "wd_12": { "name": "wd_12", "object_class": "Equation", - "value": "0.0 + wd_11" + "value": "0.02 + wd_11" }, "wd_13": { "name": "wd_13", "object_class": "Equation", - "value": "0.0 + wd_12" + "value": "0.02 + wd_12" }, "wd_14": { "name": "wd_14", "object_class": "Equation", - "value": "0.0 + wd_13" + "value": "0.02 + wd_13" }, "wd_15": { "name": "wd_15", "object_class": "Equation", - "value": "0.0 + wd_14" + "value": "0.02 + wd_14" }, "wd_16": { "name": "wd_16", "object_class": "Equation", - "value": "0.0 + wd_15" + "value": "0.02 + wd_15" }, "wd_17": { "name": "wd_17", "object_class": "Equation", - "value": "0.0 + wd_16" + "value": "0.02 + wd_16" }, "wd_18": { "name": "wd_18", "object_class": "Equation", - "value": "0.0 + wd_17" + "value": "0.02 + wd_17" }, "wd_19": { "name": "wd_19", "object_class": "Equation", - "value": "0.0 + wd_18" + "value": "0.02 + wd_18" }, "wd_20": { "name": "wd_20", "object_class": "Equation", - "value": "0.0 + wd_19" + "value": "0.02 + wd_19" }, "wd_21": { "name": "wd_21", "object_class": "Equation", - "value": "0.0 + wd_20" + "value": "0.02 + wd_20" }, "wd_22": { "name": "wd_22", "object_class": "Equation", - "value": "0.0 + wd_21" + "value": "0.02 + wd_21" }, "wd_23": { "name": "wd_23", "object_class": "Equation", - "value": "0.0 + wd_22" + "value": "0.02 + wd_22" }, "wd_24": { "name": "wd_24", "object_class": "Equation", - "value": "0.0 + wd_23" + "value": "0.02 + wd_23" }, "wd_25": { "name": "wd_25", "object_class": "Equation", - "value": "0.0 + wd_24" + "value": "0.02 + wd_24" }, "wd_26": { "name": "wd_26", "object_class": "Equation", - "value": "0.0 + wd_25" + "value": "0.02 + wd_25" }, "wd_27": { "name": "wd_27", "object_class": "Equation", - "value": "0.0 + wd_26" + "value": "0.02 + wd_26" }, "wd_28": { "name": "wd_28", "object_class": "Equation", - "value": "0.0 + wd_27" + "value": "0.02 + wd_27" }, "wd_29": { "name": "wd_29", "object_class": "Equation", - "value": "0.0 + wd_28" + "value": "0.02 + wd_28" }, "wd_30": { "name": "wd_30", "object_class": "Equation", - "value": "0.0 + wd_29" + "value": "0.02 + wd_29" }, "wd_31": { "name": "wd_31", "object_class": "Equation", - "value": "0.0 + wd_30" + "value": "0.02 + wd_30" }, "wd_32": { "name": "wd_32", "object_class": "Equation", - "value": "0.0 + wd_31" + "value": "0.02 + wd_31" }, "wd_33": { "name": "wd_33", "object_class": "Equation", - "value": "0.0 + wd_32" + "value": "0.02 + wd_32" }, "wd_34": { "name": "wd_34", "object_class": "Equation", - "value": "0.0 + wd_33" + "value": "0.02 + wd_33" }, "wd_35": { "name": "wd_35", "object_class": "Equation", - "value": "0.0 + wd_34" + "value": "0.02 + wd_34" }, "wd_36": { "name": "wd_36", "object_class": "Equation", - "value": "0.0 + wd_35" + "value": "0.02 + wd_35" }, "wd_37": { "name": "wd_37", "object_class": "Equation", - "value": "0.0 + wd_36" + "value": "0.02 + wd_36" }, "wd_38": { "name": "wd_38", "object_class": "Equation", - "value": "0.0 + wd_37" + "value": "0.02 + wd_37" }, "wd_39": { "name": "wd_39", "object_class": "Equation", - "value": "0.0 + wd_38" + "value": "0.02 + wd_38" }, "wd_40": { "name": "wd_40", "object_class": "Equation", - "value": "0.0 + wd_39" + "value": "0.02 + wd_39" }, "wd_41": { "name": "wd_41", "object_class": "Equation", - "value": "0.0 + wd_40" + "value": "0.02 + wd_40" }, "wd_42": { "name": "wd_42", "object_class": "Equation", - "value": "0.0 + wd_41" + "value": "0.02 + wd_41" }, "wd_43": { "name": "wd_43", "object_class": "Equation", - "value": "0.0 + wd_42" + "value": "0.02 + wd_42" }, "wd_44": { "name": "wd_44", "object_class": "Equation", - "value": "0.0 + wd_43" + "value": "0.02 + wd_43" }, "wd_45": { "name": "wd_45", "object_class": "Equation", - "value": "0.0 + wd_44" + "value": "0.02 + wd_44" }, "wd_46": { "name": "wd_46", "object_class": "Equation", - "value": "0.0 + wd_45" + "value": "0.02 + wd_45" }, "wd_47": { "name": "wd_47", "object_class": "Equation", - "value": "0.0 + wd_46" + "value": "0.02 + wd_46" }, "wd_48": { "name": "wd_48", "object_class": "Equation", - "value": "0.0 + wd_47" + "value": "0.02 + wd_47" }, "wd_49": { "name": "wd_49", "object_class": "Equation", - "value": "0.0 + wd_48" + "value": "0.02 + wd_48" }, "wd_50": { "name": "wd_50", "object_class": "Equation", - "value": "0.0 + wd_49" + "value": "0.02 + wd_49" }, "wd_51": { "name": "wd_51", "object_class": "Equation", - "value": "0.0 + wd_50" + "value": "0.02 + wd_50" }, "wd_52": { "name": "wd_52", "object_class": "Equation", - "value": "0.0 + wd_51" + "value": "0.02 + wd_51" }, "wd_53": { "name": "wd_53", "object_class": "Equation", - "value": "0.0 + wd_52" + "value": "0.02 + wd_52" }, "wd_54": { "name": "wd_54", "object_class": "Equation", - "value": "0.0 + wd_53" + "value": "0.02 + wd_53" }, "wd_55": { "name": "wd_55", "object_class": "Equation", - "value": "0.0 + wd_54" + "value": "0.02 + wd_54" }, "wd_56": { "name": "wd_56", "object_class": "Equation", - "value": "0.0 + wd_55" + "value": "0.02 + wd_55" }, "wd_57": { "name": "wd_57", "object_class": "Equation", - "value": "0.0 + wd_56" + "value": "0.02 + wd_56" }, "wd_58": { "name": "wd_58", "object_class": "Equation", - "value": "0.0 + wd_57" + "value": "0.02 + wd_57" }, "wd_59": { "name": "wd_59", "object_class": "Equation", - "value": "0.0 + wd_58" + "value": "0.02 + wd_58" }, "wd_60": { "name": "wd_60", "object_class": "Equation", - "value": "0.0 + wd_59" + "value": "0.02 + wd_59" }, "wd_61": { "name": "wd_61", "object_class": "Equation", - "value": "0.0 + wd_60" + "value": "0.02 + wd_60" }, "wd_62": { "name": "wd_62", "object_class": "Equation", - "value": "0.0 + wd_61" + "value": "0.02 + wd_61" }, "wd_63": { "name": "wd_63", "object_class": "Equation", - "value": "0.0 + wd_62" + "value": "0.02 + wd_62" }, "wd_64": { "name": "wd_64", "object_class": "Equation", - "value": "0.0 + wd_63" + "value": "0.02 + wd_63" }, "wd_65": { "name": "wd_65", "object_class": "Equation", - "value": "0.0 + wd_64" + "value": "0.02 + wd_64" }, "wd_66": { "name": "wd_66", "object_class": "Equation", - "value": "0.0 + wd_65" + "value": "0.02 + wd_65" }, "wd_67": { "name": "wd_67", "object_class": "Equation", - "value": "0.0 + wd_66" + "value": "0.02 + wd_66" }, "wd_68": { "name": "wd_68", "object_class": "Equation", - "value": "0.0 + wd_67" + "value": "0.02 + wd_67" }, "wd_69": { "name": "wd_69", "object_class": "Equation", - "value": "0.0 + wd_68" + "value": "0.02 + wd_68" }, "wd_70": { "name": "wd_70", "object_class": "Equation", - "value": "0.0 + wd_69" + "value": "0.02 + wd_69" }, "wd_71": { "name": "wd_71", "object_class": "Equation", - "value": "0.0 + wd_70" + "value": "0.02 + wd_70" }, "wd_72": { "name": "wd_72", "object_class": "Equation", - "value": "0.0 + wd_71" + "value": "0.02 + wd_71" }, "wd_73": { "name": "wd_73", "object_class": "Equation", - "value": "0.0 + wd_72" + "value": "0.02 + wd_72" }, "wd_74": { "name": "wd_74", "object_class": "Equation", - "value": "0.0 + wd_73" + "value": "0.02 + wd_73" }, "wd_75": { "name": "wd_75", "object_class": "Equation", - "value": "0.0 + wd_74" + "value": "0.02 + wd_74" }, "wd_76": { "name": "wd_76", "object_class": "Equation", - "value": "0.0 + wd_75" + "value": "0.02 + wd_75" }, "wd_77": { "name": "wd_77", "object_class": "Equation", - "value": "0.0 + wd_76" + "value": "0.02 + wd_76" }, "wd_78": { "name": "wd_78", "object_class": "Equation", - "value": "0.0 + wd_77" + "value": "0.02 + wd_77" }, "wd_79": { "name": "wd_79", "object_class": "Equation", - "value": "0.0 + wd_78" + "value": "0.02 + wd_78" }, "wd_80": { "name": "wd_80", "object_class": "Equation", - "value": "0.0 + wd_79" + "value": "0.02 + wd_79" }, "wd_81": { "name": "wd_81", "object_class": "Equation", - "value": "0.0 + wd_80" + "value": "0.02 + wd_80" }, "wd_82": { "name": "wd_82", "object_class": "Equation", - "value": "0.0 + wd_81" + "value": "0.02 + wd_81" }, "wd_83": { "name": "wd_83", "object_class": "Equation", - "value": "0.0 + wd_82" + "value": "0.02 + wd_82" }, "wd_84": { "name": "wd_84", "object_class": "Equation", - "value": "0.0 + wd_83" + "value": "0.02 + wd_83" }, "wd_85": { "name": "wd_85", "object_class": "Equation", - "value": "0.0 + wd_84" + "value": "0.02 + wd_84" }, "wd_86": { "name": "wd_86", "object_class": "Equation", - "value": "0.0 + wd_85" + "value": "0.02 + wd_85" }, "wd_87": { "name": "wd_87", "object_class": "Equation", - "value": "0.0 + wd_86" + "value": "0.02 + wd_86" }, "wd_88": { "name": "wd_88", "object_class": "Equation", - "value": "0.0 + wd_87" + "value": "0.02 + wd_87" }, "wd_89": { "name": "wd_89", "object_class": "Equation", - "value": "0.0 + wd_88" + "value": "0.02 + wd_88" }, "wd_90": { "name": "wd_90", "object_class": "Equation", - "value": "0.0 + wd_89" + "value": "0.02 + wd_89" }, "wd_91": { "name": "wd_91", "object_class": "Equation", - "value": "0.0 + wd_90" + "value": "0.02 + wd_90" }, "wd_92": { "name": "wd_92", "object_class": "Equation", - "value": "0.0 + wd_91" + "value": "0.02 + wd_91" }, "wd_93": { "name": "wd_93", "object_class": "Equation", - "value": "0.0 + wd_92" + "value": "0.02 + wd_92" }, "wd_94": { "name": "wd_94", "object_class": "Equation", - "value": "0.0 + wd_93" + "value": "0.02 + wd_93" }, "wd_95": { "name": "wd_95", "object_class": "Equation", - "value": "0.0 + wd_94" + "value": "0.02 + wd_94" }, "wd_96": { "name": "wd_96", "object_class": "Equation", - "value": "0.0 + wd_95" + "value": "0.02 + wd_95" }, "wd_97": { "name": "wd_97", "object_class": "Equation", - "value": "0.0 + wd_96" + "value": "0.02 + wd_96" }, "wd_98": { "name": "wd_98", "object_class": "Equation", - "value": "0.0 + wd_97" + "value": "0.02 + wd_97" }, "wd_99": { "name": "wd_99", "object_class": "Equation", - "value": "0.0 + wd_98" + "value": "0.02 + wd_98" }, "wd_100": { "name": "wd_100", "object_class": "Equation", - "value": "0.0 + wd_99" + "value": "0.02 + wd_99" }, "wd_101": { "name": "wd_101", "object_class": "Equation", - "value": "0.0 + wd_100" + "value": "0.02 + wd_100" }, "wd_102": { "name": "wd_102", "object_class": "Equation", - "value": "0.0 + wd_101" + "value": "0.02 + wd_101" }, "wd_103": { "name": "wd_103", "object_class": "Equation", - "value": "0.0 + wd_102" + "value": "0.02 + wd_102" }, "wd_104": { "name": "wd_104", "object_class": "Equation", - "value": "0.0 + wd_103" + "value": "0.02 + wd_103" }, "wd_105": { "name": "wd_105", "object_class": "Equation", - "value": "0.0 + wd_104" + "value": "0.02 + wd_104" }, "wd_106": { "name": "wd_106", "object_class": "Equation", - "value": "0.0 + wd_105" + "value": "0.02 + wd_105" }, "wd_107": { "name": "wd_107", "object_class": "Equation", - "value": "0.0 + wd_106" + "value": "0.02 + wd_106" }, "wd_108": { "name": "wd_108", "object_class": "Equation", - "value": "0.0 + wd_107" + "value": "0.02 + wd_107" }, "wd_109": { "name": "wd_109", "object_class": "Equation", - "value": "0.0 + wd_108" + "value": "0.02 + wd_108" }, "wd_110": { "name": "wd_110", "object_class": "Equation", - "value": "0.0 + wd_109" + "value": "0.02 + wd_109" }, "wd_111": { "name": "wd_111", "object_class": "Equation", - "value": "0.0 + wd_110" + "value": "0.02 + wd_110" }, "wd_112": { "name": "wd_112", "object_class": "Equation", - "value": "0.0 + wd_111" + "value": "0.02 + wd_111" }, "wd_113": { "name": "wd_113", "object_class": "Equation", - "value": "0.0 + wd_112" + "value": "0.02 + wd_112" }, "wd_114": { "name": "wd_114", "object_class": "Equation", - "value": "0.0 + wd_113" + "value": "0.02 + wd_113" }, "wd_115": { "name": "wd_115", "object_class": "Equation", - "value": "0.0 + wd_114" + "value": "0.02 + wd_114" }, "wd_116": { "name": "wd_116", "object_class": "Equation", - "value": "0.0 + wd_115" + "value": "0.02 + wd_115" }, "wd_117": { "name": "wd_117", "object_class": "Equation", - "value": "0.0 + wd_116" + "value": "0.02 + wd_116" }, "wd_118": { "name": "wd_118", "object_class": "Equation", - "value": "0.0 + wd_117" + "value": "0.02 + wd_117" }, "wd_119": { "name": "wd_119", "object_class": "Equation", - "value": "0.0 + wd_118" + "value": "0.02 + wd_118" }, "wd_120": { "name": "wd_120", "object_class": "Equation", - "value": "0.0 + wd_119" + "value": "0.02 + wd_119" }, "wd_121": { "name": "wd_121", "object_class": "Equation", - "value": "0.0 + wd_120" + "value": "0.02 + wd_120" }, "wd_122": { "name": "wd_122", "object_class": "Equation", - "value": "0.0 + wd_121" + "value": "0.02 + wd_121" }, "wd_123": { "name": "wd_123", "object_class": "Equation", - "value": "0.0 + wd_122" + "value": "0.02 + wd_122" }, "wd_124": { "name": "wd_124", "object_class": "Equation", - "value": "0.0 + wd_123" + "value": "0.02 + wd_123" }, "wd_125": { "name": "wd_125", "object_class": "Equation", - "value": "0.0 + wd_124" + "value": "0.02 + wd_124" }, "wd_126": { "name": "wd_126", "object_class": "Equation", - "value": "0.0 + wd_125" + "value": "0.02 + wd_125" }, "wd_127": { "name": "wd_127", "object_class": "Equation", - "value": "0.0 + wd_126" + "value": "0.02 + wd_126" }, "wd_128": { "name": "wd_128", "object_class": "Equation", - "value": "0.0 + wd_127" + "value": "0.02 + wd_127" }, "wd_129": { "name": "wd_129", "object_class": "Equation", - "value": "0.0 + wd_128" + "value": "0.02 + wd_128" }, "wd_130": { "name": "wd_130", "object_class": "Equation", - "value": "0.0 + wd_129" + "value": "0.02 + wd_129" }, "wd_131": { "name": "wd_131", "object_class": "Equation", - "value": "0.0 + wd_130" + "value": "0.02 + wd_130" }, "wd_132": { "name": "wd_132", "object_class": "Equation", - "value": "0.0 + wd_131" + "value": "0.02 + wd_131" }, "wd_133": { "name": "wd_133", "object_class": "Equation", - "value": "0.0 + wd_132" + "value": "0.02 + wd_132" }, "wd_134": { "name": "wd_134", "object_class": "Equation", - "value": "0.0 + wd_133" + "value": "0.02 + wd_133" }, "wd_135": { "name": "wd_135", "object_class": "Equation", - "value": "0.0 + wd_134" + "value": "0.02 + wd_134" }, "wd_136": { "name": "wd_136", "object_class": "Equation", - "value": "0.0 + wd_135" + "value": "0.02 + wd_135" }, "wd_137": { "name": "wd_137", "object_class": "Equation", - "value": "0.0 + wd_136" + "value": "0.02 + wd_136" }, "wd_138": { "name": "wd_138", "object_class": "Equation", - "value": "0.0 + wd_137" + "value": "0.02 + wd_137" }, "wd_139": { "name": "wd_139", "object_class": "Equation", - "value": "0.0 + wd_138" + "value": "0.02 + wd_138" }, "wd_140": { "name": "wd_140", "object_class": "Equation", - "value": "0.0 + wd_139" + "value": "0.02 + wd_139" }, "wd_141": { "name": "wd_141", "object_class": "Equation", - "value": "0.0 + wd_140" + "value": "0.02 + wd_140" }, "wd_142": { "name": "wd_142", "object_class": "Equation", - "value": "0.0 + wd_141" + "value": "0.02 + wd_141" }, "wd_143": { "name": "wd_143", "object_class": "Equation", - "value": "0.0 + wd_142" + "value": "0.02 + wd_142" }, "wd_144": { "name": "wd_144", "object_class": "Equation", - "value": "0.0 + wd_143" + "value": "0.02 + wd_143" }, "wd_145": { "name": "wd_145", "object_class": "Equation", - "value": "0.0 + wd_144" + "value": "0.02 + wd_144" }, "wd_146": { "name": "wd_146", "object_class": "Equation", - "value": "0.0 + wd_145" + "value": "0.02 + wd_145" }, "wd_147": { "name": "wd_147", "object_class": "Equation", - "value": "0.0 + wd_146" + "value": "0.02 + wd_146" }, "wd_148": { "name": "wd_148", "object_class": "Equation", - "value": "0.0 + wd_147" + "value": "0.02 + wd_147" }, "wd_149": { "name": "wd_149", "object_class": "Equation", - "value": "0.0 + wd_148" + "value": "0.02 + wd_148" }, "wd_150": { "name": "wd_150", "object_class": "Equation", - "value": "0.0 + wd_149" + "value": "0.02 + wd_149" }, "wd_151": { "name": "wd_151", "object_class": "Equation", - "value": "0.0 + wd_150" + "value": "0.02 + wd_150" }, "wd_152": { "name": "wd_152", "object_class": "Equation", - "value": "0.0 + wd_151" + "value": "0.02 + wd_151" }, "wd_153": { "name": "wd_153", "object_class": "Equation", - "value": "0.0 + wd_152" + "value": "0.02 + wd_152" }, "wd_154": { "name": "wd_154", "object_class": "Equation", - "value": "0.0 + wd_153" + "value": "0.02 + wd_153" }, "wd_155": { "name": "wd_155", "object_class": "Equation", - "value": "0.0 + wd_154" + "value": "0.02 + wd_154" }, "wd_156": { "name": "wd_156", "object_class": "Equation", - "value": "0.0 + wd_155" + "value": "0.02 + wd_155" }, "wd_157": { "name": "wd_157", "object_class": "Equation", - "value": "0.0 + wd_156" + "value": "0.02 + wd_156" }, "wd_158": { "name": "wd_158", "object_class": "Equation", - "value": "0.0 + wd_157" + "value": "0.02 + wd_157" }, "wd_159": { "name": "wd_159", "object_class": "Equation", - "value": "0.0 + wd_158" + "value": "0.02 + wd_158" }, "wd_160": { "name": "wd_160", "object_class": "Equation", - "value": "0.0 + wd_159" + "value": "0.02 + wd_159" }, "wd_161": { "name": "wd_161", "object_class": "Equation", - "value": "0.0 + wd_160" + "value": "0.02 + wd_160" }, "wd_162": { "name": "wd_162", "object_class": "Equation", - "value": "0.0 + wd_161" + "value": "0.02 + wd_161" }, "wd_163": { "name": "wd_163", "object_class": "Equation", - "value": "0.0 + wd_162" + "value": "0.02 + wd_162" }, "wd_164": { "name": "wd_164", "object_class": "Equation", - "value": "0.0 + wd_163" + "value": "0.02 + wd_163" }, "wd_165": { "name": "wd_165", "object_class": "Equation", - "value": "0.0 + wd_164" + "value": "0.02 + wd_164" }, "wd_166": { "name": "wd_166", "object_class": "Equation", - "value": "0.0 + wd_165" + "value": "0.02 + wd_165" }, "wd_167": { "name": "wd_167", "object_class": "Equation", - "value": "0.0 + wd_166" + "value": "0.02 + wd_166" }, "wd_168": { "name": "wd_168", "object_class": "Equation", - "value": "0.0 + wd_167" + "value": "0.02 + wd_167" }, "wd_169": { "name": "wd_169", "object_class": "Equation", - "value": "0.0 + wd_168" + "value": "0.02 + wd_168" }, "wd_170": { "name": "wd_170", "object_class": "Equation", - "value": "0.0 + wd_169" + "value": "0.02 + wd_169" }, "wd_171": { "name": "wd_171", "object_class": "Equation", - "value": "0.0 + wd_170" + "value": "0.02 + wd_170" }, "wd_172": { "name": "wd_172", "object_class": "Equation", - "value": "0.0 + wd_171" + "value": "0.02 + wd_171" }, "wd_173": { "name": "wd_173", "object_class": "Equation", - "value": "0.0 + wd_172" + "value": "0.02 + wd_172" }, "wd_174": { "name": "wd_174", "object_class": "Equation", - "value": "0.0 + wd_173" + "value": "0.02 + wd_173" }, "wd_175": { "name": "wd_175", "object_class": "Equation", - "value": "0.0 + wd_174" + "value": "0.02 + wd_174" }, "wd_176": { "name": "wd_176", "object_class": "Equation", - "value": "0.0 + wd_175" + "value": "0.02 + wd_175" }, "wd_177": { "name": "wd_177", "object_class": "Equation", - "value": "0.0 + wd_176" + "value": "0.02 + wd_176" }, "wd_178": { "name": "wd_178", "object_class": "Equation", - "value": "0.0 + wd_177" + "value": "0.02 + wd_177" }, "wd_179": { "name": "wd_179", "object_class": "Equation", - "value": "0.0 + wd_178" + "value": "0.02 + wd_178" }, "wd_180": { "name": "wd_180", "object_class": "Equation", - "value": "0.0 + wd_179" + "value": "0.02 + wd_179" }, "wd_181": { "name": "wd_181", "object_class": "Equation", - "value": "0.0 + wd_180" + "value": "0.02 + wd_180" }, "wd_182": { "name": "wd_182", "object_class": "Equation", - "value": "0.0 + wd_181" + "value": "0.02 + wd_181" }, "wd_183": { "name": "wd_183", "object_class": "Equation", - "value": "0.0 + wd_182" + "value": "0.02 + wd_182" }, "wd_184": { "name": "wd_184", "object_class": "Equation", - "value": "0.0 + wd_183" + "value": "0.02 + wd_183" }, "wd_185": { "name": "wd_185", "object_class": "Equation", - "value": "0.0 + wd_184" + "value": "0.02 + wd_184" }, "wd_186": { "name": "wd_186", "object_class": "Equation", - "value": "0.0 + wd_185" + "value": "0.02 + wd_185" }, "wd_187": { "name": "wd_187", "object_class": "Equation", - "value": "0.0 + wd_186" + "value": "0.02 + wd_186" }, "wd_188": { "name": "wd_188", "object_class": "Equation", - "value": "0.0 + wd_187" + "value": "0.02 + wd_187" }, "wd_189": { "name": "wd_189", "object_class": "Equation", - "value": "0.0 + wd_188" + "value": "0.02 + wd_188" }, "wd_190": { "name": "wd_190", "object_class": "Equation", - "value": "0.0 + wd_189" + "value": "0.02 + wd_189" }, "wd_191": { "name": "wd_191", "object_class": "Equation", - "value": "0.0 + wd_190" + "value": "0.02 + wd_190" }, "wd_192": { "name": "wd_192", "object_class": "Equation", - "value": "0.0 + wd_191" + "value": "0.02 + wd_191" }, "wd_193": { "name": "wd_193", "object_class": "Equation", - "value": "0.0 + wd_192" + "value": "0.02 + wd_192" }, "wd_194": { "name": "wd_194", "object_class": "Equation", - "value": "0.0 + wd_193" + "value": "0.02 + wd_193" }, "wd_195": { "name": "wd_195", "object_class": "Equation", - "value": "0.0 + wd_194" + "value": "0.02 + wd_194" }, "wd_196": { "name": "wd_196", "object_class": "Equation", - "value": "0.0 + wd_195" + "value": "0.02 + wd_195" }, "wd_197": { "name": "wd_197", "object_class": "Equation", - "value": "0.0 + wd_196" + "value": "0.02 + wd_196" }, "wd_198": { "name": "wd_198", "object_class": "Equation", - "value": "0.0 + wd_197" + "value": "0.02 + wd_197" }, "wd_199": { "name": "wd_199", "object_class": "Equation", - "value": "0.0 + wd_198" + "value": "0.02 + wd_198" }, "wd_200": { "name": "wd_200", "object_class": "Equation", - "value": "0.0 + wd_199" + "value": "0.02 + wd_199" }, "wd_201": { "name": "wd_201", "object_class": "Equation", - "value": "0.0 + wd_200" + "value": "0.02 + wd_200" }, "wd_202": { "name": "wd_202", "object_class": "Equation", - "value": "0.0 + wd_201" + "value": "0.02 + wd_201" }, "wd_203": { "name": "wd_203", "object_class": "Equation", - "value": "0.0 + wd_202" + "value": "0.02 + wd_202" }, "wd_204": { "name": "wd_204", "object_class": "Equation", - "value": "0.0 + wd_203" + "value": "0.02 + wd_203" }, "wd_205": { "name": "wd_205", "object_class": "Equation", - "value": "0.0 + wd_204" + "value": "0.02 + wd_204" }, "wd_206": { "name": "wd_206", "object_class": "Equation", - "value": "0.0 + wd_205" + "value": "0.02 + wd_205" }, "wd_207": { "name": "wd_207", "object_class": "Equation", - "value": "0.0 + wd_206" + "value": "0.02 + wd_206" }, "wd_208": { "name": "wd_208", "object_class": "Equation", - "value": "0.0 + wd_207" + "value": "0.02 + wd_207" }, "wd_209": { "name": "wd_209", "object_class": "Equation", - "value": "0.0 + wd_208" + "value": "0.02 + wd_208" }, "wd_210": { "name": "wd_210", "object_class": "Equation", - "value": "0.0 + wd_209" + "value": "0.02 + wd_209" }, "wd_211": { "name": "wd_211", "object_class": "Equation", - "value": "0.0 + wd_210" + "value": "0.02 + wd_210" }, "wd_212": { "name": "wd_212", "object_class": "Equation", - "value": "0.0 + wd_211" + "value": "0.02 + wd_211" }, "wd_213": { "name": "wd_213", "object_class": "Equation", - "value": "0.0 + wd_212" + "value": "0.02 + wd_212" }, "wd_214": { "name": "wd_214", "object_class": "Equation", - "value": "0.0 + wd_213" + "value": "0.02 + wd_213" }, "wd_215": { "name": "wd_215", "object_class": "Equation", - "value": "0.0 + wd_214" + "value": "0.02 + wd_214" }, "wd_216": { "name": "wd_216", "object_class": "Equation", - "value": "0.0 + wd_215" + "value": "0.02 + wd_215" }, "wd_217": { "name": "wd_217", "object_class": "Equation", - "value": "0.0 + wd_216" + "value": "0.02 + wd_216" }, "wd_218": { "name": "wd_218", "object_class": "Equation", - "value": "0.0 + wd_217" + "value": "0.02 + wd_217" }, "wd_219": { "name": "wd_219", "object_class": "Equation", - "value": "0.0 + wd_218" + "value": "0.02 + wd_218" }, "wd_220": { "name": "wd_220", "object_class": "Equation", - "value": "0.0 + wd_219" + "value": "0.02 + wd_219" }, "wd_221": { "name": "wd_221", "object_class": "Equation", - "value": "0.0 + wd_220" + "value": "0.02 + wd_220" }, "wd_222": { "name": "wd_222", "object_class": "Equation", - "value": "0.0 + wd_221" + "value": "0.02 + wd_221" }, "wd_223": { "name": "wd_223", "object_class": "Equation", - "value": "0.0 + wd_222" + "value": "0.02 + wd_222" }, "wd_224": { "name": "wd_224", "object_class": "Equation", - "value": "0.0 + wd_223" + "value": "0.02 + wd_223" }, "wd_225": { "name": "wd_225", "object_class": "Equation", - "value": "0.0 + wd_224" + "value": "0.02 + wd_224" }, "wd_226": { "name": "wd_226", "object_class": "Equation", - "value": "0.0 + wd_225" + "value": "0.02 + wd_225" }, "wd_227": { "name": "wd_227", "object_class": "Equation", - "value": "0.0 + wd_226" + "value": "0.02 + wd_226" }, "wd_228": { "name": "wd_228", "object_class": "Equation", - "value": "0.0 + wd_227" + "value": "0.02 + wd_227" }, "wd_229": { "name": "wd_229", "object_class": "Equation", - "value": "0.0 + wd_228" + "value": "0.02 + wd_228" }, "wd_230": { "name": "wd_230", "object_class": "Equation", - "value": "0.0 + wd_229" + "value": "0.02 + wd_229" }, "wd_231": { "name": "wd_231", "object_class": "Equation", - "value": "0.0 + wd_230" + "value": "0.02 + wd_230" }, "wd_232": { "name": "wd_232", "object_class": "Equation", - "value": "0.0 + wd_231" + "value": "0.02 + wd_231" }, "wd_233": { "name": "wd_233", "object_class": "Equation", - "value": "0.0 + wd_232" + "value": "0.02 + wd_232" }, "wd_234": { "name": "wd_234", "object_class": "Equation", - "value": "0.0 + wd_233" + "value": "0.02 + wd_233" }, "wd_235": { "name": "wd_235", "object_class": "Equation", - "value": "0.0 + wd_234" + "value": "0.02 + wd_234" }, "wd_236": { "name": "wd_236", "object_class": "Equation", - "value": "0.0 + wd_235" + "value": "0.02 + wd_235" }, "wd_237": { "name": "wd_237", "object_class": "Equation", - "value": "0.0 + wd_236" + "value": "0.02 + wd_236" }, "wd_238": { "name": "wd_238", "object_class": "Equation", - "value": "0.0 + wd_237" + "value": "0.02 + wd_237" }, "wd_239": { "name": "wd_239", "object_class": "Equation", - "value": "0.0 + wd_238" + "value": "0.02 + wd_238" }, "wd_240": { "name": "wd_240", "object_class": "Equation", - "value": "0.0 + wd_239" + "value": "0.02 + wd_239" }, "wd_241": { "name": "wd_241", "object_class": "Equation", - "value": "0.0 + wd_240" + "value": "0.02 + wd_240" }, "wd_242": { "name": "wd_242", "object_class": "Equation", - "value": "0.0 + wd_241" + "value": "0.02 + wd_241" }, "wd_243": { "name": "wd_243", "object_class": "Equation", - "value": "0.0 + wd_242" + "value": "0.02 + wd_242" }, "wd_244": { "name": "wd_244", "object_class": "Equation", - "value": "0.0 + wd_243" + "value": "0.02 + wd_243" }, "wd_245": { "name": "wd_245", "object_class": "Equation", - "value": "0.0 + wd_244" + "value": "0.02 + wd_244" }, "wd_246": { "name": "wd_246", "object_class": "Equation", - "value": "0.0 + wd_245" + "value": "0.02 + wd_245" }, "wd_247": { "name": "wd_247", "object_class": "Equation", - "value": "0.0 + wd_246" + "value": "0.02 + wd_246" }, "wd_248": { "name": "wd_248", "object_class": "Equation", - "value": "0.0 + wd_247" + "value": "0.02 + wd_247" }, "wd_249": { "name": "wd_249", "object_class": "Equation", - "value": "0.0 + wd_248" + "value": "0.02 + wd_248" }, "wd_250": { "name": "wd_250", "object_class": "Equation", - "value": "0.0 + wd_249" + "value": "0.02 + wd_249" }, "wd_251": { "name": "wd_251", "object_class": "Equation", - "value": "0.0 + wd_250" + "value": "0.02 + wd_250" }, "wd_252": { "name": "wd_252", "object_class": "Equation", - "value": "0.0 + wd_251" + "value": "0.02 + wd_251" }, "wd_253": { "name": "wd_253", "object_class": "Equation", - "value": "0.0 + wd_252" + "value": "0.02 + wd_252" }, "wd_254": { "name": "wd_254", "object_class": "Equation", - "value": "0.0 + wd_253" + "value": "0.02 + wd_253" }, "wd_255": { "name": "wd_255", "object_class": "Equation", - "value": "0.0 + wd_254" + "value": "0.02 + wd_254" }, "wd_256": { "name": "wd_256", "object_class": "Equation", - "value": "0.0 + wd_255" + "value": "0.02 + wd_255" }, "wd_257": { "name": "wd_257", "object_class": "Equation", - "value": "0.0 + wd_256" + "value": "0.02 + wd_256" }, "wd_258": { "name": "wd_258", "object_class": "Equation", - "value": "0.0 + wd_257" + "value": "0.02 + wd_257" }, "wd_259": { "name": "wd_259", "object_class": "Equation", - "value": "0.0 + wd_258" + "value": "0.02 + wd_258" }, "wd_260": { "name": "wd_260", "object_class": "Equation", - "value": "0.0 + wd_259" + "value": "0.02 + wd_259" }, "wd_261": { "name": "wd_261", "object_class": "Equation", - "value": "0.0 + wd_260" + "value": "0.02 + wd_260" }, "wd_262": { "name": "wd_262", "object_class": "Equation", - "value": "0.0 + wd_261" + "value": "0.02 + wd_261" }, "wd_263": { "name": "wd_263", "object_class": "Equation", - "value": "0.0 + wd_262" + "value": "0.02 + wd_262" }, "wd_264": { "name": "wd_264", "object_class": "Equation", - "value": "0.0 + wd_263" + "value": "0.02 + wd_263" }, "wd_265": { "name": "wd_265", "object_class": "Equation", - "value": "0.0 + wd_264" + "value": "0.02 + wd_264" }, "wd_266": { "name": "wd_266", "object_class": "Equation", - "value": "0.0 + wd_265" + "value": "0.02 + wd_265" }, "wd_267": { "name": "wd_267", "object_class": "Equation", - "value": "0.0 + wd_266" + "value": "0.02 + wd_266" }, "wd_268": { "name": "wd_268", "object_class": "Equation", - "value": "0.0 + wd_267" + "value": "0.02 + wd_267" }, "wd_269": { "name": "wd_269", "object_class": "Equation", - "value": "0.0 + wd_268" + "value": "0.02 + wd_268" }, "wd_270": { "name": "wd_270", "object_class": "Equation", - "value": "0.0 + wd_269" + "value": "0.02 + wd_269" }, "wd_271": { "name": "wd_271", "object_class": "Equation", - "value": "0.0 + wd_270" + "value": "0.02 + wd_270" }, "wd_272": { "name": "wd_272", "object_class": "Equation", - "value": "0.0 + wd_271" + "value": "0.02 + wd_271" }, "wd_273": { "name": "wd_273", "object_class": "Equation", - "value": "0.0 + wd_272" + "value": "0.02 + wd_272" }, "wd_274": { "name": "wd_274", "object_class": "Equation", - "value": "0.0 + wd_273" + "value": "0.02 + wd_273" }, "wd_275": { "name": "wd_275", "object_class": "Equation", - "value": "0.0 + wd_274" + "value": "0.02 + wd_274" }, "wd_276": { "name": "wd_276", "object_class": "Equation", - "value": "0.0 + wd_275" + "value": "0.02 + wd_275" }, "wd_277": { "name": "wd_277", "object_class": "Equation", - "value": "0.0 + wd_276" + "value": "0.02 + wd_276" }, "wd_278": { "name": "wd_278", "object_class": "Equation", - "value": "0.0 + wd_277" + "value": "0.02 + wd_277" }, "wd_279": { "name": "wd_279", "object_class": "Equation", - "value": "0.0 + wd_278" + "value": "0.02 + wd_278" }, "wd_280": { "name": "wd_280", "object_class": "Equation", - "value": "0.0 + wd_279" + "value": "0.02 + wd_279" }, "wd_281": { "name": "wd_281", "object_class": "Equation", - "value": "0.0 + wd_280" + "value": "0.02 + wd_280" }, "wd_282": { "name": "wd_282", "object_class": "Equation", - "value": "0.0 + wd_281" + "value": "0.02 + wd_281" }, "wd_283": { "name": "wd_283", "object_class": "Equation", - "value": "0.0 + wd_282" + "value": "0.02 + wd_282" }, "wd_284": { "name": "wd_284", "object_class": "Equation", - "value": "0.0 + wd_283" + "value": "0.02 + wd_283" }, "wd_285": { "name": "wd_285", "object_class": "Equation", - "value": "0.0 + wd_284" + "value": "0.02 + wd_284" }, "wd_286": { "name": "wd_286", "object_class": "Equation", - "value": "0.0 + wd_285" + "value": "0.02 + wd_285" }, "wd_287": { "name": "wd_287", "object_class": "Equation", - "value": "0.0 + wd_286" + "value": "0.02 + wd_286" }, "wd_288": { "name": "wd_288", "object_class": "Equation", - "value": "0.0 + wd_287" + "value": "0.02 + wd_287" }, "wd_289": { "name": "wd_289", "object_class": "Equation", - "value": "0.0 + wd_288" + "value": "0.02 + wd_288" }, "wd_290": { "name": "wd_290", "object_class": "Equation", - "value": "0.0 + wd_289" + "value": "0.02 + wd_289" }, "wd_291": { "name": "wd_291", "object_class": "Equation", - "value": "0.0 + wd_290" + "value": "0.02 + wd_290" }, "wd_292": { "name": "wd_292", "object_class": "Equation", - "value": "0.0 + wd_291" + "value": "0.02 + wd_291" }, "wd_293": { "name": "wd_293", "object_class": "Equation", - "value": "0.0 + wd_292" + "value": "0.02 + wd_292" }, "wd_294": { "name": "wd_294", "object_class": "Equation", - "value": "0.0 + wd_293" + "value": "0.02 + wd_293" }, "wd_295": { "name": "wd_295", "object_class": "Equation", - "value": "0.0 + wd_294" + "value": "0.02 + wd_294" }, "wd_296": { "name": "wd_296", "object_class": "Equation", - "value": "0.0 + wd_295" + "value": "0.02 + wd_295" }, "wd_297": { "name": "wd_297", "object_class": "Equation", - "value": "0.0 + wd_296" + "value": "0.02 + wd_296" }, "wd_298": { "name": "wd_298", "object_class": "Equation", - "value": "0.0 + wd_297" + "value": "0.02 + wd_297" }, "wd_299": { "name": "wd_299", "object_class": "Equation", - "value": "0.0 + wd_298" + "value": "0.02 + wd_298" }, "wd_300": { "name": "wd_300", "object_class": "Equation", - "value": "0.0 + wd_299" + "value": "0.02 + wd_299" }, "wd_301": { "name": "wd_301", "object_class": "Equation", - "value": "0.0 + wd_300" + "value": "0.02 + wd_300" }, "wd_302": { "name": "wd_302", "object_class": "Equation", - "value": "0.0 + wd_301" + "value": "0.02 + wd_301" }, "wd_303": { "name": "wd_303", "object_class": "Equation", - "value": "0.0 + wd_302" + "value": "0.02 + wd_302" }, "wd_304": { "name": "wd_304", "object_class": "Equation", - "value": "0.0 + wd_303" + "value": "0.02 + wd_303" }, "wd_305": { "name": "wd_305", "object_class": "Equation", - "value": "0.0 + wd_304" + "value": "0.02 + wd_304" }, "wd_306": { "name": "wd_306", "object_class": "Equation", - "value": "0.0 + wd_305" + "value": "0.02 + wd_305" }, "wd_307": { "name": "wd_307", "object_class": "Equation", - "value": "0.0 + wd_306" + "value": "0.02 + wd_306" }, "wd_308": { "name": "wd_308", "object_class": "Equation", - "value": "0.0 + wd_307" + "value": "0.02 + wd_307" }, "wd_309": { "name": "wd_309", "object_class": "Equation", - "value": "0.0 + wd_308" + "value": "0.02 + wd_308" }, "wd_310": { "name": "wd_310", "object_class": "Equation", - "value": "0.0 + wd_309" + "value": "0.02 + wd_309" }, "wd_311": { "name": "wd_311", "object_class": "Equation", - "value": "0.0 + wd_310" + "value": "0.02 + wd_310" }, "wd_312": { "name": "wd_312", "object_class": "Equation", - "value": "0.0 + wd_311" + "value": "0.02 + wd_311" }, "wd_313": { "name": "wd_313", "object_class": "Equation", - "value": "0.0 + wd_312" + "value": "0.02 + wd_312" }, "wd_314": { "name": "wd_314", "object_class": "Equation", - "value": "0.0 + wd_313" + "value": "0.02 + wd_313" }, "wd_315": { "name": "wd_315", "object_class": "Equation", - "value": "0.0 + wd_314" + "value": "0.02 + wd_314" }, "wd_316": { "name": "wd_316", "object_class": "Equation", - "value": "0.0 + wd_315" + "value": "0.02 + wd_315" }, "wd_317": { "name": "wd_317", "object_class": "Equation", - "value": "0.0 + wd_316" + "value": "0.02 + wd_316" }, "wd_318": { "name": "wd_318", "object_class": "Equation", - "value": "0.0 + wd_317" + "value": "0.02 + wd_317" }, "wd_319": { "name": "wd_319", "object_class": "Equation", - "value": "0.0 + wd_318" + "value": "0.02 + wd_318" }, "wd_320": { "name": "wd_320", "object_class": "Equation", - "value": "0.0 + wd_319" + "value": "0.02 + wd_319" }, "wd_321": { "name": "wd_321", "object_class": "Equation", - "value": "0.0 + wd_320" + "value": "0.02 + wd_320" }, "wd_322": { "name": "wd_322", "object_class": "Equation", - "value": "0.0 + wd_321" + "value": "0.02 + wd_321" }, "wd_323": { "name": "wd_323", "object_class": "Equation", - "value": "0.0 + wd_322" + "value": "0.02 + wd_322" }, "wd_324": { "name": "wd_324", "object_class": "Equation", - "value": "0.0 + wd_323" + "value": "0.02 + wd_323" }, "wd_325": { "name": "wd_325", "object_class": "Equation", - "value": "0.0 + wd_324" + "value": "0.02 + wd_324" }, "wd_326": { "name": "wd_326", "object_class": "Equation", - "value": "0.0 + wd_325" + "value": "0.02 + wd_325" }, "wd_327": { "name": "wd_327", "object_class": "Equation", - "value": "0.0 + wd_326" + "value": "0.02 + wd_326" }, "wd_328": { "name": "wd_328", "object_class": "Equation", - "value": "0.0 + wd_327" + "value": "0.02 + wd_327" }, "wd_329": { "name": "wd_329", "object_class": "Equation", - "value": "0.0 + wd_328" + "value": "0.02 + wd_328" }, "wd_330": { "name": "wd_330", "object_class": "Equation", - "value": "0.0 + wd_329" + "value": "0.02 + wd_329" }, "wd_331": { "name": "wd_331", "object_class": "Equation", - "value": "0.0 + wd_330" + "value": "0.02 + wd_330" }, "wd_332": { "name": "wd_332", "object_class": "Equation", - "value": "0.0 + wd_331" + "value": "0.02 + wd_331" }, "wd_333": { "name": "wd_333", "object_class": "Equation", - "value": "0.0 + wd_332" + "value": "0.02 + wd_332" }, "wd_334": { "name": "wd_334", "object_class": "Equation", - "value": "0.0 + wd_333" + "value": "0.02 + wd_333" }, "wd_335": { "name": "wd_335", "object_class": "Equation", - "value": "0.0 + wd_334" + "value": "0.02 + wd_334" }, "wd_336": { "name": "wd_336", "object_class": "Equation", - "value": "0.0 + wd_335" + "value": "0.02 + wd_335" }, "wd_337": { "name": "wd_337", "object_class": "Equation", - "value": "0.0 + wd_336" + "value": "0.02 + wd_336" }, "wd_338": { "name": "wd_338", "object_class": "Equation", - "value": "0.0 + wd_337" + "value": "0.02 + wd_337" }, "wd_339": { "name": "wd_339", "object_class": "Equation", - "value": "0.0 + wd_338" + "value": "0.02 + wd_338" }, "wd_340": { "name": "wd_340", "object_class": "Equation", - "value": "0.0 + wd_339" + "value": "0.02 + wd_339" }, "wd_341": { "name": "wd_341", "object_class": "Equation", - "value": "0.0 + wd_340" + "value": "0.02 + wd_340" }, "wd_342": { "name": "wd_342", "object_class": "Equation", - "value": "0.0 + wd_341" + "value": "0.02 + wd_341" }, "wd_343": { "name": "wd_343", "object_class": "Equation", - "value": "0.0 + wd_342" + "value": "0.02 + wd_342" }, "wd_344": { "name": "wd_344", "object_class": "Equation", - "value": "0.0 + wd_343" + "value": "0.02 + wd_343" }, "wd_345": { "name": "wd_345", "object_class": "Equation", - "value": "0.0 + wd_344" + "value": "0.02 + wd_344" }, "wd_346": { "name": "wd_346", "object_class": "Equation", - "value": "0.0 + wd_345" + "value": "0.02 + wd_345" }, "wd_347": { "name": "wd_347", "object_class": "Equation", - "value": "0.0 + wd_346" + "value": "0.02 + wd_346" }, "wd_348": { "name": "wd_348", "object_class": "Equation", - "value": "0.0 + wd_347" + "value": "0.02 + wd_347" }, "wd_349": { "name": "wd_349", "object_class": "Equation", - "value": "0.0 + wd_348" + "value": "0.02 + wd_348" }, "wd_350": { "name": "wd_350", "object_class": "Equation", - "value": "0.0 + wd_349" + "value": "0.02 + wd_349" }, "wd_351": { "name": "wd_351", "object_class": "Equation", - "value": "0.0 + wd_350" + "value": "0.02 + wd_350" }, "wd_352": { "name": "wd_352", "object_class": "Equation", - "value": "0.0 + wd_351" + "value": "0.02 + wd_351" }, "wd_353": { "name": "wd_353", "object_class": "Equation", - "value": "0.0 + wd_352" + "value": "0.02 + wd_352" }, "wd_354": { "name": "wd_354", "object_class": "Equation", - "value": "0.0 + wd_353" + "value": "0.02 + wd_353" }, "wd_355": { "name": "wd_355", "object_class": "Equation", - "value": "0.0 + wd_354" + "value": "0.02 + wd_354" }, "wd_356": { "name": "wd_356", "object_class": "Equation", - "value": "0.0 + wd_355" + "value": "0.02 + wd_355" }, "wd_357": { "name": "wd_357", "object_class": "Equation", - "value": "0.0 + wd_356" + "value": "0.02 + wd_356" }, "wd_358": { "name": "wd_358", "object_class": "Equation", - "value": "0.0 + wd_357" + "value": "0.02 + wd_357" }, "wd_359": { "name": "wd_359", "object_class": "Equation", - "value": "0.0 + wd_358" + "value": "0.02 + wd_358" }, "wd_360": { "name": "wd_360", "object_class": "Equation", - "value": "0.0 + wd_359" + "value": "0.02 + wd_359" }, "wd_361": { "name": "wd_361", "object_class": "Equation", - "value": "0.0 + wd_360" + "value": "0.02 + wd_360" }, "wd_362": { "name": "wd_362", "object_class": "Equation", - "value": "0.0 + wd_361" + "value": "0.02 + wd_361" }, "wd_363": { "name": "wd_363", "object_class": "Equation", - "value": "0.0 + wd_362" + "value": "0.02 + wd_362" }, "wd_364": { "name": "wd_364", "object_class": "Equation", - "value": "0.0 + wd_363" + "value": "0.02 + wd_363" }, "wd_365": { "name": "wd_365", "object_class": "Equation", - "value": "0.0 + wd_364" + "value": "0.02 + wd_364" }, "wd_366": { "name": "wd_366", "object_class": "Equation", - "value": "0.0 + wd_365" + "value": "0.02 + wd_365" }, "wd_367": { "name": "wd_367", "object_class": "Equation", - "value": "0.0 + wd_366" + "value": "0.02 + wd_366" }, "wd_368": { "name": "wd_368", "object_class": "Equation", - "value": "0.0 + wd_367" + "value": "0.02 + wd_367" }, "wd_369": { "name": "wd_369", "object_class": "Equation", - "value": "0.0 + wd_368" + "value": "0.02 + wd_368" }, "wd_370": { "name": "wd_370", "object_class": "Equation", - "value": "0.0 + wd_369" + "value": "0.02 + wd_369" }, "wd_371": { "name": "wd_371", "object_class": "Equation", - "value": "0.0 + wd_370" + "value": "0.02 + wd_370" }, "wd_372": { "name": "wd_372", "object_class": "Equation", - "value": "0.0 + wd_371" + "value": "0.02 + wd_371" }, "wd_373": { "name": "wd_373", "object_class": "Equation", - "value": "0.0 + wd_372" + "value": "0.02 + wd_372" }, "wd_374": { "name": "wd_374", "object_class": "Equation", - "value": "0.0 + wd_373" + "value": "0.02 + wd_373" }, "wd_375": { "name": "wd_375", "object_class": "Equation", - "value": "0.0 + wd_374" + "value": "0.02 + wd_374" }, "wd_376": { "name": "wd_376", "object_class": "Equation", - "value": "0.0 + wd_375" + "value": "0.02 + wd_375" }, "wd_377": { "name": "wd_377", "object_class": "Equation", - "value": "0.0 + wd_376" + "value": "0.02 + wd_376" }, "wd_378": { "name": "wd_378", "object_class": "Equation", - "value": "0.0 + wd_377" + "value": "0.02 + wd_377" }, "wd_379": { "name": "wd_379", "object_class": "Equation", - "value": "0.0 + wd_378" + "value": "0.02 + wd_378" }, "wd_380": { "name": "wd_380", "object_class": "Equation", - "value": "0.0 + wd_379" + "value": "0.02 + wd_379" }, "wd_381": { "name": "wd_381", "object_class": "Equation", - "value": "0.0 + wd_380" + "value": "0.02 + wd_380" }, "wd_382": { "name": "wd_382", "object_class": "Equation", - "value": "0.0 + wd_381" + "value": "0.02 + wd_381" }, "wd_383": { "name": "wd_383", "object_class": "Equation", - "value": "0.0 + wd_382" + "value": "0.02 + wd_382" }, "wd_384": { "name": "wd_384", "object_class": "Equation", - "value": "0.0 + wd_383" + "value": "0.02 + wd_383" }, "wd_385": { "name": "wd_385", "object_class": "Equation", - "value": "0.0 + wd_384" + "value": "0.02 + wd_384" }, "wd_386": { "name": "wd_386", "object_class": "Equation", - "value": "0.0 + wd_385" + "value": "0.02 + wd_385" }, "wd_387": { "name": "wd_387", "object_class": "Equation", - "value": "0.0 + wd_386" + "value": "0.02 + wd_386" }, "wd_388": { "name": "wd_388", "object_class": "Equation", - "value": "0.0 + wd_387" + "value": "0.02 + wd_387" }, "wd_389": { "name": "wd_389", "object_class": "Equation", - "value": "0.0 + wd_388" + "value": "0.02 + wd_388" }, "wd_390": { "name": "wd_390", "object_class": "Equation", - "value": "0.0 + wd_389" + "value": "0.02 + wd_389" }, "wd_391": { "name": "wd_391", "object_class": "Equation", - "value": "0.0 + wd_390" + "value": "0.02 + wd_390" }, "wd_392": { "name": "wd_392", "object_class": "Equation", - "value": "0.0 + wd_391" + "value": "0.02 + wd_391" }, "wd_393": { "name": "wd_393", "object_class": "Equation", - "value": "0.0 + wd_392" + "value": "0.02 + wd_392" }, "wd_394": { "name": "wd_394", "object_class": "Equation", - "value": "0.0 + wd_393" + "value": "0.02 + wd_393" }, "wd_395": { "name": "wd_395", "object_class": "Equation", - "value": "0.0 + wd_394" + "value": "0.02 + wd_394" }, "wd_396": { "name": "wd_396", "object_class": "Equation", - "value": "0.0 + wd_395" + "value": "0.02 + wd_395" }, "wd_397": { "name": "wd_397", "object_class": "Equation", - "value": "0.0 + wd_396" + "value": "0.02 + wd_396" }, "wd_398": { "name": "wd_398", "object_class": "Equation", - "value": "0.0 + wd_397" + "value": "0.02 + wd_397" }, "wd_399": { "name": "wd_399", "object_class": "Equation", - "value": "0.0 + wd_398" + "value": "0.02 + wd_398" }, "wd_400": { "name": "wd_400", "object_class": "Equation", - "value": "0.0 + wd_399" + "value": "0.02 + wd_399" }, "wd_401": { "name": "wd_401", "object_class": "Equation", - "value": "0.0 + wd_400" + "value": "0.02 + wd_400" }, "wd_402": { "name": "wd_402", "object_class": "Equation", - "value": "0.0 + wd_401" + "value": "0.02 + wd_401" }, "wd_403": { "name": "wd_403", "object_class": "Equation", - "value": "0.0 + wd_402" + "value": "0.02 + wd_402" }, "wd_404": { "name": "wd_404", "object_class": "Equation", - "value": "0.0 + wd_403" + "value": "0.02 + wd_403" }, "wd_405": { "name": "wd_405", "object_class": "Equation", - "value": "0.0 + wd_404" + "value": "0.02 + wd_404" }, "wd_406": { "name": "wd_406", "object_class": "Equation", - "value": "0.0 + wd_405" + "value": "0.02 + wd_405" }, "wd_407": { "name": "wd_407", "object_class": "Equation", - "value": "0.0 + wd_406" + "value": "0.02 + wd_406" }, "wd_408": { "name": "wd_408", "object_class": "Equation", - "value": "0.0 + wd_407" + "value": "0.02 + wd_407" }, "wd_409": { "name": "wd_409", "object_class": "Equation", - "value": "0.0 + wd_408" + "value": "0.02 + wd_408" }, "wd_410": { "name": "wd_410", "object_class": "Equation", - "value": "0.0 + wd_409" + "value": "0.02 + wd_409" }, "wd_411": { "name": "wd_411", "object_class": "Equation", - "value": "0.0 + wd_410" + "value": "0.02 + wd_410" }, "wd_412": { "name": "wd_412", "object_class": "Equation", - "value": "0.0 + wd_411" + "value": "0.02 + wd_411" }, "wd_413": { "name": "wd_413", "object_class": "Equation", - "value": "0.0 + wd_412" + "value": "0.02 + wd_412" }, "wd_414": { "name": "wd_414", "object_class": "Equation", - "value": "0.0 + wd_413" + "value": "0.02 + wd_413" }, "wd_415": { "name": "wd_415", "object_class": "Equation", - "value": "0.0 + wd_414" + "value": "0.02 + wd_414" }, "wd_416": { "name": "wd_416", "object_class": "Equation", - "value": "0.0 + wd_415" + "value": "0.02 + wd_415" }, "wd_417": { "name": "wd_417", "object_class": "Equation", - "value": "0.0 + wd_416" + "value": "0.02 + wd_416" }, "wd_418": { "name": "wd_418", "object_class": "Equation", - "value": "0.0 + wd_417" + "value": "0.02 + wd_417" }, "wd_419": { "name": "wd_419", "object_class": "Equation", - "value": "0.0 + wd_418" + "value": "0.02 + wd_418" }, "wd_420": { "name": "wd_420", "object_class": "Equation", - "value": "0.0 + wd_419" + "value": "0.02 + wd_419" }, "wd_421": { "name": "wd_421", "object_class": "Equation", - "value": "0.0 + wd_420" + "value": "0.02 + wd_420" }, "wd_422": { "name": "wd_422", "object_class": "Equation", - "value": "0.0 + wd_421" + "value": "0.02 + wd_421" }, "wd_423": { "name": "wd_423", "object_class": "Equation", - "value": "0.0 + wd_422" + "value": "0.02 + wd_422" }, "wd_424": { "name": "wd_424", "object_class": "Equation", - "value": "0.0 + wd_423" + "value": "0.02 + wd_423" }, "wd_425": { "name": "wd_425", "object_class": "Equation", - "value": "0.0 + wd_424" + "value": "0.02 + wd_424" }, "wd_426": { "name": "wd_426", "object_class": "Equation", - "value": "0.0 + wd_425" + "value": "0.02 + wd_425" }, "wd_427": { "name": "wd_427", "object_class": "Equation", - "value": "0.0 + wd_426" + "value": "0.02 + wd_426" }, "wd_428": { "name": "wd_428", "object_class": "Equation", - "value": "0.0 + wd_427" + "value": "0.02 + wd_427" }, "wd_429": { "name": "wd_429", "object_class": "Equation", - "value": "0.0 + wd_428" + "value": "0.02 + wd_428" }, "wd_430": { "name": "wd_430", "object_class": "Equation", - "value": "0.0 + wd_429" + "value": "0.02 + wd_429" }, "wd_431": { "name": "wd_431", "object_class": "Equation", - "value": "0.0 + wd_430" + "value": "0.02 + wd_430" }, "wd_432": { "name": "wd_432", "object_class": "Equation", - "value": "0.0 + wd_431" + "value": "0.02 + wd_431" }, "wd_433": { "name": "wd_433", "object_class": "Equation", - "value": "0.0 + wd_432" + "value": "0.02 + wd_432" }, "wd_434": { "name": "wd_434", "object_class": "Equation", - "value": "0.0 + wd_433" + "value": "0.02 + wd_433" }, "wd_435": { "name": "wd_435", "object_class": "Equation", - "value": "0.0 + wd_434" + "value": "0.02 + wd_434" }, "wd_436": { "name": "wd_436", "object_class": "Equation", - "value": "0.0 + wd_435" + "value": "0.02 + wd_435" }, "wd_437": { "name": "wd_437", "object_class": "Equation", - "value": "0.0 + wd_436" + "value": "0.02 + wd_436" }, "wd_438": { "name": "wd_438", "object_class": "Equation", - "value": "0.0 + wd_437" + "value": "0.02 + wd_437" }, "wd_439": { "name": "wd_439", "object_class": "Equation", - "value": "0.0 + wd_438" + "value": "0.02 + wd_438" }, "wd_440": { "name": "wd_440", "object_class": "Equation", - "value": "0.0 + wd_439" + "value": "0.02 + wd_439" }, "wd_441": { "name": "wd_441", "object_class": "Equation", - "value": "0.0 + wd_440" + "value": "0.02 + wd_440" }, "wd_442": { "name": "wd_442", "object_class": "Equation", - "value": "0.0 + wd_441" + "value": "0.02 + wd_441" }, "wd_443": { "name": "wd_443", "object_class": "Equation", - "value": "0.0 + wd_442" + "value": "0.02 + wd_442" }, "wd_444": { "name": "wd_444", "object_class": "Equation", - "value": "0.0 + wd_443" + "value": "0.02 + wd_443" }, "wd_445": { "name": "wd_445", "object_class": "Equation", - "value": "0.0 + wd_444" + "value": "0.02 + wd_444" }, "wd_446": { "name": "wd_446", "object_class": "Equation", - "value": "0.0 + wd_445" + "value": "0.02 + wd_445" }, "wd_447": { "name": "wd_447", "object_class": "Equation", - "value": "0.0 + wd_446" + "value": "0.02 + wd_446" }, "wd_448": { "name": "wd_448", "object_class": "Equation", - "value": "0.0 + wd_447" + "value": "0.02 + wd_447" }, "wd_449": { "name": "wd_449", "object_class": "Equation", - "value": "0.0 + wd_448" + "value": "0.02 + wd_448" }, "wd_450": { "name": "wd_450", "object_class": "Equation", - "value": "0.0 + wd_449" + "value": "0.02 + wd_449" }, "wd_451": { "name": "wd_451", "object_class": "Equation", - "value": "0.0 + wd_450" + "value": "0.02 + wd_450" }, "wd_452": { "name": "wd_452", "object_class": "Equation", - "value": "0.0 + wd_451" + "value": "0.02 + wd_451" }, "wd_453": { "name": "wd_453", "object_class": "Equation", - "value": "0.0 + wd_452" + "value": "0.02 + wd_452" }, "wd_454": { "name": "wd_454", "object_class": "Equation", - "value": "0.0 + wd_453" + "value": "0.02 + wd_453" }, "wd_455": { "name": "wd_455", "object_class": "Equation", - "value": "0.0 + wd_454" + "value": "0.02 + wd_454" }, "wd_456": { "name": "wd_456", "object_class": "Equation", - "value": "0.0 + wd_455" + "value": "0.02 + wd_455" }, "wd_457": { "name": "wd_457", "object_class": "Equation", - "value": "0.0 + wd_456" + "value": "0.02 + wd_456" }, "wd_458": { "name": "wd_458", "object_class": "Equation", - "value": "0.0 + wd_457" + "value": "0.02 + wd_457" }, "wd_459": { "name": "wd_459", "object_class": "Equation", - "value": "0.0 + wd_458" + "value": "0.02 + wd_458" }, "wd_460": { "name": "wd_460", "object_class": "Equation", - "value": "0.0 + wd_459" + "value": "0.02 + wd_459" }, "wd_461": { "name": "wd_461", "object_class": "Equation", - "value": "0.0 + wd_460" + "value": "0.02 + wd_460" }, "wd_462": { "name": "wd_462", "object_class": "Equation", - "value": "0.0 + wd_461" + "value": "0.02 + wd_461" }, "wd_463": { "name": "wd_463", "object_class": "Equation", - "value": "0.0 + wd_462" + "value": "0.02 + wd_462" }, "wd_464": { "name": "wd_464", "object_class": "Equation", - "value": "0.0 + wd_463" + "value": "0.02 + wd_463" }, "wd_465": { "name": "wd_465", "object_class": "Equation", - "value": "0.0 + wd_464" + "value": "0.02 + wd_464" }, "wd_466": { "name": "wd_466", "object_class": "Equation", - "value": "0.0 + wd_465" + "value": "0.02 + wd_465" }, "wd_467": { "name": "wd_467", "object_class": "Equation", - "value": "0.0 + wd_466" + "value": "0.02 + wd_466" }, "wd_468": { "name": "wd_468", "object_class": "Equation", - "value": "0.0 + wd_467" + "value": "0.02 + wd_467" }, "wd_469": { "name": "wd_469", "object_class": "Equation", - "value": "0.0 + wd_468" + "value": "0.02 + wd_468" }, "wd_470": { "name": "wd_470", "object_class": "Equation", - "value": "0.0 + wd_469" + "value": "0.02 + wd_469" }, "wd_471": { "name": "wd_471", "object_class": "Equation", - "value": "0.0 + wd_470" + "value": "0.02 + wd_470" }, "wd_472": { "name": "wd_472", "object_class": "Equation", - "value": "0.0 + wd_471" + "value": "0.02 + wd_471" }, "wd_473": { "name": "wd_473", "object_class": "Equation", - "value": "0.0 + wd_472" + "value": "0.02 + wd_472" }, "wd_474": { "name": "wd_474", "object_class": "Equation", - "value": "0.0 + wd_473" + "value": "0.02 + wd_473" }, "wd_475": { "name": "wd_475", "object_class": "Equation", - "value": "0.0 + wd_474" + "value": "0.02 + wd_474" }, "wd_476": { "name": "wd_476", "object_class": "Equation", - "value": "0.0 + wd_475" + "value": "0.02 + wd_475" }, "wd_477": { "name": "wd_477", "object_class": "Equation", - "value": "0.0 + wd_476" + "value": "0.02 + wd_476" }, "wd_478": { "name": "wd_478", "object_class": "Equation", - "value": "0.0 + wd_477" + "value": "0.02 + wd_477" }, "wd_479": { "name": "wd_479", "object_class": "Equation", - "value": "0.0 + wd_478" + "value": "0.02 + wd_478" }, "wd_480": { "name": "wd_480", "object_class": "Equation", - "value": "0.0 + wd_479" + "value": "0.02 + wd_479" }, "wd_481": { "name": "wd_481", "object_class": "Equation", - "value": "0.0 + wd_480" + "value": "0.02 + wd_480" }, "wd_482": { "name": "wd_482", "object_class": "Equation", - "value": "0.0 + wd_481" + "value": "0.02 + wd_481" }, "wd_483": { "name": "wd_483", "object_class": "Equation", - "value": "0.0 + wd_482" + "value": "0.02 + wd_482" }, "wd_484": { "name": "wd_484", "object_class": "Equation", - "value": "0.0 + wd_483" + "value": "0.02 + wd_483" }, "wd_485": { "name": "wd_485", "object_class": "Equation", - "value": "0.0 + wd_484" + "value": "0.02 + wd_484" }, "wd_486": { "name": "wd_486", "object_class": "Equation", - "value": "0.0 + wd_485" + "value": "0.02 + wd_485" }, "wd_487": { "name": "wd_487", "object_class": "Equation", - "value": "0.0 + wd_486" + "value": "0.02 + wd_486" }, "wd_488": { "name": "wd_488", "object_class": "Equation", - "value": "0.0 + wd_487" + "value": "0.02 + wd_487" }, "wd_489": { "name": "wd_489", "object_class": "Equation", - "value": "0.0 + wd_488" + "value": "0.02 + wd_488" }, "wd_490": { "name": "wd_490", "object_class": "Equation", - "value": "0.0 + wd_489" + "value": "0.02 + wd_489" }, "wd_491": { "name": "wd_491", "object_class": "Equation", - "value": "0.0 + wd_490" + "value": "0.02 + wd_490" }, "wd_492": { "name": "wd_492", "object_class": "Equation", - "value": "0.0 + wd_491" + "value": "0.02 + wd_491" }, "wd_493": { "name": "wd_493", "object_class": "Equation", - "value": "0.0 + wd_492" + "value": "0.02 + wd_492" }, "wd_494": { "name": "wd_494", "object_class": "Equation", - "value": "0.0 + wd_493" + "value": "0.02 + wd_493" }, "wd_495": { "name": "wd_495", "object_class": "Equation", - "value": "0.0 + wd_494" + "value": "0.02 + wd_494" }, "wd_496": { "name": "wd_496", "object_class": "Equation", - "value": "0.0 + wd_495" + "value": "0.02 + wd_495" }, "wd_497": { "name": "wd_497", "object_class": "Equation", - "value": "0.0 + wd_496" + "value": "0.02 + wd_496" }, "wd_498": { "name": "wd_498", "object_class": "Equation", - "value": "0.0 + wd_497" + "value": "0.02 + wd_497" }, "wd_499": { "name": "wd_499", "object_class": "Equation", - "value": "0.0 + wd_498" + "value": "0.02 + wd_498" }, "wd_500": { "name": "wd_500", "object_class": "Equation", - "value": "0.0 + wd_499" + "value": "0.02 + wd_499" }, "O2write": { "name": "O2write", From 9b636ca20ec05ad75b5bb8ada62df2cbe94b0b9a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 12:04:34 -0500 Subject: [PATCH 321/378] rename import --- src/hsp2/hsp2/HYDR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/HYDR.py b/src/hsp2/hsp2/HYDR.py index 5b97e581..c2f3c50e 100644 --- a/src/hsp2/hsp2/HYDR.py +++ b/src/hsp2/hsp2/HYDR.py @@ -148,7 +148,7 @@ def hydr(siminfo, parameters, ts, ftables, state): if hsp2_local_py != False: from hsp2_local_py import state_step_hydr else: - from hsp2.state.state_fn_defaults import state_step_hydr + 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' From aba52365ccc1f0747ce413036029faf792a3cb1b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 12:08:51 -0500 Subject: [PATCH 322/378] add import --- src/hsp2/hsp2/SEDTRN.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/SEDTRN.py b/src/hsp2/hsp2/SEDTRN.py index a353e9d8..99e65287 100644 --- a/src/hsp2/hsp2/SEDTRN.py +++ b/src/hsp2/hsp2/SEDTRN.py @@ -10,7 +10,7 @@ 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 +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 From aa601affeaf9a4a1fffebea8e84106c714ff8e89 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 12:14:49 -0500 Subject: [PATCH 323/378] use non obj function version --- src/hsp2/state/state.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 4c24c881..24274c9e 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -611,7 +611,7 @@ def sedtrn_get_ix(state, domain): 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.get_state_ix(var_path) + sedtrn_ix[i] = get_state_ix(var_path) return sedtrn_ix @@ -622,7 +622,7 @@ def sedmnt_get_ix(state, domain): 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.get_state_ix(var_path) + sedmnt_ix[i] = get_state_ix(var_path) return sedmnt_ix @@ -645,7 +645,7 @@ def rqual_get_ix(state, domain): 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.get_state_ix(var_path) + rqual_ix[i] = get_state_ix(var_path) return rqual_ix From a87371ace15cdab9d1c5cf20774171b0a4574a3e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 12:31:18 -0500 Subject: [PATCH 324/378] use non obj function version --- src/hsp2/state/state.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 24274c9e..cebd3604 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -611,7 +611,7 @@ def sedtrn_get_ix(state, domain): 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] = get_state_ix(var_path) + sedtrn_ix[i] = get_state_ix(state.state_paths, var_path) return sedtrn_ix @@ -622,7 +622,7 @@ def sedmnt_get_ix(state, domain): 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] = get_state_ix(var_path) + sedmnt_ix[i] = get_state_ix(state.state_paths, var_path) return sedmnt_ix @@ -645,7 +645,7 @@ def rqual_get_ix(state, domain): 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] = get_state_ix(var_path) + rqual_ix[i] = get_state_ix(state.state_paths, var_path) return rqual_ix From c35d974a7535e01b1ed132a037aa1f566b5fca39 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 12:33:31 -0500 Subject: [PATCH 325/378] make sure all are jitted --- src/hsp2/state/state.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index cebd3604..5caee498 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -563,6 +563,7 @@ def rqual_state_vars(): return rqual_state +@njit(cache=True) def rqual_init_ix(state, domain): # get a list of keys for all rqual state variables rqual_state = rqual_state_vars() @@ -604,7 +605,7 @@ def hydr_get_ix(state, domain): return hydr_ix -@njit +@njit(cache=True) def sedtrn_get_ix(state, domain): # get a list of keys for all sedtrn state variables sedtrn_state = ["RSED4", "RSED5", "RSED6"] @@ -615,7 +616,7 @@ def sedtrn_get_ix(state, domain): return sedtrn_ix -@njit +@njit(cache=True) def sedmnt_get_ix(state, domain): # get a list of keys for all sedmnt state variables sedmnt_state = ["DETS"] From a4549e53c8de021cc328b540cc87ed5f022d8345 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 9 Jan 2026 12:35:23 -0500 Subject: [PATCH 326/378] dont jit stuff that shouldnt be! --- src/hsp2/state/state.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hsp2/state/state.py b/src/hsp2/state/state.py index 5caee498..dd8c248e 100644 --- a/src/hsp2/state/state.py +++ b/src/hsp2/state/state.py @@ -546,6 +546,7 @@ def sedmnt_init_ix(state, domain): return sedmnt_ix +@njit(cache=True) def rqual_state_vars(): rqual_state = [ "DOX", @@ -562,8 +563,6 @@ def rqual_state_vars(): ] return rqual_state - -@njit(cache=True) def rqual_init_ix(state, domain): # get a list of keys for all rqual state variables rqual_state = rqual_state_vars() From 369f341548c807980a4c6aa3f0f8cd6606d9c12a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 16 Jan 2026 15:50:04 -0500 Subject: [PATCH 327/378] parsing help --- .../state_specl_ops/compare_eq_to_specl.py | 39 ++++++++++----- src/hsp2/hsp2/om_equation.py | 1 - src/hsp2/hsp2tools/readUCI.py | 47 ++++++++++++++++--- 3 files changed, 68 insertions(+), 19 deletions(-) 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/om_equation.py b/src/hsp2/hsp2/om_equation.py index 4316e90c..58bb5d24 100644 --- a/src/hsp2/hsp2/om_equation.py +++ b/src/hsp2/hsp2/om_equation.py @@ -251,7 +251,6 @@ def tokenize_ops(ps): bnf = None - def BNF(): """ expop :: '^' 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", "") From d8d2f2e1b91d26ad508a7c765ed8793de81dbe72 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 07:53:12 -0500 Subject: [PATCH 328/378] annotate and better handking --- src/hsp2/hsp2tools/readUCI.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2tools/readUCI.py b/src/hsp2/hsp2tools/readUCI.py index a9011084..c6ec9249 100644 --- a/src/hsp2/hsp2tools/readUCI.py +++ b/src/hsp2/hsp2tools/readUCI.py @@ -695,6 +695,7 @@ def specactions(info, llines): # like /SPEC_ATIONS/CONDITIONALS/COND_1 sa_if.append(line) 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": # must replace this with a stack to push/pop From 548c6e03d4780a48aa2580ecafc8a1bd746de225 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:07:16 -0500 Subject: [PATCH 329/378] separated specl parser into its own file and added draft IF parser --- src/hsp2/hsp2tools/data/ParseTable.csv | 1 + src/hsp2/hsp2tools/readUCI.py | 78 +------------- src/hsp2/hsp2tools/uci_parse_specactions.py | 113 ++++++++++++++++++++ 3 files changed, 115 insertions(+), 77 deletions(-) create mode 100644 src/hsp2/hsp2tools/uci_parse_specactions.py diff --git a/src/hsp2/hsp2tools/data/ParseTable.csv b/src/hsp2/hsp2tools/data/ParseTable.csv index 7dfbdd58..544e66e2 100644 --- a/src/hsp2/hsp2tools/data/ParseTable.csv +++ b/src/hsp2/hsp2tools/data/ParseTable.csv @@ -2432,3 +2432,4 @@ 2430,SPEC-ACTIONS,ACTIONS,SPEC-ACTIONS,SPEC-ACTIONS,TC,C,71,73,na 2431,SPEC-ACTIONS,ACTIONS,SPEC-ACTIONS,SPEC-ACTIONS,TS,C,74,77,na 2432,SPEC-ACTIONS,ACTIONS,SPEC-ACTIONS,SPEC-ACTIONS,NUM,C,77,80,na +2432,SPEC-ACTIONS,ACTIONS,SPEC-ACTIONS,SPEC-ACTIONS,condition,C,80,580,na diff --git a/src/hsp2/hsp2tools/readUCI.py b/src/hsp2/hsp2tools/readUCI.py index 8299cb1f..1ea8c00f 100644 --- a/src/hsp2/hsp2tools/readUCI.py +++ b/src/hsp2/hsp2tools/readUCI.py @@ -275,7 +275,7 @@ def readUCI(uciname, hdfname, overwrite=True): elif line.startswith("MONTH-DATA"): monthdata(info, getlines(f)) elif line.startswith("SPEC-ACTIONS"): - specactions(info, getlines(f)) + specactions_parse(info, getlines(f)) colnames = ( "AFACTR", @@ -606,82 +606,6 @@ def ftables(info, llines): lst.append(parseD(line, parse["FTABLES", "FTABLE"])) -def specactions(info, llines): - store, parse, path, *_ = info - lines = iter(llines) - # Notes: - # - Only "classic" special actions are handled here. - # - Other type of SA are recognized by the parser, but not stored in hdf5 - # - The CURLVL code is a place-holder. This has not been thought through. - # - Each type of actions "head_[action type]" should include an "CURLVL" - # column to match with conditional expression if applicable - # - The value of CURLVL matches with an expression - sa_actions = [] # referred to as "classic" in old HSPF code comments - head_actions = [ - "OPTYP", - "RANGE1", - "RANGE2", - "DC", - "DS", - "YR", - "MO", - "DA", - "HR", - "MN", - "D", - "T", - "VARI", - "S1", - "S2", - "AC", - "VALUE", - "TC", - "TS", - "NUM", - "CURLVL", - ] - sa_mult = [] - head_mult = [] - sa_uvquan = [] - head_uvquan = [] - sa_conditional = [] - head_conditional = [] - sa_distrb = [] - head_distrb = [] - sa_uvname = [] - head_uvname = [] - sa_if = [] - head_if = [] - in_if = False # are we in an if block? - curlvl = 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": - 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. - elif line[0:2] == "IF": - sa_if.append(line) - curlvl = len(sa_if) - elif line[0:7] == "END IF": - sa_if.append(line) - curlvl = curlvl - 1 - else: - # ACTIONS block - d = parseD(line, parse["SPEC-ACTIONS", "ACTIONS"]) - d["CURLVL"] = curlvl - sa_actions.append(d.copy()) - if sa_actions: - dfftable = pd.DataFrame(sa_actions, columns=head_actions).replace("na", "") - dfftable.to_hdf(store, key=f"/SPEC_ACTIONS/ACTIONS", data_columns=True) - - def ext(info, lines): store, parse, path, *_ = info lst = [] diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py new file mode 100644 index 00000000..9865d8d5 --- /dev/null +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -0,0 +1,113 @@ +""" +Provides tools to support parsing of SPEC-ACTIONS blocks from UCI files. +""" +import pandas as pd + +def specactions_parse(info, llines): + store, parse, path, *_ = info + lines = iter(llines) + # Notes: + # - Only "classic" special actions are currently active. + # - Other type of SA are recognized by the parser, but not stored in hdf5 + # - The condition shows parent IF-THEN-ELSE entries if applicable + # - Each action "head_[action type]" should include an "condition" + # column to match with condition expression if applicable + # - The condition matches an index in /SPECACTIONS/conditions table + sa_actions = [] # referred to as "classic" in old HSPF code comments + head_actions = [ + "OPTYP", "RANGE1", "RANGE2", "DC", "DS", "YR", "MO", "DA", + "HR", "MN", "D", "T", "VARI", "S1", "S2", "AC", "VALUE", + "TC", "TS", "NUM", "condition", + ] + sa_mult = [] + head_mult = [] + sa_uvquan = [] + head_uvquan = [] + open_conditions = [] + sa_distrb = [] + head_distrb = [] + sa_uvname = [] + head_uvname = [] + sa_conditions = [] + head_conditions = ["cond_id", "parent_id", "sibling_id", "expression"] + active_condition = -1 + 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:8] == "DISTRB": + sa_distrb.append(line) + elif line[2:8] == "UVNAME": + sa_uvname.append(line) + # - 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 "condition" + # like AND OR at the end of an "IF" line, + # and that indicates continuing to the next line + # - Do the IF-THEN parsing built off the equation parser + # using Tim's assembled CONDTIONAL statement + # to populate the spec actions exec op_tokens + # Reminder: special action allows 3 kinds of parentheses + # do a global search and replace all to () + elif (line.strip()[:2] == "IF") or (line.strip()[:7] == "ELSE IF"): + # now we have at least 1 prior condition (maybe the opening IF) + line = get_ifs(lines, line, 'THEN') + d = parseD(line, parse["SPEC-ACTIONS", "conditions"]) + # IF cant have siblings, only ELSE/ELSE IF can + if not (line.strip()[:7] == "ELSE IF"): + sibling_id = -1 + else: + sibling_id = sa_conditions[-1,]['cond_id'] + d['sibling_id'] = sibling_id + d["parent_id"] = specl_get_parent_condition(open_conditions) + open_conditions.append(d["cond_id"]) + sa_conditions.append(line) + elif line.strip()[:4] == "ELSE": + # now we have at least 1 prior condition (maybe the opening IF) + d = parseD(line, parse["SPEC-ACTIONS", "conditions"]) + sibling_id = sa_conditions[-1,]['cond_id'] + d['sibling_id'] = sibling_id + d["parent_id"] = parent_condition + elif line.strip() == "END IF": + #print("found END IF") + # must replace this with a stack to push/pop + # in order to track nested conditions. + if (len(open_conditions) > 0): + open_conditions.pop() + else: + # ACTIONS block + # todo: TIm has a single function that parses a line + d = parseD(line, parse["SPEC-ACTIONS", "ACTIONS"]) + d["parent_id"] = specl_get_parent_condition(open_conditions) + sa_actions.append(d) + + if sa_actions: + dfftable = pd.DataFrame(sa_actions, columns=head_actions).replace("na", "") + dfftable.to_hdf(store, key=f"/SPEC_ACTIONS/ACTIONS", data_columns=True) + if sa_conditions: + dfftable = pd.DataFrame(sa_conditions, columns=head_conditions).replace("na", "") + # indicate this as a lower case since it is NOT an actual TABLE in HSPF + dfftable.to_hdf(store, key=f"/SPEC_ACTIONS/conditions", data_columns=True) + + +def specl_get_parent_condition(open_conditions): + # if there are open conditiosn on the stack, then, any new + # IF or ELSE IF will use this to find it + if len(open_conditions) > 0: + parent_condition = open_conditions[-1] + else: + parent_condition = -1 + return(parent_condition) + +def get_ifs(lines, line, line_end='THEN'): + end_ln = len(line_end) + while line[-end_ln:] != line_end: + nline = next(lines).strip() + line = line + " " + nline + return(line) \ No newline at end of file From 3a40dea6d7a62d3b438ca9ec7452be0df285ec27 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:11:53 -0500 Subject: [PATCH 330/378] added UCI setup to make testing possible --- .../land_spec/{ => HSP2Results}/hwmA51800.uci | 0 .../land_spec/{ => HSP2Results}/hwmA51800.wdm | Bin .../{ => HSP2Results}/met_A51800.wdm | Bin .../{ => HSP2Results}/prad_A51800.wdm | Bin tests/land_spec/test_land_specl.py | 195 ++++++++++++++++++ 5 files changed, 195 insertions(+) rename tests/land_spec/{ => HSP2Results}/hwmA51800.uci (100%) rename tests/land_spec/{ => HSP2Results}/hwmA51800.wdm (100%) rename tests/land_spec/{ => HSP2Results}/met_A51800.wdm (100%) rename tests/land_spec/{ => HSP2Results}/prad_A51800.wdm (100%) create mode 100644 tests/land_spec/test_land_specl.py diff --git a/tests/land_spec/hwmA51800.uci b/tests/land_spec/HSP2Results/hwmA51800.uci similarity index 100% rename from tests/land_spec/hwmA51800.uci rename to tests/land_spec/HSP2Results/hwmA51800.uci diff --git a/tests/land_spec/hwmA51800.wdm b/tests/land_spec/HSP2Results/hwmA51800.wdm similarity index 100% rename from tests/land_spec/hwmA51800.wdm rename to tests/land_spec/HSP2Results/hwmA51800.wdm diff --git a/tests/land_spec/met_A51800.wdm b/tests/land_spec/HSP2Results/met_A51800.wdm similarity index 100% rename from tests/land_spec/met_A51800.wdm rename to tests/land_spec/HSP2Results/met_A51800.wdm diff --git a/tests/land_spec/prad_A51800.wdm b/tests/land_spec/HSP2Results/prad_A51800.wdm similarity index 100% rename from tests/land_spec/prad_A51800.wdm rename to tests/land_spec/HSP2Results/prad_A51800.wdm diff --git a/tests/land_spec/test_land_specl.py b/tests/land_spec/test_land_specl.py new file mode 100644 index 00000000..ee8d7087 --- /dev/null +++ b/tests/land_spec/test_land_specl.py @@ -0,0 +1,195 @@ +# 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 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.hsp2tools.readUCI import * +from hsp2.hsp2.configuration import activities +from src.hsp2.hsp2tools.commands import import_uci, run +from pandas import read_hdf +from hsp2.hsp2.om_timer import timer_class + +timer = timer_class() + +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) + +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, 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, 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_500.ix in state.op_exec_lists[] + +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 +activity = 'HYDR' +seg_path = "/STATE/" + state.model_root_name + "/" + RCHRES.name +activity_path = seg_path + "/" + activity +activity_id = state.set_state(activity_path, 0.0) +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 = om_operations["model_object_cache"]["/STATE/RCHRES_R001/Rlocal"] +Rlocal_ts = Rlocal.read_ts() +rchres1 = om_operations["model_object_cache"]["/STATE/RCHRES_R001"] +Rlocal_check = ModelLinkage( + "Rlocal1", rchres1, {"right_path": "/TIMESERIES/TS010", "link_type": 3} +) +# Calls: +# - ts = Rlocal.io_manager.read_ts(Category.INPUTS, None, Rlocal.ts_name) +# - ts = transform(ts, Rlocal.ts_name, 'SAME', Rlocal.siminfo) +Rlocal.io_manager._output._store.keys() +# write it back. We can give an arbitrary name or it will default to write back to the source path in right_path variable +ts1 = ( + precip_ts.read_ts() +) # same as precip_ts.ts_ix[precip_ts.ix], same as state['ts_ix'][precip_ts.ix] +# we can specify a custom path to write this TS to +precip_ts.write_path = "/RESULTS/test_TS039" +precip_ts.write_ts() +# precip_ts.write_ts is same as: +# ts4 = precip_ts.format_ts(ts1, ['tsvalue'], siminfo['tindex']) +# ts4.to_hdf(precip_ts.io_manager._output._store, precip_ts.write_path, format='t', data_columns=True, complevel=precip_ts.complevel) + +start = time.time() +iterate_models( + model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, siminfo["steps"], -1 +) +end = time.time() +print( + len(model_exec_list), + "components iterated over state_ix", + siminfo["steps"], + "time steps took", + 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']) From 9ec5c13ef27151265c620521e6a1237985b1efe0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:16:20 -0500 Subject: [PATCH 331/378] added proper include --- src/hsp2/hsp2tools/readUCI.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2tools/readUCI.py b/src/hsp2/hsp2tools/readUCI.py index 1ea8c00f..bba53af0 100644 --- a/src/hsp2/hsp2tools/readUCI.py +++ b/src/hsp2/hsp2tools/readUCI.py @@ -9,6 +9,7 @@ import pandas as pd from hsp2 import hsp2tools +frpm hsp2.hsp2tools.uci_parse_specactions import specactions_parse pd.set_option("io.hdf.default_format", "table") From 10449034d5a3c30777be88b9d9835a6c8843ac67 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:22:45 -0500 Subject: [PATCH 332/378] typo --- src/hsp2/hsp2tools/readUCI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2tools/readUCI.py b/src/hsp2/hsp2tools/readUCI.py index bba53af0..ae665eee 100644 --- a/src/hsp2/hsp2tools/readUCI.py +++ b/src/hsp2/hsp2tools/readUCI.py @@ -9,7 +9,7 @@ import pandas as pd from hsp2 import hsp2tools -frpm hsp2.hsp2tools.uci_parse_specactions import specactions_parse +from hsp2.hsp2tools.uci_parse_specactions import specactions_parse pd.set_option("io.hdf.default_format", "table") From 79fac7abad191b7f76bdaa5c6dfb4221feea0478 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:26:12 -0500 Subject: [PATCH 333/378] fix bad IF block in UCI --- tests/land_spec/HSP2Results/hwmA51800.uci | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/land_spec/HSP2Results/hwmA51800.uci b/tests/land_spec/HSP2Results/hwmA51800.uci index 46811761..3b16c8fb 100644 --- a/tests/land_spec/HSP2Results/hwmA51800.uci +++ b/tests/land_spec/HSP2Results/hwmA51800.uci @@ -54,21 +54,21 @@ SPEC-ACTIONS <****><-><--><><-><--><-><-><-><-><><> <----><-><-><-><-><--------> <> <-><-> ***Action Lines for fertilizer -IF (prec < 0.1) THEN - PERLND 1 DY 11984 1 1 12 2 3 FNO3 += 0. - PERLND 1 DY 11984 2 1 12 2 3 FNO3 += 0.090044 - PERLND 1 DY 11984 3 1 12 2 3 FNO3 += 1.917460 - PERLND 1 DY 11984 4 1 12 2 3 FNO3 += 2.733176 - PERLND 1 DY 11984 5 1 12 2 3 FNO3 += 0.123E-06 - PERLND 1 DY 11984 6 1 12 2 3 FNO3 += 6.302083 - PERLND 1 DY 11984 7 1 12 2 3 FNO3 += 0.207089 -***Action Lines for Adjusting Refractory Storage -*** commented out for testing -*** PERLND 1 1984 1 1 3 SPRON -= 0. YR 1 22 -*** PERLND 1 1984 1 1 3 UPRON -= 38.97500 YR 1 22 -*** PERLND 1 1984 1 1 3 LPRON -= 10.92700 YR 1 22 -*** PERLND 1 1984 1 1 3 APRON -= 6.131000 YR 1 22 - + IF (prec < 0.1) THEN + PERLND 1 DY 11984 1 1 12 2 3 FNO3 += 0. + PERLND 1 DY 11984 2 1 12 2 3 FNO3 += 0.090044 + PERLND 1 DY 11984 3 1 12 2 3 FNO3 += 1.917460 + PERLND 1 DY 11984 4 1 12 2 3 FNO3 += 2.733176 + PERLND 1 DY 11984 5 1 12 2 3 FNO3 += 0.123E-06 + PERLND 1 DY 11984 6 1 12 2 3 FNO3 += 6.302083 + PERLND 1 DY 11984 7 1 12 2 3 FNO3 += 0.207089 + ***Action Lines for Adjusting Refractory Storage + *** commented out for testing + *** PERLND 1 1984 1 1 3 SPRON -= 0. YR 1 22 + *** PERLND 1 1984 1 1 3 UPRON -= 38.97500 YR 1 22 + *** PERLND 1 1984 1 1 3 LPRON -= 10.92700 YR 1 22 + *** PERLND 1 1984 1 1 3 APRON -= 6.131000 YR 1 22 + END IF END SPEC-ACTIONS PERLND From 1c5945e540ab25766e0655adedf06e2ec183bac8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:32:21 -0500 Subject: [PATCH 334/378] fdebug --- src/hsp2/hsp2tools/uci_parse_specactions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 9865d8d5..a458b5f1 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -109,5 +109,6 @@ def get_ifs(lines, line, line_end='THEN'): end_ln = len(line_end) while line[-end_ln:] != line_end: nline = next(lines).strip() + print(nline) line = line + " " + nline return(line) \ No newline at end of file From 2b928a3c8931fa5edb788343d3fe6a8804342d6e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:35:23 -0500 Subject: [PATCH 335/378] fdebug --- src/hsp2/hsp2tools/uci_parse_specactions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index a458b5f1..6488c94e 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -109,6 +109,6 @@ def get_ifs(lines, line, line_end='THEN'): end_ln = len(line_end) while line[-end_ln:] != line_end: nline = next(lines).strip() - print(nline) + print(line, nline) line = line + " " + nline return(line) \ No newline at end of file From e1207bb49db33e2bef2aa701aa7f28f0d55b48d3 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:44:56 -0500 Subject: [PATCH 336/378] fdebug --- src/hsp2/hsp2tools/uci_parse_specactions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 6488c94e..f8c42690 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -107,6 +107,8 @@ def specl_get_parent_condition(open_conditions): def get_ifs(lines, line, line_end='THEN'): end_ln = len(line_end) + print("Start line:", line) + print("********************") while line[-end_ln:] != line_end: nline = next(lines).strip() print(line, nline) From 87d7b9440b9dbaf805b70ead101aab03531cfabf Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:47:05 -0500 Subject: [PATCH 337/378] try strippin --- src/hsp2/hsp2tools/uci_parse_specactions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index f8c42690..b479c164 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -108,8 +108,9 @@ def specl_get_parent_condition(open_conditions): def get_ifs(lines, line, line_end='THEN'): end_ln = len(line_end) print("Start line:", line) + print("Searching for:", line_end) print("********************") - while line[-end_ln:] != line_end: + while line.strip()[-end_ln:] != line_end: nline = next(lines).strip() print(line, nline) line = line + " " + nline From 82bc8cc9e09aebbdc241f41e48321ca76551f5e1 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:48:38 -0500 Subject: [PATCH 338/378] import fn and debug off --- src/hsp2/hsp2tools/uci_parse_specactions.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index b479c164..6c65c431 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -2,6 +2,7 @@ Provides tools to support parsing of SPEC-ACTIONS blocks from UCI files. """ import pandas as pd +from hsp2.hsp2tools.readUCI import parseD def specactions_parse(info, llines): store, parse, path, *_ = info @@ -107,9 +108,6 @@ def specl_get_parent_condition(open_conditions): def get_ifs(lines, line, line_end='THEN'): end_ln = len(line_end) - print("Start line:", line) - print("Searching for:", line_end) - print("********************") while line.strip()[-end_ln:] != line_end: nline = next(lines).strip() print(line, nline) From 51cd39570bbb5842656292776fa836762b65443b Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:53:36 -0500 Subject: [PATCH 339/378] import as new lib to avoid circularity --- src/hsp2/hsp2tools/uci_parse_specactions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 6c65c431..0e03c5af 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -2,7 +2,7 @@ Provides tools to support parsing of SPEC-ACTIONS blocks from UCI files. """ import pandas as pd -from hsp2.hsp2tools.readUCI import parseD +from hsp2.hsp2tools import readUCI ucifn def specactions_parse(info, llines): store, parse, path, *_ = info @@ -59,7 +59,7 @@ def specactions_parse(info, llines): elif (line.strip()[:2] == "IF") or (line.strip()[:7] == "ELSE IF"): # now we have at least 1 prior condition (maybe the opening IF) line = get_ifs(lines, line, 'THEN') - d = parseD(line, parse["SPEC-ACTIONS", "conditions"]) + d = ucifn.parseD(line, parse["SPEC-ACTIONS", "conditions"]) # IF cant have siblings, only ELSE/ELSE IF can if not (line.strip()[:7] == "ELSE IF"): sibling_id = -1 @@ -71,7 +71,7 @@ def specactions_parse(info, llines): sa_conditions.append(line) elif line.strip()[:4] == "ELSE": # now we have at least 1 prior condition (maybe the opening IF) - d = parseD(line, parse["SPEC-ACTIONS", "conditions"]) + d = ucifn.parseD(line, parse["SPEC-ACTIONS", "conditions"]) sibling_id = sa_conditions[-1,]['cond_id'] d['sibling_id'] = sibling_id d["parent_id"] = parent_condition @@ -84,7 +84,7 @@ def specactions_parse(info, llines): else: # ACTIONS block # todo: TIm has a single function that parses a line - d = parseD(line, parse["SPEC-ACTIONS", "ACTIONS"]) + d = ucifn.parseD(line, parse["SPEC-ACTIONS", "ACTIONS"]) d["parent_id"] = specl_get_parent_condition(open_conditions) sa_actions.append(d) From 1af9bbec01388eaadceefc6eeec284d23fe567e7 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 12:54:37 -0500 Subject: [PATCH 340/378] correcdt syntax --- src/hsp2/hsp2tools/uci_parse_specactions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 0e03c5af..419ecd9e 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -2,7 +2,7 @@ Provides tools to support parsing of SPEC-ACTIONS blocks from UCI files. """ import pandas as pd -from hsp2.hsp2tools import readUCI ucifn +from hsp2.hsp2tools import readUCI as ucifn def specactions_parse(info, llines): store, parse, path, *_ = info From 78601b8857325a153ba78d648018b22b2f3053a9 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 13:03:59 -0500 Subject: [PATCH 341/378] debug --- src/hsp2/hsp2tools/uci_parse_specactions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 419ecd9e..34d167ec 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -60,6 +60,7 @@ def specactions_parse(info, llines): # now we have at least 1 prior condition (maybe the opening IF) line = get_ifs(lines, line, 'THEN') d = ucifn.parseD(line, parse["SPEC-ACTIONS", "conditions"]) + print("Found d:", d) # IF cant have siblings, only ELSE/ELSE IF can if not (line.strip()[:7] == "ELSE IF"): sibling_id = -1 From f524f948aa994332e6eb84c7c26196b0ece48178 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 13:05:42 -0500 Subject: [PATCH 342/378] correct parse columns --- src/hsp2/hsp2tools/data/ParseTable.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2tools/data/ParseTable.csv b/src/hsp2/hsp2tools/data/ParseTable.csv index 544e66e2..1562158e 100644 --- a/src/hsp2/hsp2tools/data/ParseTable.csv +++ b/src/hsp2/hsp2tools/data/ParseTable.csv @@ -2433,3 +2433,4 @@ 2431,SPEC-ACTIONS,ACTIONS,SPEC-ACTIONS,SPEC-ACTIONS,TS,C,74,77,na 2432,SPEC-ACTIONS,ACTIONS,SPEC-ACTIONS,SPEC-ACTIONS,NUM,C,77,80,na 2432,SPEC-ACTIONS,ACTIONS,SPEC-ACTIONS,SPEC-ACTIONS,condition,C,80,580,na +2432,SPEC-ACTIONS,conditions,SPEC-ACTIONS,SPEC-ACTIONS,condition,C,0,80,na From 7119fed232b52850d5eb7a7eab8f3ca6dd1c8816 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 13:09:46 -0500 Subject: [PATCH 343/378] add index column --- src/hsp2/hsp2tools/uci_parse_specactions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 34d167ec..35fa02f7 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -66,6 +66,7 @@ def specactions_parse(info, llines): sibling_id = -1 else: sibling_id = sa_conditions[-1,]['cond_id'] + d['cond_id'] = len(sa_conditions) # set to next index value d['sibling_id'] = sibling_id d["parent_id"] = specl_get_parent_condition(open_conditions) open_conditions.append(d["cond_id"]) From 5821622477f2f9e812cb40f871c3bf00e7754b2d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 13:13:27 -0500 Subject: [PATCH 344/378] debug --- src/hsp2/hsp2tools/uci_parse_specactions.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 35fa02f7..8721098d 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -40,20 +40,6 @@ def specactions_parse(info, llines): elif line[2:8] == "DISTRB": sa_distrb.append(line) elif line[2:8] == "UVNAME": - sa_uvname.append(line) - # - 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 "condition" - # like AND OR at the end of an "IF" line, - # and that indicates continuing to the next line - # - Do the IF-THEN parsing built off the equation parser - # using Tim's assembled CONDTIONAL statement - # to populate the spec actions exec op_tokens # Reminder: special action allows 3 kinds of parentheses # do a global search and replace all to () elif (line.strip()[:2] == "IF") or (line.strip()[:7] == "ELSE IF"): @@ -85,7 +71,8 @@ def specactions_parse(info, llines): open_conditions.pop() else: # ACTIONS block - # todo: TIm has a single function that parses a line + # todo: Tim has a single function that parses a line + print("trYING ACtion PARSER", line) d = ucifn.parseD(line, parse["SPEC-ACTIONS", "ACTIONS"]) d["parent_id"] = specl_get_parent_condition(open_conditions) sa_actions.append(d) From 48a13b22841959b08be332a2b94633fc7ee57672 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 13:14:31 -0500 Subject: [PATCH 345/378] fix oops --- src/hsp2/hsp2tools/uci_parse_specactions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 8721098d..3c5e2054 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -40,6 +40,7 @@ def specactions_parse(info, llines): elif line[2:8] == "DISTRB": sa_distrb.append(line) elif line[2:8] == "UVNAME": + sa_uvname.append(line) # Reminder: special action allows 3 kinds of parentheses # do a global search and replace all to () elif (line.strip()[:2] == "IF") or (line.strip()[:7] == "ELSE IF"): From ea8a7a07a18df1b2bd2866663488329c789492f5 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 13:17:43 -0500 Subject: [PATCH 346/378] clean up line --- src/hsp2/hsp2tools/uci_parse_specactions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 3c5e2054..0962e01a 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -45,7 +45,7 @@ def specactions_parse(info, llines): # do a global search and replace all to () elif (line.strip()[:2] == "IF") or (line.strip()[:7] == "ELSE IF"): # now we have at least 1 prior condition (maybe the opening IF) - line = get_ifs(lines, line, 'THEN') + line = get_ifs(lines, line, 'THEN').strip() d = ucifn.parseD(line, parse["SPEC-ACTIONS", "conditions"]) print("Found d:", d) # IF cant have siblings, only ELSE/ELSE IF can From c1853c5e92fdd4641c050e7a1bd38bc9e700b427 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 13:19:53 -0500 Subject: [PATCH 347/378] do not clean line it is fixed width --- src/hsp2/hsp2tools/uci_parse_specactions.py | 2 +- tests/land_spec/HSP2Results/hwmA51800.uci | 30 ++++++++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 0962e01a..6ab6750c 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -45,7 +45,7 @@ def specactions_parse(info, llines): # do a global search and replace all to () elif (line.strip()[:2] == "IF") or (line.strip()[:7] == "ELSE IF"): # now we have at least 1 prior condition (maybe the opening IF) - line = get_ifs(lines, line, 'THEN').strip() + line = get_ifs(lines, line, 'THEN') d = ucifn.parseD(line, parse["SPEC-ACTIONS", "conditions"]) print("Found d:", d) # IF cant have siblings, only ELSE/ELSE IF can diff --git a/tests/land_spec/HSP2Results/hwmA51800.uci b/tests/land_spec/HSP2Results/hwmA51800.uci index 3b16c8fb..4c43c706 100644 --- a/tests/land_spec/HSP2Results/hwmA51800.uci +++ b/tests/land_spec/HSP2Results/hwmA51800.uci @@ -54,21 +54,21 @@ SPEC-ACTIONS <****><-><--><><-><--><-><-><-><-><><> <----><-><-><-><-><--------> <> <-><-> ***Action Lines for fertilizer - IF (prec < 0.1) THEN - PERLND 1 DY 11984 1 1 12 2 3 FNO3 += 0. - PERLND 1 DY 11984 2 1 12 2 3 FNO3 += 0.090044 - PERLND 1 DY 11984 3 1 12 2 3 FNO3 += 1.917460 - PERLND 1 DY 11984 4 1 12 2 3 FNO3 += 2.733176 - PERLND 1 DY 11984 5 1 12 2 3 FNO3 += 0.123E-06 - PERLND 1 DY 11984 6 1 12 2 3 FNO3 += 6.302083 - PERLND 1 DY 11984 7 1 12 2 3 FNO3 += 0.207089 - ***Action Lines for Adjusting Refractory Storage - *** commented out for testing - *** PERLND 1 1984 1 1 3 SPRON -= 0. YR 1 22 - *** PERLND 1 1984 1 1 3 UPRON -= 38.97500 YR 1 22 - *** PERLND 1 1984 1 1 3 LPRON -= 10.92700 YR 1 22 - *** PERLND 1 1984 1 1 3 APRON -= 6.131000 YR 1 22 - END IF +IF (prec < 0.1) THEN + PERLND 1 DY 11984 1 1 12 2 3 FNO3 += 0. + PERLND 1 DY 11984 2 1 12 2 3 FNO3 += 0.090044 + PERLND 1 DY 11984 3 1 12 2 3 FNO3 += 1.917460 + PERLND 1 DY 11984 4 1 12 2 3 FNO3 += 2.733176 + PERLND 1 DY 11984 5 1 12 2 3 FNO3 += 0.123E-06 + PERLND 1 DY 11984 6 1 12 2 3 FNO3 += 6.302083 + PERLND 1 DY 11984 7 1 12 2 3 FNO3 += 0.207089 +***Action Lines for Adjusting Refractory Storage +*** commented out for testing +*** PERLND 1 1984 1 1 3 SPRON -= 0. YR 1 22 +*** PERLND 1 1984 1 1 3 UPRON -= 38.97500 YR 1 22 +*** PERLND 1 1984 1 1 3 LPRON -= 10.92700 YR 1 22 +*** PERLND 1 1984 1 1 3 APRON -= 6.131000 YR 1 22 +END IF END SPEC-ACTIONS PERLND From ad70addc43b1e157768434b815e548cd20761d99 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 13:23:05 -0500 Subject: [PATCH 348/378] ddebug --- src/hsp2/hsp2tools/uci_parse_specactions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 6ab6750c..1485a2a1 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -82,6 +82,8 @@ def specactions_parse(info, llines): dfftable = pd.DataFrame(sa_actions, columns=head_actions).replace("na", "") dfftable.to_hdf(store, key=f"/SPEC_ACTIONS/ACTIONS", data_columns=True) if sa_conditions: + print("Saving conditions to h5", sa_conditions) + print("With Haader", head_conditions) dfftable = pd.DataFrame(sa_conditions, columns=head_conditions).replace("na", "") # indicate this as a lower case since it is NOT an actual TABLE in HSPF dfftable.to_hdf(store, key=f"/SPEC_ACTIONS/conditions", data_columns=True) From 6112736a46557f6e632e3529a915819b8d8bd67e Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 13:24:57 -0500 Subject: [PATCH 349/378] appen the dict? --- src/hsp2/hsp2tools/uci_parse_specactions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 1485a2a1..8c670ef1 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -30,7 +30,7 @@ def specactions_parse(info, llines): sa_uvname = [] head_uvname = [] sa_conditions = [] - head_conditions = ["cond_id", "parent_id", "sibling_id", "expression"] + head_conditions = ["cond_id", "parent_id", "sibling_id", "condition"] active_condition = -1 for line in lines: if line[2:5] == "MULT": @@ -57,7 +57,7 @@ def specactions_parse(info, llines): d['sibling_id'] = sibling_id d["parent_id"] = specl_get_parent_condition(open_conditions) open_conditions.append(d["cond_id"]) - sa_conditions.append(line) + sa_conditions.append(d) elif line.strip()[:4] == "ELSE": # now we have at least 1 prior condition (maybe the opening IF) d = ucifn.parseD(line, parse["SPEC-ACTIONS", "conditions"]) From 2fcf1102dbec2a87ac647c76a089ef9242b21e34 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 15:05:30 -0500 Subject: [PATCH 350/378] rename column for associated condition --- src/hsp2/hsp2tools/uci_parse_specactions.py | 2 +- tests/land_spec/test_land_specl.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 8c670ef1..5a9e743d 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -55,7 +55,7 @@ def specactions_parse(info, llines): sibling_id = sa_conditions[-1,]['cond_id'] d['cond_id'] = len(sa_conditions) # set to next index value d['sibling_id'] = sibling_id - d["parent_id"] = specl_get_parent_condition(open_conditions) + d["condition"] = specl_get_parent_condition(open_conditions) open_conditions.append(d["cond_id"]) sa_conditions.append(d) elif line.strip()[:4] == "ELSE": diff --git a/tests/land_spec/test_land_specl.py b/tests/land_spec/test_land_specl.py index ee8d7087..6d5216a7 100644 --- a/tests/land_spec/test_land_specl.py +++ b/tests/land_spec/test_land_specl.py @@ -17,7 +17,7 @@ timer = timer_class() -fpath = "./tests/testcbp/HSP2results/PL3_5250_0001.h5" +fpath = "./tests/land_spec/HSP2Results/hwmA51800.h5" # try also: # fpath = './tests/testcbp/HSP2results/JL1_6562_6560.h5' From 80e864961c8a612b0c00782f4e40ff2391f1b124 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 15:22:33 -0500 Subject: [PATCH 351/378] info --- src/hsp2/hsp2io/hdf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hsp2/hsp2io/hdf.py b/src/hsp2/hsp2io/hdf.py index 201552ee..c0d012c8 100644 --- a/src/hsp2/hsp2io/hdf.py +++ b/src/hsp2/hsp2io/hdf.py @@ -88,6 +88,7 @@ def read_parameters(self) -> Model: elif op == "FTABLES": model.ftables[module] = self._store[path] elif op == "SPEC_ACTIONS": + print(op, "Reading module", module, "from path", path) model.specactions[module] = self._store[path] elif op == "MONTHDATA": if not model.monthdata: From 101e1e5623303faca53dd89cef069f4a30240fd5 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 16:05:39 -0500 Subject: [PATCH 352/378] update name in dataframe for condition proper maping --- src/hsp2/hsp2tools/uci_parse_specactions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 5a9e743d..d8a2ea73 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -63,7 +63,7 @@ def specactions_parse(info, llines): d = ucifn.parseD(line, parse["SPEC-ACTIONS", "conditions"]) sibling_id = sa_conditions[-1,]['cond_id'] d['sibling_id'] = sibling_id - d["parent_id"] = parent_condition + d["parent_id"] = specl_get_parent_condition(open_conditions) elif line.strip() == "END IF": #print("found END IF") # must replace this with a stack to push/pop @@ -75,7 +75,7 @@ def specactions_parse(info, llines): # todo: Tim has a single function that parses a line print("trYING ACtion PARSER", line) d = ucifn.parseD(line, parse["SPEC-ACTIONS", "ACTIONS"]) - d["parent_id"] = specl_get_parent_condition(open_conditions) + d["condition"] = specl_get_parent_condition(open_conditions) sa_actions.append(d) if sa_actions: From b16a2998ea9c7594e8e78dd3567ed0a0ab4986a2 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 16:08:02 -0500 Subject: [PATCH 353/378] oops overwrite condition column --- src/hsp2/hsp2tools/uci_parse_specactions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index d8a2ea73..991fdef4 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -55,7 +55,7 @@ def specactions_parse(info, llines): sibling_id = sa_conditions[-1,]['cond_id'] d['cond_id'] = len(sa_conditions) # set to next index value d['sibling_id'] = sibling_id - d["condition"] = specl_get_parent_condition(open_conditions) + d["parent_id"] = specl_get_parent_condition(open_conditions) open_conditions.append(d["cond_id"]) sa_conditions.append(d) elif line.strip()[:4] == "ELSE": From 24cf32b287dcb9f1ce0d50e0f5456b3aa1310274 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 16:20:23 -0500 Subject: [PATCH 354/378] extra non-IFed conditions --- tests/land_spec/HSP2Results/hwmA51800.uci | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/land_spec/HSP2Results/hwmA51800.uci b/tests/land_spec/HSP2Results/hwmA51800.uci index 4c43c706..92e30eb4 100644 --- a/tests/land_spec/HSP2Results/hwmA51800.uci +++ b/tests/land_spec/HSP2Results/hwmA51800.uci @@ -62,13 +62,13 @@ IF (prec < 0.1) THEN PERLND 1 DY 11984 5 1 12 2 3 FNO3 += 0.123E-06 PERLND 1 DY 11984 6 1 12 2 3 FNO3 += 6.302083 PERLND 1 DY 11984 7 1 12 2 3 FNO3 += 0.207089 +END IF ***Action Lines for Adjusting Refractory Storage *** commented out for testing -*** PERLND 1 1984 1 1 3 SPRON -= 0. YR 1 22 -*** PERLND 1 1984 1 1 3 UPRON -= 38.97500 YR 1 22 -*** PERLND 1 1984 1 1 3 LPRON -= 10.92700 YR 1 22 -*** PERLND 1 1984 1 1 3 APRON -= 6.131000 YR 1 22 -END IF + PERLND 1 1984 1 1 3 SPRON -= 0. YR 1 22 + PERLND 1 1984 1 1 3 UPRON -= 38.97500 YR 1 22 + PERLND 1 1984 1 1 3 LPRON -= 10.92700 YR 1 22 + PERLND 1 1984 1 1 3 APRON -= 6.131000 YR 1 22 END SPEC-ACTIONS PERLND From 219cf4a3262462edca524f05869bacf58579fdfb Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 16:28:08 -0500 Subject: [PATCH 355/378] does specl lock need a custom END getter? --- src/hsp2/hsp2tools/readUCI.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2tools/readUCI.py b/src/hsp2/hsp2tools/readUCI.py index ae665eee..8dd432e1 100644 --- a/src/hsp2/hsp2tools/readUCI.py +++ b/src/hsp2/hsp2tools/readUCI.py @@ -100,10 +100,10 @@ def reader(filename): yield f"{nline: <90}" # prevent short line problems -def getlines(f): +def getlines(f, line_end="END"): lines = [] for line in f: - if line.startswith("END"): + if line.startswith(line_end): break lines.append(line) return lines @@ -276,7 +276,7 @@ def readUCI(uciname, hdfname, overwrite=True): elif line.startswith("MONTH-DATA"): monthdata(info, getlines(f)) elif line.startswith("SPEC-ACTIONS"): - specactions_parse(info, getlines(f)) + specactions_parse(info, getlines(f, "END SPEC-ACTIONS")) colnames = ( "AFACTR", From 8cb060d2ece3b7630f9aa3196a7ad2305a066427 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 16:32:09 -0500 Subject: [PATCH 356/378] debug off. rename functions for better understanding. --- src/hsp2/hsp2tools/uci_parse_specactions.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/hsp2/hsp2tools/uci_parse_specactions.py b/src/hsp2/hsp2tools/uci_parse_specactions.py index 991fdef4..ce7673a3 100644 --- a/src/hsp2/hsp2tools/uci_parse_specactions.py +++ b/src/hsp2/hsp2tools/uci_parse_specactions.py @@ -45,9 +45,8 @@ def specactions_parse(info, llines): # do a global search and replace all to () elif (line.strip()[:2] == "IF") or (line.strip()[:7] == "ELSE IF"): # now we have at least 1 prior condition (maybe the opening IF) - line = get_ifs(lines, line, 'THEN') + line = get_til_end(lines, line, 'THEN') d = ucifn.parseD(line, parse["SPEC-ACTIONS", "conditions"]) - print("Found d:", d) # IF cant have siblings, only ELSE/ELSE IF can if not (line.strip()[:7] == "ELSE IF"): sibling_id = -1 @@ -65,15 +64,12 @@ def specactions_parse(info, llines): d['sibling_id'] = sibling_id d["parent_id"] = specl_get_parent_condition(open_conditions) elif line.strip() == "END IF": - #print("found END IF") - # must replace this with a stack to push/pop - # in order to track nested conditions. + # must pop stack to track nested conditions. if (len(open_conditions) > 0): open_conditions.pop() else: # ACTIONS block # todo: Tim has a single function that parses a line - print("trYING ACtion PARSER", line) d = ucifn.parseD(line, parse["SPEC-ACTIONS", "ACTIONS"]) d["condition"] = specl_get_parent_condition(open_conditions) sa_actions.append(d) @@ -82,8 +78,6 @@ def specactions_parse(info, llines): dfftable = pd.DataFrame(sa_actions, columns=head_actions).replace("na", "") dfftable.to_hdf(store, key=f"/SPEC_ACTIONS/ACTIONS", data_columns=True) if sa_conditions: - print("Saving conditions to h5", sa_conditions) - print("With Haader", head_conditions) dfftable = pd.DataFrame(sa_conditions, columns=head_conditions).replace("na", "") # indicate this as a lower case since it is NOT an actual TABLE in HSPF dfftable.to_hdf(store, key=f"/SPEC_ACTIONS/conditions", data_columns=True) @@ -98,10 +92,9 @@ def specl_get_parent_condition(open_conditions): parent_condition = -1 return(parent_condition) -def get_ifs(lines, line, line_end='THEN'): +def get_til_end(lines, line, line_end='THEN'): end_ln = len(line_end) while line.strip()[-end_ln:] != line_end: nline = next(lines).strip() - print(line, nline) line = line + " " + nline return(line) \ No newline at end of file From a435ed74c4cc742d13b5a2e6f10b42e26c355f3d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 17:21:14 -0500 Subject: [PATCH 357/378] debug off. --- src/hsp2/hsp2/om_model_object.py | 2 +- src/hsp2/hsp2io/hdf.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 30451052..d7c90877 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -63,7 +63,7 @@ def __init__(self, name, container=False, model_props=None, state=None): self.state_path = ( "" # Ex: "/STATE/RCHRES_001" # the pointer to this object state ) - self.inputs = {} # associative array with key=local_variable_name, value=hdf5_path Ex: [ 'Qin' : '/STATE/RCHRES_001/IVOL' ] + self.inputs = {} # associative array with key=local_variable_name, value=hdf5_path Ex: [ 'Qin' : '/STATE/mtn_lake/RCHRES_001/IVOL' ] self.inputs_ix = {} # associative array with key=local_variable_name, value=state_ix integer key self.ix = False self.paths_found = False # this should be False at start diff --git a/src/hsp2/hsp2io/hdf.py b/src/hsp2/hsp2io/hdf.py index c0d012c8..201552ee 100644 --- a/src/hsp2/hsp2io/hdf.py +++ b/src/hsp2/hsp2io/hdf.py @@ -88,7 +88,6 @@ def read_parameters(self) -> Model: elif op == "FTABLES": model.ftables[module] = self._store[path] elif op == "SPEC_ACTIONS": - print(op, "Reading module", module, "from path", path) model.specactions[module] = self._store[path] elif op == "MONTHDATA": if not model.monthdata: From 20a4da4fa94b31e8c00140ce03316fbcc6e2096d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 17:21:52 -0500 Subject: [PATCH 358/378] remove unneeded comment change --- src/hsp2/hsp2/om_model_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index d7c90877..30451052 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -63,7 +63,7 @@ def __init__(self, name, container=False, model_props=None, state=None): self.state_path = ( "" # Ex: "/STATE/RCHRES_001" # the pointer to this object state ) - self.inputs = {} # associative array with key=local_variable_name, value=hdf5_path Ex: [ 'Qin' : '/STATE/mtn_lake/RCHRES_001/IVOL' ] + self.inputs = {} # associative array with key=local_variable_name, value=hdf5_path Ex: [ 'Qin' : '/STATE/RCHRES_001/IVOL' ] self.inputs_ix = {} # associative array with key=local_variable_name, value=state_ix integer key self.ix = False self.paths_found = False # this should be False at start From 53c2092a9589758d2f64a7136e5d21ba0b0017c1 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 17:29:53 -0500 Subject: [PATCH 359/378] reorg to work around testing file location trouble --- tests/land_spec/{ => HSP2Results}/test_land_specl.py | 2 ++ 1 file changed, 2 insertions(+) rename tests/land_spec/{ => HSP2Results}/test_land_specl.py (96%) diff --git a/tests/land_spec/test_land_specl.py b/tests/land_spec/HSP2Results/test_land_specl.py similarity index 96% rename from tests/land_spec/test_land_specl.py rename to tests/land_spec/HSP2Results/test_land_specl.py index 6d5216a7..d24def2c 100644 --- a/tests/land_spec/test_land_specl.py +++ b/tests/land_spec/HSP2Results/test_land_specl.py @@ -38,6 +38,8 @@ ftables = parameter_obj.ftables specactions = parameter_obj.specactions monthdata = parameter_obj.monthdata +conditions = specactions['conditions'] +actions = specactions['ACTIONS'] start, stop = siminfo["start"], siminfo["stop"] From 8e8986e10019952da98dd4044f13ce8a76c61b5a Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 20 Jan 2026 22:35:28 +0000 Subject: [PATCH 360/378] reformat --- .../land_spec/HSP2Results/test_land_specl.py | 167 +----------------- 1 file changed, 8 insertions(+), 159 deletions(-) diff --git a/tests/land_spec/HSP2Results/test_land_specl.py b/tests/land_spec/HSP2Results/test_land_specl.py index d24def2c..eb10eba7 100644 --- a/tests/land_spec/HSP2Results/test_land_specl.py +++ b/tests/land_spec/HSP2Results/test_land_specl.py @@ -2,18 +2,20 @@ # bare bones tester - must be run from the HSPsquared source directory import os + import numpy +from hsp2.hsp2.configuration import activities from hsp2.hsp2.main import * -from hsp2.state.state import * from hsp2.hsp2.om import * +from hsp2.hsp2.om_timer import timer_class from hsp2.hsp2.SPECL import * from hsp2.hsp2io.hdf import HDF5 from hsp2.hsp2io.io import IOManager from hsp2.hsp2tools.readUCI import * -from hsp2.hsp2.configuration import activities -from src.hsp2.hsp2tools.commands import import_uci, run +from hsp2.state.state import * from pandas import read_hdf -from hsp2.hsp2.om_timer import timer_class + +from src.hsp2.hsp2tools.commands import import_uci, run timer = timer_class() @@ -38,160 +40,7 @@ ftables = parameter_obj.ftables specactions = parameter_obj.specactions monthdata = parameter_obj.monthdata -conditions = specactions['conditions'] -actions = specactions['ACTIONS'] +conditions = specactions["conditions"] +actions = specactions["ACTIONS"] 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, 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, 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_500.ix in state.op_exec_lists[] - -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 -activity = 'HYDR' -seg_path = "/STATE/" + state.model_root_name + "/" + RCHRES.name -activity_path = seg_path + "/" + activity -activity_id = state.set_state(activity_path, 0.0) -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 = om_operations["model_object_cache"]["/STATE/RCHRES_R001/Rlocal"] -Rlocal_ts = Rlocal.read_ts() -rchres1 = om_operations["model_object_cache"]["/STATE/RCHRES_R001"] -Rlocal_check = ModelLinkage( - "Rlocal1", rchres1, {"right_path": "/TIMESERIES/TS010", "link_type": 3} -) -# Calls: -# - ts = Rlocal.io_manager.read_ts(Category.INPUTS, None, Rlocal.ts_name) -# - ts = transform(ts, Rlocal.ts_name, 'SAME', Rlocal.siminfo) -Rlocal.io_manager._output._store.keys() -# write it back. We can give an arbitrary name or it will default to write back to the source path in right_path variable -ts1 = ( - precip_ts.read_ts() -) # same as precip_ts.ts_ix[precip_ts.ix], same as state['ts_ix'][precip_ts.ix] -# we can specify a custom path to write this TS to -precip_ts.write_path = "/RESULTS/test_TS039" -precip_ts.write_ts() -# precip_ts.write_ts is same as: -# ts4 = precip_ts.format_ts(ts1, ['tsvalue'], siminfo['tindex']) -# ts4.to_hdf(precip_ts.io_manager._output._store, precip_ts.write_path, format='t', data_columns=True, complevel=precip_ts.complevel) - -start = time.time() -iterate_models( - model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, siminfo["steps"], -1 -) -end = time.time() -print( - len(model_exec_list), - "components iterated over state_ix", - siminfo["steps"], - "time steps took", - 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']) From 88c26751181b1f23a9afc2bda6639260684488ec Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 20 Jan 2026 17:39:20 -0500 Subject: [PATCH 361/378] remove reference to class in parallel branch --- tests/land_spec/HSP2Results/test_land_specl.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/land_spec/HSP2Results/test_land_specl.py b/tests/land_spec/HSP2Results/test_land_specl.py index d24def2c..5a7eda8b 100644 --- a/tests/land_spec/HSP2Results/test_land_specl.py +++ b/tests/land_spec/HSP2Results/test_land_specl.py @@ -11,11 +11,7 @@ from hsp2.hsp2io.io import IOManager from hsp2.hsp2tools.readUCI import * from hsp2.hsp2.configuration import activities -from src.hsp2.hsp2tools.commands import import_uci, run from pandas import read_hdf -from hsp2.hsp2.om_timer import timer_class - -timer = timer_class() fpath = "./tests/land_spec/HSP2Results/hwmA51800.h5" # try also: From 53054871fe02e5ffe9532c2f4f604b4ad84e2b07 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 06:04:17 -0500 Subject: [PATCH 362/378] typo --- tests/land_spec/HSP2Results/test_land_specl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/land_spec/HSP2Results/test_land_specl.py b/tests/land_spec/HSP2Results/test_land_specl.py index 54a10376..33a0db19 100644 --- a/tests/land_spec/HSP2Results/test_land_specl.py +++ b/tests/land_spec/HSP2Results/test_land_specl.py @@ -10,7 +10,7 @@ from hsp2.state.state import * -th = "./tests/land_spec/HSP2Results/hwmA51800.h5" +fpath = "./tests/land_spec/HSP2Results/hwmA51800.h5" # try also: # fpath = './tests/testcbp/HSP2results/JL1_6562_6560.h5' From 687e9f5d08a90f7082cefe6d4ce33c5a0ea7ebc4 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 06:18:10 -0500 Subject: [PATCH 363/378] Move exploratory code from tests to examples to avoid triggering spurious errors --- .../HSP2Results => examples/state_specl_ops}/test_land_specl.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {tests/land_spec/HSP2Results => examples/state_specl_ops}/test_land_specl.py (100%) diff --git a/tests/land_spec/HSP2Results/test_land_specl.py b/examples/state_specl_ops/test_land_specl.py similarity index 100% rename from tests/land_spec/HSP2Results/test_land_specl.py rename to examples/state_specl_ops/test_land_specl.py From ca3cd99e046c1329b243923e1d30325cbce32ce6 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 06:45:12 -0500 Subject: [PATCH 364/378] close hdf at end of demo script --- examples/state_specl_ops/test_land_specl.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/state_specl_ops/test_land_specl.py b/examples/state_specl_ops/test_land_specl.py index 33a0db19..fb88e9c1 100644 --- a/examples/state_specl_ops/test_land_specl.py +++ b/examples/state_specl_ops/test_land_specl.py @@ -35,3 +35,4 @@ actions = specactions["ACTIONS"] start, stop = siminfo["start"], siminfo["stop"] +hdf5_instance._store.close() From 95d4203b41a056ced08c9f6132dd896facd7d246 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 06:46:17 -0500 Subject: [PATCH 365/378] change name from test so not auto triggered --- .../state_specl_ops/{test_land_specl.py => demo_land_specl.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/state_specl_ops/{test_land_specl.py => demo_land_specl.py} (100%) diff --git a/examples/state_specl_ops/test_land_specl.py b/examples/state_specl_ops/demo_land_specl.py similarity index 100% rename from examples/state_specl_ops/test_land_specl.py rename to examples/state_specl_ops/demo_land_specl.py From dd7eb6147488a433258737bc263d67f11c17dece Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 07:22:18 -0500 Subject: [PATCH 366/378] initialize HSP2 rchres etc earlier in the process --- src/hsp2/hsp2/main.py | 4 +++- src/hsp2/hsp2/om.py | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index d41d2955..d427698c 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -32,7 +32,8 @@ state_om_model_run_prep, state_load_dynamics_om, state_om_model_run_finish, - hsp2_domain_dependencies + hsp2_domain_dependencies, + state_om_model_root_object ) from hsp2.hsp2.om_timer import timer_class from hsp2.hsp2.SPECL import specl_load_om @@ -101,6 +102,7 @@ def main( ) om_operations = om_init_state() # set up operational model specific containers state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) + state_om_model_root_object(state, om_operations, siminfo) # 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) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index ed8f9d53..c8a17cf0 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -193,10 +193,7 @@ def state_om_model_root_object(state, om_operations, siminfo): def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): - # insure model base is set - timer = timer_class() - state_om_model_root_object(state, om_operations, siminfo) - # now instantiate and link objects + # instantiate and link objects # 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"] From e8fd513bb10f0bf92fd0a055f92e76207b44761d Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 21 Jan 2026 07:48:56 -0500 Subject: [PATCH 367/378] use direct dictionary referecnes instead of copies (which should pass by reference but maybe dont) --- src/hsp2/hsp2/om.py | 30 +++------------------ tests/testcbp/HSP2results/check_equation.py | 1 + 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index c8a17cf0..f6a4ac8d 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -195,39 +195,23 @@ def state_om_model_root_object(state, om_operations, siminfo): def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): # instantiate and link objects # 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 + om_operations["model_data"], om_operations["model_root_object"], state, om_operations["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_path_loader(model_object_cache) + model_path_loader(om_operations["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 # 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[ + om_operations["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( - # len(model_root_object.state.state_ix) - # ) - model_tokenizer_recursive(model_root_object, model_object_cache, model_exec_list) - #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) + model_tokenizer_recursive(om_operations["model_root_object"], om_operations["model_object_cache"], 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" - 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" @@ -237,12 +221,6 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): 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 diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 52624294..851c9661 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -50,6 +50,7 @@ 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) +state_om_model_root_object(state, om_operations, siminfo) # 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) From edc451fabf97d8d2bb0d3527fd145fbcf2709edc Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 09:08:16 -0500 Subject: [PATCH 368/378] break out state initializers to handle reorder --- src/hsp2/hsp2/main.py | 4 +++- src/hsp2/hsp2/om.py | 4 +++- tests/testcbp/HSP2results/check_equation.py | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index d427698c..89b897e3 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -33,7 +33,8 @@ state_load_dynamics_om, state_om_model_run_finish, hsp2_domain_dependencies, - state_om_model_root_object + state_om_model_root_object, + om_init_hsp2_segments ) from hsp2.hsp2.om_timer import timer_class from hsp2.hsp2.SPECL import specl_load_om @@ -109,6 +110,7 @@ def main( # Iterate through all segments and add crucial paths to state # before loading dynamic components that may reference them state_init_hsp2(state, opseq, activities, timer) + om_init_hsp2_segments(state, om_operations) # 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 diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index f6a4ac8d..dc5db446 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -164,7 +164,6 @@ def state_load_dynamics_om(state, io_manager, siminfo, om_operations): 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. - timer = timer_class() if "model_root_object" not in om_operations.keys(): model_root_object = ModelObject( state.model_root_name, False, {}, state, om_operations["model_object_cache"] @@ -180,6 +179,9 @@ def state_om_model_root_object(state, om_operations, siminfo): 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 + + +def om_init_hsp2_segments(state, om_operations): 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 diff --git a/tests/testcbp/HSP2results/check_equation.py b/tests/testcbp/HSP2results/check_equation.py index 851c9661..abfd8786 100644 --- a/tests/testcbp/HSP2results/check_equation.py +++ b/tests/testcbp/HSP2results/check_equation.py @@ -10,11 +10,12 @@ from hsp2.hsp2io.hdf import HDF5 from hsp2.hsp2io.io import IOManager from hsp2.state.state import * +from hsp2.hsp2.om_timer import timer_class fpath = "./tests/testcbp/HSP2results/PL3_5250_0001.h5" # try also: # fpath = './tests/testcbp/HSP2results/JL1_6562_6560.h5' - +timer = timer_class() # 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() From b7dc74cb351e93616fd91d980ad13e023bad994c Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 09:13:23 -0500 Subject: [PATCH 369/378] break out state initializers to handle reorder --- .../state_specl_ops/demo_specl_initialize.py | 104 +++++++++++++----- src/hsp2/hsp2/main.py | 6 +- src/hsp2/hsp2/om.py | 2 +- 3 files changed, 83 insertions(+), 29 deletions(-) diff --git a/examples/state_specl_ops/demo_specl_initialize.py b/examples/state_specl_ops/demo_specl_initialize.py index 2f6b3fbb..1c79b71c 100644 --- a/examples/state_specl_ops/demo_specl_initialize.py +++ b/examples/state_specl_ops/demo_specl_initialize.py @@ -1,36 +1,90 @@ +# 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 -########################################################################################## -# LOAD HSP2 RUNTIME CODE AND UCI FILE -########################################################################################## -import os, numpy +import os +import numpy from hsp2.hsp2.main import * +from hsp2.state.state import * from hsp2.hsp2.om import * -from hsp2.hsp2.state import * +from hsp2.hsp2.SPECL import * from hsp2.hsp2io.hdf import HDF5 from hsp2.hsp2io.io import IOManager -hdf5_instance = HDF5("./tests/test10specl/HSP2results/test10specl.demo.h5") +from hsp2.state.state import * +from hsp2.hsp2.om_timer import timer_class +fpath = "./tests/test10specl/HSP2results/test10specl.h5" +timer = timer_class() +# try also: +# fpath = './tests/testcbp/HSP2results/JL1_6562_6560.h5' -iomanager = IOManager(hdf5_instance) -uci_obj = iomanager.read_uci() -siminfo = uci_obj.siminfo -opseq = uci_obj.opseq -state = init_state_dicts() -state_siminfo_hsp2(uci_obj, siminfo, iomanager, state) +# 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) + +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 -# Add support for dynamic functions to operate on STATE -state_load_dynamics_hsp2(state, iomanager, siminfo) -state_init_hsp2(state, opseq, activities) -state["specactions"] = uci_obj.specactions # stash the specaction dict in state -om_init_state(state) # set up operational model specific state entries -specl_load_state(state, iomanager, siminfo) # traditional special actions -state_load_dynamics_om(state, iomanager, siminfo) -state_om_model_run_prep(state, iomanager, siminfo) -state_context_hsp2(state, "RCHRES", "R005", "SEDTRN") -domain, state_paths, state_ix, dict_ix, ts_ix, op_tokens = state["domain"], state["state_paths"], state["state_ix"], state["dict_ix"], state["ts_ix"], state["op_tokens"] -ep_list = np.asarray(["RSED1", "RSED2", "RSED3", "RSED4", "RSED5", "RSED6"], dtype='U') -model_exec_list = model_domain_dependencies(state, domain, ep_list, True) -get_domain_state(state_paths, state_ix, domain, ep_list) +# read user control, parameters, states, and flags parameters and map to local variables +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 = {} +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 = 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) +state_om_model_root_object(state, om_operations, 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, timer) +om_init_hsp2_segments(state, om_operations) +# now initialize all state variables for mutable variables +hsp2_domain_dependencies(state, opseq, activities, om_operations, False) +# 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) +# - finally stash specactions in state, not domain (segment) dependent so do it once +specl_load_om(om_operations, specactions) # load traditional special actions +state_load_dynamics_om( + 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(opseq, activities, state, om_operations, siminfo) +section_timing["state om initialization()"] = str(timer.split()) + "seconds" +statenb = state_class_lite(0) +state_copy(state, statenb) +####################################################################################### diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index 89b897e3..ded51f0f 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -104,15 +104,15 @@ def main( om_operations = om_init_state() # set up operational model specific containers state_siminfo_hsp2(state, parameter_obj, siminfo, io_manager) state_om_model_root_object(state, om_operations, siminfo) - # 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, timer) om_init_hsp2_segments(state, om_operations) # now initialize all state variables for mutable variables hsp2_domain_dependencies(state, opseq, activities, om_operations, False) + # 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) # - finally stash specactions in state, not domain (segment) dependent so do it once specl_load_om(om_operations, specactions) # load traditional special actions state_load_dynamics_om( diff --git a/src/hsp2/hsp2/om.py b/src/hsp2/hsp2/om.py index dc5db446..aec93525 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -190,7 +190,7 @@ def om_init_hsp2_segments(state, om_operations): # Create an object shell for this # 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, {}) + segment = ModelObject(seg_name, om_operations["model_root_object"], {}) om_operations["model_object_cache"][segment.state_path] = segment From b09c01990250fb30d03b630b7a1512aa20f6e53a Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 11:41:07 -0500 Subject: [PATCH 370/378] do not enclose in parens does this help testing? --- src/hsp2/hsp2/om_model_object.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index b0c549d1..338ce4ba 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -63,9 +63,7 @@ def __init__( 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.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: From 205c8ee80e235e6cd6fa9cf105f386c7a02e70a1 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 12:09:29 -0500 Subject: [PATCH 371/378] restore parens --- src/hsp2/hsp2/om_model_object.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_model_object.py b/src/hsp2/hsp2/om_model_object.py index 338ce4ba..b0c549d1 100644 --- a/src/hsp2/hsp2/om_model_object.py +++ b/src/hsp2/hsp2/om_model_object.py @@ -63,7 +63,9 @@ def __init__( 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.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: From 4efdafe69482173fdfef74b74892f40aa59b98d8 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 16:57:58 -0500 Subject: [PATCH 372/378] develop-state-class --- examples/state_specl_ops/debug_pyt_est.py | 77 +++++++++++++++++++++++ tests/convert/regression_base.py | 2 +- 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 examples/state_specl_ops/debug_pyt_est.py diff --git a/examples/state_specl_ops/debug_pyt_est.py b/examples/state_specl_ops/debug_pyt_est.py new file mode 100644 index 00000000..5cd13d98 --- /dev/null +++ b/examples/state_specl_ops/debug_pyt_est.py @@ -0,0 +1,77 @@ +from pathlib import Path + +import pytest +from hsp2.hsp2tools.commands import import_uci, run +from hsp2.hsp2tools.HDF5 import HDF5 + +from convert.regression_base import RegressTest as RegressTestBase + + +class RegressTest(RegressTestBase): + def _get_hsp2_data(self, test_root) -> None: + test_root_hspf = Path(test_root) / "HSPFresults" + hspf_uci = test_root_hspf.resolve() / f"{self.compare_case}.uci" + assert hspf_uci.exists() + + temp_h5file = test_root_hspf / f"{self.compare_case}.h5" + if temp_h5file.exists(): + temp_h5file.unlink() + + self.temp_h5file = temp_h5file + + import_uci(str(hspf_uci), str(self.temp_h5file)) + run(self.temp_h5file, saveall=True, compress=False) + self.hsp2_data = HDF5(str(self.temp_h5file)) + + def _init_files(self): + test_dir = Path(__file__).resolve().parent + assert test_dir.name == "tests" + + test_root = test_dir / self.compare_case + assert test_root.exists() + + self._get_hbn_data(str(test_root)) + self._get_hsp2_data(str(test_root)) + + +@pytest.mark.parametrize( + "case", + [ + # "test05", + # "test09", + "test10", + "test10specl", + # "test10b", + ], +) +def test_case(case): + test = RegressTest(case, threads=1) + results = test.run_test() + test.temp_h5file.unlink() + + found = False + mismatches = [] + for key, results in results.items(): + no_data_hsp2, no_data_hspf, match, diff = results + if any([no_data_hsp2, no_data_hspf]): + continue + if not match: + mismatches.append((case, key, results)) + found = True + assert found + + if mismatches: + for case, key, results in mismatches: + _, _, _, diff = results + print(case, key, f"{diff:0.00%}") + raise ValueError("results don't match hspf output") + + +# demo the code in regression_base.py with this: +# creates a shell object namd "self" that can have attributes just added +self = type('', (), {})() +self.compare_case='test10' +self.html_file = os.path.join( + tests_root_dir, f"HSPF_HSP2_{self.compare_case}.html" +) +self.html_file diff --git a/tests/convert/regression_base.py b/tests/convert/regression_base.py index 6cfc4f87..f874ec8e 100644 --- a/tests/convert/regression_base.py +++ b/tests/convert/regression_base.py @@ -47,7 +47,7 @@ def _init_files(self): for test_dir in test_dirs: if test_dir == self.compare_case: test_root = os.path.join(tests_root_dir, test_dir) - + print("Paths loaded, getting hdf5 ad hbn data") self._get_hdf5_data(test_root) self._get_hbn_data(test_root) From 29ef8b65d0276fb5eba2db61ba7a1caff6b1ee4d Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 17:05:47 -0500 Subject: [PATCH 373/378] develop-state-class --- tests/convert/regression_base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/convert/regression_base.py b/tests/convert/regression_base.py index f874ec8e..a271b0ad 100644 --- a/tests/convert/regression_base.py +++ b/tests/convert/regression_base.py @@ -47,8 +47,9 @@ def _init_files(self): for test_dir in test_dirs: if test_dir == self.compare_case: test_root = os.path.join(tests_root_dir, test_dir) - print("Paths loaded, getting hdf5 ad hbn data") + print("Paths loaded, getting hdf5 data") self._get_hdf5_data(test_root) + print("hdf5 loaded, getting hbn data") self._get_hbn_data(test_root) def _get_hbn_data(self, test_dir: str) -> None: From 6b9373543065da4a80fe54e40fc0d50edd3f7a95 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 17:07:45 -0500 Subject: [PATCH 374/378] info --- tests/convert/regression_base.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/convert/regression_base.py b/tests/convert/regression_base.py index a271b0ad..9e22c47a 100644 --- a/tests/convert/regression_base.py +++ b/tests/convert/regression_base.py @@ -47,13 +47,14 @@ def _init_files(self): for test_dir in test_dirs: if test_dir == self.compare_case: test_root = os.path.join(tests_root_dir, test_dir) - print("Paths loaded, getting hdf5 data") + print("Paths loaded, getting hdf5 data from", test_root) self._get_hdf5_data(test_root) - print("hdf5 loaded, getting hbn data") + print("hdf5 loaded, getting hbn data from", test_root) self._get_hbn_data(test_root) def _get_hbn_data(self, test_dir: str) -> None: sub_dir = os.path.join(test_dir, "HSPFresults") + print("Loading hbn data from", sub_dir) self.hspf_data_collection = {} for file in os.listdir(sub_dir): if file.lower().endswith(".hbn"): @@ -73,6 +74,7 @@ def get_hspf_time_series(self, ops: OperationsTuple) -> Union[pd.Series, None]: def _get_hdf5_data(self, test_dir: str) -> None: sub_dir = os.path.join(test_dir, "HSP2results") + print("Loading hdf5 data from", sub_dir) for file in os.listdir(sub_dir): if file.lower().endswith(".h5") or file.lower().endswith(".hdf"): self.hsp2_data = HDF5(os.path.join(sub_dir, file)) From 38adfeeef83c7ce85203fa0a16b87bb003400c50 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 17:37:54 -0500 Subject: [PATCH 375/378] allow tests_root_dir to be passed in instead of guessing --- tests/convert/regression_base.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/convert/regression_base.py b/tests/convert/regression_base.py index 9e22c47a..0cb86872 100644 --- a/tests/convert/regression_base.py +++ b/tests/convert/regression_base.py @@ -23,6 +23,7 @@ def __init__( tcodes: List[str] = ["2"], ids: List[str] = [], threads: int = os.cpu_count() - 1, + tests_root_dir = None ) -> None: self.compare_case = compare_case self.operations = operations @@ -30,31 +31,31 @@ def __init__( self.tcodes = tcodes self.ids = ids self.threads = threads - + if tests_root_dir is None: + current_directory = os.path.dirname( + os.path.abspath(inspect.getframeinfo(inspect.currentframe()).filename) + ) + source_root_path = os.path.split(os.path.split(current_directory)[0])[0] + self.tests_root_dir = os.path.join(source_root_path, "tests") + else: + self.tests_root_dir = tests_root_dir self._init_files() def _init_files(self): - current_directory = os.path.dirname( - os.path.abspath(inspect.getframeinfo(inspect.currentframe()).filename) - ) - source_root_path = os.path.split(os.path.split(current_directory)[0])[0] - tests_root_dir = os.path.join(source_root_path, "tests") self.html_file = os.path.join( - tests_root_dir, f"HSPF_HSP2_{self.compare_case}.html" + self.tests_root_dir, f"HSPF_HSP2_{self.compare_case}.html" ) test_dirs = os.listdir(tests_root_dir) for test_dir in test_dirs: if test_dir == self.compare_case: test_root = os.path.join(tests_root_dir, test_dir) - print("Paths loaded, getting hdf5 data from", test_root) + self._get_hdf5_data(test_root) - print("hdf5 loaded, getting hbn data from", test_root) self._get_hbn_data(test_root) def _get_hbn_data(self, test_dir: str) -> None: sub_dir = os.path.join(test_dir, "HSPFresults") - print("Loading hbn data from", sub_dir) self.hspf_data_collection = {} for file in os.listdir(sub_dir): if file.lower().endswith(".hbn"): @@ -74,7 +75,6 @@ def get_hspf_time_series(self, ops: OperationsTuple) -> Union[pd.Series, None]: def _get_hdf5_data(self, test_dir: str) -> None: sub_dir = os.path.join(test_dir, "HSP2results") - print("Loading hdf5 data from", sub_dir) for file in os.listdir(sub_dir): if file.lower().endswith(".h5") or file.lower().endswith(".hdf"): self.hsp2_data = HDF5(os.path.join(sub_dir, file)) From c70a3436ebd4c2dd58120880fa5c9ba0b995320f Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 22 Jan 2026 07:03:56 -0500 Subject: [PATCH 376/378] test directory handling --- tests/convert/regression_base.py | 4 ++-- tests/test_regression.py | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/tests/convert/regression_base.py b/tests/convert/regression_base.py index 0cb86872..c77b27c1 100644 --- a/tests/convert/regression_base.py +++ b/tests/convert/regression_base.py @@ -46,10 +46,10 @@ def _init_files(self): self.tests_root_dir, f"HSPF_HSP2_{self.compare_case}.html" ) - test_dirs = os.listdir(tests_root_dir) + test_dirs = os.listdir(self.tests_root_dir) for test_dir in test_dirs: if test_dir == self.compare_case: - test_root = os.path.join(tests_root_dir, test_dir) + test_root = os.path.join(self.tests_root_dir, test_dir) self._get_hdf5_data(test_root) self._get_hbn_data(test_root) diff --git a/tests/test_regression.py b/tests/test_regression.py index 21051a77..19f8e8d0 100644 --- a/tests/test_regression.py +++ b/tests/test_regression.py @@ -8,6 +8,23 @@ class RegressTest(RegressTestBase): + def __init__( + self, + compare_case: str, + operations: List[str] = [], + activities: List[str] = [], + tcodes: List[str] = ["2"], + ids: List[str] = [], + threads: int = os.cpu_count() - 1, + tests_root_dir = None + ) -> None: + if tests_root_dir is None: + tests_root_dir = Path(__file__).resolve().parent + super(RegressTest, self).__init__( + compare_case, operations, activities, + tcodes, ids, threads, tests_root_dir + ) + def _get_hsp2_data(self, test_root) -> None: test_root_hspf = Path(test_root) / "HSPFresults" hspf_uci = test_root_hspf.resolve() / f"{self.compare_case}.uci" @@ -24,10 +41,9 @@ def _get_hsp2_data(self, test_root) -> None: self.hsp2_data = HDF5(str(self.temp_h5file)) def _init_files(self): - test_dir = Path(__file__).resolve().parent - assert test_dir.name == "tests" + assert self.tests_root_dir.name == "tests" - test_root = test_dir / self.compare_case + test_root = self.tests_root_dir / self.compare_case assert test_root.exists() self._get_hbn_data(str(test_root)) From 23b5db6ccba1fef992d5dbfb122a4a69e52f52b2 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 22 Jan 2026 07:30:03 -0500 Subject: [PATCH 377/378] get fixed tests --- tests/test_regression.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_regression.py b/tests/test_regression.py index 19f8e8d0..8f1fa658 100644 --- a/tests/test_regression.py +++ b/tests/test_regression.py @@ -1,8 +1,10 @@ from pathlib import Path +import os import pytest from hsp2.hsp2tools.commands import import_uci, run from hsp2.hsp2tools.HDF5 import HDF5 +from typing import Dict, List, Tuple, Union from .convert.regression_base import RegressTest as RegressTestBase @@ -41,9 +43,10 @@ def _get_hsp2_data(self, test_root) -> None: self.hsp2_data = HDF5(str(self.temp_h5file)) def _init_files(self): + print("Checking tests_root_dir has tests in the name") assert self.tests_root_dir.name == "tests" - test_root = self.tests_root_dir / self.compare_case + print("Checking case tests_dir exists:", test_root) assert test_root.exists() self._get_hbn_data(str(test_root)) From 8541f473a48cc759573d675913b339c34f402479 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Fri, 23 Jan 2026 11:22:46 -0500 Subject: [PATCH 378/378] pass objects to clean up routine --- src/hsp2/hsp2/main.py | 2 +- src/hsp2/hsp2/om.py | 7 +++---- tests/test_regression.py | 11 +++-------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index ded51f0f..3f588aae 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -541,7 +541,7 @@ def main( msglist = msg(1, "Done", final=True) # Finish operational models - state_om_model_run_finish(statenb, io_manager, siminfo) + state_om_model_run_finish(statenb, io_manager, om_operations) 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 aec93525..066090e7 100644 --- a/src/hsp2/hsp2/om.py +++ b/src/hsp2/hsp2/om.py @@ -227,10 +227,9 @@ def state_om_model_run_prep(opseq, activities, state, om_operations, siminfo): hsp2_domain_dependencies(state, opseq, activities, om_operations, False) return - -def state_om_model_run_finish(state, io_manager, siminfo): +def state_om_model_run_finish(state, io_manager, om_operations): # write logs and other post-processing steps (if any) - finish_model(state, io_manager, siminfo) + finish_model(state, io_manager, om_operations) return True @@ -714,7 +713,7 @@ def step_model(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, step): return -def finish_model(state, io_manager, siminfo): +def finish_model(state, io_manager, om_operations): # 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"][ diff --git a/tests/test_regression.py b/tests/test_regression.py index 8f1fa658..eb8f50a9 100644 --- a/tests/test_regression.py +++ b/tests/test_regression.py @@ -10,14 +10,9 @@ class RegressTest(RegressTestBase): - def __init__( - self, - compare_case: str, - operations: List[str] = [], - activities: List[str] = [], - tcodes: List[str] = ["2"], - ids: List[str] = [], - threads: int = os.cpu_count() - 1, + def __init__(self, compare_case: str, operations: List[str] = [], + activities: List[str] = [], tcodes: List[str] = ["2"], + ids: List[str] = [], threads: int = os.cpu_count() - 1, tests_root_dir = None ) -> None: if tests_root_dir is None: