# coding: utf-8
#
Basic test of the wflow BMI interface + reservoir
# In[10]:
import os
import os.path
import getopt
import sys
import getopt
from wflow.wf_DynamicFramework import *
import pcraster as pcr
import wflow.wflow_bmi as bmi
import logging
import wflow.wflow_adapt as adapter
import calendar
import os
import numpy as np
import configparser
# reload(bmi)
""" Todo: include error handling:
- When WFlow_ids in the mapping section of config are not in the map
- When RTC doesn't have data on the WFlow simulation period
- When a RTC id in the id mapping section is not part of the model
- ...
Todo: add logging
"""
def ConfigSectionMap(section):
dict1 = {}
options = Config.options(section)
for option in options:
try:
dict1[option] = Config.get(section, option)
if dict1[option] == -1:
DebugPrint("skip: %s" % option)
except:
print(("exception on %s!" % option))
dict1[option] = None
return dict1
def gettimestepfname(name, path, timestep):
"""
Get the pcraster filename fro this step
:param name:
:param path:
:param timestep:
:return:
"""
below_thousand = timestep % 1000
above_thousand = timestep / 1000
fname = str(name + "%0" + str(8 - len(name)) + ".f.%03.f") % (
above_thousand,
below_thousand,
)
fname = os.path.join(path, fname)
return fname
########################################################################
## Process command-line options #
########################################################################
argv = sys.argv
try:
opts, args = getopt.getopt(argv[1:], "c:w:I:")
print(opts)
except getopt.error as msg:
print("cannot parse commandline")
sys.exit(2)
if not opts:
print("cannot parse commandline")
sys.exit(2)
for o, a in opts:
if o == "-c":
configfile = a
if o == "-w":
cur_dir = os.path.abspath(a)
if o == "-I":
IniFile = a
Config = configparser.ConfigParser()
# inifile = Config.read('c:\FEWS\SI-WAMI\SI-WAMI\Modules\RTC\wflow_rtctools.ini')
inifile = Config.read(configfile)
########################################################################
## Parse ini-file #
########################################################################
# cur_dir = os.getcwd()
Config.sections()
os.chdir(cur_dir)
dir_rtc = os.path.join(cur_dir, (ConfigSectionMap("model")["dir_rtc_model"]))
dir_wflow = os.path.join(cur_dir, (ConfigSectionMap("model")["dir_wflow_model"]))
Bin_RTC = os.path.join(cur_dir, (ConfigSectionMap("RTC wrapper engine")["bin_rtc"]))
inflow_map = os.path.join(dir_wflow, (ConfigSectionMap("id_maps")["samplemap_in"]))
outflow_map = os.path.join(dir_wflow, (ConfigSectionMap("id_maps")["samplemap_out"]))
ldd_map = os.path.join(dir_wflow, (ConfigSectionMap("ldd")["ldd_res"]))
# id's wflow and RTC reservoir inflow points
id_in_rtc = []
id_in_wflow = list(ConfigSectionMap("id_mapping_inflow"))
for index in range(len(id_in_wflow)):
id_in_rtc.append(ConfigSectionMap("id_mapping_inflow")[id_in_wflow[index]])
# id's wflow and RTC reservoir outflow points
id_out_rtc = []
id_out_wflow = list(ConfigSectionMap("id_mapping_outflow"))
for index in range(len(id_out_wflow)):
id_out_rtc.append(ConfigSectionMap("id_mapping_outflow")[id_out_wflow[index]])
########################################################################
## Initialize models #
########################################################################
# In[]: Initialize the RTC-Tools model
os.chdir(Bin_RTC)
from wflow.wrappers.rtc.wrapperExtended import BMIWrapperExtended
# RTC_model = BMIWrapperExtended(engine=os.path.join(Bin_RTC,"RTCTools_BMI"))
RTC_model = BMIWrapperExtended(engine=os.path.join(Bin_RTC, "RTCTools_BMI"))
print("RTCmodel", Bin_RTC, RTC_model)
RTC_model.initialize("..")
# In[]: Initialize the WFlow model
os.chdir(dir_wflow)
LA_model = bmi.wflowbmi_csdms()
LA_model.initialize((IniFile), loglevel=logging.DEBUG)
# now get the forcings that wflow expects
# The bmi is such that you can get the input variables and the output variables. However, the
# input variable list also contains the in/out variables. So to
# get the input only we subtract the two lists.
invars = LA_model.get_input_var_names()
outvars = LA_model.get_output_var_names()
inputmstacks = list(set(invars) - set(outvars))
# In[]: Investigate start time, end time and time step of both models
print("WFlow:")
LA_dt = LA_model.get_time_step()
# LA_start = LA_model.get_start_time()
timeutc = adapter.getStartTimefromRuninfo("inmaps/runinfo.xml")
print(timeutc)
LA_start = calendar.timegm(timeutc.timetuple())
timeutc = adapter.getEndTimefromRuninfo("inmaps/runinfo.xml")
LA_end = calendar.timegm(timeutc.timetuple())
# LA_end = LA_model.get_end_time()
print(LA_dt)
print(timeutc)
print(LA_start)
print(LA_end)
print("RTC-Tools")
RTC_dt = RTC_model.get_time_step()
RTC_start = RTC_model.get_start_time()
RTC_end = RTC_model.get_end_time()
print(RTC_dt)
print(RTC_start)
print(RTC_end)
if LA_start != RTC_start:
print("Error: start time of both models is not identical !!!")
if LA_dt != RTC_dt:
print("Error: time step of both models is not identical !!!")
# In[]: Read and map reservoir inflow and outflow locations
Reservoir_inflow = pcr.pcr2numpy(
pcr.scalar(pcr.readmap(os.path.abspath(inflow_map))), np.NaN
)
Reservoir_outflow = pcr.pcr2numpy(
pcr.scalar(pcr.readmap(os.path.abspath(outflow_map))), np.NaN
)
inflow_list = list(np.unique(Reservoir_inflow[~np.isnan(Reservoir_inflow)]))
outflow_list = list(np.unique(Reservoir_outflow[~np.isnan(Reservoir_outflow)]))
# In[]: Overwrite TopoLdd with modified version
ldd = pcr.pcr2numpy(
pcr.readmap(os.path.join(dir_wflow, ldd_map)), np.NaN
).astype(np.float32)
LA_model.set_value("TopoLdd", np.flipud(ldd).copy())
########################################################################
## Run models #
########################################################################
t = LA_start
timecounter = 0
inmstackbuf = {} # Keep track of input mapatsatck by name
while t < min(LA_end, RTC_end):
# first read forcing mapstacks (set in API section) and give to the model
for thisstack in inputmstacks:
toread = gettimestepfname(
thisstack, os.path.join(dir_wflow, "inmaps"), timecounter + 1
)
inmstackbuf[thisstack] = np.flipud(
pcr.pcr2numpy(pcr.scalar(pcr.readmap(os.path.abspath(toread))), -999.0)
).copy()
LA_model.set_value(thisstack, inmstackbuf[thisstack])
print("calculation timestep = " + str(timecounter))
# Get the inflow from the wflow model runoff map and map
inflowQ = np.flipud(LA_model.get_value("SurfaceRunoff")).copy()
# Map the sum of WFlow Inflow to RTC
for idx, wflow_id in enumerate(id_in_wflow):
value = np.ndarray(shape=(1, 1), dtype=float, order="F")
value[0][0] = np.sum(inflowQ[np.where(Reservoir_inflow == int(wflow_id))])
rtc_id = id_in_rtc[id_in_wflow.index(str(wflow_id))]
print(rtc_id + " = " + str(value[0][0]))
RTC_model.set_value(rtc_id, value)
# run the RTC-Tools model
RTC_model.update(-1.0)
# Extract RTC outflow and add to on WFlow 'IF' (abstractions)
inflowfield = inmstackbuf["IF"]
for idx, wflow_id in enumerate(id_out_wflow):
rtc_id = id_out_rtc[id_out_wflow.index(str(wflow_id))]
Qout = RTC_model.get_var(rtc_id)
Qout = 300.0
if np.isfinite(Qout): # no nan's into wflow
inflowfield[Reservoir_outflow == int(wflow_id)] += Qout
LA_model.set_value("IF", np.flipud(inflowfield).copy())
# This not not bmi but needed to update the kinematic wave reservoir
LA_model.update()
t += LA_dt
timecounter += 1
LA_model.finalize()
RTC_model.finalize()