From 938f68e7b21574bf7e5fbd5e44a3dd1821ec6714 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 16 Oct 2025 14:33:38 -0400 Subject: [PATCH 001/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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/353] 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 5f8a6d6bcf505d2cc1e753a7ef750732a31162bb Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 5 Jan 2026 13:10:45 -0500 Subject: [PATCH 149/353] 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 150/353] 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 151/353] 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 152/353] 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 153/353] 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 154/353] 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 155/353] 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 156/353] 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 157/353] 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 158/353] 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 159/353] 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 160/353] 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 161/353] 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 162/353] 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 163/353] 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 164/353] 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 165/353] 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 166/353] 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 167/353] 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 168/353] 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 169/353] 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 170/353] 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 171/353] 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 172/353] 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 173/353] 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 174/353] 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 175/353] 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 176/353] 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 177/353] 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 178/353] 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 179/353] 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 180/353] 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 181/353] 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 182/353] 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 183/353] 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 184/353] 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 185/353] 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 186/353] 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 187/353] 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 188/353] 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 189/353] 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 190/353] 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 191/353] 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 192/353] 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 193/353] 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 194/353] 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 195/353] 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 196/353] 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 197/353] 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 198/353] 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 199/353] 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 200/353] 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 201/353] 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 202/353] 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 203/353] 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 204/353] 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 205/353] 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 206/353] 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 207/353] 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 208/353] 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 209/353] 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 210/353] 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 211/353] 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 212/353] 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 213/353] 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 214/353] 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 215/353] 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 216/353] 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 217/353] 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 218/353] 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 219/353] 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 220/353] 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 221/353] 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 222/353] 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 223/353] 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 224/353] 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 225/353] 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 226/353] 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 227/353] 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 228/353] 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 229/353] 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 230/353] 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 231/353] 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 232/353] 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 233/353] 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 234/353] 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 235/353] 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 236/353] 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 237/353] 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 238/353] 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 239/353] 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 240/353] 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 241/353] 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 242/353] 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 243/353] 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 244/353] 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 245/353] 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 246/353] 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 247/353] 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 248/353] 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 249/353] 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 250/353] 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 251/353] 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 252/353] 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 253/353] 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 254/353] 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 255/353] 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 256/353] 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 257/353] 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 258/353] 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 259/353] 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 260/353] 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 261/353] 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 262/353] 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 263/353] 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 264/353] 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 265/353] 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 266/353] 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 267/353] 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 268/353] 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 269/353] 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 270/353] 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 271/353] 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 272/353] 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 273/353] 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 274/353] 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 275/353] 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 276/353] 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 277/353] 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 278/353] 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 279/353] 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 280/353] 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 281/353] 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 282/353] 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 283/353] 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 284/353] 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 285/353] 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 286/353] 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 287/353] 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 288/353] 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 289/353] 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 290/353] 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 291/353] 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 292/353] 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 293/353] 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 294/353] 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 295/353] 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 296/353] 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 297/353] 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 298/353] 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 299/353] 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 300/353] 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 301/353] 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 302/353] 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 303/353] 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 304/353] 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 305/353] 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 306/353] 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 307/353] 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 308/353] 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 309/353] 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 310/353] 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 311/353] 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 312/353] 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 313/353] 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 314/353] 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 315/353] 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 316/353] 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 317/353] 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 318/353] 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 319/353] 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 320/353] 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 321/353] 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 322/353] 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 323/353] 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 324/353] 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 325/353] 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 dd7eb6147488a433258737bc263d67f11c17dece Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Wed, 21 Jan 2026 07:22:18 -0500 Subject: [PATCH 326/353] 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 327/353] 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 328/353] 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 329/353] 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 330/353] 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 331/353] 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 332/353] 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 333/353] 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 334/353] 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 335/353] 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 336/353] 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 337/353] 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 338/353] 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: From 7829bf7adcb48d95062308720f0b487167ff94c9 Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 27 Jan 2026 02:37:11 +0000 Subject: [PATCH 339/353] merged changes from utilities.py into this branch --- src/hsp2/hsp2/utilities.py | 80 +++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/src/hsp2/hsp2/utilities.py b/src/hsp2/hsp2/utilities.py index 4cd17dd2..7c210ccf 100644 --- a/src/hsp2/hsp2/utilities.py +++ b/src/hsp2/hsp2/utilities.py @@ -14,7 +14,7 @@ from numba import types from numba.typed import Dict from numpy import float64, full, tile, zeros -from pandas import Series, date_range +from pandas import Series, date_range, Timedelta from pandas.tseries.offsets import Minute from hsp2.hsp2io.protocols import Category, SupportsReadTS, SupportsWriteTS @@ -213,8 +213,9 @@ def transform(ts, name, how, siminfo): NOTE: these routines work for both regular and sparse timeseries input """ - tsfreq = ts.index.freq - freq = Minute(siminfo["delt"]) + tsfreq = Timedelta("1 " + ts.index.freqstr) + fmins = Minute(siminfo["delt"]) + freq = Timedelta(fmins).to_timedelta64() stop = siminfo["stop"] # append duplicate of last point to force processing last full interval @@ -226,7 +227,7 @@ def transform(ts, name, how, siminfo): elif tsfreq is None: # Sparse time base, frequency not defined ts = ts.reindex(siminfo["tbase"]).ffill().bfill() elif how == "SAME": - ts = ts.resample(freq).ffill() # tsfreq >= freq assumed, or bad user choice + ts = ts.resample(fmins).ffill() # tsfreq >= freq assumed, or bad user choice elif not how: if name in flowtype: if "Y" in str(tsfreq) or "M" in str(tsfreq) or tsfreq > freq: @@ -236,24 +237,24 @@ def transform(ts, name, how, siminfo): ratio = 1.0 / 8766.0 else: ratio = freq / tsfreq - ts = (ratio * ts).resample(freq).ffill() # HSP2 how = div + ts = (ratio * ts).resample(fmins).ffill() # HSP2 how = div else: - ts = ts.resample(freq).sum() + ts = ts.resample(fmins).sum() else: if "Y" in str(tsfreq) or "M" in str(tsfreq) or tsfreq > freq: - ts = ts.resample(freq).ffill() + ts = ts.resample(fmins).ffiio_managerll() else: - ts = ts.resample(freq).mean() + ts = ts.resample(fmins).mean() elif how == "MEAN": - ts = ts.resample(freq).mean() + ts = ts.resample(fmins).mean() elif how == "SUM": - ts = ts.resample(freq).sum() + ts = ts.resample(fmins).sum() elif how == "MAX": - ts = ts.resample(freq).max() + ts = ts.resample(fmins).max() elif how == "MIN": - ts = ts.resample(freq).min() + ts = ts.resample(fmins).min() elif how == "LAST": - ts = ts.resample(freq).ffill() + ts = ts.resample(fmins).ffill() elif how == "DIV": if "Y" in str(tsfreq) or "M" in str(tsfreq): mult = 1 @@ -268,13 +269,13 @@ def transform(ts, name, how, siminfo): ratio = 1.0 / (8766.0 * mult) else: ratio = freq / tsfreq - ts = (ratio * ts).resample(freq).ffill() # HSP2 how = div + ts = (ratio * ts).resample(fmins).ffill() # HSP2 how = div else: - ts = (ts * (freq / ts.index.freq)).resample(freq).ffill() + ts = (ts * (freq / tsfreq)).resample(fmins).ffill() elif how == "ZEROFILL": - ts = ts.resample(freq).fillna(0.0) + ts = ts.resample(fmins).fillna(0.0) elif how == "INTERPOLATE": - ts = ts.resample(freq).interpolate() + ts = ts.resample(fmins).interpolate() else: print(f"UNKNOWN method in TRANS, {how}") return zeros(1) @@ -287,7 +288,8 @@ def hoursval(siminfo, hours24, dofirst=False, lapselike=False): """create hours flags, flag on the hour or lapse table over full simulation""" start = siminfo["start"] stop = siminfo["stop"] - freq = Minute(siminfo["delt"]) + fmins = Minute(siminfo["delt"]) + freq = Timedelta(fmins).to_timedelta64() dr = date_range( start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq=Minute(60) @@ -297,16 +299,17 @@ def hoursval(siminfo, hours24, dofirst=False, lapselike=False): hours[0] = 1 ts = Series(hours[0 : len(dr)], dr) + tsfreq = Timedelta("1 " + ts.index.freqstr) if lapselike: - if ts.index.freq > freq: # upsample - ts = ts.resample(freq).asfreq().ffill() - elif ts.index.freq < freq: # downsample - ts = ts.resample(freq).mean() + if tsfreq > freq: # upsample + ts = ts.resample(fmins).asfreq().ffill() + elif tsfreq < freq: # downsample + ts = ts.resample(fmins).mean() else: - if ts.index.freq > freq: # upsample - ts = ts.resample(freq).asfreq().fillna(0.0) - elif ts.index.freq < freq: # downsample - ts = ts.resample(freq).max() + if tsfreq > freq: # upsample + ts = ts.resample(fmins).asfreq().fillna(0.0) + elif tsfreq < freq: # downsample + ts = ts.resample(fmins).max() return ts.truncate(start, stop).to_numpy() @@ -321,16 +324,18 @@ def monthval(siminfo, monthly): """returns value at start of month for all times within the month""" start = siminfo["start"] stop = siminfo["stop"] - freq = Minute(siminfo["delt"]) + fmins = Minute(siminfo["delt"]) + freq = Timedelta(fmins).to_timedelta64() months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").ffill() + tsfreq = Timedelta("1 " + ts.index.freqstr) - if ts.index.freq > freq: # upsample - ts = ts.resample(freq).asfreq().ffill() - elif ts.index.freq < freq: # downsample - ts = ts.resample(freq).mean() + if tsfreq > freq: # upsample + ts = ts.resample(fmins).asfreq().ffill() + elif tsfreq < freq: # downsample + ts = ts.resample(fmins).mean() return ts.truncate(start, stop).to_numpy() @@ -339,16 +344,19 @@ def dayval(siminfo, monthly): interpolation to day, but constant within day""" start = siminfo["start"] stop = siminfo["stop"] - freq = Minute(siminfo["delt"]) + fmins = Minute(siminfo["delt"]) + freq = Timedelta(fmins).to_timedelta64() months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").interpolate("time") + tsfreq = Timedelta("1 " + ts.index.freqstr) - if ts.index.freq > freq: # upsample - ts = ts.resample(freq).ffill() - elif ts.index.freq < freq: # downsample - ts = ts.resample(freq).mean() + + if tsfreq > freq: # upsample + ts = ts.resample(fmins).ffill() + elif tsfreq < freq: # downsample + ts = ts.resample(fmins).mean() return ts.truncate(start, stop).to_numpy() From 15f5020d99e8bc3e99d0da68446bb9113f05d556 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Mon, 26 Jan 2026 21:39:10 -0500 Subject: [PATCH 340/353] integrated the changes to main.py get_flows for pandas > 3.0 --- 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 3f588aae..87af52c1 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -723,23 +723,23 @@ def get_flows( t = data_frame[smemn].astype(float64).to_numpy()[0:steps] if MFname in ts and AFname in ts: - t *= ts[MFname][:steps] * ts[AFname][0:steps] + t = t * ts[MFname][:steps] * ts[AFname][0:steps] msg(4, f"MFACTOR modified by timeseries {MFname}") msg(4, f"AFACTR modified by timeseries {AFname}") elif MFname in ts: - t *= afactr * ts[MFname][0:steps] + t = t * afactr * ts[MFname][0:steps] msg(4, f"MFACTOR modified by timeseries {MFname}") elif AFname in ts: - t *= mfactor * ts[AFname][0:steps] + t = t * mfactor * ts[AFname][0:steps] msg(4, f"AFACTR modified by timeseries {AFname}") else: - t *= factor + t = t * factor # if poht to iheat, imprecision in hspf conversion factor requires a slight adjustment if (smemn == "POHT" or smemn == "SOHT") and tmemn == "IHEAT": - t *= 0.998553 + t = t * 0.998553 if (smemn == "PODOXM" or smemn == "SODOXM") and tmemn == "OXIF1": - t *= 1.000565 + t = t * 1.000565 # ??? ISSUE: can fetched data be at different frequency - don't know how to transform. if tmemn in ts: From e7c5fe735f81a4efc23e1f7e13cf7c8c553fbc76 Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 27 Jan 2026 11:50:20 +0000 Subject: [PATCH 341/353] use root class object getter --- src/hsp2/hsp2/om_special_action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_special_action.py b/src/hsp2/hsp2/om_special_action.py index 8577ff3c..d92452c7 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.model_object_cache[self.find_var_path("timer")] + si = self.get_object(self, "timer") if len(model_props["YR"]) > 0: # translate date to equivalent model step datestring = ( From aa31b7efb7fb935b734bfc8a2d1717ced195de41 Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 27 Jan 2026 15:06:20 +0000 Subject: [PATCH 342/353] fix args --- src/hsp2/hsp2/om_special_action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsp2/hsp2/om_special_action.py b/src/hsp2/hsp2/om_special_action.py index d92452c7..abd1a8d5 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.get_object(self, "timer") + si = self.get_object("timer") if len(model_props["YR"]) > 0: # translate date to equivalent model step datestring = ( From de6db7aa4599d5af499eae0e628a88fe8b9d865d Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 27 Jan 2026 15:50:51 +0000 Subject: [PATCH 343/353] create new HDF5 close() method and call at the end of run(). --- src/hsp2/hsp2io/hdf.py | 5 ++++- src/hsp2/hsp2tools/commands.py | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hsp2/hsp2io/hdf.py b/src/hsp2/hsp2io/hdf.py index 201552ee..62bf7582 100644 --- a/src/hsp2/hsp2io/hdf.py +++ b/src/hsp2/hsp2io/hdf.py @@ -13,9 +13,12 @@ def __init__(self, file_path: str) -> None: self._store = pd.HDFStore(file_path) None - def __del__(self): + def close(self): self._store.close() + def __del__(self): + self.close() + def __enter__(self): return self diff --git a/src/hsp2/hsp2tools/commands.py b/src/hsp2/hsp2tools/commands.py index 057670e2..abadb83f 100644 --- a/src/hsp2/hsp2tools/commands.py +++ b/src/hsp2/hsp2tools/commands.py @@ -24,6 +24,7 @@ def run(h5file, saveall=True, compress=True): hdf5_instance = HDF5(h5file) io_manager = IOManager(hdf5_instance) main(io_manager, saveall=saveall, jupyterlab=compress) + hdf5_instance.close() def import_uci(ucifile, h5file): From 8bbedea27c1b7647a006975fed4d88409b309631 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Tue, 27 Jan 2026 16:52:03 -0500 Subject: [PATCH 344/353] changes to main and utilities to adapt to pandas 3 deprecations --- src/hsp2/hsp2/main.py | 12 +++--- src/hsp2/hsp2/utilities.py | 80 +++++++++++++++++++++----------------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/hsp2/hsp2/main.py b/src/hsp2/hsp2/main.py index b7ed561f..5b1aab0c 100644 --- a/src/hsp2/hsp2/main.py +++ b/src/hsp2/hsp2/main.py @@ -704,23 +704,23 @@ def get_flows( t = data_frame[smemn].astype(float64).to_numpy()[0:steps] if MFname in ts and AFname in ts: - t *= ts[MFname][:steps] * ts[AFname][0:steps] + t = t * ts[MFname][:steps] * ts[AFname][0:steps] msg(4, f"MFACTOR modified by timeseries {MFname}") msg(4, f"AFACTR modified by timeseries {AFname}") elif MFname in ts: - t *= afactr * ts[MFname][0:steps] + t = t * afactr * ts[MFname][0:steps] msg(4, f"MFACTOR modified by timeseries {MFname}") elif AFname in ts: - t *= mfactor * ts[AFname][0:steps] + t = t * mfactor * ts[AFname][0:steps] msg(4, f"AFACTR modified by timeseries {AFname}") else: - t *= factor + t = t * factor # if poht to iheat, imprecision in hspf conversion factor requires a slight adjustment if (smemn == "POHT" or smemn == "SOHT") and tmemn == "IHEAT": - t *= 0.998553 + t = t * 0.998553 if (smemn == "PODOXM" or smemn == "SODOXM") and tmemn == "OXIF1": - t *= 1.000565 + t = t * 1.000565 # ??? ISSUE: can fetched data be at different frequency - don't know how to transform. if tmemn in ts: diff --git a/src/hsp2/hsp2/utilities.py b/src/hsp2/hsp2/utilities.py index 4cd17dd2..7c210ccf 100644 --- a/src/hsp2/hsp2/utilities.py +++ b/src/hsp2/hsp2/utilities.py @@ -14,7 +14,7 @@ from numba import types from numba.typed import Dict from numpy import float64, full, tile, zeros -from pandas import Series, date_range +from pandas import Series, date_range, Timedelta from pandas.tseries.offsets import Minute from hsp2.hsp2io.protocols import Category, SupportsReadTS, SupportsWriteTS @@ -213,8 +213,9 @@ def transform(ts, name, how, siminfo): NOTE: these routines work for both regular and sparse timeseries input """ - tsfreq = ts.index.freq - freq = Minute(siminfo["delt"]) + tsfreq = Timedelta("1 " + ts.index.freqstr) + fmins = Minute(siminfo["delt"]) + freq = Timedelta(fmins).to_timedelta64() stop = siminfo["stop"] # append duplicate of last point to force processing last full interval @@ -226,7 +227,7 @@ def transform(ts, name, how, siminfo): elif tsfreq is None: # Sparse time base, frequency not defined ts = ts.reindex(siminfo["tbase"]).ffill().bfill() elif how == "SAME": - ts = ts.resample(freq).ffill() # tsfreq >= freq assumed, or bad user choice + ts = ts.resample(fmins).ffill() # tsfreq >= freq assumed, or bad user choice elif not how: if name in flowtype: if "Y" in str(tsfreq) or "M" in str(tsfreq) or tsfreq > freq: @@ -236,24 +237,24 @@ def transform(ts, name, how, siminfo): ratio = 1.0 / 8766.0 else: ratio = freq / tsfreq - ts = (ratio * ts).resample(freq).ffill() # HSP2 how = div + ts = (ratio * ts).resample(fmins).ffill() # HSP2 how = div else: - ts = ts.resample(freq).sum() + ts = ts.resample(fmins).sum() else: if "Y" in str(tsfreq) or "M" in str(tsfreq) or tsfreq > freq: - ts = ts.resample(freq).ffill() + ts = ts.resample(fmins).ffiio_managerll() else: - ts = ts.resample(freq).mean() + ts = ts.resample(fmins).mean() elif how == "MEAN": - ts = ts.resample(freq).mean() + ts = ts.resample(fmins).mean() elif how == "SUM": - ts = ts.resample(freq).sum() + ts = ts.resample(fmins).sum() elif how == "MAX": - ts = ts.resample(freq).max() + ts = ts.resample(fmins).max() elif how == "MIN": - ts = ts.resample(freq).min() + ts = ts.resample(fmins).min() elif how == "LAST": - ts = ts.resample(freq).ffill() + ts = ts.resample(fmins).ffill() elif how == "DIV": if "Y" in str(tsfreq) or "M" in str(tsfreq): mult = 1 @@ -268,13 +269,13 @@ def transform(ts, name, how, siminfo): ratio = 1.0 / (8766.0 * mult) else: ratio = freq / tsfreq - ts = (ratio * ts).resample(freq).ffill() # HSP2 how = div + ts = (ratio * ts).resample(fmins).ffill() # HSP2 how = div else: - ts = (ts * (freq / ts.index.freq)).resample(freq).ffill() + ts = (ts * (freq / tsfreq)).resample(fmins).ffill() elif how == "ZEROFILL": - ts = ts.resample(freq).fillna(0.0) + ts = ts.resample(fmins).fillna(0.0) elif how == "INTERPOLATE": - ts = ts.resample(freq).interpolate() + ts = ts.resample(fmins).interpolate() else: print(f"UNKNOWN method in TRANS, {how}") return zeros(1) @@ -287,7 +288,8 @@ def hoursval(siminfo, hours24, dofirst=False, lapselike=False): """create hours flags, flag on the hour or lapse table over full simulation""" start = siminfo["start"] stop = siminfo["stop"] - freq = Minute(siminfo["delt"]) + fmins = Minute(siminfo["delt"]) + freq = Timedelta(fmins).to_timedelta64() dr = date_range( start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq=Minute(60) @@ -297,16 +299,17 @@ def hoursval(siminfo, hours24, dofirst=False, lapselike=False): hours[0] = 1 ts = Series(hours[0 : len(dr)], dr) + tsfreq = Timedelta("1 " + ts.index.freqstr) if lapselike: - if ts.index.freq > freq: # upsample - ts = ts.resample(freq).asfreq().ffill() - elif ts.index.freq < freq: # downsample - ts = ts.resample(freq).mean() + if tsfreq > freq: # upsample + ts = ts.resample(fmins).asfreq().ffill() + elif tsfreq < freq: # downsample + ts = ts.resample(fmins).mean() else: - if ts.index.freq > freq: # upsample - ts = ts.resample(freq).asfreq().fillna(0.0) - elif ts.index.freq < freq: # downsample - ts = ts.resample(freq).max() + if tsfreq > freq: # upsample + ts = ts.resample(fmins).asfreq().fillna(0.0) + elif tsfreq < freq: # downsample + ts = ts.resample(fmins).max() return ts.truncate(start, stop).to_numpy() @@ -321,16 +324,18 @@ def monthval(siminfo, monthly): """returns value at start of month for all times within the month""" start = siminfo["start"] stop = siminfo["stop"] - freq = Minute(siminfo["delt"]) + fmins = Minute(siminfo["delt"]) + freq = Timedelta(fmins).to_timedelta64() months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").ffill() + tsfreq = Timedelta("1 " + ts.index.freqstr) - if ts.index.freq > freq: # upsample - ts = ts.resample(freq).asfreq().ffill() - elif ts.index.freq < freq: # downsample - ts = ts.resample(freq).mean() + if tsfreq > freq: # upsample + ts = ts.resample(fmins).asfreq().ffill() + elif tsfreq < freq: # downsample + ts = ts.resample(fmins).mean() return ts.truncate(start, stop).to_numpy() @@ -339,16 +344,19 @@ def dayval(siminfo, monthly): interpolation to day, but constant within day""" start = siminfo["start"] stop = siminfo["stop"] - freq = Minute(siminfo["delt"]) + fmins = Minute(siminfo["delt"]) + freq = Timedelta(fmins).to_timedelta64() months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").interpolate("time") + tsfreq = Timedelta("1 " + ts.index.freqstr) - if ts.index.freq > freq: # upsample - ts = ts.resample(freq).ffill() - elif ts.index.freq < freq: # downsample - ts = ts.resample(freq).mean() + + if tsfreq > freq: # upsample + ts = ts.resample(fmins).ffill() + elif tsfreq < freq: # downsample + ts = ts.resample(fmins).mean() return ts.truncate(start, stop).to_numpy() From e7331cc2783d70bbcaf7b4edcb4d4adac9d73d31 Mon Sep 17 00:00:00 2001 From: Rob Date: Thu, 29 Jan 2026 02:03:24 +0000 Subject: [PATCH 345/353] code for cmd prmpt test regression --- tests/cmd_regression.py | 86 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 tests/cmd_regression.py diff --git a/tests/cmd_regression.py b/tests/cmd_regression.py new file mode 100644 index 00000000..5cf0356c --- /dev/null +++ b/tests/cmd_regression.py @@ -0,0 +1,86 @@ +# This is code to be executed in a python shell to run regressions tests +# Note: This code must be run from the tests dir due to importing +# the `convert` directory where the regression_base file lives +# todo: make this convert path passable by argument +import numpy as np +from convert.regression_base import RegressTest + +case = "test10specl" +base_case = "test10" +#case = "testcbp" +tdir = "/opt/model/HSPsquared/tests" +#import_uci(str(hsp2_specl_uci), str(temp_specl_h5file)) +#run(temp_specl_h5file, saveall=True, compress=False) + +############# RegressTest data loader +## TEST CASE +test = RegressTest(case, threads=1) +# test object hydr +rchres_hydr_hsp2_test_table = test.hsp2_data._read_table('RCHRES', '001', 'HYDR') +perlnd_pwat_hsp2_test_table = test.hsp2_data._read_table('PERLND', '001', 'PWATER') +rchres_hydr_hsp2_test = test.hsp2_data.get_time_series('RCHRES', '001', 'RO', 'HYDR') +rchres_hydr_hspf_test = test.get_hspf_time_series( ('RCHRES', 'HYDR', '001', 'RO', 2)) #Note: the order of arguments is wonky in Regressbase +rchres_hydr_hsp2_test_mo = rchres_hydr_hsp2_test.resample('MS').mean() +rchres_hydr_hspf_test_mo = rchres_hydr_hspf_test.resample('MS').mean() +## BASE CASE +base = RegressTest(base_case, threads=1) +# base object hydr +rchres_hydr_hsp2_base_table = base.hsp2_data._read_table('RCHRES', '001', 'HYDR') +perlnd_pwat_hsp2_base_table = base.hsp2_data._read_table('PERLND', '001', 'PWATER') +rchres_hydr_hsp2_base = base.hsp2_data.get_time_series('RCHRES', '001', 'RO', 'HYDR') +rchres_hydr_hspf_base = base.get_hspf_time_series( ('RCHRES', 'HYDR', '001', 'RO', 2)) #Note: the order of arguments is wonky in Regressbase +rchres_hydr_hsp2_base_mo = rchres_hydr_hsp2_base.resample('MS').mean() +rchres_hydr_hspf_base_mo = rchres_hydr_hspf_base.resample('MS').mean() + +# Show quantiles +np.quantile(rchres_hydr_hsp2_test, [0,0.25,0.5,0.75,1.0]) +np.quantile(rchres_hydr_hspf_test, [0,0.25,0.5,0.75,1.0]) +np.quantile(rchres_hydr_hsp2_base, [0,0.25,0.5,0.75,1.0]) +np.quantile(rchres_hydr_hspf_base, [0,0.25,0.5,0.75,1.0]) +# Monthly mean value comparisons +rchres_hydr_hsp2_test_mo +rchres_hydr_hspf_test_mo +rchres_hydr_hsp2_base_mo +rchres_hydr_hspf_base_mo + +# Compare ANY arbitrary timeseries, not just the ones coded into the RegressTest object +# 3rd argument is tolerance to use +tol = 10.0 +test.compare_time_series(rchres_hydr_hsp2_base_table['RO'], rchres_hydr_hsp2_test_table['RO'], tol) +# Example: (True, 8.7855425) + +# Compare inflows and outflows +np.mean(perlnd_pwat_hsp2_test_table['PERO']) * 6000 * 0.0833 +np.mean(rchres_hydr_hsp2_test_table['IVOL']) +np.mean(rchres_hydr_hsp2_test_table['ROVOL']) +np.mean(perlnd_pwat_hsp2_base_table['PERO']) * 6000 * 0.0833 +np.mean(rchres_hydr_hsp2_base_table['IVOL']) +np.mean(rchres_hydr_hsp2_base_table['ROVOL']) + +# now do a comparison +# HYDR diff should be almost nonexistent +test.check_con(params = ('RCHRES', 'HYDR', '001', 'ROVOL', 2)) +# this is very large for PWTGAS +test.check_con(params = ('PERLND', 'PWTGAS', '001', 'POHT', '2'))\ +# Other mismatches in PERLND +test.check_con(params = ('PERLND', 'PWATER', '001', 'AGWS', '2')) +test.check_con(params = ('PERLND', 'PWATER', '001', 'PERO', '2')) +# Now run the full test +results = test.run_test() +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 + +print(mismatches) + +if mismatches: + for case, key, results in mismatches: + diff = results + print(case, key, f"{diff:0.00%}") + From eee69593fd4a25f5f8b11ba2ece213b619a06552 Mon Sep 17 00:00:00 2001 From: Rob Date: Thu, 29 Jan 2026 02:27:49 +0000 Subject: [PATCH 346/353] removed seemingly inactive file that causes compile problems at times --- {src/hsp2/hsp2 => examples}/ACIDPH.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {src/hsp2/hsp2 => examples}/ACIDPH.txt (100%) diff --git a/src/hsp2/hsp2/ACIDPH.txt b/examples/ACIDPH.txt similarity index 100% rename from src/hsp2/hsp2/ACIDPH.txt rename to examples/ACIDPH.txt From acc1e364b2b80cd88f5bcfdb484be3d00c3cf29a Mon Sep 17 00:00:00 2001 From: "Robert W. Burgholzer" Date: Thu, 29 Jan 2026 16:38:01 +0000 Subject: [PATCH 347/353] trigger test bot with pre pandas 3 for testing --- environment.yml | 2 +- environment_dev.yml | 2 +- examples/state_specl_ops/compare_eq_to_specl.py | 1 + pyproject.toml | 2 +- ...FSingle_vs_PythonDouble_precision_test10.png | Bin 0 -> 52018 bytes 5 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 tests/convert/HSPFSingle_vs_PythonDouble_precision_test10.png diff --git a/environment.yml b/environment.yml index 343e179d..d7ea70c3 100644 --- a/environment.yml +++ b/environment.yml @@ -10,7 +10,7 @@ dependencies: # Running HSP2 - scipy # Scipy also installs numpy # Pandas installs most scientific Python modules, such as Numpy, etc. - - pandas + - pandas <3.0 - numba - numpy - hdf5 diff --git a/environment_dev.yml b/environment_dev.yml index 78bfc5a9..78dbb137 100644 --- a/environment_dev.yml +++ b/environment_dev.yml @@ -12,7 +12,7 @@ dependencies: # Running HSP2 - scipy # Scipy also installs numpy # Pandas installs most scientific Python modules, such as Numpy, etc. - - pandas >=2.0 + - pandas >=2.0,<3.0 - numba - numpy - hdf5 diff --git a/examples/state_specl_ops/compare_eq_to_specl.py b/examples/state_specl_ops/compare_eq_to_specl.py index 5e21d9b2..af3b8a34 100644 --- a/examples/state_specl_ops/compare_eq_to_specl.py +++ b/examples/state_specl_ops/compare_eq_to_specl.py @@ -1,4 +1,5 @@ # if testing manually you may need to os.chdir('./tests/test10specl/HSP2results') +# todo: make sure thsi is path independent. import os import pandas as pd import numpy as np diff --git a/pyproject.toml b/pyproject.toml index ea38e3cd..7e8abc8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ dependencies = [ "cltoolbox", "numba", "numpy<2.0", - "pandas", + "pandas<3.0", "tables", "pyparsing" ] diff --git a/tests/convert/HSPFSingle_vs_PythonDouble_precision_test10.png b/tests/convert/HSPFSingle_vs_PythonDouble_precision_test10.png new file mode 100644 index 0000000000000000000000000000000000000000..03bd1e714a37e29385e0cd49810bb1f2965295c4 GIT binary patch literal 52018 zcmd43c~ld7*YD|YjvOCB^mvpRR1{PcWRNj{ii%ML6_GiB$RvbOh5!K(52#Ga6p$eY znN%PMgfImn3Iq}$$`nW#gb*Tx5J^ZN3`rM0@4Hs7?)%=mR`?tACt8l8g)-Ve^4$oUi*eX`=Rv=3&j=1EFymgj-ghoF+n)1yhJ!4{)6 zIy+4hibfseDrJ;!a@V9(+$3y_Y|UyeBxzI-Ij^*UIt&Vs}lSVgTik#kpfI9!R$jqqhEVp*B zKe6gFL#4k|AFm@G#CkYN;QQ2}oSL-GD3M!XIVz-rh$`pIM)lsvTcbWuvrN@JWv@;5 ziRY_Q&k@jvO!M;UrPzllex3Cf&2pzb4<&dRN@G8d5d5cJ_ShJJJ`+M{;3#LF78tfn_rvHI(z4>dE#% zlbmuZq@pv3uv=dBa!HV;LD-_*gf|1k=`&6tzPB#d9e;?|^)7iZMyJyaQ?8wsJ;6zf zzD`n|X^$6UH|KQfHjZ}QnyU9DU(-80E?#?!^Ku^z)Oj_V9q0&y@1I|ky0W_A{5UEsLsI)E-E^QHk`_g=Xf({AstN!>g7EY3|=wHZz0iIG3r(l zKQkniA9}>-J@k9XN9)Oa=AiCkXA~ZmFKIL%c?2I=z51AaH819tVdQ=7!mnRl8AsE1 z#JPB|73{$^j4BWzp za}L>eg-{v|dx+;dsFF?j0)4HOs;L7WzcajM>vH#iMpBLuk}&ID-R}@l?A8WFCEM)a zSg!7YP@-W|VaQf7NRRut$uG|?oAp>B-f4e=mPo7B2?_0p)a-vnnmT1Fc_HHG5#sq3 z169KMsl@0MZzEiY{Y=PZgHu)z6bRBiKUj#PIH0T04WR4&_|vKGg?NEMUrqVB{`pc) zzI?bsH%$OysS)xM2TD9Re0L=-Pd#ekefc%649A3*#Z5gHD{SsCbS9%X4jBj{Cs>@$ zlb~zOO5s0@BQd-?*;&WPF1e7xfFf*64di*SW%CICpvQE`$6RKR?t5&vkLE12qb6@i zH-_s^nrn-Zv@?R0+S=+aDt5|&6{GML+jm4=1c8V z%kO08sIQ7;hB(EXMKG1oeE}6D_1Shq7_Jy(zi11|4wXq`b!lE&^jbXRK^S}vgEFo) z`8^MQm|1)-4HI0%lJ2Oj38=9^xnrD1U@o)67}K${bm$ij-Rmf4;ml3>JWR-oXd;v` zkEzu(R>uWBFoNM|Yvv|U#+gAVa_f|>J?=T_Qc0%}L9BIhoP^ItzStZ?N-Npw(Fm6f zx(d>Q@?|a$70gu!v<73l;Hg}LgOoY9fts|?U_)x}Af53C-RpFA4^<_t_H4%N*1np8 zcZnE}nL3vk#SoZ#?!_@eGy(pvnm&&9u&$}e&6=q@*_dM^Nwu9OZ>##I*2dj?%0CX;cnCJQ&GEe!n|#?MuNwOlltRGIHhYJR!-AX0WQyop_EPjs9a zoekZ^Z6@sEq`4P#3SJL(YnM?8UHmS(o@IUrOzCavapb9+sJhYnK6kh7-XGu?I9bMH zsSD_|T8MNS?bBLg^9vp!7~hs=qy#3;-$Bx{$s@%=rign*=`3+)T6|&9WsLJ5GaWB7 za+ZU=H_p2{6$brDFWS7Asp^@j%puZWN}goCvO?~&?rMhRtV}1fGP{O-GXD-n2)azr zbUhzIkeQ=%+TeXFDE-CO8I1==)395hD`R8VsLMxNp*Z^nXbjb05F`JeJ4cQXA6#=>oQxUHu_$XB8Ho9Q|h)8puaV zl$@)6%a9Lc_&dq%qCv?|KsYC{!9vklDh4F5Y=#^qrNIfvxOWxjQGPJw=SI>l*m)fE zXjOHsU(s3j%wm?^6-C+}!em(Tr)FsAYo?BJwU!9O`xbWgJj#+N@Q|VOliNP?2kj$XHd;?~)>&4b-rgFbtGO-RSY+S$Um}`##iH+fdo7&#) zf3QK1m^=dfVPSZXJb`=sRW>&tEpiZFP}&ZsZMato2Eiqf{4uY*_eO*)MPce0*+_F=)lDKirIdj+k<`La5HqBtEKI@qXwpj3?LrBtfje2;D z!6Y|2=ab-ep|z8#Zt-|Pzh=L3fB9OQhu}c!d~HxZg5%UjPBG!!3fMHce1s7sTuh1T zwwqkDp33wnH^Ew)e%r&zod)@D)D+mK!5ud=S)n*dla|Gsla^za9a@6Ob}XmP*ez2#1XsV| zmeExt5S;s=dl^TNdAfBN3Fo;Wb`E_jb!(>i$yH~i&z0o5aa5Pd!yri{Q=J`qKl^X3 z+u70Zf&KMi)3Tw5tS;-B5b18`KKk9&b7+zFvr7%VGk1{tdT>N`WxYNTdv>?r0qdDU zpL^5U^3DU*S{-VNP%~F#PAZgl2}azM=BWJz-8i(Hm<79?inYvCCD`t-ObhaG>)sf` zIN2kd?F!fX@kR{I_icEE4bUvN!Z#PSUVyfcZb*@?)jG#72bm0oP-|H3PB5B&e=+u0 zd5{H{aZ1BcaZrDf)=!kau3?(jJy_yC4ztdN{mFUj=N#&ieVXvZgqN3g5MSz~+HZ^= zzJm-oMivv`b#ssn_{UAA2F7eTAo-qk%znMDmL^8@iFr2&ru655@kjf6z(h11|B4Yb zj)%t(LXM+$dpnkI=C9cJt1=X*XNi5c&k*m$SU!NLtD1RJuPJ_Rq_0Q!n`OE?O<0}T z$II$#w(zGC<2XfC>N2NPDg9HR+2+#?Qq+sE{aL)*OJsc-f%pWL1%x-QW*;3&_4F$T zsd6tWLK)yD=VWSiZEwa$CK`UgP56a4kR14qWj}hN0_$smj1i3ZFQw7*CpNif{cK2$G zU^3EEvL>v>JJ!7Y7wrdkhgupVyaVl3 zM{vORc8^JV+1!U;o#{*p%{>9;hHS0#JpEQjd!QQa$5=KcgQ@f=1Zu?uI<-v0o6n2e z+X|W~eEU`8CRdn6X9Gu#eC(phTt=2yZQYbb<+^0d9XDKh8@%%4+d}tiWjXZ^GR#RV ztWHr?vWtW?b+L*Mn&UNj2h}8%$Ivf2xHz5gxvpD`jmVG;J)rK=28xW>A&bOT*$-YS z?u}O8EM*i%p)B{!;$PizP-=pd!-I)6v(bO}F@R*ymwDp-6{8+rc9@P!>`j9zEb5w~ z)0B*~M)k52$$iTQ#WM4bYLYtL@S0hz1|PvxS42BQH!3$`=Lbp`dQ_2qWgjB*VMS^M zSZ=Fx9*Tw}sj-bu^bMa$>lqO-J%B4OpH$^}h1rVjxGQN6HLwXui3!=Dhj!wH83ENbuBGoS1{(~ZT zG~b?kN5w+HvTsdT;$%W}>#SjZwJ4e4s}0L$Ns?DU$a%X&SksmV)+tu)PWHrCey})Y zLD%92a)^It?z(#pCVI%Fzs`?(b8wC%1Y&C?4Yl$~v!7xA!%(<*vmfcvy823|qH)Ax zLc2GkW%HT3Y04sP=)JYvNS{@Jmu6b|;G!JevE}PsBVL8)ph=uK=rG-9Q$LfL>s9De zwuH%jT)1Sy8?p|i)VSk6Y->of>gbiBjQ&qTMWEyWvmhc$z3*`A>ZFkavYB9og#D=q zNSO8FM5Ozr39VVx`t*`zMcC|XProf+@bdj5WbdwADeo3aB+SkwP5r>5l6LR1|P zrA9^y7k@MJiK?sfB25m*czUd(p-OZTRIQny_a2HryFps+sXnY-$YwSVv^-Xb1(pu9 zG#95m{<1&g*M_fHPaObf4kfx zHETauel$YWX>A_K-AbFq(8C+jpbC=XeJn(6f8ytk(M_raY#N&X;Z$WJ$k6 zocE3F4$T=nZ4C(@5BKk?O5@0P<56k$BUvS_3BGPps4S;yE>F8blU{F(n*NqBhnD87 zLs{XD)P~_^3~7_)9rYUF)1o(jBTXj(gVAWHqOUvCnUAQ98c~p?CVIli;)VvvIRRyO zCM_1Fl;Fcw^0c=dnC#%~xXClUd6ReO5;z^L52v_9?kBpa0bxE*ip9>xshk6+>n7UT z33eWnWo;H;Oh4fh#s|^^`j%hpNw5Pb>OXRb$A6VW%EQn1YB+GNy6+Jl1({i7>=B-d z>`f}#{IcX>DDXpIT;_T=&a;$YsyJ+bxIl8bSWWb<7)(_mbr+8(I^m(PSuM;k+*S}A zDZg52C1|*7D^MMizz5tF0)oV}!5NQZt!2|E#4(Q971d5{;Lvf8abZ9`Y8^S-l_FOh z>V7Iz!8F-Ow4QJ3CK7JBbCI2AdBy(nb@nED+<`EKTzcIEW1K~Z9r5+;kEM_lRiH|6 zqN#eTmEhufSTw(xACO)Uv$^5avH{tk3~bCQQAW(kd?GhgySt&Xp{+U9#f8QXIH&>_ zs^-pZ$}|KxQ&V|(y5{`mHCv%Glk}lt(>YS?3qr#Mm8xV4amK~88paBvjnDUk20s72 zPinzs?!i&k&*?9>2$71tUb%Lu(U{$0OF&fb8#1(POp?+_C6M&FWe1sB`6lq@+!mBt ztmP4Zt@n9Bc5|~m8O0#ZRADmkiKM*|fHu9eUPm%%nf^RvV`BL+zaKN|`NLXRHDn_+ zdElH-5VpBKtHjhoXCd7c=Nkg1CIdHHQZ?3kXG6>G%w2_*^;A>{H)bxkDloilw^rLP zTp01{UY9p5!xzLp7l_jZhZ<8soNnOAHg8J}f&F5&dBr{6@diTb3-@L@>Lge|S|4Ll zVx~B0H`&%EevJB{0U-}K^2H9C={)6@{W@AABb8LL`K6J!;Wvee)g5Xt!88y{Xg8gM zdw~@2#y~EMsp+=A|U$NGGz3X zIPsMz+CCHQ=rG-Q>>AdDKk7cb9lW>OW#D5+5AVq!JmXmsT5V_k;7JzBO8F&|&1Tn7MMcfpIn2+;LLVB2OyJol4CT zRU%tatne&c1?z`(TOUM@QRFLXUQD2wf{_@v5t_EomI<|ig=DSk&2vrF`a8j^f96lo zF_QB7Uz0-{TG7T$#?#S^Y48sM&KKTc@cBGT6F4a)M^3?X#7ph@8Le|?jNS@^k3t>p z-IICOU^9t6EK4bL=zC+T`j^t&rd#j3fQ91&`g;UVoo7C0Gf@G8h~{g;l3Rq>Z=O|C zetPmaFoi(+Jpr^kWw+j)QZODt>h)x1Vk6G9V6je;(P8CdIM|RWF<>sT-H;xtn$RZT zRf)ibkqhs?2{cjd(&3xU{kTfj=6o}1a7R$c0p8~b{~ay2(`J=C+#|K|kE)CI2V4E6 zXAEtX13EqCZ3f3B=K{)XPmDn2bVH)`HGt5US5H@(TORWrv=O#J@g+c+r;QI$1nyW_ zqvbXCf%=vT=#P+S75Y?t3=-3WiRF@U_NJmAgZ%I!V^4T$sJam?gE9%U3%tytE>j_U z>ZB2|oh(62`+x|Q81#851yafRuXIw|{;D7{xd< zTt>o#=h;9}5IP2{wQ`<=Ge+-L*Tg2*Sv;5P1Z9%l{G}g=A`VB@F~+{mb|E9_qy0os z|JJAF@f2u)?r9M$ny*_NK-EM=*Ez|Jg~1>l9~Hu8mf6i=;q?;E_;NK7inoEeh1rrz zZ2NVc;8dad&~9c(C9&4(QPh|T_W^D%h>Fsrao7&As^dl$3gUIv8G-4m#+S-2nJF1L z>>o7QDV<2@t3IOHHkOc=fs5u`@D-jVTGx-dq+V@v4SGGd*TUOqx@kw?@nyHOX>>H* zD2nd~=a6=L_!wct;e8IcF-zkZczu@A%F!#WVG1oU#i;{=8us9vvF}!0>u7kJqgjBX zqe6WyndkLpoqc)Cpr4kBuV!u%Dg8*NFqBes;%T;#z&uj%^7yH_V+dr3v62;}b56TR z*yT+1(yR`NO}96tj@@@^sS6^H_+^tIc_@w*H7t{!N2heR&4wJ8ghP4DV+)%%ouR5s zhOd%Jy~Lm*QcGmQB-KG59fIwzVU<_bMGJ3286+M3k>5&+tf+a+I81c9R;+~s5^C9D2dNGK-2bxkwMs`^vv}TyFKs z+W;YLHWF$b(>RKEvP`|2|7vJwT#*0y76N`ScTGo}XgzXPpo)jXkLvXQJ zVO`OM&?%_%<{GvcU9}gvISC9*1YAPBz6LpT`{w$(x_LT_^#x6U&n0+e%O$ivi+rw| zL^IPcJ1zG4tUEQzd}^~LnHUQ}wgxp5riQ~t!vfgb3j)zqFF~`&i$w$hA!aJS4Jqow zY&q)}($@uV?#vAj^J`=LU79%>SxolxsKokD&wu8LA`N0TBU(YbY4(=Bj%DYzR^|t9 zEj&1a&G;*w0YhtL&^M*0cA17dZzc+GKUnw#X8?TtzZUaHy8AMZ7bIaikiuusK-3;hv zTJ59^XPLy4{SpRG9b58;Myb+~%tom5>}H6<%26^i80p=UXi=cujSJ}ta8 ztLCr_uM*8*TJg*a z1JacKYOr9{-c(600gSKdE8$pu=KN|oe2ChY_^dnvTHEA*STsS0{YZ>R1^ilfbf7ivHQYj%eU~no``ixe}QRQP-B> z?1NEf@dpM=reCNQO7|tj!HOz29jmHh*7A}XgJ@mOJ{vw?WuY5KHVWu)zni2`!xRil z`-)76U`#b3M+G{*ey8hHxO_E+W>imYs90FWS1hmssy~Fc)#VzPBh;&=0`rZ?y*b|# zW4z&`XB-P~B~X0*`39fT#?-D)_2JsORLjTnXGE5o)-Bpy_lJGdsBL4fls2RUwMYwX zEGLV}JwVLj7RONbfQ=+$9o`G78@8=Uvpm2D^z@q`5C{wNgXMYeg_IGan9a2X9+RB+ zet27$p0#a?&bcQ9^8r!$o>yBN)2*Gk(fb(E1{D$Ju_m;pm`@;1!TrfF6xpdwi(QMQ zKZb2elX!Q^0w}b!ko0O)8%?1v`81pnjzXD;qP6ctthSI7Tm1%vH{bN2S?m)Y8?`b} zC_60AoNAQPRBznlNuA6c&xaE8LstK&AKx-laHu#ghq=gIG=5%OHBKiJ~d`!gmm z<e1|TL~uc8q{kMR z^3(H{Bk2(q9Kxd1e+$lIjh&@Vj)tMlW*xJY5gG~DEfgm_x0IE_nQO?RaC&^UYqU93 z66hV{9dmQ;2q(`4+WHAjnZ!hUJ)kxSHkZ?ccWjLLcG`E=W>qT|$T3y9b|HK}8+aeN z5|KnAX$T)=yoz41?z=9TIfk)yc-|!TMaRMEtCC#!&iNP7x^mrrZhi~&SNVf|`DZxL zmx)x;i>iBV3^Z~Mt#Uub?GAND7rC9Z+mo{T;*jdXax$#R&C8L-$xC#{rw)gH30xR@ z5459tm7)3Do&%ja#Dvcp`A1AJM-YNhd|Aus@9p2hW4vsPMVssTyHg~euuR(HnO$BC zbkId*QD-;)x#O;MT3LdtW7X^Z;q|>z`GA=F^}QV5bwuJEdlUo3OD;&l4`FnzE08PXWV?DVmOeW zcc+BS-gN#rVG^?%Ua=q+^W9P)T^@u$2j)SexOryiTfb#Hx@BV!4XL{X2P$iEE7ID9 zN;{I(Ojj=)oE_xPg+36y#@C@R2sriLr+jL2@JCkOx!7Gj1)F9Mf!nSZvv|R$@Lqt* zZDzV0Qdj3u9!$d50ej}K)pPuXXsEZiy=np~6xL@jm4D?t_$!zl-Uu|&bS=c@USkF= zBJJ8WJ&{PDwDjyxj-lI*AX9NP1ujk|C(%@pVWg)HYAskD9INV&J%W96*n=2f;;g!B z8Wk3K1UUMJnV5(8I#!;QaB3AU=W<8o$BD1%TO185(QVh3QT`2O$0OpTrwM4*{Hf~S z1`j0MM5w1g4(+*g{?a|2NKo847n?VSVFTZ-+csrK?@wP?z+B6R32e?TB-?)A3h&zX zss&h_+PFViY2iMu;m0}ep*;m{+h_Hd=J~yq4fXW@thDuQU4&Kav>t*L1@%|E!neqJ z${||Sn|dvxacS(@1MQlGa?)5sG;w0eJso|ntG-phG(^WiUE+G;ep>oP5jj_kt~=f^ z%7ZTSl_)k-Abbte&B7PZsZ9=p_YiWmKjM~QtXOWy+|*W!(6|mh#=qehkcF>cib7|| zhwXJG1-7b!lf-(; zC~`D0|A-j`SGA?i{AfibMm9N5=wRxy5m1-clTsT8n6D&9865II++Ys}RIzlK2UQJv z8rAflmc(R#`)WjlL(5^)rxzZs92v|r>9*}U;gdM#!(v1HqF}py)MCv`B&iTE#s2Nq z#OrEsF>Cl_pZ~ZoIsF8y9)lnk)2u90HXQno0}E)NAML)~xS=qAHF2;CQ`)~AfPwp( z(*H$+zwV=Jj?3fOB!c+ni=7EMsip~{jzd<-bDf{Cuei_SqL2LT^7d>430d?B;Fgwd z5Mx0&=+pyT9X1U*4;;Z2w0%?G7GLe z>$ab1{R~~pd%F30>xZ#=%~D^U9y5sJ3KCmQ)(&tIrl06LPU-S4_eK!HYO1z+B_D;X zqgg(HKws%mBis~ln@jVQNxccm=#mh0;enuil%?Y2ju-Wj0y+U;eR-X)U zdAj%`=v<J`^aP&l4KP=3z@hJh?u&J&|ud|)$528 zto{2W6IviqW#8VE?OaUiQY&1@{-PrxXO&ZKk09rB4=qGA_gi~M;=TYDb)B2x`7|A% zJUz7YOx#0TBa;;1V@&L_Pe8ja$GbuH_Tz-nfK%|z_w&&|R05N)rIa_fY}uTE6#M&@ zt zTnAvJFj<=C3+ZT#2W4P8A(r^J0$Eam3Te^wzI&g!oPS?EWcu^p-$0zb$&7h0PZ>;c zY#d?#_HF6>m8ee9k4Jf{ENZxIq(2!WOPzrn4TuH$;b7+~e2BxM)uNeY(y{8Pkv0b3 zB^|vHcn*Jei!^X|>jvPQImlC|#+I4=Tw%dM@WA8|7CUuwC(uYOQO7F6fvRV{tjiR3 z0{kZ17ytvIho~;#^dqFgf17WvGXERQxBpib;N%xYKp`v;vH%G;$@!KRgLZImkd-jq z{9-y@ay=al=Lb_OTKl5ZB<_e@BUomdvTe+k4+|AQ&A6iG($r>AXj@ib6dvv%UQ%C0 z#NIt?E<@S;Dmh_q%7IV+trEoiy4KlA>&?~X{h#&5F~-5&0>2U9KCJ+%U|s8p{R)PU z$^7C=xPQx!Rd)5@S4=?7l>HEN*j7ifl+l-h5lqv;hekn(xfISpoNhfhi)STUx%)XeIc3RgrY=~dp0<}uMJN% z_O49;+}Eac_M{E(y;W6t94z|P0|9%ZjVB@%R(%M^MZxn|q<0D6gL*c@;W3N?on2#E zKepzP5Rr%+yR~!_ks#cyWH+VD6cJD~03kcVliZMMFAb zep`B-i)5e6B}?(}6pYHXi$~rzBEiL`f{P=yYW>-V>O`EMHw(g-6%=CS;OD$S0C+f|b*I2Ik_D%yiJpMXKH7|I%6DMrie2 z1?kDk2$TS%i1&8?2z{?Xcl@&axOP7_NPuWtVz!}pYtc&~NZ)KboVV%EPrLi>naanH z2i_P+eLa=%GH6ei*%*!ZO6f%1qSa={dPE6+{hK1*P+U`iut`iD>h?$~O0=g=+L=<0 zQ3`@5Fwl=q-ScpaK@S=lkcr@!%ShiaU~N0ENkfnYL;B*D;P9A5Q+DedO2PwGVll()^v zi4V4HB;gt-Zx1NvMJ3nS;+kdb>kOyoby~5pZ1#mizTW7)5lyEK_{DNEZe5OtEd23o zw*bL)2-JL0ZcTrs@ql~4s=~7=;+7Ukbr3Y1_juYM@cXCHJs-_U2_7is*y=9U zy%menmV$yQK{HkFrCoe87Q{Z6MpT>`XcKLaMPkgX08dRxbect-#AM^l&c_yb-yt*| zFx`oC*My5X#|GRTjoaSp_)>{l*qXl@?fsd@k_u1m$!!0POC8DU@}xirmjYy19+_!{ zmGXaS_G7P`0?=?qZ7RrnRWWL@rrFq2X4lJzuNF@(Im$5sk+8=?i@AJ>YW%rzBSCl3 zbk!m*GF6QA{nD(S&$h!%MW>41srQ7+DLBLhNDN_>U{vQ z6jK%Kyc+SN2p}J)bo{t%nX3RtiSzg|m@_Eq8bix8WplJT_hGUQ1 zUC@=XE$5c^`LdFk%GXs$5w~v{wS?VLl6dZ#po_$;;kE+E<;#-7_H~i5;uVdztWx7- z-Ph3#3-vwrlu7w3+#PRRvs|+;zF6M89qA;1ojP#I1R4NQMfkqaQs+#1%k%&KbQ(j1 z|4VXa_uzO`$8O05)zuj5w9E@n*R=j%5^!q9%3J^Tv`4c0HMfb~1)U|Ah<67A3|-%_ z0!sTP9fR5c6-w~|f}^o)JwpIl!!!J;cs66ymb7t>@wzUbspQ(~E zn|nQi_cGlWlkiA7)<%Ass1!4L(Qe>puk0VnxEF`L<6)g|CMWBeP~*ohblVbP^{wy& z*AJWutsl(O^rhbXRClP4wicN7YHEi&Xi9J865HQTZ*?Ia`@=bn6Br%xv0H6SU=shS z7Au*TY1%wMyRaI>AeTJmBw=X{_5^N`??#n2*g?(zsdmdldF5Qp zVlVE2SPPff{wgCsTaOo>WlWCu&4l`5%mY(??1XGQN!=5fvp03`6Z=AlJEXmTr{<-Q z{qGtMNR4i~G0gg~pE?mqVNSCV4r8k}rESd+Qm&r5Cp1N$+o<_`E2--=TO+g+YwvI2 z?KBg0&Z%;0wQY5nmX7v{?j!3cOFW&d6n`f8@F!~-H0~eyq!^I{_3%pz6V>3~$Vfo) zAh)SEjV=esc-zjOJWId$P!-ea0UK2!+;DW*Bf*$kxiIBzxrHH44ojoZxc)1Y4sPivW zg54BtAa?2r-VE=wI~b$^)QKuT ze~Ri=R#!Vgq8*#-{8=zHcH-={wixrM4xko{YMMmMH%%;PrC|^}F5d@ndF)!Ju)}2b zKa6<)DXC*h@j;9op@+>?C@KshYT!5u}T$<=)ZqVwxVZnHu5FKOX z4q3gQY07!NK9`e;*VC{q>x-Ps=5>7yi}7jHSN(WTREO>uqJUVQ(dJz){TU?_U-;px zdG)M%R(45e5}ypfStZa18%BOu4k1m|4F((g$1eRy$FE;|Zm0nxDOWd)M5a~0aIk^> zUjLOt|G$#*`X3jXEBg~96%6m417>QhnZP{DT~gG~b}^usN!Xs00f2!c$B}la^REUU zxXMM$yimQy{Vd$tVESI^X$ruxq+g*W*!qh8L zagfKW6B5J{Olca5=XGle;H}m%RV5mn!W-!rN4D!404P;vBM^E{CzRkT-y$cshgzoB zmTAL4gSdjrAd$DVsf5#$ZIM=mLXCXco`(@kFAP_N#=PziBFxtL zj3QGVo&hY|Jt+-{d{zp;Vf{Krov@}DB%D9i^7Ph1a&xlBJMKkUN$Fq(FZm5DJi9OD zk*(l>kGOoxS&XR<96a!G#m7-)-XV5mrC^fJhdS>4iqE=~&j0Wpl3@a*&{I$7mm_Dp zUq@oA^Yj9A-I;%+hs1wPxTc~`F;7#R2s~KsHZS+bpmc}zx8Uv+!U=@B^9QAW{nnLB zwk5CEm02T~f9}xfr|%Y9sLq#aUdTXmBEEe}KmmR9yZcjpzHfFj{-WbTnfJ9%g1?x_ z9d1o^3MdZOM74gyT>W|2_=!hLc9gn(!p@rLrTT~64{| zFG+A?;DE(eft&g}9alzwL4{)Ek0MWhQ>U*!2i_iA9DK!j#sk{beM6BKLq%JwWQh%J z5@@iObd)m7p#y$2cS3lC|s4Y~kA@domiVZxTvGtvnYcs|sgDSHWJxQ4yq)Ej5b zZT^G3quZaAk2@hD0UZJcdlvMnwz;S~j@KM}FBHsgW=q7`kF}WR_0^kFu*r0oauWae zz}Wr$FK4PMy_4)!al8xQ%m!#TYw*M%241?oOf*<%OhW~&7K znqifG!aoNm#0wn|_`)5z?gts>G3n>PW>-Jnh(b_%eIkE)H#G6h^YCVKTCYxi-S3yg znr*1HQ@tWLo(N_08(N*AYK+g;R>n4ntj`0y zz!~UF z)8Evd)OAiN-sk5DBhzzpHUcctnZA#Paha4qaK2%< z_{4lFXBG70@7~5R2GgG!S|4qlxEXv~s`U%{G&H~uTG|Fp0+w8DG^Q$Dr=8N77w*3n za6J3PPQYC(o(HJQVQwHGkiJEC)d9Nyj)S;;ZVb@hSD~lo_g^$Pa+*E0Z3#8Wz0PKy zU^>KRKgP)TXl}Qmz^%&V3_}%Me%EcqFW3|<31_+(7q8G@hlt|>H=!0PG^2y}%GVd& z;zXuJDv*ELsSnU%Goij?Ca)n75f$~VSB{K<)|){0`CwXEbO6Z;g8KFsS8b-F5rI`- zwmSuXTKjSV*7oh!zXP-dYv8-GmXqy9!mKhxkB`kcVY zutm9GIt@?C{=V?OqqZp;$~2e#^6S=PHjl6=qAC*;IMX~`#}w1b1iXZr7)RM=;D}q* zVmn&zi`$ch0Q&`BK>94v9^_WoR_mUgU|P53Lq>3`N76BO*{(VJzHGOJfNZT7vdtO? zef$0(UE`=zWvaZvfCcnQ@#Rm^0uJ4?f1+_mdaSFxIwmejS&C-@jDlL@f=_8I&_3b> zyCnHd)!P`fdWdT*M_53JS_F)T4KfV?B z-CJFE-k4&n%|>b<<-_N#P1Dg*^un5GR>`gB0<=d{Rk4JGW?B)JUn|e;QRC$CDJJ~~ zD3Aq}DY>kFpQK0~_y?s{TZb;D8mR);qj~km2c=mqA!;Ak+McdCx*mH7fYB=@{|5$LjjzFC$CInv?J=FV%i>nB64@`X)WvNw+VL!*(_|LTiih`Xz=3JQmW4RD ztgU&a67^v|PaA-`ia?6?jt)~iU~Uu^ZKuH?)u^u)5lhxzmrNx1+DoD8o1hOtF0n*R z2LG7VY7@WKvJItOK<@F2qEf3k`pJVfv9tkzI1GAOtDVUVX93hyTV};Fgka(Y!u~>qgBGQ+PvRR#sVtb1W0EMYz^-}pH5w6x(xb!q3Pwyzlq z&3v5i)_Ih$CoSa65_@FV;K<}ypCYcZDhAu|N+)Tu{pWV8yQoG2FftCf2HiO}Y6y@` z+N=Ife^EO+9|L{k&?u*iO|OD#puX?$(_Kf^AJcD7+O2d7>nCnod}dy*nFw}XI7>b$ z^>9J!V|3-stw373(viS+QZ@fPq>b>GHNcKKwZlr&R5iuD!HLY zTz*r(ed%W?H`C7Vjti*FxXO`N)~P$AkbPCOclkGTN-{i;Fy!e z6~8WTMt#ygcI8hOjp(#^x=a_mJf8jNXF*Exyq$*R@2kgaVa0Lau~yZ<|E z&h`%5j|=!O%((xpsV(=6w8`Tiw}JeGc54i#-^gfI|22XWDGQ{n?+F5N&0Ca1Rv^tc z{amSY2yIL(ki#VCkMhX(V-mWH*}^QID&YQP1F2hL5SaNHuCT2Ds(=cbu(73hLtZYOU;j zHztO;`btsS3$m!x9+Vv4#rXwZUjuolxR&kjI=!l)_^;n&8Jia`rR$tUA40pM^_ra3 z=!LgN+%BS14vt@qp~u_J(Hk({?Dd>_mPFHLa^mI@83CQuX>xo{bC&n5J{HrOuH#w( z+T$#$MgXVo>E}$<5opS9KT@G3b)HGC*0ZkQML_0$onyBz5G-;j4t}ZuM&~sMx3e3@ z!?RQ18iVIq+l};UnT!*xs{p1?c{yJ8^$49`T@4Og^>Id#RdT}3=9G-d^1;?_}B}mv~6lS z9PPaD7Ao3URAN#AQ#ud;N)LU%_K|p7*TEj^nIC!qbipbRwf%+0)ZSKVBl$}UUjy=Y3-Hv5YPoIKjm&e^Z-D*QkKK>`qYl#w zU;dfHuVFF4#Lj@+^A;O#>VB=r-YJ=W0((fSQ0`n;$nIMg4VH`=bT)Nj2Ki?Lj-)6V zx5A<_vjF0!#0eByUc?%7&7N}p7jy$3F>d!tFNKSZtUn2Eu^l@yr~5oirJsbzSBTt8)^9I>OU{MNOOwl_9XMr}OutxX#|n-r>R2PvMZ=^9EHc zqiO?VO0l;~u!FdPsH&^=O4AmG&Alro4kZ{q4?7Ht5r>KVqE7lmG>*8x7kc@;cwY|# zM8%zTG;U?HpM#JA6v(x2!hYTb;E^Rdrr6I!$t&Ny(>5q6C%_c>Uxkf%Yh^@Fq5&arH>@xYCUu5AGdjqCK9cZ{qUcL%RX!eqA0(u$vG<4erZkWKaDz@61 z-SVU2oUDQ%Uau#!N4z$gCaHX29OcIiqzzeklL9hv$uO}MaPb#gE~KC~!~exkseQy4 zod;yI;K3G{Ve0V`)UClhqoh(bHH-mDTjvc^-~k^CKvDk0qYM~Ke9S`X^!&FXWz`1& z&m(gIi|@8%GSW1*4GeYJwxlg-v&QiC$HtPCc%WRzn^S-M`>eL( z0u~-0wJ#C@XkYh&pg3H_^316M8e%nVIXc>2cPjasVW^H}CGoaD5<6Oc9Vmpi08@a( z_xe^ZO7}cOrUdy!OP29CVB= zH5JS>7bsVai%jTAItjHxWf3Y$Y$>r}=KrAX-Q$`5|NsA9<&}Duba=f<B}IjB;l6 zQlvzslH-&Y5}T02*erQP<*>^6xC%*PIn8Oaq)eEF7={(*G$Wgh*=*m(ygu*m?|b=u zzn{zH_q%*Am+#@<>+x>RC-o>x{Bn8^~q$8BGf9b2Ms99Ka0GX?FLlH1o z71Nu`r=khXxoNY9LG! z2Xw#CRGdBi+&Tj|NC3v!u)?a@;4;y~VW~Kf()lJ2GSw zNzan6-i$^RkFO}r)zq=1B6R>iO;?^=dwHGTUs7fQUSMgvWE@gK@h>rSb>i3 zN|n^!fxhz@cay$tGxWd~yG@P60mgfdahd74;14|nmK zFP(Rs>SNM((|tszh0aHp++#zX=2NuNF|51r3+>F~z7mB}_7FQ>4`XWZ?IyikmVPL4 zKP@CXkm*B*DtCkg+vb;0xdjh3G2MuP?k*CZ;MmnZF2?nHoNXivlZW$V^}U+*Ry_4@{m zdTv~bXFH^iEAc*-=g=l)7ylRr=Uu+YI1Th7la>XapJIP@21^QG0-@46tDJ{p{uE%B zTr839WBL~Y+RZvxgXVBaU5j2GRN&rF4sS6SZ9G`!c+iHH|Dbwh{@Z?)IM zX!uc%#i!4Az+)$>^zhHD@Vspu?YO5H%lx$V)Hq+;O7z}lPHb^Wph}IzZ6ZWeyDoTt zVfj?>LEUYM_H;q^n&$XxuGJy63!Mv;AzP0jzVVUEI@xtjS%1|nTNrO(ZUQ0E6J`oPvgc5WdO8FgDN z-{J9hQUSFy~1{@I2WvGbe6o_aIy!?Gv82>D{LLf~R-& zxWBZiFT;NmI^0q<&tLdkOWR%WSUFLJ`Yz6#vfxJhgH6`MS1N2JU-rfjJFGa0YnS<6oEhwiCHycAWQ(B%%IeIK>? z9mZl2)pD*yQpxa3AZ?DV2bcI>xb34~Mr@#f2ps)6PRI;N_S0yOVNN;GZANnji(vr_ zPU5bm@N6w`lOJx&rt?9M#3z*?Uj_(XGl>uJ!-H{Ha=M7-TPLtMy_FU}pZzoUeop68 zhH$>pLJH8S=P>Rhw^76GG}7yyHd3E0JzFr#T{_FX*G&PlGfF^)Zs z4ob~{%$Zt#&l!ue0zn7uKHkqoj7-J4#Bx?X5Nap%^Fo-UUeG%e_<_SuB+q(owX$le8D7Gg)OtS7 zEDFYUu*2{T25W#dvJ+iWoeME7X0!i*BK#HW@t5-;ZcLC9Z09zJW@8Dqb*njj`~kK@ zV<3-F6P2Mb&0Nr-F5va-^xEt9Xm=`T_DVFhj#nGlgGTE-7Kp0ZBIoa4XL+k?D+{Rw z?CrpW6>-t|`Jv$^jb{t$&o*VndgJCLUop5tFvI_*(g8i%zqQo=y@Rp;R7(X7SrizN zm8_8yGWC73zP&ZMH}%zRy1WBS#;gG_$ySP&<4GU1&MpF+Yh8E2T;8fruIn7-7WzC0 zVsKxL*WZ)`tv=h>_8a$BD>LUFaXF1d;gj**>fJy!WFb7vTL5dzU8+gu(NZPX{WQ=ia;7LryZmv5 zT8cr(yD%^r^S+}Z*tPu%{%k({O$q3+Xdxdz7;(>Sxg2o0CQe=re&vXoTGHvVu#Mv; zM9_JfW03(Pgnwm)r#DWsb;MnTg6`2vwGyi=>I`M`{(Agz#y8HTf_~845JTUmXEFLNWnp_V*7`jUe zco54#jnVv*=p*%bMk?BIHKbIY^Sx39IHVNoEue0~I1r|Ng1U(vjjFyl5=s~QRcJ+C z%u0@n2?S|Yle@t56PcC5Q^g}7b>Gh<6deF;q^h2MAHJy7H|{1%_CfjS>wrVlQ;HCv z7ue2&&Z~571b0V84e$Gado~}r^-(;%wgqoy0W;!zeZA1w0SO#E!$PETZ{=)p(B2So ze%Q`Wb#kfjLi$^EEV3f=?F`5r3=VK6No;N>FQE!(Y>8>{BU|7vGCN`0d=dXoq4P@9 z6~nD}aunc$CFSY#kvG}3bxHN@ycCvB>>C$b6N^V?PTFaOb{m#F%2h4t$Df!f8ci6Z z{e9@|s54O?npT@jU23w5quwa=wexm@u~eOj*3V0E`#T2tVN7bB(?)b%jvIZxjZ`A8 z?~`rPJbf#>jOs`e-@GDjoupI|TZW3#gvo)b6T#&$$;knbQLx*%Ep*_Z)u~f^6i(V5 z$Q%8%Y<5?V?C>n;(K=uKqmw7>b!z-1O|r4-E{joC@<+J_F%@=|4AafLwui;+QG>bV zs+T`Bv0sCS-Z*p~!|$lQJQb`tW|q-s);W)7!(VGY->qRG8H>=a?R%ETKt9gi4f|1%0;9&pu2FWDaI*RwJnmr2}A%Pt6Kc7Dbbk44Fi)QZxI;l+Lq=O}C zUQn7WWZ$Tw^n?e?#~L3q?iY+^240R|7qhTIcH6hHO5jN{z59GJgxmAl0`Di;Ah#|N zVn5QRo{yrKo|8pPL{ORu!)VEBnEB@|ZsbV-z{n2@oaO$Cd#8}(27f9%fbpee(*#<+ zwYA6M-5(={H7TsY#nywE6P~Q-Eo_>187|rXvp8;l4N>Ng9dDlL7>ct`H|#yF2MaL! z?K{OJf}TILsOvLS!;Di&Db!j=2YC%xg};m?(~__K%|@n#fcRh;GgT}bayIX>HXoH0 zd11!5t>u(c@cTYPbSJvcS{s@Ud~h>3Kh*2Gns`}*9BiOUMoTT|Qn1{U;0k1`Z47j` za^9MK3~LYoa#j-`KW%n?)%3l<%LD1I5TzZpaQawW?YX7X2!jSVeri>I;TIs3Lj38a zg#L+}d%BF0nlGNiZoD(J@Hk${zL=YA_0w5C@sjJi+c~4x)HtKz@Ki(&BgfC|{^kU# zP?TK7{b@WI`&{|VM)>&cn2DS2umCy`fAB$)X7_+d;S0Az+o$dTqt}KxS9kh=oFgCFk1(M?aGs6zTJc8%G6HzH z5`@P7B!x+zZD~clcyuy{8gS;*Q&#$d9?CV&P8pxdjrYr4p;vg+%GuxAthoFlP%l`I zxeJM-YYC~cb%gD6GT)q{oWK0~93dT+6y82myU(A$*&OjzKZh33;K5v1%U*vGan#z% zg4^gc6*F(kybJoJD}=ENZbcJ^Fzp5H+~B-g5Kv`08&au^eeZ_9a>JiWOjLl# z=58RrW*BmGOb14ff>Jld?39pqRJ~}g3h4=n{&UH37`^=|#y+#`P-dxkSx*2HMrQc7~)!fy%c z7YPxs1V0{YnD1OTbh-QefVgalV9Ry>?(R)*I0+P^)K{x+Q-0lp=C^e@ehOLgGv8Wn zJnvgDfr`GUpii{m!%9GmWDi;DS;s$SO94|p|1p()|G$+g^`FjPbHq(Q3ol%&uDZ8$ zch0r))L02A!gCPV(Jdf2t{bB|&={a5kLw0R16z3&e&8P_Ro1r<1SqgNzx9NJg3GYO z=aFx>bTHd>FOQ@&?w01K|7zB0R+i~jP_|;}qB0SLSAlHg%s5DdOY>^kyMv6C)PZXS zexjHiQhyEsQ9x}y?5jfuo&_@||JnYUL>E{CeZ&a^ZAAYt(_rFrVP4;Y3qD`Us92+M6qpP0MR;!^UZ$Z-RZ3N4uWah9=@mqV;9n?y8WAWQYuIcS=Vwt$|L+%Lf9i4*BW~wu6h*1-BA5 z-vwjnBVH_+58aftFg9|4;R2@3mCF2w-?eJk{v~GWbpem>#lG`fJ&G=<88&^tb?I{X z)+HAw$A}IeBcO`uhq+-_vws!-nQJ8;V!>#2uX26yz&8GLv-iQHqA*F>+r|mMK5}_z zcW?BZH>$nnYVW)lu76xfEhl`&VOu5gP3^hQXJ2l8x~aQOUUZ_hL2GJH+!h(3<+@N% zUd@0JBkam+X&SdorLlS}{qFvQn}&;zs%6?Mk#3_!}u zQ5bW*5v=saVJ6g>YlPNutG{Y47*7UC1&qFZw{|L{b>*en;PS-PKK{gYvvWx`Wo?EP zqm&W__x{>#mbOc}tm=4{R(lY!la&@UzmuiA53goe^9(u?+L7<(;gQ47#}SA4{9@9L zBl4Fek4%W6Y-hg+$JJoW?<@epjcbjG4&FbB0ZuI+^Qf+yJ8LDaxmx3HBYt+l;?Pnm z>QdCHW`4kMeXnil!5b8>KQ5lvsi6c7Wk0kKreiL+;1&;2&6iw>_R%YyxtiVnO}e<# z5+NFTP4Zpso&7F?cm-$Q`_yhRTK;M;Ll{Z<^q1?o(PDe!@%WCa@T}jOwyE8)__+|R zsngOk`q9l|f8O8mvi7Res|l)Kk*6~^D&(KFsLoa2W0z#>%_^9w>ZWomQ?T^S!9H>BB6+wZ!38@;=HEiiK#GDTmbum@mVK#t z7gstGHPpCVK@;9cedUz}XLT>ju4hLfF(9}}S58OW6nDDkQcuRH0y>bmqp(I%Q=jeE zX`J!;^knLcDiEvWk(;>n$SJ)%_s_D=<@>9CS&&LsemcI(l`N~D~+?OREO`?kGCx(gr8w;^mBMhKlyo5?fy z{OK$~-r_2X#vFCEaGSZ~I(Dncp<7h&7FWCOeJ*8atA8rzR!*GnywH};;lkWOQa2%UOGs>8VIYhx390%@19UFRqNRw>ob0%Ba{KMh_5O1{0 zpUl270JJJRDiAwKTcm#$dhUe$9l>&Zy$XOs+4d|53;M>g4QT8TNc@-Cg(9>E3ShAFiRNd}3`DdWM%p?B!?B5}|Qg9~)}5jA_x#OZs* z{*lM*E!5w;!2+Nub!K6w-K;Lz2{tEi#X;i9yzb!1PFQQ)BEf9wve!xhul+-6M8~us zujHa*gkt(g5t6xp{grp|gI3}@)N(ko6`hQlvec{%1Z;-vPaC<7)7b{v4sFvQo24I2 zx!~U2=x$rNs)Z*I2>9YVC*HX&gBlTNW7A-ul7FJ5d94ckqOO})r0@`yCJY19*2_ws zt-|-4#%AP=OJSKDF!;#6Dgia3hT%Jf!HHD*4JRkxD}CjZ9LX!D$!Pfb!GYy>c8ek| z3$~AaSVG=DI5?4`8st2FHgfAAC&wMnc1iH_9uSZF`5}gf0T@3y$l4CWGMA+Lf|7FX z>`iFsEqZp1TOXqereg_5x1ES}mDHiUAF-Jcf7D#=`w08$Qer)PPynt4LhbMdyZ%axK@R zWJBM)aZvWO32xH(D)aG?TG^0ixYu#GB{3@!d8HOvZiH zGmRCa08pFtqLPx2v2d0GwpFE;@DKo*i!k$4_2mWu@LK5nv1sjpzq;}!YVv|E zebEE$k<_PreHd^^++#fqR8Q>s-rd)-lAted_LqfpQn`&YDpzt!*lEIaxd{e&u(TWU zRbw!%jU4r(>EJI0bBNb3Dfai<*BL(OI@c~Yap03*ck(Y4b z>?P#@%P#(eY_EXw7GLwu`!sGr%FMhYtdqYTsnL#id|uT9d^5lA=5d{wei5)$AmR72O#gy_&P18Pq_N2G&RO%u2Mlf{v%)zAT&IVnhX=8jfLW*EEZp?;dt+Q2xvF^wp_^_? zg=bGao)CVllk-{?d1j7*Pt5bsoNKB-$|N*jfIf9Mh?V+3j+K-E-BXd`Q}-b}&jRpi zZX35;NbcquD1y-}tzam(4{xhz2z_2~_Lcd}pUM$yW)FH>8!+SKSsRbv8=TQIuVJ+M zcI9!<`$*>k{2=YZn4!72Ko;0Za=XfA4I}Ut>IY`{@jXSWOgVMZ%0ZiM(HUWb7tZE_ z^bU)-CvwUUL|2>xiR7gJi*m_Z6@jBBN*ic>lt-Z<=Yo_^6ep3_@)>1##3Qop^E)MeS(4pr9-gn>YfxLT z`k_MlPI2KyTiUU zteKMuhF)cE4F=Be%76~(`jXx?8sqRZtTTYCn-WAl%=*O7pIu0E98X_5I8m-vuCs9c zvKpRp4b@>3nr!O={(R-xTHxh9p)dq+xbHIcvw`&hzwODXODb}zmM8GpXPX11y8c_W z2Mype6L3cei}qr8?D{7k5;eGf$Z4->sQ*2YU9L$l(D4xkiNVW1f7EwmqgL&ohbosf zo5_%Xg<0R{;Gk7Ekb+ner8e2es6bSrfx@_DW0mYPLzu_5x10Poe?4HHKP%OYUiWb| zmSPa#fyP5^psUMsawbe5i}*}W178)J!IDr{UE2*dmTAf)KnKKlJdWOIklz%)F&%c1 zK6Uo}?}(mYbFDqO{T6~M^I`_OAGhY5%2I=ek1kga_aDbp*#P&F3&_Hk0Y4RGL(^n! zp5;i}=Bnr_;*NJaGnn|)xc=T z`it5VJ2a2m&Sd_j%=GJYOZ1U(k?~s83)qbd>Uwi8^|&VkE^X(o@s?|qF>8UEr10O9 z)MtA}9(D8-&`OReFr&cJFw6LPLFu>Nyvfi=Q&Q(Gx~5HYg=fr<(o>WG#O&f$dwOMuf$!7X{zWJbB`hNRmg)@%+EC*udSLr2zg4H6;w^C1+Q%=- z3m1mx)LCOu`;%q&yD>1&5Anz$XjkgZf$J5nGG4Al!E{$V6mT&Vne9PP27%eh zq8Jr1e#_oUq+QibVjweJYM$PcHiJ$}%W%#HrpMi0xN6d(N%w^>bi?R821V?(PHSVp z=Y=Cf-i>)jY#J_Ckz&?Hk}#DA#iBNC+*AwJf6r3&?=VPGX7u}l{S`j{MEs;#zJY%b zEqgTo54VkO*%FHdMG|-(PnZ2@l2v=x0|t;4H^qSUJ|j3hLDuu>%u&*!rIHTW)VshT zO5nUdx_kFltaM|PG+^*f8nTnp*}zmYV)3^5yflFzTC@F!eLaUY3cR%j6v$4Q6CJkc z9=;9n)%S%Qw%PL>2Bu@G!{Etu9au==6ZaYb=}aG=6heRC?SBMq^PK-m)bg#?5O?HD zfY(CHH9_AstjI>XfD2^Yy7?~Qx=3j`b9yKN&Yh;A^e`u z-i)2rZ}~9080fYbp;RO*(aw1afa#P^&J?$>X${e$Pkl73OMJ9{s;tOal3J> zZ%j8~4j3&fUQULo3IKOm1+S&Jtp^$QIPbeuS_F{WsI{l!@CoTxX<%Q8$7|^0*D4fP zfPlyVzsqkn44{5YzjV*+*>f~+9DaDudH38uq*l_X2e$L`fMA9x7-x82NaeJe(32c5_rGC^|Si7 zznL!10%er6&hY;KkvHv2Tb{CpI7|LQZ2dPzq=4-K9ze?MI*$y9NKHZTKbB#kZGx)8 zfI>pRao4qzzNS~mpeZw!TjbED+|_x2B2yj)%daxhnO^;q{qqE9M}Fh22w))Y1(+hM z9)#HYeQBwQdXTXKYJ}2!T@9OqA=^J6q*TI2wD6;YsxZ587rfg|SNgX;{Aa+?$7{Jz zxjyUqw4b>CE(oBlvFiT@BqN-*j*g)Ns|Ns$0$yKd1x`G~^V-3%+WsGFFM0<@>;cSJ zl>WYXi8oQi)WK1Y$AXM{ZKi2%#jGt3T>deb@ELVF2xzB;uvIhSuJN%Bgdt|E;;0J> znbFxE>^{CSxH*)&(9<`l!NvjEq>5tM5|ZN=ITXLI=4|rd>!Gr8*Q(7O2TOJ6X~XSY zA0em)iXvjAW9@{}1}QBBpg(|J$?WiBGepG4Whpbn7xWGm_BS~_xqt**dDPP%t+7PH z;Dq%!zhM#;H5W|T$+CZ`7XCfj`wsUgT^fE}aH)a!O5y-KBq-F-p$BXL;5Sf{s{_sR zQ9nQZ1j}H2U-wZPq-S?#7N(5Dycg^1&s#t&c3B(dOiHT~j3tBG>uwa)ZAbPwg6$AoY~SB8Rbmf+am2kn%4ZcIkxSW>{_Q#Y)CE2zdeIa40#6wJ&zok{2d&9-nH&;Ju1A_ch#0#cT<% z^MMocSlTYoAE{Z*u7-0N zG3#pxWe?uY`2m_5zqAa0a6O`VMyiEQ^w-)jui=YJ8(mOQ9nKb1?2rCnhSJ2b^Enwg zi#;3v25gBv!&Si#f(}CDbEcjJ7+0Y-wfq>Tu&%WD7tNv9MDFP#PztRyfIN-0SH5b{ zK=}6U!iy-o;HG8}Os(D@z{yt7e&gzK06nuTML}GtfjSDpe}16c@IZhmrTMz#+3~R+ zuOc;wZ_$|5$r>%@$wHk6xEmN21WWl~@Tcm$9u9B3^!}3epgTOR{Lv~lj#5RL_0g6M z+1=DiD9bhTZ#A6j*~_q*0E})+>rd`I*C3T6%KkjTaZF^ojTxGsWWMUxJ)|4_$~%XU z{PRqja%kQ;W-?bAXf=1rw02go<8Rv7b~9^>>FG0!kjXj;3dyg;4qw76x{EpKh8M2( zHp@c@#ita_a^ua^htJ(jzO>QBt%)YJ(;{|-Q(U6XHARV!sQMHlL-OloFR~wMgM&N-hab zI3T18^uh;b@V+&SwKv93P`{NaQu_Ovs?Q11>uUN!iQnu6)$^im=Yr2V<kPRY5Z$V)jczy=7##eaH%90+Xr#sn@I^zgv0gd~n znc)5i#s_Q0t+ED^Ky38og&tA|U6<}FrIaPJr#Mcax;WBP#18~Smf=Wd|gY)B3_ zP^@2tvI>qsx{sP911lQsDaWKqm+f6q6 zouRbyD<$Bqoxo0_8#QKlM4cW?brR-ctk=1#+aS1cu~?0NtcYw(Cm-mcE2hoem%jEd zoKHOD8yIe$1+8ShzB33ZsmNY9f0zWPVBqERgP8=wr}ff8u-l+~73eMt(gd(nYfAe+ zVx`Z2I(+?Kx>)Fc;;$IEs!ISdTs8>7W@e3q;&g1f;hrEc(~bOh^_^4Ld(w>UCd6d| z!t(AWzT@*X6vuzC+y0jrs_9|^RM2vwjtK!H0i z3R%^$CYqN)N$!|QkBoKcz7y7fUQYvd#d=_sxV3fgvn;iV^l`TU|@bS7Y4fZy0WQi@t zn?NU_{)(6{)jGpjkN1C~U#g=dhP*;~=g78~Yg-a}f4{x!pw`Iv69WTI>vW;$`fj?{ z(P!S^{T;ON-WDr`bIeEq%BSo#6ORD@uO~r%&xA$$^ZBlPYu1Mqu(}BVxn!sv?Q#`B z>HA$i1aXiBTy-i$-lyzqUGAI@={1F%n7{gNs!DncD(wW<71+05lpgw!NU+Z}xkmc( zyZn1FRXrJz9UmQ<#y5WtkJ13j+wd*0cjvz0gNqyYd`Ph3g7jJbKi;dJHu@v=5wE)! zN9s;*G~C#=uhQS;lx-I7(uL=t@z$z{0;Q6fb?Nw0f5}vCBJCx;@%)Kx?N)bfM`S)K z1w^g+%?*svsLe7InXk_}E&bLnJeTUaMVTgwM?NHYB)>%RGOeC^WJE7m5Q#6!DT#lL zQ+sB^M^VzfP32@&<&(8ikGOfj-oEUK*i+97a*r;Jr``71oPaph@ge*A!lejRDXmJ5 zZ9(iT%(46K9(C{)1GJi6^{jBHKJvY~nE_c1vgEl&TD!F94ota8E5PbuYHF$+@$>jDSddGe%m;Fk zN(s4P&^;n*z?~qth9552wVlid0}of>9qHY2>{V&bAJQBY7ig)6`~8LOn_M0`=1gm8 zlQx20$bAQU-W8fG{d%*q>6rhtw%U|MY*!v*SP4S8daC zWLd`(39t$MPbYk(E8A|HP<5Ed!R{JoZS^r!HCwG&it1SeeQLsl8|cqef%Fo{vQ{}m zJd@eBl6nZHQ}#J|FtIj?{Gl4H|7uv}`H&U9cVRp0%=6Hgha1;+=3IAlERoJkHjGKZ z=T}N*0D7lax-}OP3*NOO)yi^Tr4Rzv2pBflI5GI3Vq3HO(*N?vK@Ls(a-T zf4^Z!DS3I?EHFwSzA9CooSCT*nJqnGP%$knia;+s%hx!bUWcR7?%tk{pWcP6p3=sQQlW1)nADo)hMM zKq+jFxfG#^s4S9$sZR?i?p>00ey%to9?8}Ez0#F*uS z3;{);Zvhk5_rml;y74)Od?VRF@-2FG!n-aoXQQ0+iAUonVfnk8R5!@|Vcx^F%2#B1 zn!@a7YPJ~ey^Mw#+AU-)9`XU;OeyTu*5-Na{qI$!KFRkDYf7aMiq{Wdb6aki4^Hg8 zH))6+9CbQ7;ad6MUNQ zffv{_dJPx;ak%Ek>-`ks*MyqkaLtcEAT9Q6F>M!T6=vT$-8J$Pow<7h?5ank*UE_{`SMQ9`a$ouWEMe=h3^HW zt9Z1Y^lxw(5V(#;maZ}#UrrxpviA))W&cHZjQ^cvdB7$Ml)M|I?Av5wznJ5^=q>SQ zxO?TE>+ZY-RHJT#%C+hiKyVx&FVR>`HNjvocXY2`Fn^P$rd^>6dCyu~L;sRqX)=EgI{^iDz(qV+^i2 z!+|K~;c(l^YyUP_BIdE!N?BF4r-{brE$=Daz9$OGV~UTf_|CH2KQfSTRTN-qhhbDpdt z1k`2rsD-FZ4j;H{JBI8P-EHQ#IW|@_zWi%Bp0pf)q>!}#*I4lBg|*16k4B1r?qeE8 zjTvTrBVzVFUOnP5_%CiNIuA<)jtQ3#)IP?l&~Ri!$1cIHA+fxqS#rsq`!sG_)y?(cvmz~#1MZBaKuFnl*|ODann)A zVGVaj;zSF|yFszIbypyq341DgG?-@mKD(UC zZ4Bkyj}As;<=yOjMpg?)_VAR+Z`gYS9HNedJs^J7x0U}4m9WsLTbNyjQC(az#b;<1 zHKC6!22Vmqj86cf-Q{h7gdc#5e0C!*r0y3a+Yjo3`Wd6PmzQt`^RIS&$lYcm`#RB3 z$^p3dakyl?aK};BJb+U2ogp-N)_#6)p3sOT{v5b&8Y)PI8uzX!$vb|nk*zd~Ya5{+ zRW|Q@;iKJ&1(sz;!JzG+q>S^>Mrf`rnKDkGUeKiB69WbIe?V!I`uBRFGy%kp!L|>M zO1-fJw68s|A~QqXc0p4GR9FplS;a|M5@*@w*&cO>;7de90u%@+WujNMxbV*!pxPH8 zm%`9Xv4||no7KaL?%5M0w=p@AD7JS-y`&-bXHsgIe}?2S75U1>iB7AYCPTxKDfoGx zrIW|T%FXDmQ9*SlsTF3VrO%9#$*@vGJ8kIJSqH#kd}=66?iq;Mr!}!OFs}b-8a-d2V6rh;Sjm!blRhDgjU{KHA+*Wk7jtom|8R+CBA+ih1YxCeWw0h zy6^kB+A&+DHWN=(R#mUMSG=fA@3>BBZan=#}V=DiI6ttG3W?ZiY+Qa zdJtXhUuvMc`>hnyskH)BTRH?aYtPmx(42FBc5|x&Ql?(zH2r> z3wlVd)FSoA?v<^Ws(HawuH)sFQp3&W8qd^-S7v<{zrRN>-a2a{w8q#znzv83l0S!p zJoR!X&iCf?z+$S1)*}NQ5tpO*=@sPq*$w8W5-Oocd!z1^#UouCK8agQW|euT?KMIk zgtIvl>2UZ=HRTj_2h%5eJhNO2pV`&E+e=Zs+bNAZAte0}vZnF8e%YkM<}KORmO9H+ zbRwGDJVS*#aK|Nf11{6q&{yrvh3>(&PX_Lycpf(iR-s9rn3Tk0ag&q>R1-wG{9e{} zTz#7PlN^V=LOfV4rI{SL(UX8grA;@2P1-EQ<&HBt`u%Y=jGB>{PUDV~oA##HTIhbN z>w4%l^(%&_cnh+e!xXq;S6s)AFzcKGOOvAg^m%)5*Ml`{cb|#y*NKSq{LbFc=lRG` zF@q{W{lu?pKiHQzZ2^m|@A5ls??w3N$iFu}@&=!WvzdDQ(r_HNT1_&Tss2mZY3}eX zr?h;Um+Da+V!-0I<3INV43wONOTvfKE5=81@U%1Pz4ELpxJB14jgDor$T;r-$WLda zI7w&Pi#k}q)5l9Nk_8CRj1kippw6_5DUgUw7Z$gYqXHYxs8k@`vGtGK`z=5)G(gZY z?Lex`s75Bw;N}I8lEz7z5g~A=ks*iY*~dNjwd4ZkeQ2Kfl3zE$z-IfdT9BR5U~HYp zz6XE4LU=`%i<0p-zU>hy8E-^i!Ne$EhQAnVi5QA#Ww`wHC`8Zwa3}6x!MjwNe%WC7 zcxYLce{#JKTyrcIqgE>@XR4Kun-Yx;zqlCy<7=R(zvj(_yE(-Y6to;y<~W1-F#Ave z`X)wyCUWQ(1boCgy%HleG^;P5S3>>c z!Ef$VZ?&LHgw)X=7Z{$~$w|@F+bxzajYe{s7w&|q9KxYuxe;Tk=l+r@CAbg8QqOB& zFx$t{J4U69-e6WN?jYB=Vq}$a99$iIR$c!>4Q{;{r@W+tn!Z5!c5B=tT;t3O>dz&K zn1S`v?Y1V2J}F(cV294D3D3MZ{o(}dg@hq8lu%+h748vvGNh>W4=(E~O zNqV1_4C7`#II6zcpbJmg+*en3_(jG^#ce}-9jM=}h{!k57WDX#R|?0+37o*(NjZr8 z)zOR5;kUOF>uz>i{Jivc-t`AE51uE~tG8Oq&}9^45Zq6Q&N}-`dqW&7P969;hI|xv z;Ba@_cU?{^@8Y@^i}5&}&x8&1>~`(2S3%Fz+;r&@Sq#L6#FaT;pQ#M4&h>kdBpYtWoaY=9R=En{{GN)s2y> zJ{Yt@(D2Pwndvy_pmU_Q;sozngwgt@ErukQkb|H3qp8+E-|jcWR&LZAZ)PQXS@>f- zJe-GIqn738Mg1*fI%e*qwt+%F;->Mbv&SNvpKc&J-4z)n)z!p~T$_n8Igq$7gSlx+ zks7V?i~KL0n&$cbF)!vRXd#8yXyw$JUGd3}>T)<@;MJtR^NvqfpgAtaHxApcAHjde z#OdY8e$#?H0zQ?|RQK-Dz2AS?Mw~%zYg_ToLLH6iZ#2Sgx_A16;Gkp`^KES3{M5<6 zBt}QP=2gLy3OEyY5Lys_>M8}?SbU~-=&3c`=cSz2583wDpM9QEZ)F?V@1T(^jxZk^ zp;w|}M-{p2)(4iQw8iNW(mLyIsG7cq7CaQCrZl$28OOu*`3K;yxqg2qOlDtmmrtky z)7rqEy@>6KXQ^9y2(J|l<3-DthcY;AcZc>l#O6pqr~r-2Qxi{N#BanT zTJ>ZE?b&2>3k$Y@H|`wTKD0|l7u@T}n8sWo*QBcV%|XTV;?My|d83%W16NN=5(uR?G1LJX&yL@k?@G z+g@KU0SK=NTyL7;;y8+Dot>}(#c?ywx<*daI4>v-#Xix zA_qj~|4u&#%pkLNhV1aMWtVg?X}Z(?VY!xsu2T}-*hO+4aum7sC~_Em38XLezqgw5 zO=qGjV$@7#gf(ZRovE+kU|-(N2e`d|N1xJreehiT{t4@+H?|pL4GPwZ{p*tHJG?;> zZ?Fp+j+pOSGPs~Qf)Oo2t`I?^`pxS}ke9F#3Dw7k^dF%MK0>2j=0))u9UZBpWu&>b z&7iwHM0A%o1`&_(jL?7j3}NN7(kbv5(D%erkrVnLh1d-dFJKHET#8CX-_&@DW0$d} zBXz-|whPzX>c4gLZ|KL)uatS;k{z68w(~~?`?dP?QFMi3IfgP!-oa^T^P}u#lR6(fbpmrxlM;pZMct*1L|xpX(|E}~U?cs4_t0V>_iDE^@(x1VSovfb_uA*d>L8{zqInYycy(Yg3{~;3ro9+r$ zr0=bXN)JN4t_-BhKWq7EjsDhQ8?@rxW(Z$x6sq}dg)!TO*6vI(#(_U%Wt@R6QqP5; z?&Yc(&+D1D{j`KsS?G$v(#AsuM@n_rp`zR$6C}G{`|Bm`_S#Yh3wF5!EIC9$8UlDr zjmwcdql~1gKvndQ1rtbGJW>Fe;DTv;YS_ERAL)#*wxxaa{H@$mN=JiRds1T9XAnWg z8R@k6ii7hCZ7`23=G9tMd@#{r+e9>Ma^;KH%_zHe7Kn^mGx%Z8mx%MI5~>;3R=>J_ zr5uBLr@DSD002g_ih0an6JM-&5$x;i?KLD$Uo4T#Vpl7@?}YH&<|Ama_xcWFcD7%< zlBRJl73U{iZWzxCGL8_w4scfc$fbgfoa2W<;zb^HJA^k3)-LQ}2y!Xs4&tC74QYHi z>+wn3Nl~kYy?!3o$0WVTm9(W@|8G4Ildsea+1a0-)7dzAua8P+byr6@jRZ-+65a{~ zqB|%;0Z%sG-Uc@7VztL1)1oN{Qi{&JVNZGIJF@lQ%U7$p^*+ne8b6@r?HvRo2nbT| zma4j&1r)XAiObZ3Jq5fSVDKv-*Y(rF<+4>L!kH^Iq@VN<+?{Nwcu~iZ=1wqpyDQ>; zak^8NrD{l8d&Ta3H1o!C^N3=Eobn<+N@9pagQvotG?HXV5~Y9r8X7dyJa2zu(V{YG zLD`Vd?b_&Vi$TItv%bihgLP$fRl!S<`-ok ziqW?xcQ#`q+ALBAR&L4=mBXatKn zZE})rChgUdJ28#Cc2-|GG^g^idZntGZ(KG#ELJcVfDEgd4-2oP5l2IKC0+Yv5z)RA z^G5{a@>~7qF=~;>X8dkJt|y@TRf4pI9OKu#W4DL?W{*Va$jB!nB})v%Nj_G><=+o^ z0}?({*a4%ICjOzyGKO_$_J=ImuvG z_XlIigX6>u2=^m3AtHW2m6#VGrU#T2)%-bEjS}`KlZ2+*nv99fFWw1Eo7a>g)Q#Wp zOO-kzfADlg)vw%c9=&)yjWI9;-_a@?u}Qe-TEURa zKu_)hZXrLbJy7n+ut`XwQ{TLUMdQKjr4UIABWU`Jy%uBoSHagx=NS{UcX=*PgT4L& zL4#Nodf5d`u1~7sM!ZE?!J-epNAJVg__z^Y$aoP3BY9em);%)Gi}0O$$@g06mj1!+ z#8T0R-+r+;x*__oc?pc!(Ic9=D$|V(UsZp*rn|JrJ2UTRIOcFM4&`(IrMhpAhjMM( z7Q$L7+9A8CrJ{upg>0s>N{XbGkQnhG3E9OAGn1?+LQ!NpZ3!{iXETOnmwmQVCNpI) zn8sk3G5hbD*7H2?^X|U)`+a|X-yi)le&(KguKT*q^SG|_IFEy(U}=q@@0vly6RNv2 z_;Y*GEPDb_bGot(tM<&Imn+MA3?%(;P%%%^Up=Q0g}3%R+{Aa?u_2Uy?RV)ezMQi4 zdaJ^?C}RL?!7K^wlfr5+RS$`}(wvu}SY25}AjP(_#{|?LqIbBiK=EJmI=IsHKp+UD zpaW>g=r@ed>Yz7A`ScBAMW7?76n@=|U9>@?8ttoA3dWQJdBjvOd6gTLKfUt%)c#Uk;%W zTF}ECF4WF4vOfq4F0=V*jxbA0xf@xBI#|2{Xb@MEY`2!%tJFguM8v+*0G`docR+(Y z(6z?LNW`7MwA_A{e7iYBqU7pajPP_$={0nnfFagxr=Mveok`n;3zR+_H04P6=woZ( zi6JB(mPZai?A&|)-|w;q?vU%Cui_18lv-5%(H$iKa^z~WkfRZA3SizSy>QT(F%;$j zD5~HPf5-nR-&b*|;6L(xSK9v83D~|#{}bCcAtABb^4RQEP^!17T=H56$|P$e)P6Ix zFg6m1l;8gcv)8FQSDwTw9YCoJX=4O?T~Nzm>JaF;pj2l8n72e$ z{x`$L$dV(g(qzDd5Nq#9&e#=---rY4CGgQewYKWG>z-^txcvN)X^{rl&=Xq#85cg) z$A(iZa7Mqy??PXm7pr71f{rLBuDBzsDBjDg$Y_9lZ%E9)wuu0&H76{?Z|S@_^xi={ zn`nxj_!}PZize)pxMCh}gO3y4U;|yu+9+NleOXW1x?v&N0F+r00k9#meqMdWm*OqZ zM!>h(JpmIl)Bmmpp-gAgq5*qdT(UW7{6A@i=26*Ra1!?XI3z1b*^3y&U=t%A#;y2gBW_*vGV8~hw?sjF?7o*RpQ(>9MfnT;dhk% zrZeI@qedC)EH02-o4k?<2GcGq-|#mMG4J8T6CAb5q>98Q-b^3$8`|J!6)yKR zjQe^sZ6>Z79?c9CURtY_6`nIbjH6=F72IYQB=Uy`U+)W-tZ&*-Zme;X22t2;8XUXM zAqZa@1a@*~4D8}-8VUhfJf^G1;u3kOH{@F3IC9Du<64HQyez;O2t8@5&6r6SU`N7WUBpNVj*-4@{FxUVO#ZqtG_ z6*5wP?y2prA%D^S`$wnH(}ybZpQbf=^gOQXk9bvqdZ6W)VOzd^*4SV=X!S{Nnq_|7 z-LRZ6YGhUAjeV?S?$0ySUmP-BD16s~pYoXT=@V6`KP~v3`ur{J0Y6L=o+Dx+oV1@l)~0oYc^zfNS%&35p?17S z{@QyefZS`zWDy_FhhEW23(HwH+ww>$Oe5%0wtqdeYGN~;Aq!n^MaYTPAwWM%?g2HT zGyJG0Z-Q{dCyJK~N}}Z`?g*xwU;#A9tH=ap*8IG@!7AyLO@$Q&*=W-q5eHcqEd& z^H`d`$aONtZt`N`vFrn6%jUYCiU*XFRu?eO*az4-hx$v~;ut3qU2xx>BUOE0fJ$yugrGpui(7K zZU2mUzyDQ{%XciOTUcPm>^hN3Jq08D&*TSYj473O4yiv;Z`=#K{#biJ%bNH-hOGJR zVN4z6i+rr$Ya|3c>4o@XIUc$mKjtVHbxcA0jux@e;IlCJk<>U}K=h`Bi0ELjrgmcA zcyfocE-6?p9kXJTHZPPeh}wX1MNUNt;CszQE*?rN_$FF36*;dh7r{OmS|ZnArp4|I zNBk=K5(CXuIAzr~h@2%mV+0unhl`^=TJ!~ejOJbhJ&ybAGUyy|O1`|HZu%-TL+QO! zGUQ;=bNc?s)4#k+lUM-7opDo=`@FbLu9g}HeN$_`HDW7&Yu?sB3~>xyznG^LJ24sS zaqq+{am(LUXl0al_QHw^b@j!a$$Y)X&?eKgM9Uwo3r1un8h^Bxw7HX3GQ}O;4n5wWHSz7P+%0kNgE5+18Ms;B_ zS>roD2d@Bw(w&9+G_%#GA8mG$Kn*)GZHrv2-AmM*gO=<47PBQm8(*W_?VU$0S=O|9 zR4ek-V-p8>t74-wOO5O=QgH&vksS1Rs(tHDuZm8Ty_3bv@NR6ZxEAxnw@iw7KR1 zX9@JGvsvntyj0nJp&Ggl8QRp{RPQ`p{$PEZ`KWTpHpS6&$1F1!it5qw#rG^`DYu@A z!cJM>>XkD!zx3a;To;DKYQM*>SoEN|Md-_HMaKTsg=S_}K~Ujh^cv2f%v$7+1{N-n zyL+3KT=3tq_WX_4nr-r8?zjlosHW150HO{*1oP)9Fq2B6JTdhQp~(1+YwCFBQ#yZL z@%_3#g+8R4jy8Pb7$R*N_+_>8sC2n++HbjXojz8<_bATaqMw)y_h=d{+$PoQ1Y(Xo z&UMdxty$mgYspH}+#W3N6Z2sEHI~$^c~z5FloHe}oU{0zCCgDT9 z-4@JOQkl2DQ2#JVb+K%^C*q+JR#1jsRhaG5gBr)3^L)Oe`~05;b60PN#fBGPMF|Ac z0~wE^)ERS|>G70YTF#zsd#%PqB$O8XDc3I|JDInm5#<*}|ti{aa_B^gSQ z$5g3q)-LOqfPv=+IkL^(xP#MYvwd(Y&prD5y`W6O-&mCl0g0i3^Nd~mQojHg#SUkj z#Z_qH64ywIdB`(7)zVc2np8@u;4nDwHiegq(P2%*Jf1=l{$QMMC5wDD=AwyGZbL91S;!Bfh$m)VP z#NW7Yu*E=Me|htiUuLz{`=P=p%R8L1KOIbQBU>Y`vv-^Q(vl?MIzhjIZX7Ze+;?2B zqwli=)o3hv*Ldwq|8&pHlhS{JEqpxb+j^Bf$MFc*#3{(MP26gd=~ft4kvp4y2vu_w zwbVnpYB$`(5hLZl^EsJfA$=gK|4$ch{}QjKu&|lL)E3NJ6?UDYsV?etfGWq)e;Uf$ z>PzQo|5kXM#2IWcJm=Alx%D|IXc3V(z5ooJM57;1d?&-4@s(|jbNmJ(g#A-C=fNH#Agjxh*S8<{mCz*S=4P$M$}J1PxEnNovhTa?xe#jABTY1d%91_+ zUH8MrYV}dM%gtd0%U%+FgE+Epff45U+l;*NIz7F!X~+*F52%&XVYj+*ya$QV7P}Kx zRHo@hf2@3>R}MRohBbDE2*0BxsQau=}FlF=OR$>g)o*2Tmp?s^f_b5Q#{a){ z7W-_il(kxQQ>m>jvEhi*OG9aw#=5L)t)a5N1)(@ugqV1#4FS{LAGHm=clE5q1a=hy zYUs__waZfK%%6IGS<<4fVeuJ2gyGQit^jGa`I1_qB?MN=b7gFTeR7qB@~WbSKM~~4 z9dPjsA?MerEmSs9G@^#fJ%hISwUgT(SeknxxOeUN$8`-5S6<@T?!Oog%s-%daX_n7WXR1|S#hhc)?mv?E)Njt z?AL)&WYP?T-wIKmao_TaE-m7T*3hOtQPXf~yaIM((@+)96voAj;#yxL>TA5RBO%c< z`KF@{D_O7hxSuwZmvmkF*{IbB1$Y3?y}V3!m~W~kaV{mLU@RBb;3mSmHO*>RO*FBP zJcIF=1}HxfQr^3hnB;l=&h%f*Gf_fKOK`?7(U>z^3gx^jpE^qXF4M79$5_#I<|`n| zaBHwZ+xG8%w%;|@x0g06od;$4^tY=@VyU^>(8mV*kJ|I6JQyLr3to@39yW@YCG9Myg9JNYpTUcS~zKt$jH~ z;3vUTUTF^R`%G3qM_Z-2YHOBE@4lRVRMA8@3V_`k+ch=-c7%hW^Qv|GWi#P<1z%(} zqn~ZLZsWe&A{hDZU@MJ{Vz9@LAEKD!?PiCJ`DDQ?zQkI%x=Age2rH!RkE99avxI{S zg22|0Re2~o8|{JwlX&zM={Uo%^-zIu^alG(y2%c3pkW$+%pBq4^VOMNcET~d9(OX9 z8a)z>-MAusT)JZq5OVj#<+<-+n;8G5_-P-uZHd%~HVOJwI%Rr0IH>(#;l$Y;|9r6R zL9BKAN0ygO`u-1AB|q45V!OBl$&aL5B)>Pyy$%1&JTEgz;b)Oq`eQW6`;fM!mgjil ztASL;I%;`Pl=edwL%DfDSJdW&y(!NSv}!plOr{DZ@lJwobkXbVg#mHqDQ~^GI>8cT zoL%i(nFw1iNJBY-%>=fddN^|8h0uNo$y+SN$LHaF)T7ICNLNR(7nRAo77wu*^8Tw2 zf_){Ft%`!=KF%TKrDvOtY)1H@X?5dW@Qpd1Us@0hxTEpV_6_QA7CirGa*KiI#o3y< zTF=XpXC+S#b6I((2EV^zNLP8V1c$K!em5j(>9%B-vNj~UjNL%ot`{H^o0!E|Ovq|p zeckU`2c-YUthzrN@c%S0@ewG>p~YmujTOMEl{Q)0nDMccHvmJ_W;amA*v-{kK1SdR zwz}fn3lmi04=pP{gIgVCOJn)8!4SDyjp8+s>u%T=6~#%_KMra25suA=&dt0wJ>uzr z;>THF5yM)&>|`xR8PvVfO|94U6g;C+m+f>mkvFE!?3xPsiFx@j_M&lGL{CkSTr8!= zMW)%M;R(=D%Uj8bAo(@b_TKvGv5)nO#HEl+X)MynzOdDNWbVQLEyneSjn; ze*OpXd07lC{(ihh6?=pJH+DQ3>?W$!8joVcUs4d=%m|B`fQXhM1SWow)*Rf%&l9#t zDU8nVS!uC_a)-tvYcJe@W)&+e?CJSneYY0rrKUsEot0g=UwvgTeeV-bb^{?rD6L3Z9dTcf%?l5AhTh z0rYMQ58fy_Fo+g1Bh8DBE1reF%ri2WMtZGRKzJ1hYf)E|xIaB|vJ*%NE@%$}m5B?4 zioJHPA)H5$;%2a&df5<4Ic3EcGDN7F%F5wa!O%OsqV-;3{KArMb78h|KAOo9)pIe; z>v(4dnph{cdZy8o3xx5TX%{oqmj-~u1Kn4qt^2*#>i5r8W1y;*Q(S_esF7U_)Q&Ii z1$}F83eZ9h!mYDwt!HIa&3(+m-V4$yFo~9H5y}Q1dup0ufLczDM0QBsVdF)DF$*$h z0Ffuy=PFj9veLJkfQJq0wH^S6Q7^4}U9F28tAv9h{-6ukKtn%)O^TO&<8YUOVAvpK zMPGJ!_FF%e<32{zT({^ST`j;1I~I7JYimDrLk*HWJrXedIVNC&-r#AI*BAV*Pr`U< z&2M+nvcPN;KN$&APxwI?ai1%1JVY=K^znO9-!{Rn6;2EV_90f~0P!4BUKdw;ioYGR z-mc@-huzm@NH6VY{@ILQeQi({f2rsA;31}DYv@6L)GbWQNdB{7J4M=(Bk_Db=5&7|qc~7F`OyDq(aJznC zaa3DsL#TAmbVup<>f;PnWftyjfdO~~a;oTsBGmQKmuGgL4GGGW>OJ&klQcKD&bBqa6l z{0Ci6c)>VmPrrgcIMB9X;Vx&NYkLh|Y zC;0`NO46>dEbV`8s1mIZn_nXYQtTiVO|#Xg+|kcqlVu>}h=%OTYN`S$eVbrwPek9| zxR@odgWM|VxqYN2V+8<^ejKx* z@1$$Z2koMLbIA1FxA!UTH!L8qk;?ZyC!>VJRsEwH*k<N6)~}D4Tc0zoO{nXEkROe``7Xx7E&V?|fIiw#jQ1jTm2+DdMXhA}6P4 zew}kVNP80N$;=^)QsA7jQxby)NByN=!+CkKLA=f=bUjDHs%hEg%6H?q8=YA1k?jS9 zGto7r<17&sz|Ybypl~bxo(_NSm)TB)fxctla{S-2nf?oJ zNNql656VqXMks$lXJmcE?yIBR49DJ|GEQ;aG{eVw;w~34sY$hG9>3@1AP^)uGpL9&Nbr3sb6jsjED5jvX{9bnD`k(+(@@l9 zDJ(FIR8x@D*@O-^6G!qxC9>k=cUe0A+g{oCpFdammjb=d!xx=3-c{=1>i0>`iBIdx z0<9!R#PpEJo2Ns9q|@Ew!cN|VZoUI&X}t^S%k5OguXiBuKizJ%xgFKa%wIFxaHw?! zsDIFY?9s&+mx=pzLjW&)sGNGkpqjQ_gdsZjg3oa!#YLz%{es7e_?T4|RtR7dd`DprdfniYi^Y?MADcm9(CvUDec40~geZ=dB!`w@KV` z_(0S`M%-;PN#B(z=RnWR+H_xo7&j}J_%SGTc)j1)s)NIyQS2|`&WF@E0eb?T<& z*})~fi95lp#69nz-wD;92rhW;*qRxxTO5`zrNzr`s4oEbx;Fp>^2-sNW%9GKjqf6@ zroV+_cvmtSjF9>_gJ#Ri%QxOq1NOWa;rxDI4``cyMw^0Y38S1m3>YBw%(!i`1f50f6MOfnvG!CQ8V}V0#TW_dM?1#rzWpHJu8O z2U|Yqr9rCbDZ73USzbzQ2 zGMrfICXF;$gC&N9u<6>^Cu zRA=G7`>w_Qh$=hczbQ$-Tt%%MHL%K-4ryA*-I}+peW;D&j$d={|B|x5OnFMScty9b zYE?c1E&WWs${P~xaC9ZfrJ$&zbb1gfiuHhv(*I9Z(9kCCtSP>JOAZkwaeWxETVk(> zKY6up*w`|;_F1lGU_y)V9c<)9s;6MVg+N)|4`3+L-6~Za)YKNlH=ADj!6>9RNL zDbwEla{=9ug=-{);Xj?LPu;tDGvOGRrmjQ6ga6{4mGr~TL79%l+KEKO#+R=OaRw4C zk$a|={)jo2ScDIj)X==S{log#H@Oo2>Q}da-To49^)*9F?c1PT*zz{w{<}ZhG1#Dh zAC_TaWnRYK8?aGA;+a{}RS5}+q?al(|G&Rr&aLzSMgJT-@O@l^TzqeO$eWIUpU+Fz z*-3%_)H@8ps}3jm|JxUNwplJYT`f{Et8-3FISCa>8(&wCq^l|qbrNvx z;;g5CdVAzQexkhVmls(RfKgJK>F(~{xCphhyfJ%jKS=Qn6~WhypzRb86P(jBKHchb zBz6QHJ5Z$S){3 z622k9!ARclypf6(6pC%eD$(cW-pm(wd^M4IT`U6bq^2^(0h9gx{R@nz=eBIwQi5k5 z54?eniHWIfY;gr6*&CTl<(`J}=0!UnCW#tUe*6dhY zTU#;@L_{vZcQWD8QG&Nm$I-WLjjyuYp=cpc_d8-GAr-aue53pyb<<%fRs}8{oik$+ zRoM;mB~NipzXsT;a*sXNH-V{GW*mBZ#3f;a%mTQr44?>l4tIDN zXuM^Bf2J4FuXLl5fsC4e>#p(hzY z9d!&8e@~vdg1b*IWc*YY<*Dv-+*#Bs6*Y)Rk}f zS=z{O-Db2VMyuI&%Y*ygDqgo=EL|fvsKob01bR1c)0OuwQ!W|Fd5*q4@$}oeGDp#6 zS;-9=+?GNNwc!hdf*8E2r9@PJ%KJ$xzyLp&9#Z8P++MkySFD)&rx{tZ#mhr7{+oXN z6`xdp{<=N?m_t*-XrVyyQnNkJ_U4rBjg_^LG+2ki>??Rc?y{6QeP%eK8V=1gR$4yV zxlqngOk+mAbg(F_8h2zC&GfpWbq=tQJM}14zf99?1HsI-L^pe0_vufrjn;2jK1iqChwZLG!5RNK1T`DWOKl@NNJ=EMo!@mS%UeaJT_I90 zD|)>B`Ti}3L*LwQi=Dc-UG_h{IpLAHrRCdT;`O?kni{|RP){7fS${AB%+jV*^89?j z*l@&Ze^TVO<&^my6wod1X|NsXGqf|2b*Q*Zm2*Br;V{P#W4YndpZg3|kfd~3Sy|^z zL?SVZN~Mlbek`NsDt`)B?^8)6(oA=^opGdb^K&bW-cw&PqJfey#c!eVs3u&bsHe5X zCe|Z49b6Awl-Zqe8Dl0vndvcn(6_i4JT?IorH3pV;A>_cPfmN2s{98_@RaLeM{~)| zm3iZiy>+jHeoHP@pFd;Uux*Kq7J0C3ld0V^NDgac>@ojWo9aCQT?>%hLFgfD4BSyP1Yy3UfB*hPrSD{% z2J-?s*vIE(PF;OHd=f$j%b|Z8vkn~*@p~ChtP&!0t+i^oQV3SJr}8AwEDV?xZUygY zrvY_E2S++sUm3~C$uxJVt`glX;&mYqtwdXz{M#UQ+8fDlO!78P0&j0Si6{M^BfH(JZ%11TY{Dh-Wyh10E2O%)pxek=49re5{S!9e zF8pZy5}*(I4O~w)t4?#fKW*b+Jv!YMyCSWk+F`hqwYIjlATQJl%?-EylzVI6-dDa; zELv=KIXy9==@^ik4=`f0F-Kge<(>KZ}(9%;9H z1xsm&tq;F>^SplUWntj!J%vo+wcLKJMbZ5F-NB5EjD^q}2B@7Tz~C62;A*X}re6k` zK+>rS0mLe9V=acIUGs_b!W#!)G3#V8k*UqM@|ewvM)pi^w9V>fI^m*^Xm&oyCLK~` zBs_8BJKNGD^aGEX>Ae@yxsMf7P;NFYfS)x|J!{>!jc4WP5}WQkxZUfEW(UM2B*IH# zidRKSUmN>_PpAkvYZ*9oetTk$*=YM!>*eD6Qa_Sb{I)vVB2ngnByS0cb>%C&5;la& zAnMzz{#tA{4(hYpF*#-}*Ta2PBqVN6y*~t&r~k7Jx4#+wo-p=W1^l_ic-Vb^2leZJ zUA#}*`f%v&vDqU5{|;oR6t5fHn_`u}*vDq;`9 z$|sdqgl=6F>j=6(-^Ha^bi};kS99kx)_sWlpo+erRDS~NqUfz}Lb_v>r>%XFpx2%E zl-gUvJ3)f#Z&9F^^9XD8!%t*A1~F{MWP|fZIt(A2=Tn+%Ymb0Ra1tKV}IQT@vEl^Ba!8+-SO~2 z@=ln9_%`G#ftdU!djY*1^pc>lGCJKuLr!C7Mt7E8*&(B*re^BBlO|kW2BedY+j<-z zXgLk4BK@PU5bDfDcLJ(2Fv)fABZ$-O)tVn8vI@_4y4G&g&&FfR=_2l0U}a6snEe=s z1^ll3uA6aw2ZI(y5G1?y@vhAG#FtYUNd~vQRo2hSD^1-%Y>OwUJT{!nH4Q0oUz)Y6 zlk7ak5Ql*;-J^HH9{m#j*^ll|1Xl`?_ilXr_+sf}g{tsPC^{M-D}T4XVHe!^1DF-&Lxd)i(gnhdNDa} zC;K~{uD_P#{$+tX z-JRig{ld=UbOwTCYu%m5$*e##tz8;cyoRV4R=vz)fVm=)Am;avOADr5Ql~;u`=-S1 zS~7uH7`_~3vj2YE<-W!c58f_w#X8+nMv7A7uD2!>hT5Oi4tl+Rm8a@st#_6jdo2() zlky^hbgT2RBN$vHJLHmP1hPD0<~V^F)uFuG`u6R(IbP-$BC#~HpU7g}8i`>GK`c>2 zR`69in#p5Lt{Up<{4r%Z&{%RtZyPB#NDJS_ydc8gi@Z^n2Ipn7Un^np`m=Q~w91Kd z9ZZt*0gfRfa&`sju@}O<0c8-se7P|@p83eJg5*(l0tAmif-Odn+#CRZh-ZyXz#p?~ zn7bpa&@Qo!?TCL#;#E{qdaqW2I1z)`aDB=Uvp(9s;ZiQ~)dmR(omB6?f`o&r%--Ox zf6d`h8JYie{P|ay-X>=i!+P5gsT)#MROAps2ix#5{$CNp2wJArJBt$X;geYtzve0@ zKkVWGzIOi?p?7}cTj-9euwT<)q=|~}N#P_iDwStKi>&Q9RA*iwUY80Qi3k4*7=!-| z7@~)v?`fzABy)JK03gxb+IrlWTB!063B>IX z0+1N*eIk*Xm(@#4bd`+OCq93!UxZp%@M!IAmZ9Ez#_edZD_8WYh3ETvi~ou!t49Y1 z2Xjf6UGlWf!O@nfaCR9Dm+@QNKVpXX-d<0)d9Yv7m_B-4yxKF}+r650v>Bd&qWIS| z$6mA`mZwe{J1ZReD}Ly6Cy4ispSs`R9SRb5hw=Tmp!P;AgN%2f?XAFF^BH+^v0i6~ z>5(JBO#|g-XaP5J1te@Rsjb8xJxF`70iixZZ1QiY6#;PCJwATP*qKTM@6Rp%rn3*S z*Z}dsKzz(eb+1?8{XRmEFufne0PW_K)}X9=9#_gv zzj&CmVd+-{bJk&J8{Dr0KJimR08{hwm9b>O<-M{>TjNEaZXp;a7yEj<_PF1Tb!DNd zq0me7VCa9ssI}ZYkZ^T+N^iZI;k35ZACTHAACeoC{i!2C{zFr>)jCs`KEHLH_BI3- z9Cdyr7?t-OPcSB*QsO4KT*Qclx>I!#(q3QYS@P*Ri-8gC0UITkvf=wL0Dw6MJWi@d z30t-6rUaR!7>;urZ!aX%!26SsuhO&JtPdW0K6vcq$U^=Ram4tNGpd3kxilL@fd zCrxJcYkv zWT|9}VT1Qpmr2TzPL=77V@ERckGQ6^24hq@Sl-86?(lzha>;|?Q67T#=eJ3bo|;}l zGM|?r3CDJ*m9CJ~e5_X|)7-im!Bl#Z#twSIuis#KyHw$t*KQ@`*+n|tqaZKOetZU1LbNoIem?6}1!c^oT;WNC2=H5mNEh2sNRO$?Yi zgP0_!FHHyNtH^e_YfMc;<@WoAuln_tQ*M7@5&-X+_Z=P7y=v+mRK-w3C*fa03h)t= zKOJlOlZ48azxLo_bV2zKAmiU54)Ee<<7__U3SII}hnw;$cr9Uf^4xFbC%o?bFJ5Nu A%>V!Z literal 0 HcmV?d00001 From 6c9231166c5de0bb01b709eeea8213974e969b85 Mon Sep 17 00:00:00 2001 From: "Robert W. Burgholzer" Date: Thu, 29 Jan 2026 20:55:51 +0000 Subject: [PATCH 348/353] used freq + convert to_timedelta to insure valid comparisons in all types --- src/hsp2/hsp2/utilities.py | 8 ++++---- tests/cmd_regression.py | 16 +++++++++------- tests/convert/regression_base.py | 5 +++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/hsp2/hsp2/utilities.py b/src/hsp2/hsp2/utilities.py index 7c210ccf..491004d6 100644 --- a/src/hsp2/hsp2/utilities.py +++ b/src/hsp2/hsp2/utilities.py @@ -213,7 +213,7 @@ def transform(ts, name, how, siminfo): NOTE: these routines work for both regular and sparse timeseries input """ - tsfreq = Timedelta("1 " + ts.index.freqstr) + tsfreq = Timedelta(ts.index.freq).to_timedelta64() fmins = Minute(siminfo["delt"]) freq = Timedelta(fmins).to_timedelta64() stop = siminfo["stop"] @@ -299,7 +299,7 @@ def hoursval(siminfo, hours24, dofirst=False, lapselike=False): hours[0] = 1 ts = Series(hours[0 : len(dr)], dr) - tsfreq = Timedelta("1 " + ts.index.freqstr) + tsfreq = Timedelta(ts.index.freq).to_timedelta64() if lapselike: if tsfreq > freq: # upsample ts = ts.resample(fmins).asfreq().ffill() @@ -330,7 +330,7 @@ def monthval(siminfo, monthly): months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").ffill() - tsfreq = Timedelta("1 " + ts.index.freqstr) + tsfreq = Timedelta(ts.index.freq).to_timedelta64() if tsfreq > freq: # upsample ts = ts.resample(fmins).asfreq().ffill() @@ -350,7 +350,7 @@ def dayval(siminfo, monthly): months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").interpolate("time") - tsfreq = Timedelta("1 " + ts.index.freqstr) + tsfreq = Timedelta(ts.index.freq).to_timedelta64() if tsfreq > freq: # upsample diff --git a/tests/cmd_regression.py b/tests/cmd_regression.py index 5cf0356c..871b15b4 100644 --- a/tests/cmd_regression.py +++ b/tests/cmd_regression.py @@ -1,4 +1,3 @@ -# This is code to be executed in a python shell to run regressions tests # Note: This code must be run from the tests dir due to importing # the `convert` directory where the regression_base file lives # todo: make this convert path passable by argument @@ -33,10 +32,10 @@ rchres_hydr_hspf_base_mo = rchres_hydr_hspf_base.resample('MS').mean() # Show quantiles -np.quantile(rchres_hydr_hsp2_test, [0,0.25,0.5,0.75,1.0]) -np.quantile(rchres_hydr_hspf_test, [0,0.25,0.5,0.75,1.0]) -np.quantile(rchres_hydr_hsp2_base, [0,0.25,0.5,0.75,1.0]) -np.quantile(rchres_hydr_hspf_base, [0,0.25,0.5,0.75,1.0]) +print("hsp2", case, np.quantile(rchres_hydr_hsp2_test, [0,0.25,0.5,0.75,1.0])) +print("hspf", case, np.quantile(rchres_hydr_hspf_test, [0,0.25,0.5,0.75,1.0])) +print("hsp2", base_case, np.quantile(rchres_hydr_hsp2_base, [0,0.25,0.5,0.75,1.0])) +print("hspf", base_case, np.quantile(rchres_hydr_hspf_base, [0,0.25,0.5,0.75,1.0])) # Monthly mean value comparisons rchres_hydr_hsp2_test_mo rchres_hydr_hspf_test_mo @@ -61,11 +60,13 @@ # HYDR diff should be almost nonexistent test.check_con(params = ('RCHRES', 'HYDR', '001', 'ROVOL', 2)) # this is very large for PWTGAS -test.check_con(params = ('PERLND', 'PWTGAS', '001', 'POHT', '2'))\ +# git: test10specl ('PERLND', 'PWTGAS', '001', 'POHT', '2') 1163640% +test.check_con(params = ('PERLND', 'PWTGAS', '001', 'POHT', '2')) # Other mismatches in PERLND test.check_con(params = ('PERLND', 'PWATER', '001', 'AGWS', '2')) test.check_con(params = ('PERLND', 'PWATER', '001', 'PERO', '2')) # Now run the full test +test.quiet = True # this lets us test without overwhelming the console results = test.run_test() found = False mismatches = [] @@ -83,4 +84,5 @@ for case, key, results in mismatches: diff = results print(case, key, f"{diff:0.00%}") - +else: + print("No mismatches found. Success!") diff --git a/tests/convert/regression_base.py b/tests/convert/regression_base.py index 6cfc4f87..613c4851 100644 --- a/tests/convert/regression_base.py +++ b/tests/convert/regression_base.py @@ -30,7 +30,7 @@ def __init__( self.tcodes = tcodes self.ids = ids self.threads = threads - + self.quiet = False # allows users to set this later self._init_files() def _init_files(self): @@ -185,7 +185,8 @@ def run_test(self) -> Dict[OperationsTuple, ResultsTuple]: def check_con(self, params: OperationsTuple) -> ResultsTuple: """Performs comparision of single constituent""" operation, activity, id, constituent, tcode = params - print(f" {operation}_{id} {activity} {constituent}\n") + if not self.quiet: + print(f" {operation}_{id} {activity} {constituent}\n") ts_hsp2 = self.hsp2_data.get_time_series(operation, id, constituent, activity) ts_hspf = self.get_hspf_time_series(params) From fcacfd4d7707bd2514e49f6a101ad0623270c79a Mon Sep 17 00:00:00 2001 From: "Robert W. Burgholzer" Date: Thu, 29 Jan 2026 21:19:36 +0000 Subject: [PATCH 349/353] check if these changes are robust into pandas 3 --- environment.yml | 2 +- environment_dev.yml | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/environment.yml b/environment.yml index d7ea70c3..343e179d 100644 --- a/environment.yml +++ b/environment.yml @@ -10,7 +10,7 @@ dependencies: # Running HSP2 - scipy # Scipy also installs numpy # Pandas installs most scientific Python modules, such as Numpy, etc. - - pandas <3.0 + - pandas - numba - numpy - hdf5 diff --git a/environment_dev.yml b/environment_dev.yml index 78dbb137..78bfc5a9 100644 --- a/environment_dev.yml +++ b/environment_dev.yml @@ -12,7 +12,7 @@ dependencies: # Running HSP2 - scipy # Scipy also installs numpy # Pandas installs most scientific Python modules, such as Numpy, etc. - - pandas >=2.0,<3.0 + - pandas >=2.0 - numba - numpy - hdf5 diff --git a/pyproject.toml b/pyproject.toml index 7e8abc8d..ea38e3cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ dependencies = [ "cltoolbox", "numba", "numpy<2.0", - "pandas<3.0", + "pandas", "tables", "pyparsing" ] From 193c4bb57e8967b79ad5eafefb18c741e2c3e5a0 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 29 Jan 2026 16:44:43 -0500 Subject: [PATCH 350/353] use pandas to_timedelta function to future proof --- examples/state_specl_ops/update_pandas.py | 134 ++++++++++++++++++++++ src/hsp2/hsp2/utilities.py | 10 +- 2 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 examples/state_specl_ops/update_pandas.py diff --git a/examples/state_specl_ops/update_pandas.py b/examples/state_specl_ops/update_pandas.py new file mode 100644 index 00000000..79beb91e --- /dev/null +++ b/examples/state_specl_ops/update_pandas.py @@ -0,0 +1,134 @@ + +from numpy import float64, ones +from pandas import DataFrame, date_range +from pandas.tseries.offsets import Minute +from datetime import datetime as dt +from typing import Union +import os +# must import Category, Modelfirst to prevent circular error with HDF5 +# this does not happen in real runtime... +from hsp2.hsp2.model import Model +from hsp2.hsp2io.protocols import Category +from hsp2.hsp2io.hdf import HDF5 +from hsp2.hsp2.utilities import ( + versions, + get_timeseries, + expand_timeseries_names, + save_timeseries, + get_gener_timeseries, + hoursval +) +from hsp2.hsp2.configuration import activities, noop, expand_masslinks +from hsp2.state.state import ( + init_state_dicts, + state_siminfo_hsp2, + state_load_dynamics_hsp2, + state_init_hsp2, + state_context_hsp2, +) +from hsp2.hsp2.om import ( + om_init_state, + state_om_model_run_prep, + state_load_dynamics_om, + state_om_model_run_finish, +) +from hsp2.hsp2.SPECL import specl_load_state + +from hsp2.hsp2io.io import IOManager, SupportsReadTS, Category + + +fpath = "./tests/test10/HSP2results/test10.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) + +# Begin code from main.py + +# 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 = {} + +####################################################################################### +# 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) +# 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) +# - 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 +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) +####################################################################################### + +# main processing loop +print(1, f"Simulation Start: {start}, Stop: {stop}") + +# Test functions pandas +# this is from PWATER, should be easy? +ts_HRFG = hoursval(siminfo, ones(24), dofirst=True).astype(float) +# do import to allow dev of hoursval3 - temporary +from numpy import float64, full, tile, zeros +ts_HRFG3 = hoursval3(siminfo, ones(24), dofirst=True).astype(float) +from hsp2.hsp2.utilities import LAPSE +ts_LAPSE = hoursval(siminfo, LAPSE, lapselike=True) +ts_LAPSE3 = hoursval3(siminfo, LAPSE, lapselike=True) + +# check these transform() calls inside of get_timeseries() +(operation, segment) = ('PERLND', 'P001') +psrc = ddext_sources[('PERLND', 'P001')] + +ts = get_timeseries( + io_manager, psrc, siminfo +) +prec_orig = ts['PREC'] + +row = psrc[0] # 0 is PRCP +data_frame = io_manager.read_ts( + category=Category.INPUTS, segment=row.SVOLNO +) +# are they the same? +(prec_orig == data_frame).all() +# True - so we don't expect transform to do anything? +precip_pandas2 = transform(data_frame, row.TMEMN, row.TRAN, siminfo) +precip_pandas3 = transform3(data_frame, row.TMEMN, row.TRAN, siminfo) + +# precip was fine, so iterate through them all and check the difference +for row in psrc: + + +# replicate with new code +data_frame = io_manager.read_ts( + category=Category.INPUTS, segment=segment +) +tsfreq = ts.index.freq +freq = Minute(siminfo["delt"]) +stop = siminfo["stop"] \ No newline at end of file diff --git a/src/hsp2/hsp2/utilities.py b/src/hsp2/hsp2/utilities.py index 491004d6..eb03c0f8 100644 --- a/src/hsp2/hsp2/utilities.py +++ b/src/hsp2/hsp2/utilities.py @@ -14,7 +14,7 @@ from numba import types from numba.typed import Dict from numpy import float64, full, tile, zeros -from pandas import Series, date_range, Timedelta +from pandas import Series, date_range, Timedelta, to_timedelta from pandas.tseries.offsets import Minute from hsp2.hsp2io.protocols import Category, SupportsReadTS, SupportsWriteTS @@ -213,7 +213,7 @@ def transform(ts, name, how, siminfo): NOTE: these routines work for both regular and sparse timeseries input """ - tsfreq = Timedelta(ts.index.freq).to_timedelta64() + tsfreq = to_timedelta(ts.index.freq).to_timedelta64() fmins = Minute(siminfo["delt"]) freq = Timedelta(fmins).to_timedelta64() stop = siminfo["stop"] @@ -299,7 +299,7 @@ def hoursval(siminfo, hours24, dofirst=False, lapselike=False): hours[0] = 1 ts = Series(hours[0 : len(dr)], dr) - tsfreq = Timedelta(ts.index.freq).to_timedelta64() + tsfreq = to_timedelta(ts.index.freq).to_timedelta64() if lapselike: if tsfreq > freq: # upsample ts = ts.resample(fmins).asfreq().ffill() @@ -330,7 +330,7 @@ def monthval(siminfo, monthly): months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").ffill() - tsfreq = Timedelta(ts.index.freq).to_timedelta64() + tsfreq = to_timedelta(ts.index.freq).to_timedelta64() if tsfreq > freq: # upsample ts = ts.resample(fmins).asfreq().ffill() @@ -350,7 +350,7 @@ def dayval(siminfo, monthly): months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").interpolate("time") - tsfreq = Timedelta(ts.index.freq).to_timedelta64() + tsfreq = to_timedelta(ts.index.freq).to_timedelta64() if tsfreq > freq: # upsample From 8df5ad015c53d4c318f0edf8316575ae5a9f2807 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 29 Jan 2026 17:26:53 -0500 Subject: [PATCH 351/353] use freq own delta property for properly formatted --- examples/state_specl_ops/update_pandas.py | 51 ++++------------------- src/hsp2/hsp2/utilities.py | 8 ++-- 2 files changed, 12 insertions(+), 47 deletions(-) diff --git a/examples/state_specl_ops/update_pandas.py b/examples/state_specl_ops/update_pandas.py index 79beb91e..97886b8e 100644 --- a/examples/state_specl_ops/update_pandas.py +++ b/examples/state_specl_ops/update_pandas.py @@ -89,46 +89,11 @@ state_om_model_run_prep(state, io_manager, siminfo) ####################################################################################### -# main processing loop -print(1, f"Simulation Start: {start}, Stop: {stop}") - -# Test functions pandas -# this is from PWATER, should be easy? -ts_HRFG = hoursval(siminfo, ones(24), dofirst=True).astype(float) -# do import to allow dev of hoursval3 - temporary -from numpy import float64, full, tile, zeros -ts_HRFG3 = hoursval3(siminfo, ones(24), dofirst=True).astype(float) -from hsp2.hsp2.utilities import LAPSE -ts_LAPSE = hoursval(siminfo, LAPSE, lapselike=True) -ts_LAPSE3 = hoursval3(siminfo, LAPSE, lapselike=True) - -# check these transform() calls inside of get_timeseries() -(operation, segment) = ('PERLND', 'P001') -psrc = ddext_sources[('PERLND', 'P001')] - -ts = get_timeseries( - io_manager, psrc, siminfo -) -prec_orig = ts['PREC'] - -row = psrc[0] # 0 is PRCP -data_frame = io_manager.read_ts( - category=Category.INPUTS, segment=row.SVOLNO -) -# are they the same? -(prec_orig == data_frame).all() -# True - so we don't expect transform to do anything? -precip_pandas2 = transform(data_frame, row.TMEMN, row.TRAN, siminfo) -precip_pandas3 = transform3(data_frame, row.TMEMN, row.TRAN, siminfo) - -# precip was fine, so iterate through them all and check the difference -for row in psrc: - - -# replicate with new code -data_frame = io_manager.read_ts( - category=Category.INPUTS, segment=segment -) -tsfreq = ts.index.freq -freq = Minute(siminfo["delt"]) -stop = siminfo["stop"] \ No newline at end of file +perland_ext = ddext_sources[('PERLND', 'P001')] +perlnd_ts = get_timeseries(io_manager, perland_ext, siminfo) +precip = perlnd_ts['PREC'] +# go another way and get the raw TS to compare to the perlnd_ts which has been converted to simulation +# intervals +precip_df = io_manager.read_ts( + category=Category.INPUTS, segment='TS039' +) \ No newline at end of file diff --git a/src/hsp2/hsp2/utilities.py b/src/hsp2/hsp2/utilities.py index eb03c0f8..d135458a 100644 --- a/src/hsp2/hsp2/utilities.py +++ b/src/hsp2/hsp2/utilities.py @@ -213,7 +213,7 @@ def transform(ts, name, how, siminfo): NOTE: these routines work for both regular and sparse timeseries input """ - tsfreq = to_timedelta(ts.index.freq).to_timedelta64() + tsfreq = ts.index.freq.delta.to_timedelta64() fmins = Minute(siminfo["delt"]) freq = Timedelta(fmins).to_timedelta64() stop = siminfo["stop"] @@ -299,7 +299,7 @@ def hoursval(siminfo, hours24, dofirst=False, lapselike=False): hours[0] = 1 ts = Series(hours[0 : len(dr)], dr) - tsfreq = to_timedelta(ts.index.freq).to_timedelta64() + tsfreq = ts.index.freq.delta.to_timedelta64() if lapselike: if tsfreq > freq: # upsample ts = ts.resample(fmins).asfreq().ffill() @@ -330,7 +330,7 @@ def monthval(siminfo, monthly): months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").ffill() - tsfreq = to_timedelta(ts.index.freq).to_timedelta64() + tsfreq = ts.index.freq.delta.to_timedelta64() if tsfreq > freq: # upsample ts = ts.resample(fmins).asfreq().ffill() @@ -350,7 +350,7 @@ def dayval(siminfo, monthly): months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").interpolate("time") - tsfreq = to_timedelta(ts.index.freq).to_timedelta64() + tsfreq = ts.index.freq.delta.to_timedelta64() if tsfreq > freq: # upsample From 389a3cbca45485444a859139eb9f01e483177315 Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 29 Jan 2026 17:31:13 -0500 Subject: [PATCH 352/353] pandas < 3 --- environment.yml | 2 +- environment_dev.yml | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/environment.yml b/environment.yml index 343e179d..026de50e 100644 --- a/environment.yml +++ b/environment.yml @@ -10,7 +10,7 @@ dependencies: # Running HSP2 - scipy # Scipy also installs numpy # Pandas installs most scientific Python modules, such as Numpy, etc. - - pandas + - pandas <3.0.0 - numba - numpy - hdf5 diff --git a/environment_dev.yml b/environment_dev.yml index 78bfc5a9..b30e9158 100644 --- a/environment_dev.yml +++ b/environment_dev.yml @@ -12,7 +12,7 @@ dependencies: # Running HSP2 - scipy # Scipy also installs numpy # Pandas installs most scientific Python modules, such as Numpy, etc. - - pandas >=2.0 + - pandas >=2.0, <3.0.0 - numba - numpy - hdf5 diff --git a/pyproject.toml b/pyproject.toml index ea38e3cd..85e33a2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ dependencies = [ "cltoolbox", "numba", "numpy<2.0", - "pandas", + "pandas<3.0.0", "tables", "pyparsing" ] From 3b3e56d5c828009f7582f168480e85c3045605ba Mon Sep 17 00:00:00 2001 From: Burgholzer Date: Thu, 29 Jan 2026 18:37:21 -0500 Subject: [PATCH 353/353] pandas 3.0.0 safe code for model execution but NOT RegressTest. QUantile analysis reveals identical results vs hspf but RegressTest fails in pandas 3.0.0 with pandas.errors.IndexingError: Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match). --- src/hsp2/hsp2/utilities.py | 46 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/hsp2/hsp2/utilities.py b/src/hsp2/hsp2/utilities.py index d135458a..fe4672d6 100644 --- a/src/hsp2/hsp2/utilities.py +++ b/src/hsp2/hsp2/utilities.py @@ -213,35 +213,35 @@ def transform(ts, name, how, siminfo): NOTE: these routines work for both regular and sparse timeseries input """ - tsfreq = ts.index.freq.delta.to_timedelta64() + tsfreq = ts.index.freq fmins = Minute(siminfo["delt"]) - freq = Timedelta(fmins).to_timedelta64() + freq = fmins.nanos stop = siminfo["stop"] # append duplicate of last point to force processing last full interval if ts.index[-1] < stop: ts[stop] = ts.iloc[-1] - if freq == tsfreq: + if freq == tsfreq.nanos: pass elif tsfreq is None: # Sparse time base, frequency not defined ts = ts.reindex(siminfo["tbase"]).ffill().bfill() elif how == "SAME": - ts = ts.resample(fmins).ffill() # tsfreq >= freq assumed, or bad user choice + ts = ts.resample(fmins).ffill() # tsfreq.nanos >= freq assumed, or bad user choice elif not how: if name in flowtype: - if "Y" in str(tsfreq) or "M" in str(tsfreq) or tsfreq > freq: + if "Y" in str(tsfreq) or "M" in str(tsfreq) or tsfreq.nanos > freq: if "M" in str(tsfreq): ratio = 1.0 / 730.5 elif "Y" in str(tsfreq): ratio = 1.0 / 8766.0 else: - ratio = freq / tsfreq + ratio = freq / tsfreq.nanos ts = (ratio * ts).resample(fmins).ffill() # HSP2 how = div else: ts = ts.resample(fmins).sum() else: - if "Y" in str(tsfreq) or "M" in str(tsfreq) or tsfreq > freq: + if "Y" in str(tsfreq) or "M" in str(tsfreq) or tsfreq.nanos > freq: ts = ts.resample(fmins).ffiio_managerll() else: ts = ts.resample(fmins).mean() @@ -268,10 +268,10 @@ def transform(ts, name, how, siminfo): elif "Y" in str(tsfreq): ratio = 1.0 / (8766.0 * mult) else: - ratio = freq / tsfreq + ratio = freq / tsfreq.nanos ts = (ratio * ts).resample(fmins).ffill() # HSP2 how = div else: - ts = (ts * (freq / tsfreq)).resample(fmins).ffill() + ts = (ts * (freq / tsfreq.nanos)).resample(fmins).ffill() elif how == "ZEROFILL": ts = ts.resample(fmins).fillna(0.0) elif how == "INTERPOLATE": @@ -289,7 +289,7 @@ def hoursval(siminfo, hours24, dofirst=False, lapselike=False): start = siminfo["start"] stop = siminfo["stop"] fmins = Minute(siminfo["delt"]) - freq = Timedelta(fmins).to_timedelta64() + freq = fmins.nanos dr = date_range( start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq=Minute(60) @@ -299,16 +299,16 @@ def hoursval(siminfo, hours24, dofirst=False, lapselike=False): hours[0] = 1 ts = Series(hours[0 : len(dr)], dr) - tsfreq = ts.index.freq.delta.to_timedelta64() + tsfreq = ts.index.freq if lapselike: - if tsfreq > freq: # upsample + if tsfreq.nanos > freq: # upsample ts = ts.resample(fmins).asfreq().ffill() - elif tsfreq < freq: # downsample + elif tsfreq.nanos < freq: # downsample ts = ts.resample(fmins).mean() else: - if tsfreq > freq: # upsample + if tsfreq.nanos > freq: # upsample ts = ts.resample(fmins).asfreq().fillna(0.0) - elif tsfreq < freq: # downsample + elif tsfreq.nanos < freq: # downsample ts = ts.resample(fmins).max() return ts.truncate(start, stop).to_numpy() @@ -325,16 +325,16 @@ def monthval(siminfo, monthly): start = siminfo["start"] stop = siminfo["stop"] fmins = Minute(siminfo["delt"]) - freq = Timedelta(fmins).to_timedelta64() + freq = fmins.nanos months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").ffill() - tsfreq = ts.index.freq.delta.to_timedelta64() + tsfreq = ts.index.freq - if tsfreq > freq: # upsample + if tsfreq.nanos > freq: # upsample ts = ts.resample(fmins).asfreq().ffill() - elif tsfreq < freq: # downsample + elif tsfreq.nanos < freq: # downsample ts = ts.resample(fmins).mean() return ts.truncate(start, stop).to_numpy() @@ -345,17 +345,17 @@ def dayval(siminfo, monthly): start = siminfo["start"] stop = siminfo["stop"] fmins = Minute(siminfo["delt"]) - freq = Timedelta(fmins).to_timedelta64() + freq = fmins.nanos months = tile(monthly, stop.year - start.year + 1).astype(float) dr = date_range(start=f"{start.year}-01-01", end=f"{stop.year}-12-31", freq="MS") ts = Series(months, index=dr).resample("D").interpolate("time") - tsfreq = ts.index.freq.delta.to_timedelta64() + tsfreq = ts.index.freq - if tsfreq > freq: # upsample + if tsfreq.nanos > freq: # upsample ts = ts.resample(fmins).ffill() - elif tsfreq < freq: # downsample + elif tsfreq.nanos < freq: # downsample ts = ts.resample(fmins).mean() return ts.truncate(start, stop).to_numpy()