metro_model.py 16.7 KB
Newer Older
1
2
# METRo : Model of the Environment and Temperature of Roads
# METRo is Free and is proudly provided by the Government of Canada
Miguel Tremblay's avatar
Miguel Tremblay committed
3
# Copyright (C) Her Majesty The Queen in Right of Canada, Environment Canada, 2006
Sasa Zhang's avatar
Sasa Zhang committed
4
#
5
#  Questions or bugs report: metro@ec.gc.ca
6
#  METRo repository: https://framagit.org/metroprojects/metro
7
#  Documentation: https://framagit.org/metroprojects/metro/wikis/home
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#
# Code contributed by:
#  Miguel Tremblay - Canadian meteorological center
#  Francois Fortin - Canadian meteorological center
#
#  $LastChangedDate$
#  $LastChangedRevision$
########################################################################
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


Sasa Zhang's avatar
Sasa Zhang committed
31
from executable_module.metro_module import Metro_module
32
import time
33
import numpy
34
35
36
37
38
39
40
41
42
import metro_logger
import metro_config
from toolbox import metro_util
from toolbox import metro_date
from toolbox import metro_constant
from data_module import metro_data_collection_output
from data_module import metro_data
from data_module import metro_infdata

Sasa Zhang's avatar
Sasa Zhang committed
43

44
45
46
47
48
_ = metro_util.init_translation('metro_model')

# To call the C function.
from model import macadam

Sasa Zhang's avatar
Sasa Zhang committed
49

50
51
class Metro_model(Metro_module):

Sasa Zhang's avatar
Sasa Zhang committed
52
    def get_receive_type(self):
53
54
        return Metro_module.DATATYPE_DATA_IN

Sasa Zhang's avatar
Sasa Zhang committed
55
    def get_send_type(self):
56
57
        return Metro_module.DATATYPE_DATA_OUT

Sasa Zhang's avatar
Sasa Zhang committed
58
    def start(self):
59
60
61
62
63
64
65
66
        Metro_module.start(self)
        pForecast = self.get_infdata_reference('FORECAST')
        forecast_data = pForecast.get_data_collection()
        pObservation = self.get_infdata_reference('OBSERVATION')
        observation_data = pObservation.get_data_collection()
        pStation = self.get_infdata_reference('STATION')
        station_data = pStation.get_data()

Sasa Zhang's avatar
Sasa Zhang committed
67
68
69
        if not metro_config.get_value('T_BYPASS_CORE'):
            self.__send_data_to_metro_core(forecast_data, observation_data, station_data)
            roadcast_data = self.__create_roadcast_collection(forecast_data, observation_data, station_data)
70
71
        else:
            roadcast_data = None
Sasa Zhang's avatar
Sasa Zhang committed
72
73
            metro_logger.print_message(metro_logger.LOGGER_MSG_INFORMATIVE,
                                       _("Bypassing METRo core, roadcast not created."))
74
75
76
77
78
79

        pForecast.set_data_collection(forecast_data)
        pObservation.set_data_collection(observation_data)
        pStation.set_data(station_data)

        # creer et ajouter infdata
Miguel Tremblay's avatar
Miguel Tremblay committed
80
        # Creation and adding infdata
Sasa Zhang's avatar
Sasa Zhang committed
81
        infdata_roadcast = metro_infdata.Metro_infdata('ROADCAST', metro_infdata.DATATYPE_METRO_DATA_COLLECTION)
82
83
        infdata_roadcast.set_data_collection(roadcast_data)
        self.add_infdata(infdata_roadcast)
Sasa Zhang's avatar
Sasa Zhang committed
84
85

    def stop(self):
86
87
        Metro_module.stop(self)

Sasa Zhang's avatar
Sasa Zhang committed
88
    def __get_nb_timesteps(self, forecast):
89
        wf_data = forecast.get_interpolated_data()
90
91
        npFT = wf_data.get_matrix_col('Time')
        return len(npFT)
92

Sasa Zhang's avatar
Sasa Zhang committed
93
    def __get_observation_lenght(self, observation):
94
95
        obs_data = observation.get_interpolated_data()
        lTime_obs = obs_data.get_matrix_col('Time').tolist()
Sasa Zhang's avatar
Sasa Zhang committed
96
        return len(lTime_obs)
97

Sasa Zhang's avatar
Sasa Zhang committed
98
99
    def __get_observation_delta_t(self, observation):
        return observation.get_attribute('DELTA_T')
100

Sasa Zhang's avatar
Sasa Zhang committed
101
    def __send_data_to_metro_core(self, forecast, observation, station):
102
103
104
105
        wf_data = forecast.get_interpolated_data()
        ro_data = observation.get_interpolated_data()
        cs_data = station

106
107
        # Start time from model is the last observation
        sStart_time = metro_config.get_value('DATA_ATTRIBUTE_LAST_OBSERVATION')
108
109
110
        fStart_time = metro_date.parse_date_string(sStart_time)

        iModel_start_y = metro_date.get_year(fStart_time)
Sasa Zhang's avatar
Sasa Zhang committed
111
112
        sMessage = _("year: [%s]") % iModel_start_y
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
113
114

        iModel_start_m = metro_date.get_month(fStart_time)
Sasa Zhang's avatar
Sasa Zhang committed
115
116
        sMessage = _("month: [%s]") % iModel_start_m
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
117
118

        iModel_start_d = metro_date.get_day(fStart_time)
Sasa Zhang's avatar
Sasa Zhang committed
119
120
        sMessage = _("day: [%s]") % iModel_start_d
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
121
122

        iModel_start_h = metro_date.get_hour(fStart_time)
Sasa Zhang's avatar
Sasa Zhang committed
123
124
        sMessage = _("hour: [%s]") % iModel_start_h
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
125
126
127

        dStation_header = cs_data.get_header()

Miguel Tremblay's avatar
Miguel Tremblay committed
128
        # test observation
129
        dObservation_header = ro_data.get_header()
Sasa Zhang's avatar
Sasa Zhang committed
130
131
        lObservation_data = ro_data.get_matrix()

132
        sMessage = "Observation_header=" + str(dObservation_header)
Sasa Zhang's avatar
Sasa Zhang committed
133
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
134
        sMessage = "Observation_data=" + str(lObservation_data)
Sasa Zhang's avatar
Sasa Zhang committed
135
136
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)

Miguel Tremblay's avatar
Miguel Tremblay committed
137
        # test forecast
138
        dForecast_header = wf_data.get_header()
Sasa Zhang's avatar
Sasa Zhang committed
139
        lForecast_data = wf_data.get_matrix()
140
141

        sMessage = "Forecast_header=" + str(dForecast_header)
Sasa Zhang's avatar
Sasa Zhang committed
142
143
144
145
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
        sMessage = "Forecast_data=" + str(lForecast_data)
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)

Miguel Tremblay's avatar
Miguel Tremblay committed
146
        # start roadlayer MATRIX
Sasa Zhang's avatar
Sasa Zhang committed
147
        npLayerType = cs_data.get_matrix_col('TYPE')
148
        lLayerType = npLayerType.astype(numpy.int32).tolist()
149
150
151
        lLayerThick = cs_data.get_matrix_col('THICKNESS').tolist()
        nNbrOfLayer = len(lLayerType)

Sasa Zhang's avatar
Sasa Zhang committed
152
153
        sMessage = _("Number of layer=") + str(nNbrOfLayer)
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
154
155
156
157
158
159

        # Append an empty box for the manuel mode
        lLayerType.append(0)
        lLayerThick.append(0.0)

        sMessage = _("roadlayer type=") + str(lLayerType)
Sasa Zhang's avatar
Sasa Zhang committed
160
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
161
        sMessage = _("roadlayer thick=") + str(lLayerThick)
Sasa Zhang's avatar
Sasa Zhang committed
162
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
163

Sasa Zhang's avatar
Sasa Zhang committed
164
165
        # end roadlayer MATRIX
        fTime = dStation_header['PRODUCTION_DATE']
166
        fTimeForecast = dForecast_header['PRODUCTION_DATE']
Sasa Zhang's avatar
Sasa Zhang committed
167

168
        fIssue_time = fStart_time
Sasa Zhang's avatar
Sasa Zhang committed
169

170
        sMessage = _("issue time=") + time.ctime(fIssue_time)
Sasa Zhang's avatar
Sasa Zhang committed
171
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
172
173
174
175
176
177

        wforiginal = forecast.get_original_data()

        ft = wforiginal.get_matrix_col('FORECAST_TIME')

        # Forecast
Sasa Zhang's avatar
Sasa Zhang committed
178
        # Get the interpolated values.
Sasa Zhang's avatar
Sasa Zhang committed
179
180
        wf_interpolated_data = forecast.get_interpolated_data()
        npAT = wf_interpolated_data.get_matrix_col('AT')
181
        lAT = npAT.tolist()
182
        lQP = wf_interpolated_data.get_matrix_col('QP').tolist()
183
184
        npWS = wf_interpolated_data.get_matrix_col('WS')
        lWS = npWS.tolist()
Sasa Zhang's avatar
Sasa Zhang committed
185
        npTD = wf_interpolated_data.get_matrix_col('TD')
186
        lTD = npTD.tolist()
187
188
189
        lAP = wf_interpolated_data.get_matrix_col('AP').tolist()
        lSF = wf_interpolated_data.get_matrix_col('SF').tolist()
        lIR = wf_interpolated_data.get_matrix_col('IR').tolist()
190
191
        npFA = wf_interpolated_data.get_matrix_col('FA')
        lFA = npFA.tolist()
192
193
        lPI = wf_interpolated_data.get_matrix_col('PI').astype(numpy.int32).tolist()
        lSC = wf_interpolated_data.get_matrix_col('SC').astype(numpy.int32).tolist()
194
195

        # Number of 30 seconds step.
196
        npFT = wf_interpolated_data.get_matrix_col('Time')
197
198
199
        nNbrTimeSteps = self.__get_nb_timesteps(forecast)
        lAH = wf_interpolated_data.get_matrix_col('AH').tolist()

Sasa Zhang's avatar
Sasa Zhang committed
200
        # Observation data
201
202
        ro_interpolated_data = observation.get_interpolated_data()
        lAT_obs = ro_interpolated_data.get_matrix_col('AT').tolist()
Sasa Zhang's avatar
Sasa Zhang committed
203
204
        lST_obs = ro_interpolated_data.get_matrix_col('ST').tolist()
        lSST_obs = ro_interpolated_data.get_matrix_col('SST').tolist()
205
        lTime_obs = ro_interpolated_data.get_matrix_col('Time').tolist()
206
207
        # Deep soil value given in command line
        bDeepTemp = metro_config.get_value('DEEP_SOIL_TEMP')
Sasa Zhang's avatar
Sasa Zhang committed
208
        dDeepTemp = float(metro_config.get_value('DEEP_SOIL_TEMP_VALUE'))
209

Sasa Zhang's avatar
Sasa Zhang committed
210
        nLenObservation = self.__get_observation_lenght(observation)
211
        fDeltaTMetroObservation = self.__get_observation_delta_t(observation)
Sasa Zhang's avatar
Sasa Zhang committed
212

213
        # Concatenate the information to send it to C.
Sasa Zhang's avatar
Sasa Zhang committed
214
215
216
217
218
        npSWO1 = observation.get_attribute('SST_VALID_INTERPOLATED').astype(numpy.int32)
        npSWO2 = observation.get_attribute('AT_VALID_INTERPOLATED').astype(numpy.int32)
        npSWO3 = observation.get_attribute('TD_VALID_INTERPOLATED').astype(numpy.int32)
        npSWO4 = observation.get_attribute('WS_VALID_INTERPOLATED').astype(numpy.int32)
        npSWO = numpy.zeros(4 * metro_constant.nNL)
219
        # Put all the arrays in one for the fortran code.
Sasa Zhang's avatar
Sasa Zhang committed
220
221
222
223
224
        for i in range(0, len(npSWO1)):
            npSWO[4 * i] = npSWO1[i]
            npSWO[4 * i + 1] = npSWO2[i]
            npSWO[4 * i + 2] = npSWO3[i]
            npSWO[4 * i + 3] = npSWO4[i]
225
        lSWO = npSWO.astype(numpy.int32).tolist()
Sasa Zhang's avatar
Sasa Zhang committed
226

227
        bNoObs = observation.get_attribute('NO_OBS')
Sasa Zhang's avatar
Sasa Zhang committed
228
229
230

        sMessage = _("------------station config START---------------------")
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
231
232
233
234

        tLatlon = dStation_header['COORDINATE']
        fLat = tLatlon[0]
        fLon = tLatlon[1]
Sasa Zhang's avatar
Sasa Zhang committed
235
236
        sMessage = _("lat,lon: ") + "(" + str(fLat) + ", " + str(fLon) + ")"
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
237
238

        bFlat = cs_data.get_station_type()
239
240
        dSstDepth = cs_data.get_sst_depth()

Sasa Zhang's avatar
Sasa Zhang committed
241
242
        sMessage = _("SST sensor depth: ") + str(dSstDepth)
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
243

244
        sMessage = _("------------station config END---------------------")
Sasa Zhang's avatar
Sasa Zhang committed
245
        metro_logger.print_message(metro_logger.LOGGER_MSG_DEBUG, sMessage)
246
        bSilent = not metro_config.get_value('INIT_LOGGER_SHELL_DISPLAY')
Sasa Zhang's avatar
Sasa Zhang committed
247
        metro_logger.print_message(metro_logger.LOGGER_MSG_EXECPRIMARY, _("Start sending data to METRo core"))
248
        bEchec = []
249

Sasa Zhang's avatar
Sasa Zhang committed
250
251
252
        macadam.Do_Metro(bFlat, fLat, fLon, lLayerThick, nNbrOfLayer, lLayerType, lAT, lQP, lWS, lAP, lSF, lIR, lFA,
                         lPI, lSC, lAT_obs, lST_obs, lSST_obs, lAH, lTime_obs, lSWO, bNoObs, fDeltaTMetroObservation,
                         nLenObservation, nNbrTimeSteps, bSilent, dSstDepth, bDeepTemp, dDeepTemp)
253
        bEchec = (macadam.get_echec())[0]
Sasa Zhang's avatar
Sasa Zhang committed
254
        # Check if the execution of the model was a success:
255
        if bEchec != 0:
Sasa Zhang's avatar
Sasa Zhang committed
256
257
            sError_message = _("Fatal error in METRo physical model.")
            metro_logger.print_message(metro_logger.LOGGER_MSG_STOP, sError_message)
258
        else:
Sasa Zhang's avatar
Sasa Zhang committed
259
            metro_logger.print_message(metro_logger.LOGGER_MSG_EXECPRIMARY, _("End of METRo core"))
260

Sasa Zhang's avatar
Sasa Zhang committed
261
    def __create_roadcast_collection(self, forecast, observation, station):
Miguel Tremblay's avatar
Miguel Tremblay committed
262
263

        # Creation of the Metro_data object for the roadcast
Sasa Zhang's avatar
Sasa Zhang committed
264
265
        lStandard_items = metro_config.get_value('XML_ROADCAST_PREDICTION_STANDARD_ITEMS')
        lExtended_items = metro_config.get_value('XML_ROADCAST_PREDICTION_EXTENDED_ITEMS')
Sasa Zhang's avatar
Sasa Zhang committed
266
        lItems = lStandard_items
267

Sasa Zhang's avatar
Sasa Zhang committed
268
        # FFTODO append all lExtended_items to metrodata
269
        roadcast = metro_data.Metro_data(lItems)
Sasa Zhang's avatar
Sasa Zhang committed
270

Miguel Tremblay's avatar
Miguel Tremblay committed
271
        # Extraction of forecast data used to create the roadcasts.
272
273
        wf_data = forecast.get_interpolated_data()

Sasa Zhang's avatar
Sasa Zhang committed
274
275
276
        # Generate the header of roadcast
        # extraction of information
        sRoadcast_version = metro_config.get_value('FILE_ROADCAST_CURRENT_VERSION')
277
278
279
        sRoadcast_station = station.get_station_name()
        fRoadcast_production_date = time.time()

Sasa Zhang's avatar
Sasa Zhang committed
280
        # Generate the roadcast matrix of data
Miguel Tremblay's avatar
Miguel Tremblay committed
281
        # Extraction of data used by metro_core in the computation
282
283
284
285
        iObservation_len = self.__get_observation_lenght(observation)
        fObservation_delta_t = self.__get_observation_delta_t(observation)
        iNb_timesteps = self.__get_nb_timesteps(forecast)

Miguel Tremblay's avatar
Miguel Tremblay committed
286
        # Extraction of roadcast data computed by metro_core
287
288
289
290
291
292
293
294
295
296
297
        lRA = (macadam.get_ra())[:iNb_timesteps]
        lSN = (macadam.get_sn())[:iNb_timesteps]
        lRC = (macadam.get_rc())[:iNb_timesteps]
        lST = (macadam.get_rt())[:iNb_timesteps]
        lFV = (macadam.get_fv())[:iNb_timesteps]
        lSF = (macadam.get_sf())[:iNb_timesteps]
        lIR = (macadam.get_ir())[:iNb_timesteps]
        lFC = (macadam.get_fc())[:iNb_timesteps]
        lFG = (macadam.get_g())[:iNb_timesteps]
        lBB = (macadam.get_bb())[:iNb_timesteps]
        lFP = (macadam.get_fp())[:iNb_timesteps]
Sasa Zhang's avatar
Sasa Zhang committed
298
        lSST = (macadam.get_sst())[:iNb_timesteps]
299

Sasa Zhang's avatar
Sasa Zhang committed
300
        if metro_config.get_value('TL'):
301
302
303
            # Temperature of levels under the ground.
            nNbrVerticalLevel = macadam.get_nbr_levels()
            lDepth = (macadam.get_depth())[:nNbrVerticalLevel]
Sasa Zhang's avatar
Sasa Zhang committed
304
305
306
            lTmpTL = (macadam.get_lt())[:nNbrVerticalLevel * iNb_timesteps]
            lTL = []
            for i in range(0, iNb_timesteps):
307
308
309
                begin = i * nNbrVerticalLevel
                end = begin + nNbrVerticalLevel
                lTL.append(lTmpTL[begin:end])
Sasa Zhang's avatar
Sasa Zhang committed
310
311
312
313
314
315
316
317
318
319
320

        # Adding the information to the header
        roadcast.set_header_value('VERSION', sRoadcast_version)
        roadcast.set_header_value('ROAD_STATION', sRoadcast_station)
        roadcast.set_header_value('PRODUCTION_DATE', fRoadcast_production_date)
        roadcast.set_header_value('LATITUDE', station.get_header()['COORDINATE'][0])
        roadcast.set_header_value('LONGITUDE', station.get_header()['COORDINATE'][1])
        roadcast.set_header_value('FILETYPE', 'roadcast')

        if metro_config.get_value('TL'):
            roadcast.set_header_value('VERTICAL_LEVELS', lDepth)
321
322
323
324
325

        # TODO MT: Le +30 est la pour que l'output soit au bon moment.
        #  Il y a eu un probleme dans la conversion entre le C et le fortran
        #  qui fait en sorte qu'il y a un decalage d'un indice.  Il faudra que
        #  ce soit corrige.
326
327
328
329
        npRT = wf_data.get_matrix_col('FORECAST_TIME')[:iNb_timesteps]
        npRT = npRT + 30
        npHH = wf_data.get_matrix_col('Time')[:iNb_timesteps]
        npAT = wf_data.get_matrix_col('AT')[:iNb_timesteps]
330
        npFA = wf_data.get_matrix_col('FA')[:iNb_timesteps]
331
        # 3.6 is to convert from m/s to km/h
Sasa Zhang's avatar
Sasa Zhang committed
332
        npWS = wf_data.get_matrix_col('WS')[:iNb_timesteps] * 3.6
333
334
335
336
        npTD = wf_data.get_matrix_col('TD')[:iNb_timesteps]
        npQP_SN = wf_data.get_matrix_col('SN')[:iNb_timesteps]
        npQP_RA = wf_data.get_matrix_col('RA')[:iNb_timesteps]
        npCC = wf_data.get_matrix_col('CC')[:iNb_timesteps]
337

338
        roadcast.init_matrix(iNb_timesteps, roadcast.get_real_nb_matrix_col())
339

Miguel Tremblay's avatar
Miguel Tremblay committed
340
        # Data added to the roadcast matrix
341
342
343
344
        roadcast.set_matrix_col('RA', lRA)
        roadcast.set_matrix_col('SN', lSN)
        roadcast.set_matrix_col('RC', lRC)
        roadcast.set_matrix_col('ST', lST)
345
346
347
348
349
350
351
        roadcast.set_matrix_col('ROADCAST_TIME', npRT)
        roadcast.set_matrix_col('HH', npHH)
        roadcast.set_matrix_col('AT', npAT)
        roadcast.set_matrix_col('WS', npWS)
        roadcast.set_matrix_col('TD', npTD)
        roadcast.set_matrix_col('QP-SN', npQP_SN)
        roadcast.set_matrix_col('QP-RA', npQP_RA)
352
353
354
355
356
        roadcast.set_matrix_col('IR', lIR)
        roadcast.set_matrix_col('SF', lSF)
        roadcast.set_matrix_col('FV', lFV)
        roadcast.set_matrix_col('FC', lFC)
        roadcast.set_matrix_col('FG', lFG)
357
        roadcast.set_matrix_col('FA', npFA.tolist())
358
359
        roadcast.set_matrix_col('BB', lBB)
        roadcast.set_matrix_col('FP', lFP)
360
        roadcast.set_matrix_col('CC', npCC)
361
        roadcast.set_matrix_col('SST', lSST)
362

Sasa Zhang's avatar
Sasa Zhang committed
363
        if metro_config.get_value('TL'):
364
365
            roadcast.append_matrix_multiCol('TL', lTL)

Miguel Tremblay's avatar
Miguel Tremblay committed
366
        # Creation of the object Metro_data_collection for the roadcast
Sasa Zhang's avatar
Sasa Zhang committed
367
368
        lStandard_attributes = metro_config.get_value('DATA_ATTRIBUTE_ROADCAST_STANDARD')
        lExtended_attributes = metro_config.get_value('DATA_ATTRIBUTE_ROADCAST_EXTENDED')
369
        lAttributes = lStandard_attributes + lExtended_attributes
Sasa Zhang's avatar
Sasa Zhang committed
370
        roadcast_collection = metro_data_collection_output.Metro_data_collection_output(roadcast, lAttributes)
371

Miguel Tremblay's avatar
Miguel Tremblay committed
372
        # Writing of data needed for the roadcast.
Sasa Zhang's avatar
Sasa Zhang committed
373
374
375
        roadcast_collection.set_attribute('OBSERVATION_LENGTH', iObservation_len)
        roadcast_collection.set_attribute('OBSERVATION_DELTAT_T', fObservation_delta_t)
        roadcast_collection.set_attribute('FORECAST_NB_TIMESTEPS', iNb_timesteps)
376
        return roadcast_collection