Closed rburghol closed 9 months ago
Notes 6/21/23:
These notes have been incorporated into the body of this issue, and in a separate issue #67
This allows you to test manually at the command line. More illuminating is the code in the body of the issue.
[rivername].h5
file and [rivername].py
filepython3
dynamic_module_import()
from https://github.com/HARPgroup/HSPsquared/blob/state/HSP2/state.py
from numba.typed import Dict
from numba import types
import numpy as np
os.chdir("/opt/model/HSPsquared")
from HSP2.utilities_specl import *
from HSP2.SPECL import specl, _specl_
from HSP2.om_model_object import *
from HSP2.om_equation import *
from HSP2.om_data_matrix import *
from HSP2.om_sim_timer import *
from HSP2.om_model_linkage import ModelLinkage, step_model_link
from HSP2.om_model_broadcast import *
hydr_ix = Dict.empty(key_type=types.unicode_type, value_type=types.int64)
op_tokens = Dict.empty(key_type=types.int64, value_type=types.i8[:])
state_paths = Dict.empty(key_type=types.unicode_type, value_type=types.int64)
state_ix = Dict.empty(key_type=types.int64, value_type=types.float64)
dict_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:,:])
ts_ix = Dict.empty(key_type=types.int64, value_type=types.float64[:])
local_path = os.getcwd()
fbase="PL3_5250_0001"
numdict = numdict=np.asarray([],dtype="float32")
io_manager, siminfo, op_tokens, state_paths, state_ix, dict_ix, ts_ix, model_object_cache = numdict,numdict,numdict,numdict,numdict,numdict,numdict,numdict
hsp2_local_py = dynamic_module_import(fbase, local_path + "/" + fbase + ".py", "hsp2_local_py")
# just set some test values
hydr_ix['O1'] = 1
from hsp2_local_py import state_step_hydr
state_step_hydr(numdict, op_tokens, state_ix, dict_ix, ts_ix, hydr_ix, 1)
# now show the values
state_ix[hydr_ix['O1']]
Sample code to put into a model [riverseg].py
file.
import sys
print("Loaded a dynamic HSP2 code file!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
def om_init_model(io_manager, siminfo, op_tokens, state_paths, state_ix, dict_ix, ts_ix, model_object_cache):
print("Initialize om_init_model from code")
@njit
def state_step_hydr(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, hydr_ix, step):
print("Do something")
print("Loaded state_step_hydr()")
@rburghol Couple notes when running the test above:
os
before the line os.chdir("/opt/model/HSPsquared")
i.e. just needs a import os
NameError: name 'dynamic_module_import' is not defined
, where does the function dynamic_module_import
get loaded from? Hey @jdkleiner -- sorry, the test code does suffer from the lack you describe :) -- dynamic_module_import()
is in the HSP2/STATE.py
file. However, you may find the actual embedded code in hsp2
more interesting. That is the code that is in the body of this issue at the top. Also, in the state
branch now there is a sample file in tests/test10/test10.py
that will function fully, and should run out of the box in that branch on your install, provided of course that there is no incompatibility that I did not foresee in a windows versus linux install?
Tested on:
Goal: have a set of functions defined by local code that are executable in
@njit
. see https://github.com/respec/HSPsquared/issues/113state
on deq1PL3_5250_0001
'/home/rob/working/modeling/hsp2/river_wd/PL3_5250_0001.py'
PL3_5250_0001.py
file in that directory, it'll load the file and the functioned defined withinPL3_5250_0001.py
is the functionom_test_fn()
fixjup
(develop with install fix for bad jupyter line) takes 7 seconds (:15 on first compile)spects
loads 20-30 OM components and takes 12 seconds (:22 on 1st compile)state
loads 0 OM, and takes 17 seconds each time (no diff w/1st compile), even if there is no dynamic code loaded, or empty dynamic code function.statex
used to disable, then sequentially enable things (run from 1984-2001):hydr()
, and does settingstate_ix[o1_ix' ...
each timestep, but no computationsmain
, and all state loading stuff in HYDR, but no njoi module loading, nor any code in hydr executed.state_info
to_hydr_()
state_paths
_hydr_()
_hydr_
main.py
load_dynamics()
(need to move this from main.py since the dynamic code must be loaded in the same module that it is called in, however, maybe we can also pass it in as part of a standard python dictionary, but then split it out as an individual function when passing thsp2_local_py = dynamic_module_import(fbase, local_path + "/" + fbase + ".py", "hsp2_local_py")
hsp2_local_py
modulehsp2_local_py.state_step_hydr(model_exec_list, op_tokens, state_ix, dict_ix, ts_ix, hydr_ix, step)
Loading and Executing
@njit
code,Since all functions called by njit code must be njit also, the dynamic functions must be defined before the first call of the larger routine, such as
_hydr_()
.Example Withdrawal
PL3_5250_0001.h5
PL3_5250_0001.py
:@njit def state_step_hydr(state_ix, dict_ix, ts_ix, hydr_ix, step): fn_defined = False state_ix[hydr_ix['O1']] = 0.0 1.547 if (step <= 1): print("Custom state_step_hydr() called") print("state at start", state_ix) if (step > 2440*364): print("state at end", state_ix) return
hsp2 hsp2 run PL3_5250_0001.h5 Rscript /opt/model/meta_model/scripts/h5/export_hsp_h5.R PL3_5250_0001.h5 hydr_10mgd.csv "//RESULTS/RCHRES_R001/HYDR/table"
hsp2 hsp2 run PL3_5250_0001.h5 Rscript /opt/model/meta_model/scripts/h5/export_hsp_h5.R PL3_5250_0001.h5 hydr.csv "//RESULTS/RCHRES_R001/HYDR/table"