rapid2 2.0.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rapid2/__init__.py ADDED
@@ -0,0 +1,79 @@
1
+ # *****************************************************************************
2
+ # __init__.py
3
+ # *****************************************************************************
4
+
5
+ # Purpose:
6
+ # This file used in Python to define packages and initialize their namespaces.
7
+ # Author:
8
+ # Cedric H. David, 2025-2025
9
+
10
+
11
+ # *****************************************************************************
12
+ # Initialization
13
+ # *****************************************************************************
14
+
15
+ # -----------------------------------------------------------------------------
16
+ # Dynamic Package Versioning
17
+ # -----------------------------------------------------------------------------
18
+ import importlib.metadata
19
+
20
+ try:
21
+ __version__ = importlib.metadata.version("rapid2")
22
+ except importlib.metadata.PackageNotFoundError:
23
+ __version__ = "unknown"
24
+
25
+ # -----------------------------------------------------------------------------
26
+ # Top-Level API Facade
27
+ # -----------------------------------------------------------------------------
28
+ from .core.chck_bas import chck_bas
29
+ from .core.chck_cpl import chck_cpl
30
+ from .core.make_0bi_tbl import make_0bi_tbl
31
+ from .core.make_CCC_mat import make_CCC_mat
32
+ from .core.make_Mus_mat import make_Mus_mat
33
+ from .core.make_Net_mat import make_Net_mat
34
+ from .core.make_Wdw_mat import make_Wdw_mat
35
+ from .core.prep_Qex_ncf import prep_Qex_ncf
36
+ from .core.prep_Qfi_ncf import prep_Qfi_ncf
37
+ from .core.prep_Qou_ncf import prep_Qou_ncf
38
+ from .core.prep_skl_ncf import prep_skl_ncf
39
+ from .core.read_bas_vec import read_bas_vec
40
+ from .core.read_con_vec import read_con_vec
41
+ from .core.read_cpl_vec import read_cpl_vec
42
+ from .core.read_crd_vec import read_crd_vec
43
+ from .core.read_kpr_vec import read_kpr_vec
44
+ from .core.read_nml_tbl import read_nml_tbl
45
+ from .core.read_std_vec import read_std_vec
46
+ from .core.read_xpr_vec import read_xpr_vec
47
+ from .core.updt_Mus_Qou import updt_Mus_Qou
48
+
49
+ # -----------------------------------------------------------------------------
50
+ # Explicit Public Interface
51
+ # -----------------------------------------------------------------------------
52
+ __all__ = [
53
+ "__version__",
54
+ "chck_bas",
55
+ "chck_cpl",
56
+ "make_0bi_tbl",
57
+ "make_CCC_mat",
58
+ "make_Mus_mat",
59
+ "make_Net_mat",
60
+ "make_Wdw_mat",
61
+ "prep_Qex_ncf",
62
+ "prep_Qfi_ncf",
63
+ "prep_Qou_ncf",
64
+ "prep_skl_ncf",
65
+ "read_bas_vec",
66
+ "read_con_vec",
67
+ "read_cpl_vec",
68
+ "read_crd_vec",
69
+ "read_kpr_vec",
70
+ "read_nml_tbl",
71
+ "read_std_vec",
72
+ "read_xpr_vec",
73
+ "updt_Mus_Qou",
74
+ ]
75
+
76
+
77
+ # *****************************************************************************
78
+ # End
79
+ # *****************************************************************************
rapid2/cli/__init__.py ADDED
File without changes
rapid2/cli/_cmpncf.py ADDED
@@ -0,0 +1,315 @@
1
+ #!/usr/bin/env python3
2
+ # *****************************************************************************
3
+ # _cmpncf.py
4
+ # *****************************************************************************
5
+
6
+ # Author:
7
+ # Cedric H. David, 2016-2026
8
+
9
+
10
+ # *****************************************************************************
11
+ # Import Python modules
12
+ # *****************************************************************************
13
+ import argparse
14
+ import sys
15
+
16
+ import netCDF4
17
+ import numpy as np
18
+ from numpy.ma import MaskedArray
19
+
20
+ from rapid2 import (
21
+ __version__,
22
+ make_0bi_tbl,
23
+ read_std_vec,
24
+ )
25
+
26
+
27
+ # *****************************************************************************
28
+ # Main
29
+ # *****************************************************************************
30
+ def main() -> None:
31
+
32
+ # -------------------------------------------------------------------------
33
+ # Initialize the argument parser and add valid arguments
34
+ # -------------------------------------------------------------------------
35
+ parser = argparse.ArgumentParser(
36
+ description=(
37
+ "Compare RAPID input/output netCDF files for numerical regression "
38
+ "testing."
39
+ ),
40
+ epilog=(
41
+ "examples:\n"
42
+ " cmpncf "
43
+ "--previous "
44
+ "input/Tutorial/Qinit_GLDAS_2.1_VIC_2010-01_GOLD.nc4 "
45
+ "--now "
46
+ "input/Tutorial/Qinit_GLDAS_2.1_VIC_2010-01.nc4 "
47
+ "--relative_tolerance 1e-6 "
48
+ "--absolute_tolerance 1e-3\n"
49
+ " cmpncf "
50
+ "--previous "
51
+ "input/Tutorial/Qext_GLDAS_2.1_VIC_2010-01_GOLD.nc4 "
52
+ "--now "
53
+ "input/Tutorial/Qext_GLDAS_2.1_VIC_2010-01.nc4 "
54
+ "--relative_tolerance 1e-6 "
55
+ "--absolute_tolerance 1e-3"
56
+ ),
57
+ formatter_class=argparse.RawDescriptionHelpFormatter,
58
+ )
59
+
60
+ parser.add_argument(
61
+ "--version", action="version", version=f"rapid2 {__version__}"
62
+ )
63
+
64
+ parser.add_argument(
65
+ "-prv",
66
+ "--previous",
67
+ dest="prv",
68
+ metavar="PREVIOUS",
69
+ type=str,
70
+ required=True,
71
+ help="specify the old netCDF file",
72
+ )
73
+
74
+ parser.add_argument(
75
+ "-now",
76
+ "--now",
77
+ dest="now",
78
+ metavar="NOW",
79
+ type=str,
80
+ required=True,
81
+ help="specify the new netCDF file",
82
+ )
83
+
84
+ parser.add_argument(
85
+ "-rtl",
86
+ "--relative_tolerance",
87
+ dest="rtl",
88
+ metavar="RELATIVE_TOLERANCE",
89
+ type=str,
90
+ required=False,
91
+ default="0",
92
+ help="specify the relative tolerance",
93
+ )
94
+
95
+ parser.add_argument(
96
+ "-atl",
97
+ "--absolute_tolerance",
98
+ dest="atl",
99
+ metavar="ABSOLUTE_TOLERANCE",
100
+ type=str,
101
+ required=False,
102
+ default="0",
103
+ help="specify the absolute tolerance",
104
+ )
105
+
106
+ # -------------------------------------------------------------------------
107
+ # Parse arguments and assign to variables
108
+ # -------------------------------------------------------------------------
109
+ args = parser.parse_args()
110
+
111
+ prv_ncf = args.prv
112
+ now_ncf = args.now
113
+ YS_rtl = args.rtl
114
+ YS_atl = args.atl
115
+
116
+ print(
117
+ f"Comparing {prv_ncf} "
118
+ f"with {now_ncf} "
119
+ f"relative tolerance {YS_rtl} "
120
+ f"absolute tolerance {YS_atl}"
121
+ )
122
+
123
+ ZS_rtl = np.float64(YS_rtl)
124
+ ZS_atl = np.float64(YS_atl)
125
+
126
+ # -------------------------------------------------------------------------
127
+ # Get metadata in netCDF files
128
+ # -------------------------------------------------------------------------
129
+ (
130
+ IV_riv_prv,
131
+ ZV_lon_prv,
132
+ ZV_lat_prv,
133
+ IV_tim_prv,
134
+ IM_tim_prv,
135
+ ) = read_std_vec(prv_ncf)
136
+
137
+ (
138
+ IV_riv_now,
139
+ ZV_lon_now,
140
+ ZV_lat_now,
141
+ IV_tim_now,
142
+ IM_tim_now,
143
+ ) = read_std_vec(now_ncf)
144
+
145
+ # -------------------------------------------------------------------------
146
+ # Compare dimension sizes
147
+ # -------------------------------------------------------------------------
148
+ if len(IV_riv_prv) == len(IV_riv_now):
149
+ IS_riv_tot = len(IV_riv_prv)
150
+ print(f"Common number of river reaches: {IS_riv_tot}")
151
+ else:
152
+ print(
153
+ f"ERROR - The number of river reaches differs: "
154
+ f"{len(IV_riv_prv)} <> {len(IV_riv_now)}"
155
+ )
156
+ sys.exit(1)
157
+
158
+ if len(IV_tim_prv) == len(IV_tim_now):
159
+ IS_tim = len(IV_tim_prv)
160
+ print(f"Common number of time steps : {IS_tim}")
161
+ else:
162
+ print(
163
+ f"ERROR - The number of time steps differs: "
164
+ f"{len(IV_tim_prv)} <> {len(IV_tim_now)}"
165
+ )
166
+ sys.exit(1)
167
+
168
+ # -------------------------------------------------------------------------
169
+ # Compare rivid values
170
+ # -------------------------------------------------------------------------
171
+ if np.array_equal(IV_riv_prv, IV_riv_now):
172
+ print("The rivids and their sort are both the same")
173
+ else:
174
+ if np.array_equal(np.sort(IV_riv_prv), np.sort(IV_riv_now)):
175
+ print("WARNING - The rivids are the same, but sorted differently")
176
+ _, _, IV_0bi_prv = make_0bi_tbl(IV_riv_now, IV_riv_prv)
177
+ else:
178
+ print("ERROR - The rivids differ")
179
+ sys.exit(1)
180
+
181
+ # -------------------------------------------------------------------------
182
+ # Compare other metadata values
183
+ # -------------------------------------------------------------------------
184
+ if np.array_equal(ZV_lon_prv, ZV_lon_now):
185
+ print("The longitude values are the same")
186
+ else:
187
+ print("ERROR - The longitude values differ")
188
+ sys.exit(1)
189
+
190
+ if np.array_equal(ZV_lat_prv, ZV_lat_now):
191
+ print("The latitude values are the same")
192
+ else:
193
+ print("ERROR - The latitude values differ")
194
+ sys.exit(1)
195
+
196
+ if np.array_equal(IV_tim_prv, IV_tim_now):
197
+ print("The time values are the same")
198
+ else:
199
+ print("ERROR - The time values differ")
200
+ sys.exit(1)
201
+
202
+ if (IM_tim_prv is None) != (IM_tim_now is None):
203
+ print("ERROR - time_bnds present in only one file")
204
+ sys.exit(1)
205
+
206
+ if (IM_tim_prv is not None) and (IM_tim_now is not None):
207
+ if np.array_equal(IM_tim_prv, IM_tim_now):
208
+ print("The time_bnds values are the same")
209
+ else:
210
+ print("ERROR - The time_bnds values differ")
211
+ sys.exit(1)
212
+ else:
213
+ print("WARNING - time_bnds variable missing: skipping comparison")
214
+
215
+ # -------------------------------------------------------------------------
216
+ # Get main variable in netCDF files
217
+ # -------------------------------------------------------------------------
218
+ p = netCDF4.Dataset(prv_ncf, "r")
219
+ n = netCDF4.Dataset(now_ncf, "r")
220
+
221
+ if "Qext" in p.variables and "Qext" in n.variables:
222
+ YS_val_tmp = "Qext"
223
+ elif "Qout" in p.variables and "Qout" in n.variables:
224
+ YS_val_tmp = "Qout"
225
+ else:
226
+ print("ERROR - Neither Qext nor Qout is common variable")
227
+ sys.exit(1)
228
+ print(f"The main variable names are the same: {YS_val_tmp}")
229
+
230
+ # -------------------------------------------------------------------------
231
+ # Compute differences
232
+ # -------------------------------------------------------------------------
233
+ ZS_rdf_max = 0
234
+ ZS_adf_max = 0
235
+ BS_fll_prv = False
236
+ BS_fll_now = False
237
+
238
+ for JS_tim in range(IS_tim):
239
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
240
+ # Initializing
241
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
242
+ ZS_rdf = 0
243
+ ZS_adf = 0
244
+
245
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
246
+ # Getting values
247
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
248
+ ZV_val_prv = p.variables[YS_val_tmp][JS_tim, :]
249
+ ZV_val_now = n.variables[YS_val_tmp][JS_tim, :]
250
+ if "IV_0bi_prv" in locals():
251
+ ZV_val_now = ZV_val_now[IV_0bi_prv]
252
+
253
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
254
+ # Converting masked values to -9999
255
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
256
+ if isinstance(ZV_val_prv, MaskedArray) and np.any(ZV_val_prv.mask):
257
+ ZV_val_prv = ZV_val_prv.filled(fill_value=-9999)
258
+ BS_fll_prv = True
259
+ if isinstance(ZV_val_now, MaskedArray) and np.any(ZV_val_now.mask):
260
+ ZV_val_now = ZV_val_now.filled(fill_value=-9999)
261
+ BS_fll_now = True
262
+
263
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
264
+ # Comparing difference values
265
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
266
+ # Tried computations with regular Python lists but they are very slow.
267
+ # Also tried using map(operator.sub,V,W) or [x-y for x,y in zip(V,W)],
268
+ # but this still results in slow computations.
269
+ # The best performance seems to be with Numpy.
270
+ ZV_adf_tmp = np.absolute(ZV_val_prv - ZV_val_now)
271
+ ZS_adf_max = max(np.max(ZV_adf_tmp), ZS_adf_max)
272
+
273
+ ZS_rdf = np.sqrt(
274
+ np.sum(ZV_adf_tmp * ZV_adf_tmp) / np.sum(ZV_val_prv * ZV_val_prv)
275
+ )
276
+ ZS_rdf_max = max(ZS_rdf, ZS_rdf_max)
277
+
278
+ # ------------------------------------------------------------------------
279
+ # Print difference values and compare to tolerances
280
+ # ------------------------------------------------------------------------
281
+ if BS_fll_prv:
282
+ print(f"WARNING - masked values replaced by -9999 in {prv_ncf}")
283
+ if BS_fll_now:
284
+ print(f"WARNING - masked values replaced by -9999 in {now_ncf}")
285
+ if BS_fll_prv or BS_fll_now:
286
+ print("-------------------------------")
287
+
288
+ print("Max relative difference :" + "{0:.2e}".format(ZS_rdf_max))
289
+ print("Max absolute difference :" + "{0:.2e}".format(ZS_adf_max))
290
+ print("-------------------------------")
291
+
292
+ if ZS_rdf_max > ZS_rtl:
293
+ print("Unacceptable rel. difference!!!")
294
+ print("-------------------------------")
295
+ sys.exit(1)
296
+
297
+ if ZS_adf_max > ZS_atl:
298
+ print("Unacceptable abs. difference!!!")
299
+ print("-------------------------------")
300
+ sys.exit(1)
301
+
302
+ print("netCDF files similar!!!")
303
+ print("-------------------------------")
304
+
305
+
306
+ # *****************************************************************************
307
+ # If executed as a script
308
+ # *****************************************************************************
309
+ if __name__ == "__main__":
310
+ main()
311
+
312
+
313
+ # *****************************************************************************
314
+ # End
315
+ # *****************************************************************************
rapid2/cli/_cpllsm.py ADDED
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env python3
2
+ # *****************************************************************************
3
+ # _cpllsm.py
4
+ # *****************************************************************************
5
+
6
+ # Author:
7
+ # Cedric H. David, 2025-2025
8
+
9
+
10
+ # *****************************************************************************
11
+ # Import Python modules
12
+ # *****************************************************************************
13
+ import argparse
14
+ import os.path
15
+ import sys
16
+
17
+ import netCDF4
18
+ import numpy as np
19
+ from tqdm import tqdm
20
+
21
+ from rapid2 import (
22
+ __version__,
23
+ chck_cpl,
24
+ prep_Qex_ncf,
25
+ read_con_vec,
26
+ read_cpl_vec,
27
+ read_crd_vec,
28
+ )
29
+
30
+
31
+ # *****************************************************************************
32
+ # Main
33
+ # *****************************************************************************
34
+ def main() -> None:
35
+
36
+ # -------------------------------------------------------------------------
37
+ # Initialize the argument parser and add valid arguments
38
+ # -------------------------------------------------------------------------
39
+ parser = argparse.ArgumentParser(
40
+ description=(
41
+ "Transform Land Surface Model data into RAPID external inflow "
42
+ "input."
43
+ ),
44
+ epilog=(
45
+ "examples:\n"
46
+ " cpllsm "
47
+ "--land_surface_model "
48
+ "input/Tutorial/GLDAS_2.1_VIC_2010-01.nc4 "
49
+ "--connectivity "
50
+ "input/Tutorial/rapid_connect_pfaf_74.csv "
51
+ "--coordinates "
52
+ "input/Tutorial/coords_pfaf_74.csv "
53
+ "--coupling "
54
+ "input/Tutorial/rapid_coupling_pfaf_74_GLDAS.csv "
55
+ "--external_inflow "
56
+ "input/Tutorial/Qext_GLDAS_2.1_VIC_2010-01.nc4"
57
+ ),
58
+ formatter_class=argparse.RawDescriptionHelpFormatter,
59
+ )
60
+
61
+ parser.add_argument(
62
+ "--version", action="version", version=f"rapid2 {__version__}"
63
+ )
64
+
65
+ parser.add_argument(
66
+ "-lsm",
67
+ "--land_surface_model",
68
+ dest="lsm",
69
+ metavar="LAND_SURFACE_MODEL",
70
+ type=str,
71
+ required=True,
72
+ help="specify the LSM file",
73
+ )
74
+
75
+ parser.add_argument(
76
+ "-con",
77
+ "--connectivity",
78
+ dest="con",
79
+ metavar="CONNECTIVITY",
80
+ type=str,
81
+ required=True,
82
+ help="specify the connectivity file",
83
+ )
84
+
85
+ parser.add_argument(
86
+ "-crd",
87
+ "--coordinates",
88
+ dest="crd",
89
+ metavar="COORDINATES",
90
+ type=str,
91
+ required=True,
92
+ help="specify the coordinates",
93
+ )
94
+
95
+ parser.add_argument(
96
+ "-cpl",
97
+ "--coupling",
98
+ dest="cpl",
99
+ metavar="COUPLING",
100
+ type=str,
101
+ required=True,
102
+ help="specify the coupling file",
103
+ )
104
+
105
+ parser.add_argument(
106
+ "-Qex",
107
+ "--external_inflow",
108
+ dest="Qex",
109
+ metavar="EXTERNAL_INFLOW",
110
+ type=str,
111
+ required=True,
112
+ help="specify the file name",
113
+ )
114
+
115
+ # -------------------------------------------------------------------------
116
+ # Parse arguments and assign to variables
117
+ # -------------------------------------------------------------------------
118
+ args = parser.parse_args()
119
+
120
+ lsm_ncf = args.lsm
121
+ con_csv = args.con
122
+ crd_csv = args.crd
123
+ cpl_csv = args.cpl
124
+ Qex_ncf = args.Qex
125
+
126
+ print(
127
+ f"Transforming data from {lsm_ncf} "
128
+ f"for {con_csv} "
129
+ f"with {crd_csv} "
130
+ f"and {cpl_csv} "
131
+ f"as {Qex_ncf}"
132
+ )
133
+
134
+ # -------------------------------------------------------------------------
135
+ # Skip if file already exists
136
+ # -------------------------------------------------------------------------
137
+ if os.path.exists(Qex_ncf):
138
+ print(f"WARNING - File already exists {Qex_ncf}. Exit without error")
139
+ sys.exit(0)
140
+
141
+ # -------------------------------------------------------------------------
142
+ # Check if files exist
143
+ # -------------------------------------------------------------------------
144
+ try:
145
+ with open(lsm_ncf):
146
+ pass
147
+ except IOError:
148
+ print(f"ERROR - Unable to open {lsm_ncf}")
149
+ sys.exit(1)
150
+
151
+ # -------------------------------------------------------------------------
152
+ # Read connectivity file
153
+ # -------------------------------------------------------------------------
154
+ print("- Read connectivity file")
155
+
156
+ IV_riv_tot, IV_dwn_tot = read_con_vec(con_csv)
157
+ IS_riv_tot = len(IV_riv_tot)
158
+ print(
159
+ " . The number of river reaches in connectivity file is: "
160
+ f"{IS_riv_tot}"
161
+ )
162
+
163
+ # -------------------------------------------------------------------------
164
+ # Read coordinate file
165
+ # -------------------------------------------------------------------------
166
+ print("- Read coordinate file")
167
+
168
+ IV_riv_tmp, ZV_lon_tot, ZV_lat_tot = read_crd_vec(crd_csv)
169
+ np.testing.assert_array_equal(IV_riv_tot, IV_riv_tmp)
170
+ print(" . The river reaches are the same as in connectivity file")
171
+
172
+ # -------------------------------------------------------------------------
173
+ # Read coupling file
174
+ # -------------------------------------------------------------------------
175
+ print("- Read coupling file")
176
+
177
+ IV_riv_tmp, ZV_skm_tot, IV_1bi_tot, IV_1bj_tot = read_cpl_vec(cpl_csv)
178
+ np.testing.assert_array_equal(IV_riv_tot, IV_riv_tmp)
179
+ print(" . The river reaches are the same as in connectivity file")
180
+
181
+ # -------------------------------------------------------------------------
182
+ # Check consistency of coupling file
183
+ # -------------------------------------------------------------------------
184
+ print("- Check consisitency of coupling file")
185
+
186
+ chck_cpl(ZV_skm_tot, IV_1bi_tot, IV_1bj_tot)
187
+ print(" . OK")
188
+
189
+ # -------------------------------------------------------------------------
190
+ # Read LSM metadata
191
+ # -------------------------------------------------------------------------
192
+ print("- Read LSM metadata")
193
+
194
+ c = netCDF4.Dataset(lsm_ncf, "r")
195
+
196
+ IS_lon_lsm = len(c.dimensions["lon"])
197
+ print(f" . The number of longitudes is: {IS_lon_lsm}")
198
+
199
+ IS_lat_lsm = len(c.dimensions["lat"])
200
+ print(f" . The number of latitudes is: {IS_lat_lsm}")
201
+
202
+ IS_tim_all = len(c.dimensions["time"])
203
+ print(f" . The number of time steps is: {IS_tim_all}")
204
+
205
+ if "Qs_acc" in c.variables:
206
+ if "_FillValue" in c.variables["Qs_acc"].ncattrs():
207
+ ZS_fll = c.variables["Qs_acc"]._FillValue
208
+ print(f" . The fill value for Qs_acc is: {ZS_fll}")
209
+ else:
210
+ raise ValueError("Qs_acc variable missing")
211
+
212
+ if "Qsb_acc" in c.variables:
213
+ if "_FillValue" in c.variables["Qsb_acc"].ncattrs():
214
+ ZS_fll = c.variables["Qsb_acc"]._FillValue
215
+ print(f" . The fill value for Qsb_acc is: {ZS_fll}")
216
+ else:
217
+ raise ValueError("Qsb_acc variable missing")
218
+
219
+ # -------------------------------------------------------------------------
220
+ # Create Qext file
221
+ # -------------------------------------------------------------------------
222
+ print("- Create Qext file")
223
+
224
+ prep_Qex_ncf(IV_riv_tot, ZV_lon_tot, ZV_lat_tot, Qex_ncf)
225
+
226
+ f = netCDF4.Dataset(Qex_ncf, "a")
227
+
228
+ # -------------------------------------------------------------------------
229
+ # Populate dynamic data
230
+ # -------------------------------------------------------------------------
231
+ print("- Populate dynamic data")
232
+
233
+ ZV_scl_tot = 1000 * ZV_skm_tot
234
+ # Scale by 1000: the multiplication of 0.001 m/mm and 1,000,000 m^2/km^2
235
+ # This directly converts an input flux of mm/s (or kg*m^-2*s-1) and an
236
+ # input area of km^2 into an output flow rate of m^3/s.
237
+
238
+ IV_0bi_tot = IV_1bi_tot - 1
239
+ IV_0bj_tot = IV_1bj_tot - 1
240
+ # Shift to 0-based indexing; entries becoming −1 have 0 area (chck_cpl.py).
241
+
242
+ for JS_tim_all in tqdm(range(IS_tim_all), desc="Processing LSM data"):
243
+ ZM_rsf_lsm = c.variables["Qs_acc"][JS_tim_all][:][:]
244
+ ZM_rsb_lsm = c.variables["Qsb_acc"][JS_tim_all][:][:]
245
+ # netCDF data are stored following: c.variables[var][time][lat][lon]
246
+ ZM_run_lsm = ZM_rsf_lsm + ZM_rsb_lsm
247
+ # ZM_run_lsm is of type 'np.ma.core.MaskedArray' or 'np.ndarray'
248
+ # We here assume that runoff data inputs are in kg/m^2/s.
249
+
250
+ ZV_Qex_tot = ZM_run_lsm[IV_0bj_tot, IV_0bi_tot]
251
+ # This uses the multidimensional list-of-locations indexing capability.
252
+ # All values at given i and j indices can be obtained by giving two
253
+ # lists of j and i indices.
254
+ ZV_Qex_tot = ZV_Qex_tot * ZV_scl_tot
255
+ # Result is now a true flow rate (m3/s) because input was a rate.
256
+
257
+ if isinstance(ZV_Qex_tot, np.ma.MaskedArray):
258
+ ZV_Qex_tot = np.where(ZV_Qex_tot.mask, 0, ZV_Qex_tot.data)
259
+ # Make sure the masked values are replaced by 0
260
+ f.variables["Qext"][JS_tim_all, :] = ZV_Qex_tot[:]
261
+ # netCDF data are stored following: f.variables[Qext][time][rivid]
262
+
263
+ f.variables["time"][:] = c.variables["time"][:]
264
+ f.variables["time_bnds"][:] = c.variables["time_bnds"][:]
265
+ # From the LSM netCDF file
266
+ c.close()
267
+
268
+
269
+ # *****************************************************************************
270
+ # If executed as a script
271
+ # *****************************************************************************
272
+ if __name__ == "__main__":
273
+ main()
274
+
275
+
276
+ # *****************************************************************************
277
+ # End
278
+ # *****************************************************************************