Index: wflow-py/UnitTests/TestBMI.py =================================================================== diff -u -rc3eed6a0f362cbe559022b2d24a46abf43e91dc9 -rde426ba5d34987feb480e55b83f47a5e1b6bb325 --- wflow-py/UnitTests/TestBMI.py (.../TestBMI.py) (revision c3eed6a0f362cbe559022b2d24a46abf43e91dc9) +++ wflow-py/UnitTests/TestBMI.py (.../TestBMI.py) (revision de426ba5d34987feb480e55b83f47a5e1b6bb325) @@ -74,9 +74,6 @@ self.assertAlmostEquals(a,b) - - #print(time.localtime(bmiobj.get_current_time())) - print("-------------- update: ") bmiobj.update() @@ -95,7 +92,6 @@ print("-------------- Grid shape: ") print(bmiobj.get_grid_shape('Altitude')) - print("-------------- Grid spacing: ") print(bmiobj.get_grid_spacing('Altitude')) @@ -105,8 +101,6 @@ print("-------------- Var type: ") print(bmiobj.get_var_type('Altitude')) - - print("-------------- Var rank: ") print(bmiobj.get_var_rank('Altitude')) @@ -119,6 +113,25 @@ print("-------------- Getvalue: ") print(bmiobj.get_value('Altitude')) + print("-------------- get_attribute_names: ") + names = bmiobj.get_attribute_names() + print names + + print("-------------- get_attribute_value: ") + print names[0] + print(bmiobj.get_attribute_value(names[0])) + + print("-------------- set_attribute_value: ") + print names[0] + bmiobj.set_attribute_value(names[0],"SET By TEST") + print(bmiobj.get_attribute_value(names[0])) + + print("-------------- set_start_time: ") + bmiobj.set_start_time(0) + print(bmiobj.get_attribute_value("run:starttime")) + + + bmiobj.finalize() #update #update_until Index: wflow-py/UnitTests/wflow_sceleton/outstate/TSoil.map =================================================================== diff -u -r41e03295c879be25c7ce831817dbf69a2018e5ba -rde426ba5d34987feb480e55b83f47a5e1b6bb325 Binary files differ Index: wflow-py/wflow/wf_DynamicFramework.py =================================================================== diff -u -r666a418a8a7170634fc9c9b10a47340ca926f889 -rde426ba5d34987feb480e55b83f47a5e1b6bb325 --- wflow-py/wflow/wf_DynamicFramework.py (.../wf_DynamicFramework.py) (revision 666a418a8a7170634fc9c9b10a47340ca926f889) +++ wflow-py/wflow/wf_DynamicFramework.py (.../wf_DynamicFramework.py) (revision de426ba5d34987feb480e55b83f47a5e1b6bb325) @@ -881,8 +881,7 @@ self._traceOut("resume") self._decrementIndentLevel() - - + def wf_QuickSuspend(self): """ Save the state variable of the current timestep in memory Index: wflow-py/wflow/wflow_bmi.py =================================================================== diff -u -r0be5ce3b9499d97a057835ff286d803f674a3928 -rde426ba5d34987feb480e55b83f47a5e1b6bb325 --- wflow-py/wflow/wflow_bmi.py (.../wflow_bmi.py) (revision 0be5ce3b9499d97a057835ff286d803f674a3928) +++ wflow-py/wflow/wflow_bmi.py (.../wflow_bmi.py) (revision de426ba5d34987feb480e55b83f47a5e1b6bb325) @@ -2,6 +2,7 @@ import os import logging +import datetime import wflow.bmi as bmi import numpy as np @@ -233,9 +234,10 @@ self.myModel = None self.dynModel = None - def initialize_config(self, filename, loglevel=logging.DEBUG): """ + *Extended functionality*, see https://github.com/eWaterCycle/bmi/blob/master/src/main/python/bmi.py + see initialize :param filename: @@ -245,7 +247,7 @@ self.currenttimestep = 1 wflow_cloneMap = 'wflow_subcatch.map' - datadir = os.path.dirname(filename) + self.datadir = os.path.dirname(filename) inifile = os.path.basename(filename) runid = "run_default" # The current pcraster framework needs a max number of timesteps :-( @@ -268,23 +270,97 @@ exec "import wflow." + modname + " as wf" self.name = modname - self.myModel = wf.WflowModel(wflow_cloneMap, datadir, runid, inifile) + self.myModel = wf.WflowModel(wflow_cloneMap, self.datadir, runid, inifile) self.dynModel = wf.wf_DynamicFramework(self.myModel, maxNrSteps, firstTimestep = 1) self.dynModel.createRunId(NoOverWrite=0,level=loglevel,model=os.path.basename(filename)) - - def initialize_state(self): + def initialize_state(self, source_directory): """ + *Extended functionality*, see https://github.com/eWaterCycle/bmi/blob/master/src/main/python/bmi.py + see initialize :param self: + :param source directory: path to dir with state files :return: nothing """ self.dynModel._runInitial() self.dynModel._runResume() + # second step to read from specific directory + if os.path.isabs(source_directory): + self.dynModel.wf_resume(source_directory) + else: + self.dynModel.wf_resume(os.path.join(self.datadir,source_directory)) + def set_start_time(self, start_time): + """ + :param start_time: time in units (seconds) since the epoch + :return: + """ + + dateobj = datetime.datetime.utcfromtimestamp(start_time) + datestrimestr = dateobj.strftime("%Y:%m:%d %H:%M:%S") + + self.dynModel._userModel().config.set("run",'starttime',datestrimestr) + + def set_end_time(self, end_time): + """ + :param end_time: time in units (seconds) since the epoch + :return: + """ + dateobj = datetime.datetime.utcfromtimestamp(end_time) + datestrimestr = dateobj.strftime("%Y:%m:%d %H:%M:%S") + + self.dynModel._userModel().config.set("run",'endtime',datestrimestr) + + def get_attribute_names(self): + """ + Get the attributes of the model return in the form of section_name:attribute_name + + :return: list of attributes + """ + attr = [] + for sect in self.dynModel._userModel().config.sections(): + for opt in self.dynModel._userModel().config.options(sect): + attr.append(sect + ":" + opt) + return attr + + def get_attribute_value(self, attribute_name): + """ + :param attribute_name: + :return: attribute value + """ + attrpath = attribute_name.split(":") + + if len(attrpath) == 2: + return self.dynModel._userModel().config.get(attrpath[0],attrpath[1]) + else: + raise Warning("attributes should follow the name:option convention") + + def set_attribute_value(self, attribute_name, attribute_value): + """ + :param attribute_name: name using the section:option notation + :param attribute_value: string value of the option + :return: + """ + + attrpath = attribute_name.split(":") + if len(attrpath) == 2: + self.dynModel._userModel().config.set(attrpath[0],attrpath[1],attribute_value) + else: + raise Warning("attributes should follow the name:option convention") + + def save_state(self, destination_directory): + """ + Ask the model to write its complete internal current state to one or more state files in the given directory. + Afterwards the given directory should only contain the state files and nothing else. + Input parameters: + File destination_directory: the directory in which the state files should be written. + """ + raise NotImplementedError + def initialize(self, filename,loglevel=logging.DEBUG): """ Initialise the model. Should be call before any other method. @@ -300,19 +376,15 @@ .. todo:: Get name of module from ini file name - """ self.initialize_config(filename,loglevel=loglevel) - self.initialize_state() + self.initialize_state('instate') - - def update(self): """ Propagate the model to the next model timestep """ - self.dynModel._runDynamic(self.currenttimestep, self.currenttimestep) self.currenttimestep = self.currenttimestep + 1 @@ -322,7 +394,6 @@ :var double time: time in the units and epoch returned by the function get_time_units. """ - curtime = self.get_current_time() if curtime > time: