Beispiel #1
0
    def __init__(self,
                 function_space,
                 wind_stress_field,
                 atm_pressure_field,
                 to_latlon,
                 ncfile_pattern,
                 init_date,
                 target_coordsys,
                 verbose=False):
        """
        :arg function_space: Target (scalar) :class:`FunctionSpace` object onto
            which data will be interpolated.
        :arg wind_stress_field: A 2D vector :class:`Function` where the output
            wind stress will be stored.
        :arg atm_pressure_field: A 2D scalar :class:`Function` where the output
            atmospheric pressure will be stored.
        :arg to_latlon: Python function that converts local mesh coordinates to
            latitude and longitude: 'lat, lon = to_latlon(x, y)'
        :arg ncfile_pattern: A file name pattern for reading the atmospheric
            model output files. E.g. 'forcings/nam_air.local.2006_*.nc'
        :arg init_date: A :class:`datetime` object that indicates the start
            date/time of the Thetis simulation. Must contain time zone. E.g.
            'datetime(2006, 5, 1, tzinfo=pytz.utc)'
        :arg target_coordsys: coordinate system in which the model grid is
            defined. This is used to rotate vectors to local coordinates.
        :kwarg bool verbose: Se True to print debug information.
        """
        self.function_space = function_space
        self.wind_stress_field = wind_stress_field
        self.atm_pressure_field = atm_pressure_field

        # construct interpolators
        self.grid_interpolator = interpolation.NetCDFLatLonInterpolator2d(
            self.function_space, to_latlon)
        self.reader = interpolation.NetCDFSpatialInterpolator(
            self.grid_interpolator, ['uwind', 'vwind', 'prmsl'])
        self.timesearch_obj = interpolation.NetCDFTimeSearch(ncfile_pattern,
                                                             init_date,
                                                             ATMNetCDFTime,
                                                             verbose=verbose)
        self.time_interpolator = interpolation.LinearTimeInterpolator(
            self.timesearch_obj, self.reader)
        lon = self.grid_interpolator.mesh_lonlat[:, 0]
        lat = self.grid_interpolator.mesh_lonlat[:, 1]
        self.vect_rotator = coordsys.VectorCoordSysRotation(
            coordsys.LL_WGS84, target_coordsys, lon, lat)
Beispiel #2
0
    def __init__(self, function_space, wind_stress_field, atm_pressure_field,
                 ncfile_pattern, init_date):
        self.function_space = function_space
        self.wind_stress_field = wind_stress_field
        self.atm_pressure_field = atm_pressure_field

        # construct interpolators
        self.grid_interpolator = interpolation.NetCDFLatLonInterpolator2d(
            self.function_space, to_latlon)
        self.reader = interpolation.NetCDFSpatialInterpolator(
            self.grid_interpolator, ['uwind', 'vwind', 'prmsl'])
        self.timesearch_obj = interpolation.NetCDFTimeSearch(
            ncfile_pattern, init_date, WRFNetCDFTime)
        self.time_interpolator = interpolation.LinearTimeInterpolator(
            self.timesearch_obj, self.reader)
        lon = self.grid_interpolator.mesh_lonlat[:, 0]
        lat = self.grid_interpolator.mesh_lonlat[:, 1]
        self.vect_rotator = coordsys.VectorCoordSysRotation(
            coordsys.LL_WGS84, coordsys.SPCS_N_OR, lon, lat)
Beispiel #3
0
    def __init__(self,
                 elev_field,
                 init_date,
                 to_latlon,
                 target_coordsys,
                 uv_field=None,
                 constituents=None,
                 boundary_ids=None,
                 data_dir=None):
        """
        :arg elev_field: Function where tidal elevation will be interpolated.
        :arg init_date: Datetime object defining the simulation init time.
        :arg to_latlon: Python function that converts local mesh coordinates to
            latitude and longitude: 'lat, lon = to_latlon(x, y)'
        :arg target_coordsys: coordinate system in which the model grid is
            defined. This is used to rotate vectors to local coordinates.
        :kwarg uv_field: Function where tidal transport will be interpolated.
        :kwarg constituents: list of tidal constituents, e.g. ['M2', 'K1']
        :kwarg boundary_ids: list of boundary_ids where tidal data will be
            evaluated. If not defined, tides will be in evaluated in the entire
            domain.
        :kward data_dir: path to directory where tidal model netCDF files are
            located.
        """
        assert init_date.tzinfo is not None, 'init_date must have time zone information'
        if constituents is None:
            constituents = ['Q1', 'O1', 'P1', 'K1', 'N2', 'M2', 'S2', 'K2']

        self.data_dir = data_dir if data_dir is not None else ''

        if not self.compute_velocity and uv_field is not None:
            warning(
                '{:}: uv_field is defined but velocity computation is not supported. uv_field will be ignored.'
                .format(__class__.__name__))
        self.compute_velocity = self.compute_velocity and uv_field is not None

        # determine nodes at the boundary
        self.elev_field = elev_field
        self.uv_field = uv_field
        fs = elev_field.function_space()
        if boundary_ids is None:
            # interpolate in the whole domain
            self.nodes = np.arange(
                self.elev_field.dat.data_with_halos.shape[0])
        else:
            bc = DirichletBC(fs, 0., boundary_ids, method='geometric')
            self.nodes = bc.nodes
        self._empty_set = self.nodes.size == 0

        xy = SpatialCoordinate(fs.mesh())
        fsx = Function(fs).interpolate(xy[0]).dat.data_ro_with_halos
        fsy = Function(fs).interpolate(xy[1]).dat.data_ro_with_halos
        if not self._empty_set:

            latlon = []
            for node in self.nodes:
                x, y = fsx[node], fsy[node]
                lat, lon = to_latlon(x, y, positive_lon=True)
                latlon.append((lat, lon))
            self.latlon = np.array(latlon)

            # compute bounding box
            bounds_lat = [self.latlon[:, 0].min(), self.latlon[:, 0].max()]
            bounds_lon = [self.latlon[:, 1].min(), self.latlon[:, 1].max()]
            if self.coord_layout == 'lon,lat':
                self.ranges = (bounds_lon, bounds_lat)
            else:
                self.ranges = (bounds_lat, bounds_lon)

            self.tide = uptide.Tides(constituents)
            self.tide.set_initial_time(init_date)
            self._create_readers()

            if self.compute_velocity:
                lat = self.latlon[:, 0]
                lon = self.latlon[:, 1]
                self.vect_rotator = coordsys.VectorCoordSysRotation(
                    coordsys.LL_WGS84, target_coordsys, lon, lat)
Beispiel #4
0
    def __init__(self,
                 function_space_2d,
                 function_space_3d,
                 fields,
                 field_names,
                 field_fnstr,
                 to_latlon,
                 basedir,
                 file_pattern,
                 init_date,
                 target_coordsys,
                 verbose=False):
        """
        :arg function_space_2d: Target (scalar) :class:`FunctionSpace` object onto
            which 2D data will be interpolated.
        :arg function_space_3d: Target (scalar) :class:`FunctionSpace` object onto
            which 3D data will be interpolated.
        :arg fields: list of :class:`Function` objects where data will be
            stored.
        :arg field_names: List of netCDF variable names for the fields. E.g.
            ['Salinity', 'Temperature'].
        :arg field_fnstr: List of variables in netCDF file names. E.g.
            ['s3d', 't3d'].
        :arg to_latlon: Python function that converts local mesh coordinates to
            latitude and longitude: 'lat, lon = to_latlon(x, y)'
        :arg basedir: Root dir where NCOM files are stored.
            E.g. '/forcings/ncom'.
        :arg file_pattern: A file name pattern for reading the NCOM output
            files (excluding the basedir). E.g.
            {year:04d}/{fieldstr:}/{fieldstr:}.glb8_2f_{year:04d}{month:02d}{day:02d}00.nc'.
        :arg init_date: A :class:`datetime` object that indicates the start
            date/time of the Thetis simulation. Must contain time zone. E.g.
            'datetime(2006, 5, 1, tzinfo=pytz.utc)'
        :arg target_coordsys: coordinate system in which the model grid is
            defined. This is used to rotate vectors to local coordinates.
        :kwarg bool verbose: Se True to print debug information.
        """
        self.function_space_2d = function_space_2d
        self.function_space_3d = function_space_3d
        for f in fields:
            assert f.function_space() in [
                self.function_space_2d, self.function_space_3d
            ], 'field \'{:}\' does not belong to given function space.'.format(
                f.name())
        assert len(fields) == len(field_names)
        assert len(fields) == len(field_fnstr)
        self.field_names = field_names
        self.fields = dict(zip(self.field_names, fields))

        # construct interpolators
        self.grid_interpolator_2d = SpatialInterpolatorNCOM2d(
            self.function_space_2d, to_latlon, basedir)
        self.grid_interpolator_3d = SpatialInterpolatorNCOM3d(
            self.function_space_3d, to_latlon, basedir)
        # each field is in different file
        # construct time search and interp objects separately for each
        self.time_interpolator = {}
        for ncvarname, fnstr in zip(field_names, field_fnstr):
            gi = self.grid_interpolator_2d if fnstr == 'ssh' else self.grid_interpolator_3d
            r = interpolation.NetCDFSpatialInterpolator(gi, [ncvarname])
            pat = file_pattern.replace('{fieldstr:}', fnstr)
            pat = os.path.join(basedir, pat)
            ts = interpolation.DailyFileTimeSearch(pat,
                                                   init_date,
                                                   verbose=verbose)
            ti = interpolation.LinearTimeInterpolator(ts, r)
            self.time_interpolator[ncvarname] = ti
        # construct velocity rotation object
        self.rotate_velocity = ('U_Velocity' in field_names
                                and 'V_Velocity' in field_names)
        self.scalar_field_names = list(self.field_names)
        if self.rotate_velocity:
            self.scalar_field_names.remove('U_Velocity')
            self.scalar_field_names.remove('V_Velocity')
            lat = self.grid_interpolator_3d.latlonz_array[:, 0]
            lon = self.grid_interpolator_3d.latlonz_array[:, 1]
            self.vect_rotator = coordsys.VectorCoordSysRotation(
                coordsys.LL_WGS84, target_coordsys, lon, lat)
Beispiel #5
0
def test():
    mesh2d = Mesh('mesh_cre-plume002.msh')
    comm = mesh2d.comm
    p1 = FunctionSpace(mesh2d, 'CG', 1)
    p1v = VectorFunctionSpace(mesh2d, 'CG', 1)
    windstress_2d = Function(p1v, name='wind stress')
    atmpressure_2d = Function(p1, name='atm pressure')

    sim_tz = timezone.FixedTimeZone(-8, 'PST')
    init_date = datetime.datetime(2015, 5, 16, tzinfo=sim_tz)
    pattern = 'forcings/atm/wrf/wrf_air.2015_*_*.nc'

    wrf = WRFInterpolator(p1, windstress_2d, atmpressure_2d, pattern,
                          init_date)

    # create a naive interpolation for first file
    xy = SpatialCoordinate(p1.mesh())
    fsx = Function(p1).interpolate(xy[0]).dat.data_with_halos
    fsy = Function(p1).interpolate(xy[1]).dat.data_with_halos

    mesh_lonlat = []
    for node in range(len(fsx)):
        lat, lon = to_latlon(fsx[node], fsy[node])
        mesh_lonlat.append((lon, lat))
    mesh_lonlat = np.array(mesh_lonlat)

    ncfile = netCDF4.Dataset('forcings/atm/wrf/wrf_air.2015_05_16.nc')
    itime = 10
    grid_lat = ncfile['lat'][:].ravel()
    grid_lon = ncfile['lon'][:].ravel()
    grid_lonlat = np.array((grid_lon, grid_lat)).T
    grid_pres = ncfile['prmsl'][itime, :, :].ravel()
    pres = scipy.interpolate.griddata(grid_lonlat,
                                      grid_pres,
                                      mesh_lonlat,
                                      method='linear')
    grid_uwind = ncfile['uwind'][itime, :, :].ravel()
    uwind = scipy.interpolate.griddata(grid_lonlat,
                                       grid_uwind,
                                       mesh_lonlat,
                                       method='linear')
    grid_vwind = ncfile['vwind'][itime, :, :].ravel()
    vwind = scipy.interpolate.griddata(grid_lonlat,
                                       grid_vwind,
                                       mesh_lonlat,
                                       method='linear')
    vrot = coordsys.VectorCoordSysRotation(coordsys.LL_WGS84,
                                           coordsys.SPCS_N_OR,
                                           mesh_lonlat[:, 0], mesh_lonlat[:,
                                                                          1])
    uwind, vwind = vrot(uwind, vwind)
    u_stress, v_stress = compute_wind_stress(uwind, vwind)

    # compare
    wrf.set_fields((itime - 8) * 3600.)  # NOTE timezone offset
    assert np.allclose(pres, atmpressure_2d.dat.data_with_halos)
    assert np.allclose(u_stress, windstress_2d.dat.data_with_halos[:, 0])

    # write fields to disk for visualization
    out_pres = File('tmp/atm_pressure.pvd')
    out_wind = File('tmp/wind_stress.pvd')
    hours = 24 * 3
    granule = 4
    simtime = np.arange(granule * hours) * 3600. / granule
    i = 0
    for t in simtime:
        wrf.set_fields(t)
        norm_atm = norm(atmpressure_2d)
        norm_wind = norm(windstress_2d)
        if comm.rank == 0:
            print('{:} {:} {:} {:}'.format(i, t, norm_atm, norm_wind))
        out_pres.write(atmpressure_2d)
        out_wind.write(windstress_2d)
        i += 1
Beispiel #6
0
def test():
    """
    Tests atmospheric model data interpolation.

    .. note::
        The following files must be present
        forcings/atm/wrf/wrf_air.2015_05_16.nc
        forcings/atm/wrf/wrf_air.2015_05_17.nc

        forcings/atm/nam/nam_air.local.2006_05_01.nc
        forcings/atm/nam/nam_air.local.2006_05_02.nc
    """
    mesh2d = Mesh('mesh_cre-plume_03_normal.msh')
    comm = mesh2d.comm
    p1 = get_functionspace(mesh2d, 'CG', 1)
    p1v = get_functionspace(mesh2d, 'CG', 1, vector=True)
    windstress_2d = Function(p1v, name='wind stress')
    atmpressure_2d = Function(p1, name='atm pressure')

    sim_tz = timezone.FixedTimeZone(-8, 'PST')

    # WRF
    # init_date = datetime.datetime(2015, 5, 16, tzinfo=sim_tz)
    # pattern = 'forcings/atm/wrf/wrf_air.2015_*_*.nc'
    # atm_time_step = 3600.  # for verification only
    # test_atm_file = 'forcings/atm/wrf/wrf_air.2015_05_16.nc'

    # NAM
    init_date = datetime.datetime(2006, 5, 1, tzinfo=sim_tz)
    pattern = 'forcings/atm/nam/nam_air.local.2006_*_*.nc'
    atm_time_step = 3*3600.
    test_atm_file = 'forcings/atm/nam/nam_air.local.2006_05_01.nc'

    atm_interp = ATMInterpolator(p1, windstress_2d, atmpressure_2d,
                                 to_latlon,
                                 pattern, init_date, COORDSYS, verbose=True)

    # create a naive interpolation for first file
    xy = SpatialCoordinate(p1.mesh())
    fsx = Function(p1).interpolate(xy[0]).dat.data_with_halos
    fsy = Function(p1).interpolate(xy[1]).dat.data_with_halos

    mesh_lonlat = []
    for node in range(len(fsx)):
        lat, lon = to_latlon(fsx[node], fsy[node])
        mesh_lonlat.append((lon, lat))
    mesh_lonlat = np.array(mesh_lonlat)

    ncfile = netCDF4.Dataset(test_atm_file)
    itime = 6
    grid_lat = ncfile['lat'][:].ravel()
    grid_lon = ncfile['lon'][:].ravel()
    grid_lonlat = np.array((grid_lon, grid_lat)).T
    grid_pres = ncfile['prmsl'][itime, :, :].ravel()
    pres = scipy.interpolate.griddata(grid_lonlat, grid_pres, mesh_lonlat, method='linear')
    grid_uwind = ncfile['uwind'][itime, :, :].ravel()
    uwind = scipy.interpolate.griddata(grid_lonlat, grid_uwind, mesh_lonlat, method='linear')
    grid_vwind = ncfile['vwind'][itime, :, :].ravel()
    vwind = scipy.interpolate.griddata(grid_lonlat, grid_vwind, mesh_lonlat, method='linear')
    vrot = coordsys.VectorCoordSysRotation(coordsys.LL_WGS84, COORDSYS, mesh_lonlat[:, 0], mesh_lonlat[:, 1])
    uwind, vwind = vrot(uwind, vwind)
    u_stress, v_stress = compute_wind_stress(uwind, vwind)

    # compare
    atm_interp.set_fields(itime*atm_time_step - 8*3600.)  # NOTE timezone offset
    assert np.allclose(pres, atmpressure_2d.dat.data_with_halos)
    assert np.allclose(u_stress, windstress_2d.dat.data_with_halos[:, 0])

    # write fields to disk for visualization
    pres_fn = 'tmp/AtmPressure2d.pvd'
    wind_fn = 'tmp/WindStress2d.pvd'
    print('Saving output to {:} {:}'.format(pres_fn, wind_fn))
    out_pres = File(pres_fn)
    out_wind = File(wind_fn)
    hours = 24*1.5
    granule = 4
    simtime = np.arange(granule*hours)*3600./granule
    i = 0
    for t in simtime:
        atm_interp.set_fields(t)
        norm_atm = norm(atmpressure_2d)
        norm_wind = norm(windstress_2d)
        if comm.rank == 0:
            print('{:} {:} {:} {:}'.format(i, t, norm_atm, norm_wind))
        out_pres.write(atmpressure_2d)
        out_wind.write(windstress_2d)
        i += 1