From 2afc900ea9a03a7e9f4bf288dd657d6671b01539 Mon Sep 17 00:00:00 2001 From: Dong Kim Date: Thu, 8 Dec 2022 10:41:49 -0700 Subject: [PATCH 1/4] BMI prototype for Hyfeature network --- run-troute-with-bmi.py | 31 + src/bmi_troute.py | 631 ++++++++++++++++++ .../troute/hyfeature_preprocess.py | 4 +- .../unittest_hyfeature.yaml | 4 +- 4 files changed, 666 insertions(+), 4 deletions(-) create mode 100644 run-troute-with-bmi.py create mode 100644 src/bmi_troute.py diff --git a/run-troute-with-bmi.py b/run-troute-with-bmi.py new file mode 100644 index 000000000..ab8cd73a6 --- /dev/null +++ b/run-troute-with-bmi.py @@ -0,0 +1,31 @@ +import sys +sys.path.append("src/") +import bmi_troute # This is the BMI t-route that we will be running from the file: bmi_troute.py +import troute.main_utilities as mu # This is used to read q_lateral data from files, won't be needed when t-route bmi is run with model engine +import troute.nhd_preprocess as nhd_prep # This is used to read q_lateral data from files, won't be needed when t-route bmi is run with model engine +model = bmi_troute.bmi_troute() +import pdb; pdb.set_trace() +#model.initialize(bmi_cfg_file='test/BMI/test_AnA_bmi.yaml') +model.initialize(bmi_cfg_file='test/unit_test_hyfeature/unittest_hyfeature.yaml') +import pdb; pdb.set_trace() +(run_sets, da_sets, parity_sets) = mu.build_run_sets(model._network, + model._forcing_parameters, + model._compute_parameters, + model._data_assimilation_parameters, + model._output_parameters, + model._parity_parameters) + + +q_lateral, coastal_boundary_depth_df = nhd_prep.nhd_forcing(run_sets[0], + model._forcing_parameters, + model._hybrid_parameters, + model._network.segment_index, + model._compute_parameters.get('cpu_pool', None), + model._network._t0, + model._network._coastal_boundary_depth_df, + ) +import pdb; pdb.set_trace() + +model.set_value('land_surface_water_source__volume_flow_rate', q_lateral.to_numpy()) + + diff --git a/src/bmi_troute.py b/src/bmi_troute.py new file mode 100644 index 000000000..fe6a43a27 --- /dev/null +++ b/src/bmi_troute.py @@ -0,0 +1,631 @@ +"""Basic Model Interface implementation for t-route.""" + +import numpy as np +import pandas as pd +from bmipy import Bmi +from pathlib import Path +import yaml +from datetime import datetime, timedelta + +import troute.main_utilities as tr +import troute.nhd_network_utilities_v02 as nnu + + + +class bmi_troute(Bmi): + + def __init__(self): + """Create a Bmi troute model that is ready for initialization.""" + super(bmi_troute, self).__init__() + #self._model = None + self._values = {} + #self._var_units = {} + self._var_loc = "node" + self._var_grid_id = 0 + #self._grids = {} + #self._grid_type = {} + + self._start_time = 0.0 + self._end_time = np.finfo("d").max + self._time_units = "s" + + #---------------------------------------------- + # Required, static attributes of the model + #---------------------------------------------- + _att_map = { + 'model_name': 'T-Route for Next Generation NWM', + 'version': '', + 'author_name': '', + 'grid_type': 'scalar', + 'time_step_size': 1, + #'time_step_type': 'donno', #unused + #'step_method': 'none', #unused + #'time_units': '1 hour' #NJF Have to drop the 1 for NGEN to recognize the unit + 'time_units': 'seconds' } + + #--------------------------------------------- + # Input variable names (CSDMS standard names) + #--------------------------------------------- + _input_var_names = ['land_surface_water_source__volume_flow_rate', + 'coastal_boundary__depth', #FIXME: this variable isn't a standard CSDMS name...couldn't find one more appropriate + 'usgs_gage_observation__volume_flow_rate', #FIXME: this variable isn't a standard CSDMS name...couldn't find one more appropriate + 'usace_gage_observation__volume_flow_rate', #FIXME: this variable isn't a standard CSDMS name...couldn't find one more appropriate + 'rfc_gage_observation__volume_flow_rate' #FIXME: this variable isn't a standard CSDMS name...couldn't find one more appropriate + ] + + #--------------------------------------------- + # Output variable names (CSDMS standard names) + #--------------------------------------------- + _output_var_names = ['channel_exit_water_x-section__volume_flow_rate', + 'channel_water_flow__speed', + 'channel_water__mean_depth', + 'lake_water~incoming__volume_flow_rate', + 'lake_water~outgoing__volume_flow_rate', + 'lake_surface__elevation' #FIXME: this variable isn't a standard CSDMS name...couldn't find one more appropriate + ] + + #------------------------------------------------------ + # Create a Python dictionary that maps CSDMS Standard + # Names to the model's internal variable names. + #------------------------------------------------------ + _var_name_units_map = { + 'channel_exit_water_x-section__volume_flow_rate':['streamflow_cms','m3 s-1'], + 'channel_water_flow__speed':['streamflow_ms','m s-1'], + 'channel_water__mean_depth':['streamflow_m','m'], + 'lake_water~incoming__volume_flow_rate':['waterbody_cms','m3 s-1'], + 'lake_water~outgoing__volume_flow_rate':['waterbody_cms','m3 s-1'], + 'lake_surface__elevation':['waterbody_m','m'], + #-------------- Dynamic inputs -------------------------------- + 'land_surface_water_source__volume_flow_rate':['streamflow_cms','m3 s-1'], + 'coastal_boundary__depth':['depth_m', 'm'], + 'usgs_gage_observation__volume_flow_rate':['streamflow_cms','m3 s-1'], + 'usace_gage_observation__volume_flow_rate':['streamflow_cms','m3 s-1'], + 'rfc_gage_observation__volume_flow_rate':['streamflow_cms','m3 s-1'] + } + + #------------------------------------------------------ + # A list of static attributes. Not all these need to be used. + #------------------------------------------------------ + _static_attributes_list = [] + + + #------------------------------------------------------------ + #------------------------------------------------------------ + # BMI: Model Control Functions + #------------------------------------------------------------ + #------------------------------------------------------------ + + #------------------------------------------------------------------- + def initialize(self, bmi_cfg_file=None): + + args = tr._handle_args_v03(['-f', bmi_cfg_file]) + + # -------------- Read in the BMI configuration -------------------------# + bmi_cfg_file = Path(bmi_cfg_file) + # ----- Create some lookup tabels from the long variable names --------# + self._var_name_map_long_first = {long_name:self._var_name_units_map[long_name][0] for \ + long_name in self._var_name_units_map.keys()} + self._var_name_map_short_first = {self._var_name_units_map[long_name][0]:long_name for \ + long_name in self._var_name_units_map.keys()} + self._var_units_map = {long_name:self._var_name_units_map[long_name][1] for \ + long_name in self._var_name_units_map.keys()} + + # This will direct all the next moves. + if bmi_cfg_file is not None: + + with bmi_cfg_file.open('r') as fp: + cfg = yaml.safe_load(fp) + self._cfg_bmi = self._parse_config(cfg) + else: + print("Error: No configuration provided, nothing to do...") + + # ------------- Initialize t-route model ------------------------------# + (self._network, + self._log_parameters, + self._preprocessing_parameters, + self._supernetwork_parameters, + self._waterbody_parameters, + self._compute_parameters, + self._forcing_parameters, + self._restart_parameters, + self._hybrid_parameters, + self._output_parameters, + self._parity_parameters, + self._data_assimilation_parameters, + self._run_parameters, + ) = tr.initialize_network(args) + + # Set number of time steps (1 hour) + self._nts = 12 + + # -------------- Initalize all the variables --------------------------# + # -------------- so that they'll be picked up with the get functions --# + for var_name in list(self._var_name_units_map.keys()): + # ---------- All the variables are single values ------------------# + # ---------- so just set to zero for now. ------------------# + self._values[var_name] = np.zeros(self._network.dataframe.shape[0]) + setattr( self, var_name, 0 ) + + ''' + # -------------- Update dimensions of DA variables --------------------# + #################################### + # Maximum lookback hours from reservoir configurations + usgs_shape = self._network._waterbody_types_df[self._network._waterbody_types_df['reservoir_type']==2].shape[0] + usace_shape = self._network._waterbody_types_df[self._network._waterbody_types_df['reservoir_type']==3].shape[0] + rfc_shape = self._network._waterbody_types_df[self._network._waterbody_types_df['reservoir_type']==4].shape[0] + + max_lookback_hrs = max(self._data_assimilation_parameters.get('timeslice_lookback_hours'), + self._waterbody_parameters.get('rfc').get('reservoir_rfc_forecasts_lookback_hours')) + + self._values['usgs_gage_observation__volume_flow_rate'] = np.zeros((usgs_shape,max_lookback_hrs*4)) + setattr( self, 'usgs_gage_observation__volume_flow_rate', 0 ) + self._values['usace_gage_observation__volume_flow_rate'] = np.zeros((usace_shape,max_lookback_hrs*4)) + setattr( self, 'usace_gage_observation__volume_flow_rate', 0 ) + self._values['rfc_gage_observation__volume_flow_rate'] = np.zeros((rfc_shape,max_lookback_hrs*4)) + setattr( self, 'rfc_gage_observation__volume_flow_rate', 0 ) + ''' + + self._start_time = 0.0 + self._end_time = self._forcing_parameters.get('dt') * self._forcing_parameters.get('nts') + self._time = 0.0 + self._time_step = self._forcing_parameters.get('dt') + self._time_units = 's' + + def update(self): + """Advance model by one time step.""" + + + # Set input data into t-route objects + self._network._qlateral = pd.DataFrame(self._values['land_surface_water_source__volume_flow_rate'], + index=self._network.dataframe.index.to_numpy()) + self._network._coastal_boundary_depth_df = pd.DataFrame(self._values['coastal_boundary__depth']) + + ''' + ( + self._run_sets, + self._da_sets, + self._parity_sets + ) = tr.build_run_sets(self._network, + self._forcing_parameters, + self._compute_parameters, + self._data_assimilation_parameters, + self._output_parameters, + self._parity_parameters) + + # Create forcing data within network object for first loop iteration + self._network.assemble_forcings( + self._run_sets[0], + self._forcing_parameters, + self._hybrid_parameters, + self._compute_parameters.get('cpu_pool', None)) + ''' + # Create data assimilation object from da_sets for first loop iteration + ###NOTE: this is just a place holder, setting DA variables will be done with set_values... + self._data_assimilation = tr.build_data_assimilation( + self._network, + self._data_assimilation_parameters, + self._waterbody_parameters, + [], #self._da_sets[0], + self._forcing_parameters, + self._compute_parameters) + + ''' + self._run_sets[0]['t0'] = self._network.t0 + self._run_sets[0]['dt'] = self._forcing_parameters.get('dt') + ''' + + # Run routing + ''' + self._run_results = tr.run_routing( + self._network, + self._data_assimilation, + [self._run_sets[0]], + self._da_sets, + self._compute_parameters, + self._forcing_parameters, + self._waterbody_parameters, + self._output_parameters, + self._hybrid_parameters, + self._data_assimilation_parameters, + self._run_parameters, + self._parity_sets) + ''' + + ( + self._run_results, + self._subnetwork_list + ) = tr.nwm_route(self._network.connections, + self._network.reverse_network, + self._network.waterbody_connections, + self._network._reaches_by_tw, + self._compute_parameters.get('parallel_compute_method','serial'), + self._compute_parameters.get('compute_kernel'), + self._compute_parameters.get('subnetwork_target_size'), + self._compute_parameters.get('cpu_pool'), + self._network.t0, + self._time_step, + self._nts, + self._forcing_parameters.get('qts_subdivisions', 12), + self._network.independent_networks, + self._network.dataframe, + self._network.q0, + self._network._qlateral, + self._data_assimilation.usgs_df, + self._data_assimilation.lastobs_df, + self._data_assimilation.reservoir_usgs_df, + self._data_assimilation.reservoir_usgs_param_df, + self._data_assimilation.reservoir_usace_df, + self._data_assimilation.reservoir_usace_param_df, + self._data_assimilation.assimilation_parameters, + self._compute_parameters.get('assume_short_ts', False), + self._compute_parameters.get('return_courant', False), + self._network._waterbody_df, + self._waterbody_parameters, + self._network._waterbody_types_df, + self._network.waterbody_type_specified, + self._network.diffusive_network_data, + self._network.topobathy_df, + self._network.refactored_diffusive_domain, + self._network.refactored_reaches, + [], #subnetwork_list, + self._network.coastal_boundary_depth_df, + self._network.unrefactored_topobathy_df,) + + # update initial conditions with results output + self._network.new_nhd_q0(self._run_results) + self._network.update_waterbody_water_elevation() + + # update t0 + self._network.new_t0(self._time_step,self._nts) + + # get reservoir DA initial parameters for next loop iteration + self._data_assimilation.update(self._run_results, + self._data_assimilation_parameters, + self._run_parameters, + self._network, + [], #self._da_sets[run_set_iterator + 1] + ) + + (self._values['channel_exit_water_x-section__volume_flow_rate'], + self._values['channel_water_flow__speed'], + self._values['channel_water__mean_depth'], + self._values['lake_water~incoming__volume_flow_rate'], + self._values['lake_water~outgoing__volume_flow_rate'], + self._values['lake_surface__elevation'], + ) = tr.create_output_dataframes( + self._run_results, + self._nts, + self._network._waterbody_df, + self._network.link_lake_crosswalk) + + self._time += self._time_step * self._nts + + def update_frac(self, time_frac): + """Update model by a fraction of a time step. + Parameters + ---------- + time_frac : float + Fraction fo a time step. + """ + time_step = self.get_time_step() + self._model.time_step = time_frac * time_step + self.update() + self._model.time_step = time_step + + def update_until(self, then): + """Update model until a particular time. + Parameters + ---------- + then : float + Time to run model until in seconds. + """ + n_steps = (then - self.get_current_time()) / self.get_time_step() + + full_nts = self._nts + self._nts = n_steps + + self.update() + + self._nts = full_nts - n_steps + + ''' + for _ in range(int(n_steps)): + self.update() + self.update_frac(n_steps - int(n_steps)) + ''' + + def finalize(self): + """Finalize model.""" + + self._values = None + self._var_loc = None + self._var_grid_id = None + self._var_name_map_long_first = None + self._var_name_map_short_first = None + self._var_units_map = None + self._cfg_bmi = None + self._network = None + self._log_parameters = None + self._preprocessing_parameters = None + self._supernetwork_parameters = None + self._waterbody_parameters = None + self._compute_parameters = None + self._forcing_parameters = None + self._restart_parameters = None + self._hybrid_parameters = None + self._output_parameters = None + self._parity_parameters = None + self._data_assimilation_parameters = None + self._run_parameters = None + self._nts = None + self._values = None + self._start_time = None + self._end_time = None + self._time = None + self._time_step = None + self._time_units = None + self._data_assimilation = None + self._run_results = None + self._subnetwork_list = None + + def get_var_type(self, var_name): + """Data type of variable. + Parameters + ---------- + var_name : str + Name of variable as CSDMS Standard Name. + Returns + ------- + str + Data type. + """ + return str(self.get_value_ptr(var_name).dtype) + + def get_var_units(self, var_name): + """Get units of variable. + Parameters + ---------- + var_name : str + Name of variable as CSDMS Standard Name. + Returns + ------- + str + Variable units. + """ + return self._var_units[var_name] + + def get_var_nbytes(self, var_name): + """Get units of variable. + Parameters + ---------- + var_name : str + Name of variable as CSDMS Standard Name. + Returns + ------- + int + Size of data array in bytes. + """ + return self.get_value_ptr(var_name).nbytes + + def get_var_itemsize(self, name): + return np.dtype(self.get_var_type(name)).itemsize + + def get_var_location(self, name): + return self._var_loc[name] + + def get_var_grid(self, var_name): + """Grid id for a variable. + Parameters + ---------- + var_name : str + Name of variable as CSDMS Standard Name. + Returns + ------- + int + Grid id. + """ + for grid_id, var_name_list in self._grids.items(): + if var_name in var_name_list: + return grid_id + + def get_grid_rank(self, grid_id): + """Rank of grid. + Parameters + ---------- + grid_id : int + Identifier of a grid. + Returns + ------- + int + Rank of grid. + """ + return len(self._model.shape) + + def get_grid_size(self, grid_id): + """Size of grid. + Parameters + ---------- + grid_id : int + Identifier of a grid. + Returns + ------- + int + Size of grid. + """ + return int(np.prod(self._model.shape)) + + def get_value_ptr(self, var_name): + """Reference to values. + Parameters + ---------- + var_name : str + Name of variable as CSDMS Standard Name. + Returns + ------- + array_like + Value array. + """ + return self._values[var_name] + + def get_value(self, var_name): + """Copy of values. + Parameters + ---------- + var_name : str + Name of variable as CSDMS Standard Name. + Returns + ------- + output_df : pd.DataFrame + Copy of values. + """ + output_df = self.get_value_ptr(var_name) + return output_df + + def get_value_at_indices(self, var_name, dest, indices): + """Get values at particular indices. + Parameters + ---------- + var_name : str + Name of variable as CSDMS Standard Name. + dest : ndarray + A numpy array into which to place the values. + indices : array_like + Array of indices. + Returns + ------- + array_like + Values at indices. + """ + dest[:] = self.get_value_ptr(var_name).take(indices) + return dest + + def set_value(self, var_name, src): + """ + Set model values + + Parameters + ---------- + var_name : str + Name of variable as CSDMS Standard Name. + src : array_like + Array of new values. + """ + val = self.get_value_ptr(var_name) + val[:] = src.reshape(val.shape) + + #self._values[var_name] = src + + def set_value_at_indices(self, name, inds, src): + """Set model values at particular indices. + Parameters + ---------- + var_name : str + Name of variable as CSDMS Standard Name. + src : array_like + Array of new values. + indices : array_like + Array of indices. + """ + val = self.get_value_ptr(name) + val.flat[inds] = src + + def get_component_name(self): + """Name of the component.""" + return self._name + + def get_input_item_count(self): + """Get names of input variables.""" + return len(self._input_var_names) + + def get_output_item_count(self): + """Get names of output variables.""" + return len(self._output_var_names) + + def get_input_var_names(self): + """Get names of input variables.""" + return self._input_var_names + + def get_output_var_names(self): + """Get names of output variables.""" + return self._output_var_names + + def get_grid_shape(self, grid_id, shape): + """Number of rows and columns of uniform rectilinear grid.""" + var_name = self._grids[grid_id][0] + shape[:] = self.get_value_ptr(var_name).shape + return shape + + def get_grid_spacing(self, grid_id, spacing): + """Spacing of rows and columns of uniform rectilinear grid.""" + spacing[:] = self._model.spacing + return spacing + + def get_grid_origin(self, grid_id, origin): + """Origin of uniform rectilinear grid.""" + origin[:] = self._model.origin + return origin + + def get_grid_type(self, grid_id): + """Type of grid.""" + return self._grid_type[grid_id] + + def get_start_time(self): + """Start time of model.""" + return self._start_time + + def get_end_time(self): + """End time of model.""" + return self._end_time + + def get_current_time(self): + return self._time + + def get_time_step(self): + return self._time_step + + def get_time_units(self): + return self._time_units + + def get_grid_edge_count(self, grid): + raise NotImplementedError("get_grid_edge_count") + + def get_grid_edge_nodes(self, grid, edge_nodes): + raise NotImplementedError("get_grid_edge_nodes") + + def get_grid_face_count(self, grid): + raise NotImplementedError("get_grid_face_count") + + def get_grid_face_nodes(self, grid, face_nodes): + raise NotImplementedError("get_grid_face_nodes") + + def get_grid_node_count(self, grid): + """Number of grid nodes. + Parameters + ---------- + grid : int + Identifier of a grid. + Returns + ------- + int + Size of grid. + """ + return self.get_grid_size(grid) + + def get_grid_nodes_per_face(self, grid, nodes_per_face): + raise NotImplementedError("get_grid_nodes_per_face") + + def get_grid_face_edges(self, grid, face_edges): + raise NotImplementedError("get_grid_face_edges") + + def get_grid_x(self, grid, x): + raise NotImplementedError("get_grid_x") + + def get_grid_y(self, grid, y): + raise NotImplementedError("get_grid_y") + + def get_grid_z(self, grid, z): + raise NotImplementedError("get_grid_z") + + def _parse_config(self, cfg): + cfg_list = [cfg.get('flag'),cfg.get('file')] + return cfg_list \ No newline at end of file diff --git a/src/troute-network/troute/hyfeature_preprocess.py b/src/troute-network/troute/hyfeature_preprocess.py index 446f356df..678650295 100644 --- a/src/troute-network/troute/hyfeature_preprocess.py +++ b/src/troute-network/troute/hyfeature_preprocess.py @@ -23,7 +23,7 @@ def build_hyfeature_network(supernetwork_parameters, waterbody_parameters, ): - + geo_file_path = supernetwork_parameters["geo_file_path"] cols = supernetwork_parameters["columns"] terminal_code = supernetwork_parameters.get("terminal_code", 0) @@ -692,7 +692,7 @@ def hyfeature_forcing( ----- """ - + # Unpack user-specified forcing parameters dt = forcing_parameters.get("dt", None) qts_subdivisions = forcing_parameters.get("qts_subdivisions", None) diff --git a/test/unit_test_hyfeature/unittest_hyfeature.yaml b/test/unit_test_hyfeature/unittest_hyfeature.yaml index a04032d8c..3468047f1 100644 --- a/test/unit_test_hyfeature/unittest_hyfeature.yaml +++ b/test/unit_test_hyfeature/unittest_hyfeature.yaml @@ -65,8 +65,8 @@ compute_parameters: nexus_file_pattern_filter : "*NEXOUT.csv" #OR "*NEXOUT.parquet" OR "nex-*" binary_nexus_file_folder : binary_files # this is required if nexus_file_pattern_filter="nex-*" coastal_boundary_input_file : channel_forcing/schout_1.nc - nts : 48 #288 for 1day - max_loop_size : 2 # [hr] + nts : 288 #288 for 1day + max_loop_size : 1 # [hr] data_assimilation_parameters: #---------- usgs_timeslices_folder : #usgs_TimeSlice/ From a89cdc04e0140b89bbf7e8c804ead612f8d5af1d Mon Sep 17 00:00:00 2001 From: Dong Kim Date: Thu, 8 Dec 2022 10:47:04 -0700 Subject: [PATCH 2/4] BMI prototype for Hyfeature network: missing files --- src/troute-network/troute/main_utilities.py | 611 ++++++++++++++++++ .../run-troute-with-bmi.py | 22 + 2 files changed, 633 insertions(+) create mode 100644 src/troute-network/troute/main_utilities.py create mode 100644 test/unit_test_hyfeature/run-troute-with-bmi.py diff --git a/src/troute-network/troute/main_utilities.py b/src/troute-network/troute/main_utilities.py new file mode 100644 index 000000000..957282dbf --- /dev/null +++ b/src/troute-network/troute/main_utilities.py @@ -0,0 +1,611 @@ +import argparse +import time +import logging +import pandas as pd +import numpy as np +from datetime import timedelta +#from .input import _input_handler_v03 +import troute.nhd_network_utilities_v02 as nnu +import troute.hyfeature_network_utilities as hnu +import troute.nhd_io as nhd_io + +#from .output import nwm_output_generator +from troute.NHDNetwork import NHDNetwork +from troute.HYFeaturesNetwork import HYFeaturesNetwork +from troute.DataAssimilation import AllDA +from troute.routing.compute import compute_nhd_routing_v02, compute_diffusive_routing + +LOG = logging.getLogger('') + +def initialize_network(args): + + # unpack user inputs + ( + log_parameters, + preprocessing_parameters, + supernetwork_parameters, + waterbody_parameters, + compute_parameters, + forcing_parameters, + restart_parameters, + hybrid_parameters, + output_parameters, + parity_parameters, + data_assimilation_parameters, + ) = _input_handler_v03(args) + + run_parameters = { + 'dt': forcing_parameters.get('dt'), + 'nts': forcing_parameters.get('nts'), + 'cpu_pool': compute_parameters.get('cpu_pool') + } + +# showtiming = log_parameters.get("showtiming", None) +# if showtiming: +# task_times = {} +# task_times['forcing_time'] = 0 +# task_times['route_time'] = 0 +# task_times['output_time'] = 0 +# main_start_time = time.time() + + cpu_pool = compute_parameters.get("cpu_pool", None) + + # Build routing network data objects. Network data objects specify river + # network connectivity, channel geometry, and waterbody parameters. Also + # perform initial warmstate preprocess. +# if showtiming: +# network_start_time = time.time() + + #if "ngen_nexus_file" in supernetwork_parameters: + if supernetwork_parameters["geo_file_type"] == 'HYFeaturesNetwork': + network = HYFeaturesNetwork(supernetwork_parameters, + waterbody_parameters, + restart_parameters, + forcing_parameters, + verbose=True, showtiming=False) + + network.create_routing_network(network.connections, + network.dataframe, + network.waterbody_connections, + network.gages, + preprocessing_parameters, + compute_parameters, + waterbody_parameters,) + elif supernetwork_parameters["geo_file_type"] == 'NHDNetwork': + network = NHDNetwork(supernetwork_parameters=supernetwork_parameters, + waterbody_parameters=waterbody_parameters, + restart_parameters=restart_parameters, + forcing_parameters=forcing_parameters, + compute_parameters=compute_parameters, + data_assimilation_parameters=data_assimilation_parameters, + preprocessing_parameters=preprocessing_parameters, + verbose=True, + showtiming=False #showtiming, + ) + +# if showtiming: +# network_end_time = time.time() +# task_times['network_time'] = network_end_time - network_start_time + + all_parameters = [log_parameters, #TODO: Delete this... + preprocessing_parameters, + supernetwork_parameters, + waterbody_parameters, + compute_parameters, + forcing_parameters, + restart_parameters, + hybrid_parameters, + output_parameters, + parity_parameters, + data_assimilation_parameters, + run_parameters + ] + + return (network, + log_parameters, + preprocessing_parameters, + supernetwork_parameters, + waterbody_parameters, + compute_parameters, + forcing_parameters, + restart_parameters, + hybrid_parameters, + output_parameters, + parity_parameters, + data_assimilation_parameters, + run_parameters) + +def build_run_sets(network, supernetwork_parameters, forcing_parameters, compute_parameters, + data_assimilation_parameters, output_parameters, parity_parameters): + + # Create run_sets: sets of forcing files for each loop + if supernetwork_parameters["geo_file_type"] == 'NHDNetwork': + run_sets = nnu.build_forcing_sets(forcing_parameters, network.t0) + elif supernetwork_parameters["geo_file_type"] == 'HYFeaturesNetwork': + run_sets = hnu.build_forcing_sets(forcing_parameters, network.t0) + + # Create da_sets: sets of TimeSlice files for each loop + if "data_assimilation_parameters" in compute_parameters: + da_sets = nnu.build_da_sets(data_assimilation_parameters, run_sets, network.t0) + + # Create parity_sets: sets of CHRTOUT files against which to compare t-route flows + if "wrf_hydro_parity_check" in output_parameters: + parity_sets = nnu.build_parity_sets(parity_parameters, run_sets) + else: + parity_sets = [] + + return run_sets, da_sets, parity_sets + +def build_forcings(network, run, forcing_parameters, hybrid_parameters, compute_parameters): + + cpu_pool = compute_parameters.get('cpu_pool', None) + # Create forcing data within network object for first loop iteration + network.assemble_forcings(run, forcing_parameters, hybrid_parameters, cpu_pool) + + return network + +def build_data_assimilation(network, data_assimilation_parameters, waterbody_parameters, da_run, forcing_parameters, compute_parameters): + + #FIXME: hack to get run_parameters. This is done in input_handler_v2. Probably need + # to find a better way to do this here though... + if not 'run_parameters' in locals(): + run_parameters = {'dt': forcing_parameters.get('dt'), + 'nts': forcing_parameters.get('nts'), + 'cpu_pool': compute_parameters.get('cpu_pool', None)} + + # Create data assimilation object from da_sets for first loop iteration + data_assimilation = AllDA(data_assimilation_parameters, + run_parameters, + waterbody_parameters, + network, + da_run) + +# if showtiming: +# forcing_end_time = time.time() +# task_times['forcing_time'] += forcing_end_time - network_end_time + + return data_assimilation + +def run_routing(network, data_assimilation, run_sets, da_sets, compute_parameters, forcing_parameters, waterbody_parameters, + output_parameters, hybrid_parameters, data_assimilation_parameters, run_parameters, parity_sets): + ''' + + ''' + parallel_compute_method = compute_parameters.get("parallel_compute_method", None) + subnetwork_target_size = compute_parameters.get("subnetwork_target_size", 1) + qts_subdivisions = forcing_parameters.get("qts_subdivisions", 1) + compute_kernel = compute_parameters.get("compute_kernel", "V02-caching") + assume_short_ts = compute_parameters.get("assume_short_ts", False) + return_courant = compute_parameters.get("return_courant", False) + cpu_pool = compute_parameters.get("cpu_pool", 1) + + # Pass empty subnetwork list to nwm_route. These objects will be calculated/populated + # on first iteration of for loop only. For additional loops this will be passed + # to function from inital loop. + subnetwork_list = [None, None, None] + + for run_set_iterator, run in enumerate(run_sets): + + t0 = run.get("t0") + dt = run.get("dt") + nts = run.get("nts") + + if parity_sets: + parity_sets[run_set_iterator]["dt"] = dt + parity_sets[run_set_iterator]["nts"] = nts + +# if showtiming: +# route_start_time = time.time() + + run_results = nwm_route( + network.connections, + network.reverse_network, + network.waterbody_connections, + network._reaches_by_tw, ## check: def name is different from return self._ .. + parallel_compute_method, + compute_kernel, + subnetwork_target_size, + cpu_pool, + network.t0, ## check if t0 is being updated + dt, + nts, + qts_subdivisions, + network.independent_networks, + network.dataframe, + network.q0, + network._qlateral, + data_assimilation.usgs_df, + data_assimilation.lastobs_df, + data_assimilation.reservoir_usgs_df, + data_assimilation.reservoir_usgs_param_df, + data_assimilation.reservoir_usace_df, + data_assimilation.reservoir_usace_param_df, + data_assimilation.assimilation_parameters, + assume_short_ts, + return_courant, + network._waterbody_df, ## check: network._waterbody_df ?? def name is different from return self._ .. + waterbody_parameters, + network._waterbody_types_df, ## check: network._waterbody_types_df ?? def name is different from return self._ .. + network.waterbody_type_specified, + network.diffusive_network_data, + network.topobathy_df, + network.refactored_diffusive_domain, + network.refactored_reaches, + subnetwork_list, + network.coastal_boundary_depth_df, + network.unrefactored_topobathy_df, + ) + + # returns list, first item is run result, second item is subnetwork items + subnetwork_list = run_results[1] + run_results = run_results[0] + +# if showtiming: +# route_end_time = time.time() +# task_times['route_time'] += route_end_time - route_start_time + + # create initial conditions for next loop itteration + network.new_nhd_q0(run_results) + network.update_waterbody_water_elevation() + + if run_set_iterator < len(run_sets) - 1: + # update t0 + network.new_t0(dt,nts) + + # update forcing data + network.assemble_forcings(run_sets[run_set_iterator + 1], + forcing_parameters, + hybrid_parameters, + cpu_pool) + + # get reservoir DA initial parameters for next loop iteration + data_assimilation.update(run_results, + data_assimilation_parameters, + run_parameters, + network, + da_sets[run_set_iterator + 1]) + +# if showtiming: +# forcing_end_time = time.time() +# task_times['forcing_time'] += forcing_end_time - route_end_time + + # TODO move the conditional call to write_lite_restart to nwm_output_generator. +# if showtiming: +# output_start_time = time.time() + + if "lite_restart" in output_parameters: + nhd_io.write_lite_restart( + network.q0, + network._waterbody_df, + t0 + timedelta(seconds = dt * nts), + output_parameters['lite_restart'] + ) + ''' + nwm_output_generator( + run, + run_results, + supernetwork_parameters, + output_parameters, + parity_parameters, + restart_parameters, + parity_sets[run_set_iterator] if parity_parameters else {}, + qts_subdivisions, + compute_parameters.get("return_courant", False), + cpu_pool, + network._waterbody_df, + network._waterbody_types_df, + data_assimilation_parameters, + data_assimilation.lastobs_df, + network.link_gage_df, + network.link_lake_crosswalk, + ) + ''' +# if showtiming: +# output_end_time = time.time() +# task_times['output_time'] += output_end_time - output_start_time + return run_results + + +def _handle_args_v03(argv): + ''' + Handle command line input argument - filepath of configuration file + ''' + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + parser.add_argument( + "-f", + "--custom-input-file", + dest="custom_input_file", + help="Path of a .yaml or .json file containing model configuration parameters. See doc/v3_doc.yaml", + ) + + return parser.parse_args(argv) + +def _input_handler_v03(args): + + ''' + Read user inputs from configuration file and set logging level + + Arguments + --------- + Args (argparse.Namespace): Command line input arguments + + Returns + ------- + log_parameters (dict): Input parameters re logging + preprocessing_parameters (dict): Input parameters re preprocessing + supernetwork_parameters (dict): Input parameters re network extent + waterbody_parameters (dict): Input parameters re waterbodies + compute_parameters (dict): Input parameters re computation settings + forcing_parameters (dict): Input parameters re model forcings + restart_parameters (dict): Input parameters re model restart + hybrid_parameters (dict): Input parameters re MC/diffusive wave model + output_parameters (dict): Input parameters re output writing + parity_parameters (dict): Input parameters re parity assessment + data_assimilation_parameters (dict): Input parameters re data assimilation + ''' + # get name of user configuration file (e.g. test.yaml) + custom_input_file = args.custom_input_file + + # read data from user configuration file + ( + log_parameters, + preprocessing_parameters, + supernetwork_parameters, + waterbody_parameters, + compute_parameters, + forcing_parameters, + restart_parameters, + hybrid_parameters, + output_parameters, + parity_parameters, + data_assimilation_parameters, + ) = nhd_io.read_config_file(custom_input_file) + + ''' + # configure python logger + log_level_set(log_parameters) + LOG = logging.getLogger('') + # if log level is at or below DEBUG, then check user inputs + if LOG.level <= 10: # DEBUG + check_inputs( + log_parameters, + preprocessing_parameters, + supernetwork_parameters, + waterbody_parameters, + compute_parameters, + forcing_parameters, + restart_parameters, + hybrid_parameters, + output_parameters, + parity_parameters, + data_assimilation_parameters + ) + ''' + return ( + log_parameters, + preprocessing_parameters, + supernetwork_parameters, + waterbody_parameters, + compute_parameters, + forcing_parameters, + restart_parameters, + hybrid_parameters, + output_parameters, + parity_parameters, + data_assimilation_parameters, + ) + +def nwm_route( + downstream_connections, + upstream_connections, + waterbodies_in_connections, + reaches_bytw, + parallel_compute_method, + compute_kernel, + subnetwork_target_size, + cpu_pool, + t0, + dt, + nts, + qts_subdivisions, + independent_networks, + param_df, + q0, + qlats, + usgs_df, + lastobs_df, + reservoir_usgs_df, + reservoir_usgs_param_df, + reservoir_usace_df, + reservoir_usace_param_df, + da_parameter_dict, + assume_short_ts, + return_courant, + waterbodies_df, + waterbody_parameters, + waterbody_types_df, + waterbody_type_specified, + diffusive_network_data, + topobathy, + refactored_diffusive_domain, + refactored_reaches, + subnetwork_list, + coastal_boundary_depth_df, + nonrefactored_topobathy, +): + + ################### Main Execution Loop across ordered networks + + + start_time = time.time() + + if return_courant: + LOG.info( + f"executing routing computation, with Courant evaluation metrics returned" + ) + else: + LOG.info(f"executing routing computation ...") + + start_time_mc = time.time() + results = compute_nhd_routing_v02( + downstream_connections, + upstream_connections, + waterbodies_in_connections, + reaches_bytw, + compute_kernel, + parallel_compute_method, + subnetwork_target_size, # The default here might be the whole network or some percentage... + cpu_pool, + t0, + dt, + nts, + qts_subdivisions, + independent_networks, + param_df, + q0, + qlats, + usgs_df, + lastobs_df, + reservoir_usgs_df, + reservoir_usgs_param_df, + reservoir_usace_df, + reservoir_usace_param_df, + da_parameter_dict, + assume_short_ts, + return_courant, + waterbodies_df, + waterbody_parameters, + waterbody_types_df, + waterbody_type_specified, + subnetwork_list, + ) + LOG.debug("MC computation complete in %s seconds." % (time.time() - start_time_mc)) + # returns list, first item is run result, second item is subnetwork items + subnetwork_list = results[1] + results = results[0] + + # run diffusive side of a hybrid simulation + if diffusive_network_data: + start_time_diff = time.time() + ''' + # retrieve MC-computed streamflow value at upstream boundary of diffusive mainstem + qvd_columns = pd.MultiIndex.from_product( + [range(nts), ["q", "v", "d"]] + ).to_flat_index() + flowveldepth = pd.concat( + [pd.DataFrame(r[1], index=r[0], columns=qvd_columns) for r in results], + copy=False, + ) + ''' + #upstream_boundary_flow={} + #for tw,v in diffusive_network_data.items(): + # upstream_boundary_link = diffusive_network_data[tw]['upstream_boundary_link'] + # flow_ = flowveldepth.loc[upstream_boundary_link][0::3] + # the very first value at time (0,q) is flow value at the first time step after initial time. + # upstream_boundary_flow[tw] = flow_ + + + # call diffusive wave simulation and append results to MC results + results.extend( + compute_diffusive_routing( + results, + diffusive_network_data, + cpu_pool, + t0, + dt, + nts, + q0, + qlats, + qts_subdivisions, + usgs_df, + lastobs_df, + da_parameter_dict, + waterbodies_df, + topobathy, + refactored_diffusive_domain, + refactored_reaches, + coastal_boundary_depth_df, + nonrefactored_topobathy, + ) + ) + LOG.debug("Diffusive computation complete in %s seconds." % (time.time() - start_time_diff)) + + LOG.debug("ordered reach computation complete in %s seconds." % (time.time() - start_time)) + + return results, subnetwork_list + +def create_output_dataframes(results, nts, waterbodies_df, link_lake_crosswalk): + + qvd_columns = pd.MultiIndex.from_product( + [range(int(nts)), ["q", "v", "d"]] + ).to_flat_index() + + flowveldepth = pd.concat( + [pd.DataFrame(r[1], index=r[0], columns=qvd_columns) for r in results], copy=False, + ) + + # create waterbody dataframe for output to netcdf file + i_columns = pd.MultiIndex.from_product( + [range(int(nts)), ["i"]] + ).to_flat_index() + + wbdy = pd.concat( + [pd.DataFrame(r[6], index=r[0], columns=i_columns) for r in results], + copy=False, + ) + + wbdy_id_list = waterbodies_df.index.values.tolist() + + i_lakeout_df = wbdy.loc[wbdy_id_list].iloc[:,-1] + q_lakeout_df = flowveldepth.loc[wbdy_id_list].iloc[:,-3] + d_lakeout_df = flowveldepth.loc[wbdy_id_list].iloc[:,-1] + # lakeout = pd.concat([i_df, q_df, d_df], axis=1) + + # replace waterbody lake_ids with outlet link ids + flowveldepth = _reindex_lake_to_link_id(flowveldepth, link_lake_crosswalk) + + q_channel_df = flowveldepth.iloc[:,-3] + v_channel_df = flowveldepth.iloc[:,-2] + d_channel_df = flowveldepth.iloc[:,-1] + + segment_ids = flowveldepth.index.values.tolist() + + return q_channel_df, v_channel_df, d_channel_df, i_lakeout_df, q_lakeout_df, d_lakeout_df#, wbdy_id_list, + +def _reindex_lake_to_link_id(target_df, crosswalk): + ''' + Utility function for replacing lake ID index values + with link ID values in a dataframe. This is used to + reinedex results dataframes + + Arguments: + ---------- + - target_df (DataFrame): Data frame to be reinexed + - crosswalk (dict): Relates lake ids to outlet link ids + + Returns: + -------- + - target_df (DataFrame): Re-indexed with link ids replacing + lake ids + ''' + + # evaluate intersection of lake ids and target_df index values + # i.e. what are the index positions of lake ids that need replacing? + lakeids = np.fromiter(crosswalk.keys(), dtype = int) + idxs = target_df.index.to_numpy() + lake_index_intersect = np.intersect1d( + idxs, + lakeids, + return_indices = True + ) + + # replace lake ids with link IDs in the target_df index array + linkids = np.fromiter(crosswalk.values(), dtype = int) + idxs[lake_index_intersect[1]] = linkids[lake_index_intersect[2]] + + # (re) set the target_df index + target_df.set_index(idxs, inplace = True) + + return target_df \ No newline at end of file diff --git a/test/unit_test_hyfeature/run-troute-with-bmi.py b/test/unit_test_hyfeature/run-troute-with-bmi.py new file mode 100644 index 000000000..230aab63a --- /dev/null +++ b/test/unit_test_hyfeature/run-troute-with-bmi.py @@ -0,0 +1,22 @@ +import sys +sys.path.append("../../src/") +import bmi_troute # This is the BMI t-route that we will be running from the file: bmi_troute.py +import troute.main_utilities as mu # This is used to read q_lateral data from files, won't be needed when t-route bmi is run with model engine +import troute.nhd_preprocess as nhd_prep # This is used to read q_lateral data from files, won't be needed when t-route bmi is run with model engine +model = bmi_troute.bmi_troute() +model.initialize(bmi_cfg_file='unittest_hyfeature.yaml') + +(run_sets, da_sets, parity_sets) = mu.build_run_sets(model._network, + model._supernetwork_parameters, + model._forcing_parameters, + model._compute_parameters, + model._data_assimilation_parameters, + model._output_parameters, + model._parity_parameters) + +# retrieve forcing input data such as lateral flow and coastal boundary data +cpu_pool = model._compute_parameters.get("cpu_pool", None) +model._network.assemble_forcings(run_sets[0], model._forcing_parameters, model._hybrid_parameters, cpu_pool) + +# move lateral flow data into BMI compatible variable (model._values) +model.set_value('land_surface_water_source__volume_flow_rate', model._network._qlateral.to_numpy()) From 0e65edbb0b016b9f7988c9dc119ef49b6ed4d82b Mon Sep 17 00:00:00 2001 From: Dong Kim Date: Thu, 8 Dec 2022 11:07:15 -0700 Subject: [PATCH 3/4] remove mislocated file --- run-troute-with-bmi.py | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 run-troute-with-bmi.py diff --git a/run-troute-with-bmi.py b/run-troute-with-bmi.py deleted file mode 100644 index ab8cd73a6..000000000 --- a/run-troute-with-bmi.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys -sys.path.append("src/") -import bmi_troute # This is the BMI t-route that we will be running from the file: bmi_troute.py -import troute.main_utilities as mu # This is used to read q_lateral data from files, won't be needed when t-route bmi is run with model engine -import troute.nhd_preprocess as nhd_prep # This is used to read q_lateral data from files, won't be needed when t-route bmi is run with model engine -model = bmi_troute.bmi_troute() -import pdb; pdb.set_trace() -#model.initialize(bmi_cfg_file='test/BMI/test_AnA_bmi.yaml') -model.initialize(bmi_cfg_file='test/unit_test_hyfeature/unittest_hyfeature.yaml') -import pdb; pdb.set_trace() -(run_sets, da_sets, parity_sets) = mu.build_run_sets(model._network, - model._forcing_parameters, - model._compute_parameters, - model._data_assimilation_parameters, - model._output_parameters, - model._parity_parameters) - - -q_lateral, coastal_boundary_depth_df = nhd_prep.nhd_forcing(run_sets[0], - model._forcing_parameters, - model._hybrid_parameters, - model._network.segment_index, - model._compute_parameters.get('cpu_pool', None), - model._network._t0, - model._network._coastal_boundary_depth_df, - ) -import pdb; pdb.set_trace() - -model.set_value('land_surface_water_source__volume_flow_rate', q_lateral.to_numpy()) - - From 5a799d9ed19235cfb77462793c9a06d5a09f9c99 Mon Sep 17 00:00:00 2001 From: Dong Kim Date: Fri, 16 Dec 2022 09:46:16 -0700 Subject: [PATCH 4/4] coastal boundary dataframe from hourly SCHISM data --- src/bmi_troute.py | 3 +- .../troute/hyfeature_network_utilities.py | 96 ++++++++++++++++-- .../troute/hyfeature_preprocess.py | 32 +++--- src/troute-network/troute/main_utilities.py | 24 ++--- src/troute-network/troute/nhd_io.py | 57 +++++++++-- .../channel_forcing/201512010000SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512010100SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512010200SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512010300SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512010400SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512010500SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512010600SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512010700SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512010800SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512010900SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011000SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011100SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011200SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011300SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011400SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011500SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011600SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011700SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011800SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512011900SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512012000SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512012100SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512012200SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512012300SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020000SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020100SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020200SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020300SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020400SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020500SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020600SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020700SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020800SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512020900SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021000SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021100SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021200SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021300SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021400SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021500SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021600SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021700SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021800SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512021900SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512022000SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512022100SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512022200SCHISM.nc | Bin 0 -> 9105 bytes .../channel_forcing/201512022300SCHISM.nc | Bin 0 -> 9105 bytes .../domain/coastal_boundary_domain.yaml | 3 +- .../run-troute-with-bmi.py | 9 +- .../unittest_hyfeature.yaml | 22 ++-- 56 files changed, 192 insertions(+), 54 deletions(-) create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010000SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010100SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010200SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010300SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010400SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010500SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010600SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010700SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010800SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512010900SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011000SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011100SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011200SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011300SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011400SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011500SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011600SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011700SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011800SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512011900SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512012000SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512012100SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512012200SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512012300SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020000SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020100SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020200SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020300SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020400SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020500SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020600SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020700SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020800SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512020900SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021000SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021100SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021200SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021300SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021400SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021500SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021600SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021700SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021800SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512021900SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512022000SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512022100SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512022200SCHISM.nc create mode 100644 test/unit_test_hyfeature/channel_forcing/201512022300SCHISM.nc diff --git a/src/bmi_troute.py b/src/bmi_troute.py index fe6a43a27..5322f6fc8 100644 --- a/src/bmi_troute.py +++ b/src/bmi_troute.py @@ -173,8 +173,7 @@ def initialize(self, bmi_cfg_file=None): def update(self): """Advance model by one time step.""" - - + # Set input data into t-route objects self._network._qlateral = pd.DataFrame(self._values['land_surface_water_source__volume_flow_rate'], index=self._network.dataframe.index.to_numpy()) diff --git a/src/troute-network/troute/hyfeature_network_utilities.py b/src/troute-network/troute/hyfeature_network_utilities.py index e1fc65860..15e89712a 100644 --- a/src/troute-network/troute/hyfeature_network_utilities.py +++ b/src/troute-network/troute/hyfeature_network_utilities.py @@ -11,6 +11,7 @@ from joblib import delayed, Parallel import pyarrow as pa import pyarrow.parquet as pq +import xarray as xr import troute.nhd_io as nhd_io @@ -23,11 +24,12 @@ def build_forcing_sets( t0 ): - run_sets = forcing_parameters.get("qlat_forcing_sets", None) - nexus_input_folder = forcing_parameters.get("nexus_input_folder", None) - nts = forcing_parameters.get("nts", None) - max_loop_size = forcing_parameters.get("max_loop_size", 12) - dt = forcing_parameters.get("dt", None) + run_sets = forcing_parameters.get("qlat_forcing_sets", None) + nexus_input_folder = forcing_parameters.get("nexus_input_folder", None) + downstream_boundary_input_folder = forcing_parameters.get("downstream_boundary_input_folder", None) + nts = forcing_parameters.get("nts", None) + max_loop_size = forcing_parameters.get("max_loop_size", 12) + dt = forcing_parameters.get("dt", None) try: nexus_input_folder = pathlib.Path(nexus_input_folder) @@ -38,6 +40,7 @@ def build_forcing_sets( raise AssertionError("Aborting simulation because the nexus_input_folder:", qlat_input_folder,"does not exist. Please check the the nexus_input_folder variable is correctly entered in the .yaml control file") from None forcing_glob_filter = forcing_parameters.get("nexus_file_pattern_filter", "*.NEXOUT") + downstream_boundary_glob_filter = forcing_parameters.get("downstream_boundary_file_pattern_filter", "*SCHISM.nc") if forcing_glob_filter=="nex-*": print("Reformating qlat nexus files as hourly binary files...") @@ -58,7 +61,7 @@ def build_forcing_sets( nexus_input_folder, forcing_glob_filter = nex_files_to_binary(nexus_files_list, binary_folder) forcing_parameters["nexus_input_folder"] = nexus_input_folder forcing_parameters["nexus_file_pattern_filter"] = forcing_glob_filter - + # TODO: Throw errors if insufficient input data are available if run_sets: #FIXME: Change it for hyfeature @@ -136,7 +139,7 @@ def build_forcing_sets( if k + max_loop_size < len(forcing_filename_list): run_sets[j]['nexus_files'] = forcing_filename_list[k:k - + max_loop_size] + + max_loop_size] else: run_sets[j]['nexus_files'] = forcing_filename_list[k:] @@ -161,6 +164,81 @@ def build_forcing_sets( k += max_loop_size j += 1 + # creates downstream boundary forcing file list + if downstream_boundary_input_folder: + # get the first and seconded files from an ordered list of all forcing files + downstream_boundary_input_folder = pathlib.Path(downstream_boundary_input_folder) + all_files = sorted(downstream_boundary_input_folder.glob(downstream_boundary_glob_filter)) + first_file = all_files[0] + second_file = all_files[1] + + # Deduce the timeinterval of the forcing data from the output timestamps of the first + df = read_file(first_file) + t1_str = pd.to_datetime(df.time.iloc[0]).strftime("%Y-%m-%d_%H:%M:%S") + t1 = datetime.strptime(t1_str,"%Y-%m-%d_%H:%M:%S") + df = read_file(second_file) + t2_str = pd.to_datetime(df.time.iloc[0]).strftime("%Y-%m-%d_%H:%M:%S") + t2 = datetime.strptime(t2_str,"%Y-%m-%d_%H:%M:%S") + dt_downstream_boundary_timedelta = t2 - t1 + dt_downstream_boundary = dt_downstream_boundary_timedelta.seconds + + bts_subdivisions = dt_downstream_boundary / dt + #forcing_parameters['qts_subdivisions']= qts_subdivisions + + # the number of files required for the simulation + nfiles = int(np.ceil(nts / bts_subdivisions)) + + # list of downstream boundary file datetimes + datetime_list = [t0 + dt_downstream_boundary_timedelta * (n) for n in + range(nfiles)] + datetime_list_str = [datetime.strftime(d, '%Y%m%d%H%M') for d in + datetime_list] + # list of downstream boundary files + downstream_boundary_filename_list = [d_str + downstream_boundary_glob_filter[1:] for d_str in + datetime_list_str] + + # check that all forcing files exist + for f in downstream_boundary_filename_list: + try: + J = pathlib.Path(downstream_boundary_input_folder.joinpath(f)) + assert J.is_file() == True + except AssertionError: + raise AssertionError("Aborting simulation because downstream boundary file", J, "cannot be not found.") from None + + # build run sets list + #run_sets = [] + k = 0 + j = 0 + nts_accum = 0 + nts_last = 0 + while k < len(downstream_boundary_filename_list): + #run_sets.append({}) + + if k + max_loop_size < len(downstream_boundary_filename_list): + run_sets[j]['downstream_boundary_files'] = downstream_boundary_filename_list[k:k + + max_loop_size] + else: + run_sets[j]['downstream_boundary_files'] = downstream_boundary_filename_list[k:] + + #nts_accum += len(run_sets[j]['nexus_files']) * qts_subdivisions + #if nts_accum <= nts: + # run_sets[j]['nts'] = int(len(run_sets[j]['nexus_files']) + # * qts_subdivisions) + #else: + # run_sets[j]['nts'] = int(nts - nts_last) + + #final_nexout = nexus_input_folder.joinpath(run_sets[j]['nexus_files' + # ][-1]) + #df = read_file(final_nexout) + #final_timestamp_str = pd.to_datetime(df.columns[1]).strftime("%Y-%m-%d_%H:%M:%S") + + #run_sets[j]['final_timestamp'] = \ + # datetime.strptime(final_timestamp_str, '%Y-%m-%d_%H:%M:%S') + + #nts_last = nts_accum + k += max_loop_size + j += 1 + return run_sets def build_qlateral_array( @@ -296,5 +374,7 @@ def read_file(file_name): elif extension=='.parquet': df = pq.read_table(file_name).to_pandas().reset_index() df.index.name = None - + elif extension=='.nc': + df = xr.open_dataset(file_name) + df = df.to_dataframe() return df \ No newline at end of file diff --git a/src/troute-network/troute/hyfeature_preprocess.py b/src/troute-network/troute/hyfeature_preprocess.py index 678650295..8bfa47119 100644 --- a/src/troute-network/troute/hyfeature_preprocess.py +++ b/src/troute-network/troute/hyfeature_preprocess.py @@ -694,15 +694,15 @@ def hyfeature_forcing( """ # Unpack user-specified forcing parameters - dt = forcing_parameters.get("dt", None) - qts_subdivisions = forcing_parameters.get("qts_subdivisions", None) - nexus_input_folder = forcing_parameters.get("nexus_input_folder", None) - qlat_file_index_col = forcing_parameters.get("qlat_file_index_col", "feature_id") - qlat_file_value_col = forcing_parameters.get("qlat_file_value_col", "q_lateral") - qlat_file_gw_bucket_flux_col = forcing_parameters.get("qlat_file_gw_bucket_flux_col", "qBucket") - qlat_file_terrain_runoff_col = forcing_parameters.get("qlat_file_terrain_runoff_col", "qSfcLatRunoff") - - + dt = forcing_parameters.get("dt", None) + qts_subdivisions = forcing_parameters.get("qts_subdivisions", None) + nexus_input_folder = forcing_parameters.get("nexus_input_folder", None) + qlat_file_index_col = forcing_parameters.get("qlat_file_index_col", "feature_id") + qlat_file_value_col = forcing_parameters.get("qlat_file_value_col", "q_lateral") + qlat_file_gw_bucket_flux_col = forcing_parameters.get("qlat_file_gw_bucket_flux_col", "qBucket") + qlat_file_terrain_runoff_col = forcing_parameters.get("qlat_file_terrain_runoff_col", "qSfcLatRunoff") + downstream_boundary_input_folder = forcing_parameters.get("downstream_boundary_input_folder", None) + # TODO: find a better way to deal with these defaults and overrides. run["t0"] = run.get("t0", t0) run["nts"] = run.get("nts") @@ -712,7 +712,8 @@ def hyfeature_forcing( run["qlat_file_index_col"] = run.get("qlat_file_index_col", qlat_file_index_col) run["qlat_file_value_col"] = run.get("qlat_file_value_col", qlat_file_value_col) run["qlat_file_gw_bucket_flux_col"] = run.get("qlat_file_gw_bucket_flux_col", qlat_file_gw_bucket_flux_col) - run["qlat_file_terrain_runoff_col"] = run.get("qlat_file_terrain_runoff_col", qlat_file_terrain_runoff_col) + run["qlat_file_terrain_runoff_col"] = run.get("qlat_file_terrain_runoff_col", qlat_file_terrain_runoff_col) + run["downstream_boundary_input_folder"] = run.get("downstream_boundary_input_folder", downstream_boundary_input_folder) #--------------------------------------------------------------------------- # Assemble lateral inflow data @@ -749,12 +750,19 @@ def hyfeature_forcing( start_time = time.time() LOG.info("creating coastal dataframe ...") - coastal_boundary_domain = nhd_io.read_coastal_boundary_domain(coastal_boundary_domain_files) + coastal_boundary_domain = nhd_io.read_coastal_boundary_domain(coastal_boundary_domain_files) + # create dataframe for hourly schism data + coastal_boundary_depth_df = nhd_io.build_coastal_dataframe( + run, + coastal_boundary_domain, + ) + # create dataframe for multi hourly schism data + ''' coastal_boundary_depth_df = nhd_io.build_coastal_ncdf_dataframe( coastal_boundary_elev_files, coastal_boundary_domain, ) - + ''' LOG.debug( "coastal boundary elevation observation DataFrame creation complete in %s seconds." \ % (time.time() - start_time) diff --git a/src/troute-network/troute/main_utilities.py b/src/troute-network/troute/main_utilities.py index 957282dbf..6f80c2059 100644 --- a/src/troute-network/troute/main_utilities.py +++ b/src/troute-network/troute/main_utilities.py @@ -40,21 +40,21 @@ def initialize_network(args): 'cpu_pool': compute_parameters.get('cpu_pool') } -# showtiming = log_parameters.get("showtiming", None) -# if showtiming: -# task_times = {} -# task_times['forcing_time'] = 0 -# task_times['route_time'] = 0 -# task_times['output_time'] = 0 -# main_start_time = time.time() + showtiming = log_parameters.get("showtiming", None) + if showtiming: + task_times = {} + task_times['forcing_time'] = 0 + task_times['route_time'] = 0 + task_times['output_time'] = 0 + main_start_time = time.time() cpu_pool = compute_parameters.get("cpu_pool", None) # Build routing network data objects. Network data objects specify river # network connectivity, channel geometry, and waterbody parameters. Also # perform initial warmstate preprocess. -# if showtiming: -# network_start_time = time.time() + if showtiming: + network_start_time = time.time() #if "ngen_nexus_file" in supernetwork_parameters: if supernetwork_parameters["geo_file_type"] == 'HYFeaturesNetwork': @@ -83,9 +83,9 @@ def initialize_network(args): showtiming=False #showtiming, ) -# if showtiming: -# network_end_time = time.time() -# task_times['network_time'] = network_end_time - network_start_time + if showtiming: + network_end_time = time.time() + task_times['network_time'] = network_end_time - network_start_time all_parameters = [log_parameters, #TODO: Delete this... preprocessing_parameters, diff --git a/src/troute-network/troute/nhd_io.py b/src/troute-network/troute/nhd_io.py index 3515cd2d6..4177d618b 100644 --- a/src/troute-network/troute/nhd_io.py +++ b/src/troute-network/troute/nhd_io.py @@ -1564,10 +1564,10 @@ def build_coastal_dataframe(coastal_boundary_elev): return coastal_df -def build_coastal_ncdf_dataframe(coastal_ncdf): - with xr.open_dataset(coastal_ncdf) as ds: - coastal_ncdf_df = ds[["elev", "depth"]] - return coastal_ncdf_df.to_dataframe() +#def build_coastal_ncdf_dataframe(coastal_ncdf): +# with xr.open_dataset(coastal_ncdf) as ds: +# coastal_ncdf_df = ds[["elev", "depth"]] +# return coastal_ncdf_df.to_dataframe() def build_coastal_ncdf_dataframe( coastal_files, @@ -1583,18 +1583,19 @@ def build_coastal_ncdf_dataframe( elev_NAVD88 = ds.variables['elev'][:, coastal_boundary_nodes].filled(fill_value = np.nan) depth_bathy = ds.variables['depth'][coastal_boundary_nodes].filled(fill_value = np.nan) timesteps = ds.variables['time'][:] + import pdb; pdb.set_trace() if len(timesteps) > 1: dt_schism = timesteps[1]-timesteps[0] else: raise RuntimeError("schism provided less than 2 time steps") - start_date = ds.variables['time'].units + start_date = ds.variables['time'].units start_date = dparser.parse(start_date,fuzzy=True) dt_timeslice = timedelta(minutes=dt_schism/60.0) - tfin = start_date + dt_timeslice*len(timesteps) + tfin = start_date + dt_timeslice*len(timesteps) timestamps = pd.date_range(start_date, tfin, freq=dt_timeslice) timestamps = timestamps.strftime('%Y-%m-%d %H:%M:%S') - + import pdb; pdb.set_trace() # create a dataframe of water depth at coastal domain nodes timeslice_schism_list=[] for t in range(0, len(timesteps)+1): @@ -1613,13 +1614,53 @@ def build_coastal_ncdf_dataframe( unstack(1, fill_value = np.nan)['depth']) timeslice_schism_list.append(timeslice_schism) - + import pdb; pdb.set_trace() coastal_boundary_depth_df = pd.concat(timeslice_schism_list, axis=1, ignore_index=False) # linearly extrapolate depth value at start date coastal_boundary_depth_df.iloc[:,0] = 2.0*coastal_boundary_depth_df.iloc[:,1] - coastal_boundary_depth_df.iloc[:,2] return coastal_boundary_depth_df + +def build_coastal_dataframe( + run, + coastal_boundary_domain, + ): + + downstream_boundary_input_folder = run.get("downstream_boundary_input_folder",None) + + if downstream_boundary_input_folder: + downstream_boundary_input_folder = pathlib.Path(downstream_boundary_input_folder) + if "downstream_boundary_files" in run: + downstream_boundary_files = run.get("downstream_boundary_files") + downstream_boundary_files = [downstream_boundary_input_folder.joinpath(f) for f in downstream_boundary_files] + + timeslice_schism_list=[] + for f in downstream_boundary_files: + ds = xr.open_dataset(f) + df = ds.to_dataframe() + tws = [] + timestamps = [] + depths= [] + for tw, boundary_node in coastal_boundary_domain.items(): + tws.append(tw) + df2 = df[df['schism_id']==boundary_node] + date = df2.time.iloc[0] + timestamps.append(pd.to_datetime(date).strftime('%Y-%m-%d %H:%M:%S')) + depths.append(df2.elev.iat[0] + df2.depth.iat[0]) + + timeslice_schism = (pd.DataFrame({ + 'stationId' : tws, + 'datetime' : timestamps, + 'depth' : depths + }). + set_index(['stationId', 'datetime']). + unstack(1, fill_value = np.nan)['depth']) + timeslice_schism_list.append(timeslice_schism) + + coastal_boundary_depth_df = pd.concat(timeslice_schism_list, axis=1, ignore_index=False) + + return coastal_boundary_depth_df def lastobs_df_output( lastobs_df, diff --git a/test/unit_test_hyfeature/channel_forcing/201512010000SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512010000SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..5cca7c92fdb8959c4aa54fe971d94725d91bc5e2 GIT binary patch literal 9105 zcmeHMO>7%Q6n?wjbvEhduZ@!wl{65w1t}OOO`)VsyT*1%6xU8-RK%e&q23UqBu!&e zA#q406p3;}RVoe~azGrQy&$Ak{gH}PDtfG{NI+ZB!X+m-A|Wc6H#5&(x!Jf#C=@gk zW#7JeZ{EE5=GmV2=G0Jpu)gkzI>2UGU_cXprN^JLebgm-h$s0Q^x{L)L-BFlzNbIU zu_zE%?!1wvp;mkh3lIy%>blh$T@ z322M5V^s75VNv6cMFdqf2y!f9$!I3Scw7m>Oc=z64<%BW;dCmSiA9qMuy>+N1Cx(R zMGqyIG9MN6jLOgE+;_q5Lq8F1o1@J^?2G4T@;Ro9s})<<$++^2_`bB)ynz%Oc_J4G z0nuIBc8VUHA6tze5=nqs$-fdyC%G*iMP<8EOo*1ojmU{>m}bHX>X)wPY-)UcmsyMXhbXJjaB3lu9BU~@y%7n^8jT! ze)G%Ej<39>iv3U(d21DUo0QYO(7y8zER$9CZ}ria-LOm>LLG`K1QY@a0fm4r|^oQB{LR=0`h}D>2F8%&W{tCd2tKf5jY?YD=DbUnkSD&HLHb59KjW^*Y@LKu{4m^U_r!w^Hk`HPKR%8ZCkk#+uhsK1y)5KsvG z#}IhLbKXNYZe|mm@9=aYk9H^hZ`_W^iwE&54W%2mjXclsBOG0@RP2+!8o9>LdE&fV zy0$X;t2F#p0SDZTdl$fsn?VFbkenu^_ zGwOI^FfpD;#S&R@Mr~zg@eGuk_;=2Wv?`*N=S5nhSPQ_NP-s!aPyZw33C*3`OLv%U z7PKueLnedpPoKEG5wA! z46Nk~*Y`O)16*COS@7a*?mw4dV6b%bFTRG6xArH>{*Gb9=X@L^h7um4)gp#+BC!Vm w?&9LI<`ko~EcO!_tSt+7IzkhrCFSSnCy8r+H literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512010100SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512010100SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..5e5fb6ca05874d7c3e1505a337165b1d17c37a09 GIT binary patch literal 9105 zcmeHMO>7%Q6n?wjbvEhduZ@!wl{661f)q@WrclzR-NklD6xU8-RK%e&q27>1Nt(u{ zLgJ80C=%s{s#F{}{#2iPnN3~1u7^!Q7*ce_Ln@g#qlUP5SgI60x)H}yxk zJYq^UGE+(GbkIq9z=R9#qvJ%CShK-CU0GxDte!Fi4IZPGxc<*-So{aMLNUccDxJlaI={ zhf_?MkBSCH`Ev#D4Y2#sPej}1Xmb$zlm4tY=J4lXBV@+IRkiWwOft?IHTI8&+sTs6$bOfI>hapb$_9Cy)5V)rZh)N7A!E9cMX~BZSc2=jsychpO8NdRw9ba`_*C-=il_d$(F!;EQ zBvhffAQRaYrj3m%G@Deb#!yd#M&?I5tXE>vBe@rtk4%R1Vg8CaD%F;RzvQ=|m;P&hvCh5CvSJK;jFFv`ChU#S@cSR-Q-EW6`1Kc ztffg^%BjPK-ccKpbu;pnD7i~^8e<(-vCcs2#oRy0W33>_3G!Ggsktsd{q-~}rLp$&@1mgjo8*5w`z-Ijx{Yr?{P@zi;GYtepUXFP za=!M2;76MuJ7~YPy#K?uI}eWUI=lbV#;?D;cH`2(o*ym`9@*M?;MH&D&wupU>Vfp< zUpQawe#O0Yw9Bb|XWV^a`R1V~oqdk=$sTui>lx>Rr_VWSj_Gpa>Y)%&2q**;0t$iu z7y@^B&b#Br&1|Cc9iC3)(e70EjoVRq@gV+7-=FgwKf=)kOT|9vYdx3vIZvE-%hy&W zznr66j_3{?rWtg*R$Dwa?H6bBe&GU_07T_@GGG?G`O@^EN5pgkuYGsk;AhklJEKmd zhEfx$Od^#RXVg|^7SBM1$@_C&q*W2EJTKB3#aaNa$6`w&eg^I;PiXGkS-!(;v!HE} z88UffVV)omySQjr7+J(oK5$OP&*O4($_MoD8{0IhYOn=b7}ohAe`e;$V2({a;29=CvO;{BmNG2wG#mN)K!V(eEVDe;Psb%SsUy`{Ubde*^8S*u?+< literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512010200SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512010200SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..816f4e51a03783efb1cca795f1df5516bbcc2838 GIT binary patch literal 9105 zcmeHMO>A355T5t^p5r7hKc#V!qLQ>kq96t1gcM2|tIxF^65`rvj6fWU3H6I&l%F;> z6%vQ!l0&(ns)z$ZIe-v?o%Z52~ok!?oRUL<|Rc!Z9%({ z-|Xzn?wk2`?Ci{*9Z3&2H9Xh=)FKhEpjCAF@t10E_s9|ES^f%l0%(3DJz+Z6&4-0N zWGgjZrj|CCV310yu;TJVQhiFzLhDqE?iKxz0ktbI?~IYE0nHG>zhW*mzA%5vTd0=3 z3Xbo_4|ybBhV+cLP$|#PCHi~kyz0r)RAM0ZbZnq^x-@k#(HHCMkHveXNozC{+fhk) zg7Q)$f1|EMi6bWge!ctVOb&sjxxy-dZc3tJy?o7K%J1W ztOmyAI4~Ak!A0C6B)o-LP9m%No*w-33^H&XxnA^S38(?|o@97&)_ z(Pl+k6cxdN{auO|z+hkP4LqC5XN6Zvkv&xEjHucHfH9>IVg*Gv!cFlUy{tw!_* zPqh?3Py6HNsa8^VO@jK{SuCYtyYag$Xx>!(&+j}V#;@!a+Ydj!bX@XJ$jZ+*KXnVf z{eyI&l5 zHMw@8$E|j{D2sVcixW?!wC=5og#*FBDn_u-nsmHcPoNc o|CbR&dF?07zntDCg4Xd@>AsC1{+(p{Pa}wbSvjJje|&rOZx>D1tN;K2 literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512010300SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512010300SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..441fea0073fb54e141607bbfea1f0261098a3f12 GIT binary patch literal 9105 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 AD*ylh literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512010600SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512010600SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..5b73273cecb87e7fc2288ff3ecf6a68c03104ca7 GIT binary patch literal 9105 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 B+~WWM literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512011000SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512011000SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..0ba3f7143364aeea112d7f1138e244be91eeb677 GIT binary patch literal 9105 zcmeHMO>A355T0lIIZpbLxHNXss-&fnC`hTXLkcC56&u?jQCvHT5s07EP2(5EC`sGc zR7f1sOF)Gas){&p$N>o?=($KVQ4XkT4;)Yw2|M_kqo*8wSa zo216eRMG|)7^vcxR$RMZsZY=>VI8%=UfFjWP`Lv0)*z}H&;&m5FP}*a&7M4E&z6gJ zNsR9je|RFfnV@Iv*;4W3Oth6Ka#kjO zG$oYfEU#l$ai(Cu0#-NLiD+9AZ3$v`vN&BV2wgm_y1M;>+uRZR7mk?Mp2v=8FDL>p z5*;OajA)+daiU{HPY@j^`cxvDmZy?l^!NQxg#e@*02m|)+%%ubhP%-KdoRlo2WP8u zGNP|;cyq9RvnzY-6Fj_wJ4CGtzLEGQqFv$0;fVN%gt37@Up1zc^5z8q9m~Pn7|DV76h`<#HLE5wB9o z05v>v-c}N>&@56SyCAf&afN1^YSj?x8PF{3XoJm4OnM;qw6Iaga6imnF-PUvlCqcW zR+KG8gJT_&uVxedgI<~V8Xng7l#A2$DrM^|UO#;K+_2&w zQI(%7U+rG$!IQGfG6Y;gtj#&L0!|{hN+~_?NI}-DK^l1EG@OeXm_^yi`ytYJgEPr?@l}?LpXk5skkTCdiYZr=c#yi z2v&v9Ks50A8BU3z!A_RC%)Z0kvJvOP^o%$QZRO zV$_jTUuq0h^xRgSuyg;ujW^6z zAGFSig-q#Lm?tR2mghV^^epB$AGk>V^AK&$`GBkXi)|WJ4cGxK0_%KVacb(Bv8k7B zwZK-kNc}3YGr;nkC7c&ubN{^z1D&P4XZ~6Aysf`c))xXJx#zv;F`V!)t>rPC6RA4@ xu+L}Ty;B~v`oHub%xgbv`u_Ab9<(lgmF`&&;@?T8|I~x{mz6y#@Y~g|{sLAu-je_T literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512011100SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512011100SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..ca57f91016613cab7dd2d184229b64ddb01fe4da GIT binary patch literal 9105 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 literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512011300SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512011300SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..442cd12d0fe65e977ca4dc47e2c0e6823a3a71f0 GIT binary patch literal 9105 zcmeHMO>A355T0lIIZpcWQyM2JYSTg_3L+RgO&~;y;)m^!D6XBx2*jZ>p?;BFC21R* zs!$-|5TPOtg{p`Hha5N{K@XfjA}&3kiXK2hQ6vOKv~UR*I3gh`*x8*)9&Q{L3AF|7 zR`KlY%=2`wMcdF3zNPNO$UG>~6 z7I2;hjUYdy`e`#z1{iTRNr7E6zK_tyOl}TaHeRF zE5a*WZ?kQA)W(oubfC;I)Y=MJ0H$6GH*E}bRR#!v*@0b;$766t zyhH|ANoZr^3e6VPs&Ujapjp__0UMQ=vj>@$q zWiQ*UC|imKN4xT;(y@^-zf61$AM5){g&Aj+vUL`6@x$j#J14Gpis_;){qat`G+A^? zirwOqZOe(JXR($>x|~y2n|ecSi0Wo+D^oU?*J%!Ru3(*k&x^Ugo5xy#o5w40^LTnU zkF^OmkEy+z$G)4#T8f*;`*HJFE2+DpK>g*kD5Z(^<8P{<`77~1y#1IQU)dqAAHIF& zpyD4^m7h!B?~#1{amDZcxnp@{^2~C>rS|e$LuZzceDz@2p6M^YpSLf((P>`za<%WX zk6x=AN`CxF^wWLM+1CzrMeAQbXg_f7>d-^c{%GLC{r0}Lv(fh+IUik%nzmeAe`o|W z0vZ90fJWdyhQLk6c{jYcnJpaOVRS;F-9q&jw?p*sp#GP>J@K3j;rM~2;+{Nf;m>89 zr{dl9XDd@a&haaUe-}TD(^KX>(jlf9mc_(@dCp=7Rc?{=7 z>J9*$v*~wll?Sc68H0o1PF Ag8%>k literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512011400SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512011400SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..ead97240b002475444725cbeaf2c564003a6b337 GIT binary patch literal 9105 zcmeHMUuc_E6hB{*uT8tJf99IDliAJ{oI)FuF4Ngrmzbn$X_j=2C_a=}m#;LV?Y1Tk zL9oLawev+8D?W(y!8h&m1}?J?BJOdFg6PCfA1ny^D2PMvx%Zs*Gi#a&vQ4>nH0Pds z&b{~C-#y9BId^_AHqcQ2U_D^-dcgzDvdbTTQhUEkjWEyhm$*}brUql9E^F1bN6OtM zsqr%9wB7{ zaH};Ekw|5MB9>ROAte`+;lE0bn&$6>UIlmV@K>?IAC6V13RLfRRrE7 zS|s`w(YJ}dLv)_#Iil|pJseFX&rXm236KPWzep@3*0&{vIVxxA^0oZwntr+ohQ zD)Xg-3Y|*((|4z$yrs(ezAEz8D)Kgx^S$uB%P*{um5=YNpijfF$QQx`nrZ|z0vZ90 zfJQ(gpb^jrXaqC@8Uc;KT}41uVnhjM>q<-umOgfhIt}K%_@~MMUNGCS>vFja&WKm2 zWPlnTId3xwS7=I<$Sw+PY+Rw)qFObAdImHJJKABR5|bE8KPPMyGTaaISIkklwxsN3 zyA@?i(co~`5Cy%uhCy)2zFn!){!9A~mgdF=OYi*@FJ1en_R4DK;VTyxdOlxX zXnZDd@lyD+y)Q>@j&+6W&K-?Bc475UPxwIC`{};O-q!QskDpiyuZ7KsTwH%>1T+E~ z0gZr0;6H}I9maXLy||gp9N%GdLZRK6$}etX^zfkmm%cagoDAXkfu-!8Tx)?ZWSpns z-SuZHQ$Eh|D@V;PoMw3V^{Xy_Y%-Uh&g8NsDFLXV`MiLcwNDl%4?V25>pOn!vPZ_K z1rei;#s}h~@nkffQ88+(SQcZT?D)Nj7x`37%i~2pqdE(~4WF;5{HO1Z@`UZXJJ;VZ z+q}>=Cl)fLXJMY85L=$}c+s<%<9uL={O3{Hobv%!oD-=# y0I<)eKD=8VwDQ07Ak1q&Y5eij79O-FewFT958~fRrvKD~_?MME%J=(M-~I*WaNqI( literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512011500SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512011500SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..7ba2386adbaed8c1d78f548ab64c1908f3314011 GIT binary patch literal 9105 zcmeHMO>7%Q6n?w*I-7L!QyM2JDrrlk7EmyDNJ_D=>cw_Q6xU8;1maMcP;V5Y{Iszt zNC<_C4@LZy5QGqisN#a4;#QErC5Ng%7o@6+grJBNE;)fXAt5T5H#5&!xp7=1)D|=o zdEdNwZ)VBMMG^Yf~cy2k7E%_+L;XFaU}>dVGtiam`G)Y)2VDGW+xM1?LnCa2Je-! z4rI}vS*qs>9=kLRcJIi`!N62<8I@`fPr zrlfC4`nIGeC4EQI1xeqPbWzeLV(BDb6)ukzTA|=7h{_!R7?BDdQjoObZjvYOB{jss zT^igBtBW08Z){wz@*4RBHE*Gcq*fK*Ecq5m`+}i?5PO6Mf~){TUlgL%^42i%2n^yd!BbZX5n-<_KB_B!MH>&QFm$UCK+_J#JHzpzYJ-M+nszHEji+7N0`R3V@c zPzWdl6aoqXg@8gpA)pXY2q*+@DFPxB!%{GtXJXnhF|eKGX)x}^pGX6kV02+s*L95| z;uV>5K@BhOw~>T0G-VmcE-`H^l%d%qTQ!P$8niMyx?nvMlN`=G$!ugYoDbtyj8Q4K zBr)pnwRvw#r(9hBBON@Qu4#=OgYD|ceC!SEdBX@yf|KP zih|wbNw($K&@-4zle!dB*XnvhZb;_M$X23cE{)Ub@4kY023jx1{%#&~1#TX<#LeUC z-8|+d+&qT%ZXWAy9&;&f9{0!1W3Hs(ssQzu6D*a+%1^(Ggyyf3|M9&?dHa=ZeEZ?M zXATMeA(8nx|HDqsHy#uG1G5(*ne*ZD$L5)c{Y|*M{6Ty9R70k`_FJj^*yZBceXC7h zzxc{$XOo|Q5&d%SbN02vJ<-P34%zoFt{!+Wx<6`u`mnvXVGo6$z+J3O7x{aWoCx5M({LHw7#J?A-ogrf_Vs(sSeg6H@- zPn>rv*H#937zw7AcK1r#t8zk<$14(o<$tR1E;0`+$SfectEdxW1B=(4Yoi#!#X>dpPG7V zeCh>946uDAO&&M|Lpf&bYx???vzLP}%sRz-Ql|0J-$Hnje20YN= A#sB~S literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512011600SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512011600SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..8812012b996d7bf3b3b733f432bb2cea413ad911 GIT binary patch literal 9105 zcmeHMO>A355T0kh=e(pZKc#V!qLLOOr62`k2e*WXwC`a%B#LV%F#>^9OsHREqaG9vVYlBY;<=20e7}k zaEokw6Z^vx@y!@L0~mD$CDt;gh70GPa>5WPN%Y&n3GI^)r~R@3_dI6 z>`5?XJ}cmvRhY@SFM}0DI}vS*qs>8##tYMh9Mi?qimThkxYZr8f2_~AcpN*dy(tKs zkn}A{-qKV(BD575AdQ?}sW9KzRcIBN76?oKIxM-Q)myFUb)H zZ>#e%tS@eOb+CT5%X{P#G`xX2l3EpfqvV?;?F~nEMA%1UXP7l$=!-_QQr=ucF5y~P zr*i(r8uPh>GM#Gs%kNHAd25aJgEi!BHRSD5PWM9h&cCosRyn@8ioP6%dAbl9P*fqH z5Kssx1QY@a0fm4sMl0vGlQ-)oC#A#XnI7Fu~}+uFvPw zC?j5yB?HvZ`Mk9xRH0dviR?Vn#zqyIb*fdPsHZ_Qv!er6D>2F8%#+MUCd2(Of5jY? zYD>aivRhEH6b-h!@~@<0Ln8s6_-Z=o>!rf9yCk!95>oL)cc~>5id;? z-I8F}`6SzNZ0Q-SrAb}NsjE%Bp*AGzW@IZ-GMCnA4t8F`Is=^-bAK<7wE{1XSK{UI z^j;oo6J8!udoPcDFORhpFOT=*<*`;$cUge?^AT1`W9_@&L_zZx$$xwNQ9gcY6Tg1= z>X|XYKO`zY=fBy?`TB!`H^+N-l`mXdIP-aQ*ZB{wE&Tdw_hK?%TKwq;|6|=_Z=CIW z?#HvwmWMt~etgFMWcv%w)xBMI{cB^+1IMoHe$ei-&5s^-wznO%-`{!KUbYQ~FRnfm z0tx|zfI>ha@E=3qCgZ#tUfhfpitjKwk)hq;>Mw44<->#cU;6gMb3BBj2bPL^@-2ry z<8hvdcUPXR4E{JruN;9bI8D>(^{c+PFJCB5XA8MSE&&M0`LuwMa}SjAyYCg-^}qPV zg3e>q5{psC6N8EIL@JiZiWs$xEsHTwZsPXDi*zcYmGL5-QJe+faxge2{HOn>@`R1s zwywNkwwusiW(yhIvoKE(h@C6zCVCcelnTO literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512011700SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512011700SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..af0a02c97ca287f4a081ab04e031b512909a2648 GIT binary patch literal 9105 zcmeHMO>A355T0lIId=N;QyM2}RnkHv3Q}t9kkS$R`hstO!9q)`3@R3pr@{0Z(hGxl_u$ zCaLif%S{^;)=Tb3mXimx#%;nlPsj0*g%YNj=o@NIf_bxD7jA zV~z$!)HpB}b=9$mpsE3WiA6kRXS0IGlOW8DL1J(?na&Po(z$HhP9?#*3uOkFa#q?N zP6}l?%kP?1oXR`Tg4Kg|BHETjTY}h=C{7mhLKjb~u5PQ~R(8bx$zA5cJa$Aor3k!6 z^mU@AiM~PfO`>lReVgbzL?4Q0Qu0*Ni~hbJst|y50{}w=ftThpS#~!XVDDu);^1y| zZbtOg4X+FaSGuytKEcE5xI@&c;2Vf_u1Q8PsC2&e?be@bT+caAtp@I5U|m=F3t7;HUY#fSGp=mI{0BP}}uBef|@l zj8RJ>MjcJ|Cr6X%crvGA)K;-9#z6V8n-eecshC#Ai+o0P7J!SP(46w0-s{Q})^FXi z{D#>UfVNq&kSRS2^8|(1xmjNTJ&QTc2hNcH+)bNvKH#bTVw*x$1J*%{z&h7ooS1lY zY~mS5EwGv`Qol;<3~+AN63&aSx&K~uZ6L-1AoS7*2SY*76w6 ziPRkcI43f%-Y5@R{9k$y=C$uO{&;8&4_XqxO1G>B@$V$lf9gT}%gP=V`s2%Q{{qEo B;_?6h literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512011800SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512011800SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..5609d12d00e7189b53187e50d0bbfc3876d6ad07 GIT binary patch literal 9105 zcmeHMO>7%Q6n?w*I!?OzX&NUfDrq2yf)tD$TnG_qyx0y2aqTolAP$uY^#&WoX&ajg zi9@*L5N@axao~^x2Sl5;&_j{Hr4k5{BdQ`HD58Z+BqZR5KopoaGtXJM*|Y!_?9y9W+#F<5sNRDb#0VFJ_%AfnB`r(V%t&;>`(E)u09Z>@S;&P0k-aV$YWg zc8Rs`U_V?DpN!FC_I#;ucy4&0f6gu+%FPT%f{z3v{rTL?-r;aCJP-`^3zM#5PgWim zghsg5X<2-!%|T7;MwzCGu?4aKL_H=>+U93y^C6;qtp+R#gus+0dAT0y=v)t8^|xci zqbSEV(WStw=pBuPYfEX?_q_NlY+o0 zNmnF2E$JCa&r15fq#sCnPSPi0=_FqjE{_#jq2Q{B${hfhkP04BkhJPhapb$_9C|}WwjC=7X(g1!iy0NP3x<(Q4 zn#{SNhL`u-OhOr&iVS3znKl;6&}@;dnnXPfTA3Z)u#t&Lj%S`?HZmE`hw&@MsFYh0 z_LAL#lBH;Hv@ickIyN@pvF_wCm*V7cf1Et#N*XQ;P=8utsWeu;|5YS3f0q1rZ$8S~FYVyl4_`lf zK=2QW%+KfF?&f^sQNe#&JiYIY7b2BN@!Y;A^O1^mPkTjwthX}q%WuQ&KdxTT&n#W| z^ZdJ?B+q{s{b+EP@cJ}G% z*_UiFz-G2^eV4N{z{LfVIWOMk{(BJyI!n*c;xp)Zo4--!R}3RQ=k4e*6z~wO=P?u$ zi9GA355T0lIIZpcWQyM2JDrq4S1rdy$rqD)BYGXSjifgBF1>#V-p?*;w%1;}c z3W-B{2~xSCDu@F}IphWf2>~r_QhGp$9H9#0r$7sroahk=QMEg}Gs(k^<07H9pxr8- zot@d;*>A`0%hcb zxX~1g$)nbW45I~QhN0G0$O16+TDWOLK%gy`h|05?FryFxi%jxKJ=F0?JvbS706Sh| zh6V=JI4~Af<*^8(ssVn9MLZSDW(AKYL6{kXME`+gI@_N~=d$rwDhbx3C^Nv6v(m8x zNuexf`CYS|iM;(PSe+F>u!6j)g1njJd@p?O@(U|urQ=)6=+iLF@rCe!rWyf_fJQ(g zpb^jrXaqC@8Uc-fMnEHQR}oN^7*T@RxDwNdrH`$mPJ?+b{;4uR0L&KbdORM3GvZ|` z8K8zw&Rb8y6`Dm#Waor7Hm=ZYP^}t7Jp<~69WAg{iAnWm4+$HE4EMwQ6?0UsEh&51 zZbjKrG&tHe`dTL5H{h3vui;~TU(p%2mnmCkAs0V<_LzO*Myr@E+T34nCyK)byQtU= zKH0XsSb73$X{5_Jb-Agx)rP2U#K z;pQ>5ck|eH^H@u9^LRgQ9&064R}`qfpAw}s(SH3y6*R9C|I1r@<@n_-^7`S27Y{1_ zDOLIT@~7>RuRgB$>p!3G*>z}sVZQ&{o)2E1U$~hr?3+#J_AO05(PMw}{lzM0_~M5j zz599U?78TLoiD|%9d3(Ozi}}3`0UmFPe%7d1MlyO?QA+7oqzgFbR}xWOo zvpE3G(_$f0dKTsh3b9Mmz5sd_bDR&HA^&-dHs^f6Q~t#^g{lT@f<}RLuGbkGdwzKA z6LxT1ey{ literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512012000SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512012000SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..9722cb096df737a80fc78d3607fffa2cd3a21c97 GIT binary patch literal 9105 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 CG~=ZJ literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512012300SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512012300SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..cbdeb250df50273acd93f4e25c120cb2b4a62a17 GIT binary patch literal 9105 zcmeHMO>A355T0lIIZpcWQyS+7m9!-)1t}OOO`(kx#}C^fQCvHX5r{)&Lj9r`C21R* zg2W-c1XONSRfG_S96(6WUbs-H^yg5a_P_yEsSr(R(t?x|+(1H9u(LapJlr@g5^4+D zt>W3)ncbcJcI?i~9vg`F*Va5*1K0uq@Iiy@^2eXlj<>53=2`wKcgoQ8KzzhwEqWf8 za<55hyi6&r@qmFU4bqA$k16#rnkB5G7ThfRUIR*3VBQ)+RRiiEApT`jvEk{1hn(qR z-YJOjP2vwvBsUZEh%;TtADrs#>X>qh2XbS*-J$0~-5uk(v0c5Lq0X*QxI>w=gfm5Z zUJ+j5PLplRqt=EDqXlJ#q1IN&0xh(%Cnja!28Pu*Fcwwiu?VB80e*=^ENN#lg2$5}%#1;NaBm`&8BC|LnV6kSfb|5*3^3)a zl)X10l;teHYgT?L=ez}0H`GbJgvIAt%6(K5&I{1n^zXFBiao` z;0K~Ni7padB6^GHZK6LC{fX!cv2;?NN_x@X_d^u|kZu5Ah#>INd?qXIMg#1wMzI};_HZZg*$h3ijS_HVbMUKuNu=*d3^;r!L_nZ z>HLiq=1T_^I_37K?@n2HV}G0Q)Pevm@U}#csvGY z#Pd`#Knab{0ymFW;^y)6 zZXRnBZXQ#6H;;WckF^vxkN4x|u~t&Gpg{fkm?))*cI!7)(ENq?oA2+D<5xGy>xb`O z*{AqtRORRE8(Sn_eOU3WpIwTCzv+v-xpX~p?Q&n_Q#&2`q9YRdb^AM!@ zykRy6pm|0tWJ=G%JV7CLamE)w&ti`Afz#waPtxX`4|vMI*d|fcfDO7n%?{+(p{Pd$i#S=pn4zhA!o7Z>T` A9smFU literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512020000SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512020000SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..e8a04c311299a5f815ae93ecef36fab99a556678 GIT binary patch literal 9105 zcmeHMUu=_A6hB|vuWQG*t;o6!g9BY6nvB}jfw*K{YumB8(vH>m=YiBozh#wfz*^B{ zCL@|Xpoxhg7$1DtgYiXq@JXYv@L&i$l4a2-M$iQ3KX^1D5WVN#bK1|cu9%pK=DUQR zd+s^++-6 z+^Lfqo2jOa4$x4=CwFn-KBYcEv&8PG`M1cvQ-f*?%o`)9szEb&#J_ARHac_YusKu8 zn?*6cN&LqX$;AXcYR(k%ho<{O-P302KyISHH}F`Xw|g=-v9rG?&=U#-yVaJi;7rk; zP=qbqYKunYQJVsq)`2ojQ??bd08E_*F6#3Lw55rNJgW}#3L!9POD?I0Iu5A^$2|97 z$EnTJz^EDr#-gD%7C}_iz%8+eC8L>);PE5~Gh+}R-kV5ehSRBRCKgR5z<3a48t8IX zD!Mlzl;te9WmbMVXTAbPFYXi3HYC~-#NK#*DxVX&cv^LJ+XPox5&I{1>ldzKN3HLCa~;+u(vf;~HXLcvf_HW28m#uA3Cpq5>-@E+63R(5|<{J7m3=4cAJYZ8B0UH4u z0UH4u0UH4u0UH4u0UH4u0ULpJML<2gk8YwB&aA*!44UYYWC*-neUa|!DVd|u4`tvuEWtUO+cmB-Ut zd8|!Xc}(rCJoc?T)>5oI-j9{XT1mqt1?siqqLe1u_rI%x=5^w~d*^XEzO+eRKYab% zKE*$xDnIAG-70zS5yfkJ7Q;`zbuhfkyA%$+c`*FhjzakA?6cvI&%GR;g;y6}JN@P2 z2e11ElAnAU`F#5e(JTAABHlOlMISzSd0Xk0Ee}ao%k&Zn}@-JB&^!v^!S&#ce-5JgC3YP=0Y+&v;ITaQwhhbx)3! z;1@E^Q}J&3*-Dp>bNtHT-h$IK7r%aaiw7q2#i?vQcScG8+%%sJ=sELnX>#CxwOrqe z7f-unj9L;g>R4hhF_uWh5?K|awh6Ns1Lem5op_N?#k4wJ=av8T-BF&f zaog7N8)mx)+UJBJU3wPg2@0{Zb1n~h7IT~roFe~uh!*F3z)}0fHi@blY=BmQb#^dc zC_Fu0c*#@-R@;lzuMs-~oSid-^WtmnKbK*kvvl^&KZBmP`Zvn>N?;_{yc<1+6CS4Z zJce^3bq4_EiS&Exg&w@Z)TAB2@!?0*iPmmdzqhCn1;_gT&CTWI8*PN$0ZhSSktj-6S)>60_2= zT}f0HvwW^uh3UNWJlMTtC!uW%v;~O0iNaJNkGgbPd39TmTiKENM|N1JexMGvA0>gG z6#ZGzUljdS(ccukr0DO8{-Nlj@k~mbijIekPbj%EqUr_!hLwVc6%;MIo8sAfS&eXT zw>me2eR;zxgY_$2(PN+B;dR_m)UMzg72l+2Pbj=S+!I0)!Ul-GY)mWV%{Al-uJSsS z^VipyFB}wgs_n17J5}YaHP#Q*khj&4w<|f{3*Wo=!lJBld}9@TH4KYY%P^ng(aY zORDBV8eTDPH3?T}j;lm=5w)ptg=URv)d=Ys(2RC;z)B@1HI#h}ZA2OENBJw|s9al; z_OjiQvZZ8jv}@vpOnh+IClX)7%lh6@Vai!j**Xik_~CUXor709aXPleE3YR?V@0PV z*)=}dwmdF9O|>+o%Q-1KoO z{B0!l-uuxHwmuWPu%|0p|H|&zy+_XPyg#}l>OZMw44)Wd`PU;5_6b0UP}2bPL^GM7W2ia1Zk zyX9vqOFYi;D~E3rO*6deyii}jPfi1X99tF=|6qfl_#vgkLHs^f6to~w~B2@#{K`UaN8z@XpK0Y@2 zoFf-l%@(0wC3XflF=wOm(rfO&mtl~zboR|ZL7unzH_HA3F%o;;iXOuW57Sy6!#R<> y0|4i6=8YTWK}-Kj52C#Gou;p6*6^TZ{8hSTJ&1oNnf_A`;$K$wsKDiuU;Pchs^n<^ literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512020200SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512020200SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..6406e56a4c83ce32089c6ff23c1e6cff9f50c128 GIT binary patch literal 9105 zcmeHMZ)hAv6o0#Sd)cI$Kef3em6}uown98FG1VH#_13#f6LP&vbE1fpGxj!QB}v=d zSwz7U=?NA5Af@7m3i;qSTl{E2t1U>eei11Fu`M?0hkR1M3AM4#o0)f6ui0D$X{*c} zw{PCOH#2X3^Y(7un`6Vtp~i;$8vu)GLJ(Sbl^!=`dAD1%5Kr#Ci~l9i0CicY@@yQrH?93J21G9sDJ+n?}e_?X4Kk{Uxzh|m2xnr<5(%Tn__6U=fuqP`| z3qm8TwAnUaYGXvxI#8x*Vr+pd0MUSjleU-)Z9YVtuhoFEKnN^pQjqJRj?VSqh#`@JNuaQqs^9HI&YE|)#l5di}yNp$0`20tx|z zfI>hapb$_9C_F8<`B}!}t|rRLU(0 zd&zD=$x<{p-aYktHZeRJ;(@OgB>iB?opBarv`)eR>wqQbOgo2HIt8-8dP{CdCUwYGqGT?O(;V)+gn0&9FUI~}9&-g=9=F8Hs}snDPA7;$ID}`r0$9U^_OETmBz}Czl((Cuaf`ay{CBlrA>VM;rr+J z3jQ&X`MGeli}Uq|1po8W2eIDYePlwj=pk?-}bkBMa{Z117ryfMVtmIMQ>t9{|3)aQp ARR910 literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512020300SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512020300SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..8cf50d3a1b307dd3214bd2d8ecb6cc443ff68640 GIT binary patch literal 9105 zcmeHMO>A355T0lIInT+XZ;Eu8r-GD6XBx2*jZ>A%0PelC+IY zgajhF1bLM;hxNtOsnC1wLqzUH~#GNWMJDQyI*f%_nNV(S} zHD0EY)_cG}l@@8mm4}r249ybOQ44m-zSn@t6_~fjQPqGZu*AQ7CNZ&i?6|X7E;=PK zzFYj^iR5O2E;);(;<1I{{@w+rJYAR>j)a~HMS5ooGXukYp}zi5xL28U6K9I{j3T_k zt+sev9J6>az z1}4-vFcx*yu?VB80e*=^A|21=1dk^{m>GlQ*x^(rH_O@u!g*?hP<8Rd@p?O@(U|umE)aN^l2E@_(FI_{zn3XPvTj7IN{!=gc`vx4Ol2(boQWFIk={Ic3G}@X59n z#L^2`OCw#*sjE%Btu{n;v&yrvxx7wuu=^_38Th=I`@4Cp6}Wl45;u>hck@`AaPyej zyLs%pd90k8CgPKr{RXg~d?3YxzX|Kqz)%kitb<@Lk07mq0ZNmcpz z`iDJ|51df^(g#lT^6;tXz_;&5!;w?bPp-Waee=r~hXiqHg){*$*XKoyNA~qPa&K-#FZ#y0P@ZkB_M$C-M#r20qKqH_L&3b8;$qMT`a`?M&n&IQuuRv*fwpg0a7Yi4p1i(-8c>%NF952rvdRT2Y^vXA1_+*S)7BT8% zY9uw8$|O>G6{EI^WibXSOx>G!kx#|6GG62}sK literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512020400SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512020400SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..23611877c728862a6bb417773f53fd842af6fbe6 GIT binary patch literal 9105 zcmeHML2O$^5Z!P4J3r}9;xw_7qLLIMH6VgOUhhWi>AG{ay%77$(f_!HY(-ExF@lD|NmDl|8o8uysjJr4@G zS4TBkrjj;zm0(wk zu`kV)#Vo&TmNQ$lUu9+t>;$w;fwllKmU3pCBG-k}%B$POxs4s6f3jb{+=M1HBMl&J zLAo7jE7CTkL8Kw1?MRC93$@~6~MvW>f8+P z%NyPptl#L09{B_fZ=()Uvx09#z6ohG(zmBC8i__?5#AU_UpAtZ^5zDTaERDHRPch@^+Ndz0kdjFD#c;j_;_VkHc)4E`$aYRR|~q6aoqX zg@8gpA)pXY2q**;0t$gUih!)d@Dj|{m6$dteeB?M8pwO$PnH1;rguQsV@c0yhs=;^yJ>ZXRkA zZXQy5HxGR`5499G5BKBdp;l6NO@jKv5-+9k_Wduip!p;6-@Wsc7{A&ouAhDV{C>$l zCM!Q*eA^}X`lFKn>COIl*DI&uJ)gZEf8^My_<@&~;y?Gy$KU_;?ZGcgA6?jeAMrpi4cw+SSs$xvljVW#CbB_ zU4ORH#p4{ka`<<`G|fk^U-hL!Q%-57;1tgb31fboPYdWp`$&0e?*nqXftRj);uA4y zna8N(>7n#^I-5)vWQ-c(%R&rPoVYvjBAtq8WxPmdlxJb=S}?dM{b%5|@`RRMUF&a{ z?FMUK;0x)(vmj59h+SOp8Q@vOQ9f`6{pTUvobmxr^%vU=sA_B*YvWiKhMei?XD6nQ z*>Zu+Y!UiZVrRxKE|}bT;WhW)%P_!MItLb?1JB$18)bgQF%o;;iylJ>57Am4LphPW y1IFwVx%cjr2d(@sJqYsJ51Vcr-NJ*`_^;AE>p}E8N%Wt35dE@}M+JYo^vz#Z2iw>H literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512020500SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512020500SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..77ab0b436a239f9f2dcb500e00f2a4daa4ab2aee GIT binary patch literal 9105 zcmeHMO>A355Z-6M=e(pZiA&@Blr%q$)PfX@V-hG4as6sLB#LXNG2-VCnNYtd4<&9J zn+l0TddZ>OXjR04Lk@6)o~Z;amG}|m22~_fTJ?uZ5CV=!hzfRgXOf2-$3;SILAzBv zJ3F(xv)_*0nc0(L$J!MVCJQ#P(L793h_MFH@%q&5k9feAW%$ZXx#@ zs7A|F(gq*XKqV-wxU@^E&*Cg@9kx)X==(KRxdQRl1gL7PiJAOgK9iVSJaW`oEW1vL zkMH1ra3Zl8r^lVel6#~$674TK<->*9k-_j&;lcj7!tBtR3cTRbv5xMIvqIa-4^g0L+9za{OQ_lN--w^0|baPBCi_$TVh%SsD9a ziYtp*0naSASa4ov)*#pkXj=kp0peiNU2qFr7fvg$u7`6QJ3{}=KI2k5n$UrCC(?(J zb|T${v8ovQMd8taE@$Xjd3+fYvTLiaAduv}I--cdy#huI2U2n{Hz5Kssx1QY@a z0fm4#H&~` z01aKt+e|_gn)8^*u5fK=RH50TS~UrJ8f)fuw6l#$OnN-`9Ji6nU_Z!TAxEX!lC+oX zmXs_7gX4X3Z)6i=69JLG<)Jp= zel@%lFp*^i#NvH!97zPS0}6ZYQL)A9G7JR4t&8@5d+A355Z-6M=Q!!hPidT_D5Rx9BCy;=m9}{tg2KHifBPdIl&PLQRvR@O!9E!xJaliXt#=I zXJ>YI_S>;LGkba<(O+BhXbpqr_cNU}h%SBnh3&m|IYKq%;r8OR=fl7n0;>u%EeGF%D>#zk{Mc=Ej(iMm|hd@+1D&;uQh&||0kk3h$( z&EvqZ9A|_@Re3BzpsF#Sz#^WCWwV@zlK{+wL1OSwGMydFq;uJLER|&DZjfor5VO*; zLrJbIX8ByRoawy%7BhRmPC(lfXbTW~63 =elrOd38HEx4t9v&+a#_>_QXTkv@U+ zNu;}xb|CFU+J*Efq)#J#A)ZNzuJEG2?+1G#fOrFp4dFa52wiQ>-EfS&ms9`;cdK$U zyf1HfeXx4HD|+M;G`xj6NX-(y7Wq1)kx+PVI1-A4_Jw$39DUh{mdfiZ$Puo!bxP-N ztuS9WDAy^sKYn-0${Q=JAE+R2svvJhIo%80yZFL#S?T!pGWs~o7U)7~Kv9K&LO>y) z5Kssx1QY@a0fm4j@FskS8T zCA%dhOTl2Pef;fAd|=2Y5?@UxeZA;R*~^%%laPuZx;<&1yxqp9^S1EE2Z`cn!7fU6 zlTWfO&zGKtS{mw7PF-&5U9};sn~|+V$y{2eKG1dz>I`&V$o<_s)C$}@T#1{9)4O@7 zO}KeT?cF@|-8|G%+&tWmn}=FS)eQ;iFQ<7ajkh0vlLgIRk^kZS=f(K7ZQ}ab$}5K@ z|BS5seD(bf!B?M<{LGO((ax_YqII8I(La|aqCdZSF#6gjEz!`ot&1zyuP=42=u6@B zyI-U(T(myxcq4Y}XuDPY&f!?s*_#LUSoAj~sVe8HvYj2p% ze%3t47czurL7pHHyELc!!Lx{?eBeC#PbY3p`GBYVi){*2HMWH{a;$Ux&gA4vqmysi za)FI(5&C6fXT~ngncR8dHTU1kFu+;bdgosT&)fJLWq!jk5_>+39zzKa(MldeIgz{r x#_Thh5AT-;E&ne)2=dyG>wY@1i3hFnU!{lEgXnjX=s)!!`eh}L3jBWgyE{(V+baM7 literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512020700SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512020700SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..fa10739c1d6e38eff7602d431b54b5edb7caa9d5 GIT binary patch literal 9105 zcmeHMO>A355Z?Ff=h*4XAB~d~m9!9vf|NM6>(CO(>3i4?iQ?Kx%#S!!Ce$y=L-}cA zQ;;~MmmCUQP*ubMiHLH89uY{8(gUg}LP)5JgrJBPE;%3&T#yhI?Cj1Y4>yjBgxZ33 zt9W*HW_M@59lJBLr$*AlO^tUqGHAgd^RrgbrH?zT7?yt?vd)#IE!0{ExcRweHyD?fp~KaR5jMjg8W}Gml|JOIOZ%? zT&K*(ck(|tk=TsW6V77UU6@bCd*_|X(b9A>5jhY^^v;x~2a>T!EFOvWN|Ua^Ox_-m zgjTrTVcX)UO%YA&0-2`CwI#BQ5%rm{X={+9EtasvSq-)<5n?8qT&I`;;fSrK0DbN-mCerSlTjIKKT6uMQIk&kZ^v@hLF7=`beMlon z`;kVG#*oI5?njzHI)L=iR6Z-Z!i)aCAMA+$;teo1hVy(N^t26k!!hz+QUM&it-;Ii zzP#bh!O&(`^vEY@cn5WmnpJ!g^36!&(bzyN9*sv2M0sNzec6as%UkNm5w4AOs^_=W znJ*la>(tsGzdJSM?RC}<*O7PBk$0k;?uG7Md||n)dVE(6eH>;hbRjgLs6s#?pb$_9 zCy)5Ksu*QUqirhL>Qruf()N>0=kK(?H$}f3ge^WJVWsbzRpeBVNOj z0ciNeysacup;^U5c7-yqHgoj0HsEtNBUaUvcN0HO$sYNW~AoGwYnV-p!};w(`g8>B>~usYrI4 zPqMAVm!5}O8tPI`U2EzMwIQsVk*!3@Tw13k++Fxo{?Ge{-utC_=!^4xL!q``lhM+}u09k33ITz#A4A|KBO=?;twC(C%dI7q=t$@F4$}zCH1r2;t~~rRtva_2?%e&Xe)( z#7BEWAvC7P$d*yb6&wlxlU&N>t z9-~fXhBK3yTq;wPF=_{27Gj{%)a{8E=~P6k<3&27JPTu2!r^7GQ1h<;hgqr$&``psX%p4(FZ literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512020800SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512020800SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..3cd1680310b8d86a7f8d8f18616a4757f0f3d3cd GIT binary patch literal 9105 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 literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512021000SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512021000SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..203df94f34e9613e21b14bbd0f3116080f7586f3 GIT binary patch literal 9105 zcmeHMO>A355Z?Fvp7WBv{FKH?ib~oNi2@47b`w&frnRx1Cd9Fm7+P_tOsHR!hmy37 zO@+iEz2s0N4yY7y;1CcJhtdldK-8!QROk^^kq{JU;gSP_0|%g@f}P!&^dbrzJ>q6iNt1{o^a+%?$Nn{SofS$K2n?-=n40Qd%CBKQ@sPxa5NTvp?eo!ST3s`-|C}}!)%Ezga#B<2q**;0tx|z zfI>hapb$_9CWmJcjuc0gCxb&WFOWh@zh zh9TyyC!q>W1rymNt__VUG#gZ_#z0SF&D@R-wpNMB4CkNXHgXy42l*@Hs8m~$_LAL_ zlBHm9yleWUTykh6C=y@IAbq3k&N|DOt&@<7ABHpIoVd}+r}MV-#~Z2gWXUN@c7so{ zt;m<2gIXHuQcmqR^`_bo*3HOPqGT?u(;Vu&40Q%NFXaAS9%=<%9Z?4w^x66Azx?*mp}@D5i@!hp$-cJ_?)`D^ z?tPgLK8%07>$$|W!(H+Em&X$iow>UIk@%jt_1^BpuC~+hcOE+zUx}LuvAFtB2q**; z0tx|zz<&&ZTa5E=dT}#bD87T}1Vg)%{x5Ea@!>)KFMVg?IT6Cq154FC=_`>>MVu$& z-PLC+Q#{VmD@Sk}Ow$Z{{i-h=nRZLF1-Doc62^i!pB6BS&av|J{+)8W{^!3qZ-^MR z%wyDv^k8}-olT|-GDdCV%R&rPoV+vfBAtq8b-YMtlxJb=N+`4_{ipwy@`TMhwy(Zn zwp*-yfiGkV&w@NbB6eZHu)wp3qkP~T`p<*7IpqVo|BGz~R5iAVwQ{TrgYL}C!O58y z9J#=Hwg`Qn*qN~l3pRINc+LIyG7NB*&i=(i;CbtRqwFs^MqLpymIi2SHwYw&{oC8+gzP|5dtcJ&1lMiT+a$qF+|>sL=J#zy1q*d*3nu literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512021100SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512021100SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..3b07f7aae031a626143db8bacb296774b04bf002 GIT binary patch literal 9105 zcmeHMUu=_A6u)2FulqK>{Xy1k7#!dd0W)h`heDHO{cJloSK6^66LqO`{g%~i1J+7R zd>Dz@1HKr87!!Qh18>SRMycV!5J*S}Axn&+Zs5Zn48|uDBhh>AJ!ktY`&LX0pt+Z< z=bn4cz4zSTJuT;)d!jGVTVMBR9fM{V%*UEUmp=Z)_CbdnA)e%~Q^$p7`VvDPbJ6p- zkb8Ahqh%^-orh_l(j=_7{Fqc9$64GuY=JGJ@6}l43dEZOpsKM3X7GQxbbN5;@DY2a zRIrPDd=vkJ6N$|@J!a1o3x}t>Bc0QBX)Hh9-4%Q;*ws0aAK%>_4u&JaP^UC$31;&4 zyd<>3ofgXyN39QPS{ukTO|C7GWsIoTgiV_aj<#4LCeEs}If)Q6(IlVH109dhW5B~qDA$oZa$XiiP_d@qBzOY*st`~J zCy)5Kssx1QY`I6#-d^;U$>$D>2Pb`q<3tG?4egpDY6yOmBm($K%l` zBVNFg0ciNdytO1$p($e`JI}SDQH5rmYSkd!Hvh-RiPC7% zE=hKsPqHn~m!5`N8tPI`?KbtU+7Q;w$X23cF0IoTXul4120Aa~{!Sih1x_BW#L2_y zojlYgoIIrVP9FMB9%?C09`474??7x8K@zYO&|3*q)g2*)!ITmXonF&z_Af$8<|9u09k3 z3ITz#A4A|Cg< zB1SFo7>OrkS9pQF3kE2@GRmeA2^HtvlBO`e8A)WVw(b0jcs7f9P3%Ss*<`2Es%e*q}% B;xqsN literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512021200SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512021200SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..1cd6c09276c384e99c57e4713c110a5a9ae232da GIT binary patch literal 9105 zcmeHMO>A355T0lIIZpcWQyM!dDrq5tf)tExQd%NKv9TQz#kJEIs5lfi&3h(BN!rGy zLU2efIg}eJMI1QffYbx@z^Nc&Q~^cwh^j~k3T@$%6C9Bc73}QJBo8-^i-g*OcB^=H zc4l{Hza6_Xv!_Q=!>uj%w*a<40DRCPyZrGdwYPfJ2=gpI%AGniH|@oOULI1V|{Z@Wy&rN_J{X}`}?Nt;=aLXI2sE_`jkmGaHeR_D8eh; z3?&lssI6hc=th}gsI?Wc08G6WZrTwLXv-zy@~kE-DTKfxlYCMSbv#lJ76bQT$7?Ln zz_=O*#-gb{77h%J($ksM|0UiKAFg*!FmK`2AFbIHgPa5 zl;teHYgTE_c3uOkAMHf6Es3@Su|HLsE!jdBPphtOkKi_T#Qxa>=H-{jgaXl{L??+J zBRWOYCh8C^5`CHIv&mdWcBL2neLvij0HhlL7^8V!6uR2FyU`eXFRLI9?$+dHL|@(T z#$fYCSN7N^cz7Fkh*~v#EAeeaW0B~-Xe<&Ff1-gvUp1z+^7aODf@^)9+WFfX%$E)- zbn5L--<`Vh&IaoT8^}Wqe6nq} zSb7d?X{5_Jb-k&#)P|^T#K;pQ>5 zck|eH^H@u9^LRgQ9&05{R~4wgoED`t(SG_(6*PY({@OcF%ke8a`yaMfg0XYe&o5oNkSm_6K7Z|tmDfKB4Q8TmSAYCyu{yLc|C#^r;!x(o z$MH}19!uOf(i?An^HAckv)6|nj~|E!K72BUoQn{nPPFK%WB$9EW=P-wSU|HbVHJv^xYrSDEWCqp=XV5zw$&syY58Rw~Zcm3JQ zl#g@#%HiLI(+nTKel?e;rc347LdmX534ovG^8%*roTy9>J*c)Dc;%ZFpNvr}B1WA^ z52q*6*<`w)V$_gW7GofL^6tcod@823@gkp5odw`(Fu0`rXW+K-gzbBFufJh-1)ys| zEM!X0!aPACc5%TMK+j^1^MUi^KabMpoDX>Fzu0C_)qri#DX=aKmu6;On4EdlQ44Hl zi`1_ZI|E!?u!QsCYwo|7VW6}03@jZ+&)fVPWqm6!l6&5Z9>WO_(?%Y{Igz>p0Ow5Z ty*uSWtN%+6!o2o_wx3UK;X!NSSLvShApV_X`cFNGe_7e1g1>+L{a;CN-#Y*R literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512021300SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512021300SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..99b1078b63142ed67c8067faa1903a7c41fc0966 GIT binary patch literal 9105 zcmeHMUuc_E6u)1RFHO6zf99IBm9?7|okERCn&~VHO-xc-nk8K$iVq{!k?i1_!HafgK~s;l0QqG1~fCCn06TJj(dgN zsiPV#Q%~C*OaqlJVa26>sXmLdxOLdPdqv-=vHBH=Hzq+sD9v$R}uc7j=*tb$mPW9Y{lg;K5)h5DE?lcw-!W*@)K5JDbQ6uFZAo=kIPZ zUpOe&X|z9ncN)sOo2>6`BKI|s_n@5ah3;K^VY#e+ysv>i4zm@y5E@WaA)pXY2q**; z0tx|zfI>hapb$_9CVI z9#VTd4}CiiwG=xK_haXwR?>1sg8K7mUP|NbyWeC%^B3g5ed94PetD0$e)iQfMR7?(45r-wsE9e7C>mE4_dCQHW+Pv^=RzDv+JV|MGr+i=Z9kld}pHP9=Q_Pah{BK zH=nI^@i<4X9PYg^O>@!fS8Mrr!79(?tb9#K7<1!%T0qa63zfp?J#xE|6JM;lM2uSD zG3s=3EIFM_$CEi3qx$%=5Ci3BZcn^Ory^P(FVY$1Ss1(G^;V_-jNDY7uzUZ$%{R;* z59?Xx3+ckMAWx8pU0il~z_W;>eBc85&jYwQk}JGh-K*4eq?~n)~l%7~m`eBh{zD^S1v+8DDaY#GZGe$56sUw3)|HP9*Pu xG4o93ty|?mYyV3Rg1q*A355Z-6M=Q!!hPf47lsH81Hw4h*Y<3fpI#m06>6xU8;1maM+p?*;wiqj@` zL!n6NC5Iw$KvfV24moftt;7uk1XTjj_E=RxRa-;@mz>~)kSZ#=vpbVK+`PC*s4Zx> zif3nMc6avMu{$$+YA`j>*zjlrgXZ@$owbNAef)*(gKjxOJjoAH$A#twQ==a9rsr`X z_Zp~1%T&__57R)UMObm^F{wU|v$%EG0^3F3tFh`8h&P8pRbx%e&;J#&$&r~ON3EHP zZI$_WEB}KNiOo2jwPwopk*QduXUeJ^E{?~d!54zjo{8f4-dH#ojs!zJ(xerb$=gek z&=5du|>`2-fpOd_A>Je&kzCJa(T`_tL{P%c}@Cli@8GoJ*R#tbnl zo7kV`%3_w!G0UDRTF03g1v>$4Q=lzCjHc|8UF5oOT6uLlIk&ze^cVISmuAp}GSUjt zV@PL_zJ>HS(zlVmgY*Q_my@}S=n60T`+l$|0*E)j*f7rXg3!^{+zrRbdr1XwaJD)p z!~61v*9Ys@yP`)vLBm_9gVe0z8h9jX!I2z)Oar9*)S}kv`AxF5@)~TMq zwZ?qmpj^jofBf#a%G+wJAE+U3uOaV1Io%80yZFL#S@rlf7kwONi*zA0pr}GXA)pXY z2q**;0tx|zfI>hapb$_9+*br-C5D$^Hm}6ALFr=~uhT%@3xBc<;AciBbUhxAMj7!k zmJC2c7xOlfP=#g*6WK+s4UH-^n^dbtKu=@M+>TDRUWv&JDPeS_u^yKtt|cX`jZvCp0;^}TCM_f7Y<#;$cQ^ksh-UOKbu_iw%| zKi!}C{EPTkyWdEx9PEzQzjq+<)WXgFXX5+f{y) z5Kssx1pZ?P++&<~*NdCcLh&6$Cm7nDbboO>hz}3)f9VGk&xsI@9$2dG$+H^zPQ-aK z-d%gPGQ{H?y>j@r!!%8&*RT5W;R(B3D%iy(Az{pi^JxL2XdSIg^zV|}^}c!eYhA>s z6&|CGrU%la>1;AxkTGgIUlwAZ;@E?U7wJ?)tK&sFqdW^^Hv)lq=|8>qlqYQ6xnu1O zv%}9i=J-N}@GQs^Bx2|1bU%0&ag-07L;u->n^QjEaeuMRfU3r}ur`i$VZff8e06N{ zm?an3$QGgR5<4??e$M313$MBVUWNhA($zcv8hGBu-zf7c$4Kn?FnSCnJVa}G4CO@f y4j8je=RUq)9<=HC@%kO|72ab2 literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512021500SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512021500SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..19d00fc01877ca86df17fc51d5a114d16be0a47d GIT binary patch literal 9105 zcmeHMO>A355T0lIIZpcWQyM!dEomVVrBX1qNuWe=YS(sf8rM!^1mX~xP`@ZfiJQiz zLgFXk$A=U92W_-1--4} z+1Z)ho&9#~&di=l#)q1l?r#EY9uK&nO?LU?PipUXs}bf|{sMPu&`dHu<}j`~9+GmW zPHMbNHEnW$hAM5+isc8C`XtQ~)=~5BmVKuN)hjS>jG(FpE#MLVa_QLU-0@j+u3Run zVtj}A!xPEP1U+fal?um;;ZRS}EFa5HhI{=_`g?n(@{@hxpg$P$2YQrA*Kww3hZNxz zZu+88dDLdVrgfrB)707uSpcR^12=8+2(;xA5qVY}DheSm$RwB4Lmh|Ig9Xoh*l}tV z8W>gMz*scY#v*{K8n`7Eu~amh6+E5~JQX%f_Oq1Q-vaOaoocN=J_* zgtDCFw#+IN^X4mH^rD@Jwjt4$Aoj)!Gljg+#nY;*+bg(@9kGArfWG`1neaN%H;B#? zT_E}<(YJ`cP4pe26{1haGAY@WUiA0FrW1ryRZQLPhRPoKkw-5~lf_=eIAQbEihz0_E)tFYxTkFUPuJv`Q=Wnkw zUplDJskJ|ScWTPp>#XmsBlp#jcaWU#h3{Q{VTG)Ed}j@P8iqx_5FW6pjew1Sjew1S zjew1Sjew1Sjew1Sjew279YsJ@VnhjM>q<;R?+~N@N#>Ha4!%Y*DQmMLi8#g&m!+QHe#qr?>K0 zo3Qej+FN<-TY0RdSb4l3E0493hN}wHUrvcqnrJtEQw7amiT~+?r{ws`4tf3X-SbBk z|Cp-$T>fE?Yeq~_);Nfq+99X*I8(g|9=&t2~AB(%f$?@6n;9*!glx+Uu#;5NM zrat>Ta(>^7(d*;gk;ZqAM)#k&cJR^2fr#gm$D{jvrz2;dI2T!q=ux@2{b3_uBVZ$7 zBVZ%&A4A|a>mzm?tR2F3r0<=vmBhK5&lw=MmbR^8rWg7uyu7YOoF31=hKt!u0gB6Vor7 zYJtsck@_`aXMjudhHzed&HeW>40M*R{>pRcd7FQujBf=-a?g9wV>sbqTF+xRCsKC+ xV4lu=bf-LM^?&I>nAd*X^7Dx;JZMe)D&4al#J`hF|EUM@FDrYL_xG>A{|h&=-Yx(D literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512021600SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512021600SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..21aa7bd215a84be2267d83fa40f091c9edaa2d37 GIT binary patch literal 9105 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 B;&uQ4 literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512022000SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512022000SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..89499a16fc813369082d0291d6daa3083f5a2012 GIT binary patch literal 9105 zcmeHMU2Gdg5Z*iAIZk@{DUFj9m9!-iEmAO!aiK)Sy~B2zD6XBx{HPMG3H3!WO41}Y z6%r5WOCHJ_s)~33DMAPd(ehg;Qh$*uL?2O!K+uY|yyOWUKtcklva>sr9Bv#J3AF|7 zR`KlY%+9~WW6%NtX0RsFrH|{_Ug?k{#FPA4>QtbazQmAjUDodv za-WH6v`jgz)0qY;O~Q)v_ek{-oW-rf7F;L#K8=;HK)f{osv2ux0sb$Sjt@@nn{=m3 z1-Hn@*YH0$k=TsW{qA(Juy3L#(mCOl_U1==qM=7Z(azEQ$d;b2P*)@r?vy57ftkEL zE(xu0t;KP~QR_pR)&??7lWR+486)bmVAG}mM_Vjmi?f<+RwBeKG|3QpprZ>tb|7#U zbbQ(@4h+h1Mp)ET#v%-=8uJS*;wdMa6R42^O0Wg}WHZ>%CmxE9wb zpTD}weBq#6r_%oT-Ki*VuCjixioB(YycOkiFLdwX3(IBY<7+GE<1m|}3!wo;6#@zY zg@8gpA)pXY2q**;0tx|zfI{GwA|NX$*l6 z@jR9cK*JF8mXlD0<`gEfb6gu5RcKbIRtTZxjnv`%BN{Q}e(=)92odwHl8czL)IFAt~p z@=%-b@{rnldFXq2sHJ#$xF0VMwUU~P64aj#@=_XaSAUZQ&7YC~;nhdQ_=Pp%`q_88 zc1r$1S^4?m(t5$yPDy^x^-Hm<_0d@WH^0WVo6*=aQ%}ZzN$-liJ^4;-&zqm0-hA$l z$I@TFaVB;AGyBA*=bS6MJM7w*cRKeUzP#-Ld#fEd@{qHs<&gc>!$<7}+jPX@>O&!* z5Kssx1QY`QF$8Wh&b#5o&1|Ch4x$qb?G99aaodd#5AuKM+Y`@;5RM*L%I-;D2%i&i zo{V=FpRG*sI7hD>{&g@-GwAiJwzzk+P#n({@~4D^F+a|y10BfD$3z@>RAWx8pot-fP;90~`K5!KMXESb2`G8*e#Wn@18e7GhIo7$}!r0hT z!(%VFa)IS+5&9KkXU5LXSloHxHTU1kFu+;byJw#U&s+W*Wqr#r5_{f>9zzKa(P|z; zIgz{r#@s`h*Kd^v&Hpbw2=dx@8-AQx!Gjj~uhJdsLG(LG^q+bV{j!or1%LnY`@aC7 Cq~UJ> literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512022100SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512022100SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..829e37a650cfc646c7bfa0c75ab6149bd672468e GIT binary patch literal 9105 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 A%m4rY literal 0 HcmV?d00001 diff --git a/test/unit_test_hyfeature/channel_forcing/201512022300SCHISM.nc b/test/unit_test_hyfeature/channel_forcing/201512022300SCHISM.nc new file mode 100644 index 0000000000000000000000000000000000000000..44f29c9f263d76654125f2bb12c6d73a9c6ff2f0 GIT binary patch literal 9105 zcmeHMO>A355Z-6M=e(pZKc#V!qLQRUq96t1IB6-7;`(7bB#LXNG2-V?nNYtd59Ozg zO@+iEz2s1Cs4C(BQjoZ{IUo*zAgEFiPzfj{L_$!Yg-cFwL?EiNvpbVK+`PC*s4Zx> zif3nMc6avMu{$$+aws)eUw3yMgJzmcXHB9@AJ?(H+$BedC;2nf@u9h))L6i}61Z2$ zg9fV6GL^J0z%)>45>{NeN2*WYEN&gP@Gj90YOHbv;;j)-)mQ^F`M*LoIXX9c)R`;0 zPKl52;D2x;u^Fewow<@bJ2MdLo^i@YiW38Uk%uFF-IK+My#qawo>(N>Els)#GkJSd z5?bL}i*1Xe)<-n04P=@o*OtgKMl@)_rcEYCTP%?fXEoS@M2J~vk}mW>Cm{6L3G*)K z1hoYm7?tCUu&D9JA_}S+3kfWe89SfnJe&kzCJa);2h-X7a4uWOC+$p{S@(fVV}_WO zwGXDbvX~X}%yMUn&I`=y13Lk2OQ0=4>`S@RZjtN4Y30>*a&BWs=%3ziT=)!4_#EjM zNG~G&66qzRUm;yV`Zdy3q>m+Y8POG9^!NQ>PXrKefUyyr7X+cFt-BkJk@u1c;NWdF zUWWJO4Q~wAZgfSDe1e9zQ3t72!Pg_-fHW5E+1nF~#$vru-WW$;HlmgC#wv1zYki%{ z`P-|^7Y@pG{PxH1j<3AA%KG6d@|G&{R+Q7d(7lT~<6J3)p=8{7rA(8lMI_c|WciLISY@LKu{Lq~#=lHdDKApG4KVMCi$4gFG zvRizTZAHHH4Ajz4mvU;qsW;Syux>`S5+!qKoyKtc3e*|sypa2Qd8ie5dAJfU52yF? zP@C}bklK5B=zDpnrFeO`A1@EJlA6mB)L%~WQW|eR{U!^VzaszRE02irl^x>x*|$$0 zlKexm^7HZc9fGetCi(8pi}6`)DgJx!5AoNppN*esdoOM-za8(0o{zuv$-WQUpNcFu z1m76Qyz_42{XNgxR}Xh3YF|2JKXCfWfd>=&6Xw}odr!-$#GCt;5^D*=7K^J7g@8gp zA)pXY2>izoxXC#0h8H)ZiQ+qmPB64P;s4@x7#|+w|I)W7o)aM)J+M^VQ(!Ink%;qT zyu1EvWr)W)dgTc1f@zvguV1yLBa?1vy5JU`ILZf>(0}g7%_$!U_`ld@KviSgSTo1EFz8NAJuyD@ zydxLb%od^V6FW0@Zr7|My{ z9Wdsc%Dr~0JZSZQ=|Pa!o@w~`*cKkN#($OWSP!D#NuvMMgXou)JSzOhr{Dbr