|
10 | 10 |
|
11 | 11 | class ECMWF_convert_to_ROMS:
|
12 | 12 |
|
13 |
| - def __init__(self): |
14 |
| - self.plotter = ECMWF_plot.ECMWF_plot() |
15 |
| - |
16 |
| - def convert_to_ROMS_units_standards(self, out_filename: str, metadata, parameter: str, config_ecmwf: ECMWF_query): |
17 |
| - dset = netCDF4.Dataset(out_filename, 'r+') |
18 |
| - |
19 |
| - da = dset.variables[metadata['short_name']][:] |
20 |
| - masked_array = np.ma.masked_where(da == dset.variables[metadata['short_name']].missing_value, da) |
21 |
| - logging.debug("[ECMWF_convert_to_ROMS] Will convert for parameter: {}".format(parameter)) |
22 |
| - if parameter in ['mean_surface_net_short_wave_radiation_flux', |
23 |
| - 'mean_surface_net_long_wave_radiation_flux', |
24 |
| - 'mean_surface_downward_long_wave_radiation_flux', |
25 |
| - 'mean_surface_latent_heat_flux', |
26 |
| - 'mean_surface_sensible_heat_flux', |
27 |
| - 'mean_surface_downward_short_wave_radiation_flux']: |
28 |
| - # masked_array = np.ma.divide(masked_array, (3600. * 3.0)) |
29 |
| - units = 'W m**-2' |
30 |
| - logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
31 |
| - elif parameter in ['specific_humidity']: |
32 |
| - units = 'kg kg-1' |
33 |
| - logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
34 |
| - elif parameter in ['10m_u_component_of_wind', '10m_v_component_of_wind']: |
35 |
| - units = 'm s-1' |
36 |
| - logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
37 |
| - elif parameter in ['2m_temperature', '2m_dewpoint_temperature']: |
38 |
| - masked_array = np.ma.subtract(masked_array, 273.15) |
39 |
| - units = 'Celsius' |
40 |
| - logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
41 |
| - elif parameter in ['evaporation']: |
42 |
| - Rho_w = 1000. # kg m - 3 |
43 |
| - masked_array = np.ma.multiply(masked_array, (Rho_w / (1 * 3600.))) |
44 |
| - units = 'kg m-2 s-1' |
45 |
| - logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
46 |
| - elif parameter in ['mean_sea_level_pressure']: |
47 |
| - # masked_array = np.ma.divide(masked_array, 100) #(1 mb = 100 Pa) |
48 |
| - units = 'Pa' |
49 |
| - logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
50 |
| - elif parameter in ['total_cloud_cover']: |
51 |
| - dset.renameVariable(metadata['short_name'], 'cloud') |
52 |
| - units = 'nondimensional' |
53 |
| - logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
54 |
| - elif parameter in ['total_precipitation']: |
55 |
| - # Convert meter (m) to rate (kgm-2s-1) |
56 |
| - Rho_w = 1000 # kg m - 3 |
57 |
| - masked_array = np.ma.multiply(masked_array, (Rho_w / (1 * 3600.))) |
58 |
| - units = 'kg m-2 s-1' |
59 |
| - logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
60 |
| - else: |
61 |
| - raise Exception("[ECMWF_convert_to_ROMS] Unable to find parameter {} to convert to ROMS format".format(parameter)) |
62 |
| - # longitude = dset.variables['longitude'][:] |
63 |
| - # latitude = dset.variables['latitude'][:] |
64 |
| - |
65 |
| - # do_plot = False |
66 |
| - # if do_plot: |
67 |
| - # self.plotter.plot_data(longitude, latitude, masked_array, time, parameter) |
68 |
| - |
69 |
| - self.write_to_ROMS_netcdf_file(config_ecmwf, |
70 |
| - masked_array, |
71 |
| - units, |
72 |
| - out_filename, |
73 |
| - parameter, |
74 |
| - dset) |
75 |
| - dset.close() |
76 |
| - |
77 |
| - # We change the reference date to be equal to the standard ROMS |
78 |
| - # reference time 1948-01-01 so that we can optionally use ocean_time as time name |
79 |
| - def change_reference_date(self, ds, config_ecmwf: ECMWF_query): |
80 |
| - |
81 |
| - era5_time = ds.variables['time'][:] |
82 |
| - era5_time_units = ds.variables['time'].units |
83 |
| - era5_time_cal = ds.variables['time'].calendar |
84 |
| - logging.debug("[ECMWF_convert_to_ROMS] Original time: {} to {} cal: {} units: {}".format(era5_time[0],era5_time[-1], era5_time_cal, era5_time_units)) |
85 |
| - |
86 |
| - dates = num2date(era5_time, units=era5_time_units, calendar=era5_time_cal) |
87 |
| - logging.debug( |
88 |
| - f"[ECMWF_convert_to_ROMS] Converted time: {dates[0]} to {dates[-1]}") |
89 |
| - |
90 |
| - # Convert back to julian day and convert to days since 1948-01-01 as that is standard for ROMS |
91 |
| - # days_to_seconds = 86400.0 |
92 |
| - times = netCDF4.date2num(dates, units=config_ecmwf.time_units) # * days_to_seconds |
93 |
| - logging.debug( |
94 |
| - f"[ECMWF_convert_to_ROMS] Converted time: {times[0]} to {times[-1]} units: {config_ecmwf.time_units}") |
95 |
| - |
96 |
| - return times, config_ecmwf.time_units, era5_time_cal |
97 |
| - |
98 |
| - def write_to_ROMS_netcdf_file(self, config_ecmwf: ECMWF_query, data_array, var_units: str, netcdf_file, |
99 |
| - parameter: str, ds): |
100 |
| - """ |
101 |
| - :param config_ecmwf: The config object containing the metadata |
102 |
| - :param data_array: the data array downloaded from ECMWF and converted to correct ROMS units |
103 |
| - :param units: the units to write to file |
104 |
| - :param netcdf_file: name of file |
105 |
| - :param parameter: the parameter to write to file - name converted to ROMS name using metadata |
106 |
| - :param longitude: longitude dimension of data |
107 |
| - :param latitude: latitude dimension of data |
108 |
| - :param time: time dimension of data |
109 |
| -
|
110 |
| - https://www.myroms.org/index.php?page=forcing |
111 |
| - """ |
112 |
| - metadata = config_ecmwf.get_parameter_metadata(parameter) |
113 |
| - logging.info( |
114 |
| - "[ECMWF_convert_to_ROMS] Writing {} to ROMS netcdf file".format(parameter)) |
115 |
| - |
116 |
| - longitude = ds.variables['longitude'][:] |
117 |
| - latitude = ds.variables['latitude'][:] |
118 |
| - time, time_units, time_calendar = self.change_reference_date(ds, config_ecmwf) |
119 |
| - |
| 13 | + def __init__(self): |
| 14 | + self.plotter = ECMWF_plot.ECMWF_plot() |
| 15 | + |
| 16 | + def convert_to_ROMS_units_standards(self, out_filename: str, metadata, parameter: str, config_ecmwf: ECMWF_query): |
| 17 | + dset = netCDF4.Dataset(out_filename, 'r+') |
| 18 | + |
| 19 | + da = dset.variables[metadata['short_name']][:] |
| 20 | + masked_array = np.ma.masked_where(da == dset.variables[metadata['short_name']].missing_value, da) |
| 21 | + logging.debug("[ECMWF_convert_to_ROMS] Will convert for parameter: {}".format(parameter)) |
| 22 | + if parameter in ['mean_surface_net_short_wave_radiation_flux', |
| 23 | + 'mean_surface_net_long_wave_radiation_flux', |
| 24 | + 'mean_surface_downward_long_wave_radiation_flux', |
| 25 | + 'mean_surface_latent_heat_flux', |
| 26 | + 'mean_surface_sensible_heat_flux', |
| 27 | + 'mean_surface_downward_short_wave_radiation_flux']: |
| 28 | + # masked_array = np.ma.divide(masked_array, (3600. * 3.0)) |
| 29 | + units = 'W m**-2' |
| 30 | + logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
| 31 | + elif parameter in ['specific_humidity']: |
| 32 | + units = 'kg kg-1' |
| 33 | + logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
| 34 | + elif parameter in ['10m_u_component_of_wind', '10m_v_component_of_wind']: |
| 35 | + units = 'm s-1' |
| 36 | + logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
| 37 | + elif parameter in ['2m_temperature', '2m_dewpoint_temperature']: |
| 38 | + masked_array = np.ma.subtract(masked_array, 273.15) |
| 39 | + units = 'Celsius' |
| 40 | + logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
| 41 | + elif parameter in ['evaporation']: |
| 42 | + Rho_w = 1000. # kg m - 3 |
| 43 | + masked_array = np.ma.multiply(masked_array, (Rho_w / (1 * 3600.))) |
| 44 | + units = 'kg m-2 s-1' |
| 45 | + logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
| 46 | + elif parameter in ['mean_sea_level_pressure']: |
| 47 | + # masked_array = np.ma.divide(masked_array, 100) #(1 mb = 100 Pa) |
| 48 | + units = 'Pa' |
| 49 | + logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
| 50 | + elif parameter in ['total_cloud_cover']: |
| 51 | + dset.renameVariable(metadata['short_name'], 'cloud') |
| 52 | + units = 'nondimensional' |
| 53 | + logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
| 54 | + elif parameter in ['total_precipitation']: |
| 55 | + # Convert meter (m) to rate (kgm-2s-1) |
| 56 | + Rho_w = 1000 # kg m - 3 |
| 57 | + masked_array = np.ma.multiply(masked_array, (Rho_w / (1 * 3600.))) |
| 58 | + units = 'kg m-2 s-1' |
| 59 | + logging.debug("[ECMWF_convert_to_ROMS] Converted parameter: {}".format(parameter)) |
| 60 | + else: |
| 61 | + raise Exception("[ECMWF_convert_to_ROMS] Unable to find parameter {} to convert to ROMS format".format(parameter)) |
| 62 | + # longitude = dset.variables['longitude'][:] |
| 63 | + # latitude = dset.variables['latitude'][:] |
| 64 | + |
| 65 | + # do_plot = False |
| 66 | + # if do_plot: |
| 67 | + # self.plotter.plot_data(longitude, latitude, masked_array, time, parameter) |
| 68 | + |
| 69 | + self.write_to_ROMS_netcdf_file(config_ecmwf, |
| 70 | + masked_array, |
| 71 | + units, |
| 72 | + out_filename, |
| 73 | + parameter, |
| 74 | + dset) |
| 75 | + dset.close() |
| 76 | + |
| 77 | + # We change the reference date to be equal to the standard ROMS |
| 78 | + # reference time 1948-01-01 so that we can optionally use ocean_time as time name |
| 79 | + def change_reference_date(self, ds, config_ecmwf: ECMWF_query): |
| 80 | + |
| 81 | + era5_time = ds.variables['time'][:] |
| 82 | + era5_time_units = ds.variables['time'].units |
| 83 | + era5_time_cal = ds.variables['time'].calendar |
| 84 | + logging.debug("[ECMWF_convert_to_ROMS] Original time: {} to {} cal: {} units: {}".format(era5_time[0],era5_time[-1], era5_time_cal, era5_time_units)) |
| 85 | + |
| 86 | + dates = num2date(era5_time, units=era5_time_units, calendar=era5_time_cal) |
| 87 | + logging.debug( |
| 88 | + f"[ECMWF_convert_to_ROMS] Converted time: {dates[0]} to {dates[-1]}") |
| 89 | + |
| 90 | + # Convert back to julian day and convert to days since 1948-01-01 as that is standard for ROMS |
| 91 | + # days_to_seconds = 86400.0 |
| 92 | + times = netCDF4.date2num(dates, units=config_ecmwf.time_units) # * days_to_seconds |
| 93 | + logging.debug( |
| 94 | + f"[ECMWF_convert_to_ROMS] Converted time: {times[0]} to {times[-1]} units: {config_ecmwf.time_units}") |
| 95 | + |
| 96 | + return times, config_ecmwf.time_units, era5_time_cal |
| 97 | + |
| 98 | + def write_to_ROMS_netcdf_file(self, config_ecmwf: ECMWF_query, data_array, var_units: str, netcdf_file, |
| 99 | + parameter: str, ds): |
| 100 | + """ |
| 101 | + :param config_ecmwf: The config object containing the metadata |
| 102 | + :param data_array: the data array downloaded from ECMWF and converted to correct ROMS units |
| 103 | + :param units: the units to write to file |
| 104 | + :param netcdf_file: name of file |
| 105 | + :param parameter: the parameter to write to file - name converted to ROMS name using metadata |
| 106 | + :param longitude: longitude dimension of data |
| 107 | + :param latitude: latitude dimension of data |
| 108 | + :param time: time dimension of data |
| 109 | +
|
| 110 | + https://www.myroms.org/index.php?page=forcing |
| 111 | + """ |
| 112 | + metadata = config_ecmwf.get_parameter_metadata(parameter) |
| 113 | + logging.info( |
| 114 | + "[ECMWF_convert_to_ROMS] Writing {} to ROMS netcdf file".format(parameter)) |
| 115 | + |
| 116 | + longitude = ds.variables['longitude'][:] |
| 117 | + latitude = ds.variables['latitude'][:] |
| 118 | + time, time_units, time_calendar = self.change_reference_date(ds, config_ecmwf) |
120 | 119 | netcdf_roms_filename = f"{out_filename[0:-3]}_roms.nc"
|
121 |
| - if os.path.exists(netcdf_roms_filename): |
| 120 | + if os.path.exists(netcdf_roms_filename): |
122 | 121 | os.remove(netcdf_roms_filename)
|
123 |
| - logging.info( |
124 |
| - "[ECMWF_convert_to_ROMS] Writing final product to file {}".format(netcdf_roms_filename)) |
125 |
| - |
126 |
| - f1 = netCDF4.Dataset(netcdf_roms_filename, 'w') |
127 |
| - f1.title = "{} ECMWF model forcing for parameter {}".format(config_ecmwf.dataset.upper(), parameter) |
128 |
| - f1.description = "Created by Trond Kristiansen (at) niva.no." \ |
129 |
| - "Atmospheric data on original grid but converted to ROMS units and parameter names." \ |
130 |
| - "Files created using the ECMWF_tools toolbox:" \ |
131 |
| - "https://github.com/trondkr/ERA5-ROMS" |
132 |
| - f1.history = f"Created {datetime.now()}" |
133 |
| - f1.link = "https://github.com/trondkr/" |
134 |
| - f1.Conventions = "CF-1.0" |
135 |
| - fill_val = 1.0e35 |
136 |
| - data_array[data_array.mask] = fill_val |
137 |
| - |
138 |
| - # Define dimensions |
139 |
| - f1.createDimension('lon', len(longitude)) |
140 |
| - f1.createDimension('lat', len(latitude)) |
141 |
| - f1.createDimension(metadata['time_name'], None) |
142 |
| - |
143 |
| - vnc = f1.createVariable('lon', 'd', 'lon', fill_value=fill_val) |
144 |
| - vnc.long_name = 'Longitude' |
145 |
| - vnc.units = 'degree_east' |
146 |
| - vnc.standard_name = 'longitude' |
147 |
| - vnc[:] = longitude |
148 |
| - |
149 |
| - vnc = f1.createVariable('lat', 'd', 'lat', fill_value=fill_val) |
150 |
| - vnc.long_name = 'Latitude' |
151 |
| - vnc.units = 'degree_north' |
152 |
| - vnc.standard_name = 'latitude' |
| 122 | + logging.info( |
| 123 | + "[ECMWF_convert_to_ROMS] Writing final product to file {}".format(netcdf_roms_filename)) |
| 124 | + |
| 125 | + f1 = netCDF4.Dataset(netcdf_roms_filename, 'w') |
| 126 | + f1.title = "{} ECMWF model forcing for parameter {}".format(config_ecmwf.dataset.upper(), parameter) |
| 127 | + f1.description = "Created by Trond Kristiansen (at) niva.no." \ |
| 128 | + "Atmospheric data on original grid but converted to ROMS units and parameter names." \ |
| 129 | + "Files created using the ECMWF_tools toolbox:" \ |
| 130 | + "https://github.com/trondkr/ERA5-ROMS" |
| 131 | + f1.history = f"Created {datetime.now()}" |
| 132 | + f1.link = "https://github.com/trondkr/" |
| 133 | + f1.Conventions = "CF-1.0" |
| 134 | + fill_val = 1.0e35 |
| 135 | + data_array[data_array.mask] = fill_val |
| 136 | + |
| 137 | + # Define dimensions |
| 138 | + f1.createDimension('lon', len(longitude)) |
| 139 | + f1.createDimension('lat', len(latitude)) |
| 140 | + f1.createDimension(metadata['time_name'], None) |
| 141 | + |
| 142 | + vnc = f1.createVariable('lon', 'd', 'lon', fill_value=fill_val) |
| 143 | + vnc.long_name = 'Longitude' |
| 144 | + vnc.units = 'degree_east' |
| 145 | + vnc.standard_name = 'longitude' |
| 146 | + vnc[:] = longitude |
| 147 | + |
| 148 | + vnc = f1.createVariable('lat', 'd', 'lat', fill_value=fill_val) |
| 149 | + vnc.long_name = 'Latitude' |
| 150 | + vnc.units = 'degree_north' |
| 151 | + vnc.standard_name = 'latitude' |
153 | 152 | # For latitude we need to reverse the order provided by ECMWF.
|
154 | 153 | # The same goes with the data
|
155 |
| - vnc[:] = latitude[::-1] |
156 |
| - |
157 |
| - vnc = f1.createVariable(metadata['time_name'], 'd', (metadata['time_name'],), fill_value=fill_val) |
158 |
| - vnc.long_name = 'time' |
159 |
| - vnc.units = time_units |
160 |
| - vnc.field = 'time, scalar, series' |
161 |
| - vnc.calendar = time_calendar |
162 |
| - vnc[:] = time |
163 |
| - |
164 |
| - vnc = f1.createVariable(metadata['roms_name'], 'd', (metadata['time_name'], 'lat', 'lon'), fill_value=fill_val) |
165 |
| - vnc.long_name = metadata["name"] |
166 |
| - vnc.standard_name = metadata["short_name"] |
167 |
| - vnc.coordinates = f"lon lat {metadata['time_name']}" |
168 |
| - vnc.units = var_units |
169 |
| - vnc.missing_value = fill_val |
| 154 | + vnc[:] = latitude[::-1] |
| 155 | + |
| 156 | + vnc = f1.createVariable(metadata['time_name'], 'd', (metadata['time_name'],), fill_value=fill_val) |
| 157 | + vnc.long_name = 'time' |
| 158 | + vnc.units = time_units |
| 159 | + vnc.field = 'time, scalar, series' |
| 160 | + vnc.calendar = time_calendar |
| 161 | + vnc[:] = time |
| 162 | + |
| 163 | + vnc = f1.createVariable(metadata['roms_name'], 'd', (metadata['time_name'], 'lat', 'lon'), fill_value=fill_val) |
| 164 | + vnc.long_name = metadata["name"] |
| 165 | + vnc.standard_name = metadata["short_name"] |
| 166 | + vnc.coordinates = f"lon lat {metadata['time_name']}" |
| 167 | + vnc.units = var_units |
| 168 | + vnc.missing_value = fill_val |
170 | 169 |
|
171 |
| - vnc[:, :, :] = data_array[:,::-1,:] |
172 |
| - logging.info( |
173 |
| - f"[ECMWF_convert_to_ROMS] Finished writing to file {netcdf_roms_filename}") |
174 |
| - os.remove(netcdf_file) |
175 |
| - f1.close() |
| 170 | + vnc[:, :, :] = data_array[:,::-1,:] |
| 171 | + logging.info( |
| 172 | + f"[ECMWF_convert_to_ROMS] Finished writing to file {netcdf_roms_filename}") |
| 173 | + os.remove(netcdf_file) |
| 174 | + f1.close() |
0 commit comments