solar_time.py
solar_time.py
— 3.4 KB
Contenu du fichier
#!/usr/bin/env python3
""""This script reads a NetCDF file containing the diurnal cycle as a
function of Greenwich time and creates a NetCDF file containing the
diurnal cycle as a function of solar time.
Author: Lionel GUEZ
"""
import netCDF4
import numpy as np
import shutil
from scipy import interpolate
import sys
from numpy import ma
if len(sys.argv) != 3:
sys.exit("Required arguments: input-netCDF-file output-netCDF-file")
shutil.copyfile(sys.argv[1], sys.argv[2])
with netCDF4.Dataset(sys.argv[1]) as f_in, \
netCDF4.Dataset(sys.argv[2], "r+") as f_out:
f_out.renameDimension("time_counter", "solar_time")
f_out.renameVariable("time_counter", "solar_time")
f_out.variables["solar_time"].units = "hours"
for name in ["bounds", "calendar", "cell_methods"]:
if name in f_out.variables["solar_time"].ncattrs():
f_out.variables["solar_time"].delncattr(name)
t_solar = np.arange(1800, 86400, 3600) # in s
f_out.variables["solar_time"][:] = t_solar / 3600
if isinstance(f_in.variables["lon"][:], ma.MaskedArray):
lon = f_in.variables["lon"][:].filled()
# So that t_UTC is not a masked array. interpolate.interp1d
# does not accept a masked array.
else:
lon = f_in.variables["lon"][:]
t_UTC = t_solar[:, np.newaxis] - lon * 240
# Add a multiple of 86400 s to t_UTC to get into the interval
# [f_in.variables["time_counter"][0] - 1800;
# f_in.variables["time_counter"][23] + 1800]:
m = np.ceil((f_in.variables["time_counter"][0] - t_UTC) / 86400 - 1 / 48)
t_UTC += m * 86400
# Check that the reference date of NetCDF variable time_counter is
# at 00:00. Then t_UTC can be used as a time_counter value.
d = netCDF4.num2date(0, f_in["time_counter"].units,
f_in["time_counter"].calendar)
assert np.all(np.array((d.hour, d.minute, d.second, d.microsecond)) == 0)
# Since t_UTC can be half an hour before
# f_in.variables["time_counter"][0] or after
# f_in.variables["time_counter"][23], extend the time series:
x = np.block([f_in.variables["time_counter"][0] - 3600,
f_in.variables["time_counter"],
f_in.variables["time_counter"][23] + 3600])
for name in f_out.variables:
if set(('solar_time', 'lat', 'lon')).issubset(f_out.variables[name].
dimensions):
print("solar_time.py: name =", name)
for i in range(f_in.dimensions["lon"].size):
# Extend f_in.variables[name][..., i] in time taking
# into account periodicity. "y" values correspond to
# "x" values. We assume that time is the first
# dimension, longitude is the last dimension and
# create "y" as having all dimensions except
# longitude, and an extended time dimension:
my_shape = f_in.variables[name].shape
y = np.empty((my_shape[0] + 2, *my_shape[1:-1]))
y[0] = f_in.variables[name][23, ..., i]
y[1:- 1] = f_in.variables[name][..., i]
y[-1] = f_in.variables[name][0, ..., i]
interpol = interpolate.interp1d(x, y, axis = 0, copy = False,
assume_sorted = True)
f_out.variables[name][..., i] = interpol(t_UTC[:, i])
