Ejemplo n.º 1
0
def _calc_results_time_series(
    tracer,
    model_time,
    node_depth,
    timezone,
    tracer_depths,
    tracer_mask,
    w_depths,
    psu_to_teos=False,
):
    time_series = namedtuple("TimeSeries", "var, time")
    if psu_to_teos:
        var = teos_tools.psu_teos(
            [
                shared.interpolate_tracer_to_depths(
                    tracer[i, :], tracer_depths, node_depth, tracer_mask, w_depths
                )
                for i in range(tracer.shape[0])
            ]
        )
    else:
        var = [
            shared.interpolate_tracer_to_depths(
                tracer[i, :], tracer_depths, node_depth, tracer_mask, w_depths
            )
            for i in range(tracer.shape[0])
        ]
    return time_series(var=var, time=[t.to(timezone) for t in model_time])
Ejemplo n.º 2
0
def nemo_sal_route(grid_T_hr, bathy, route_name, obs_sal):
    """Get the salanity data form the NEMO run that matches the time and
    locations of the ferry route by integrated distance weighted
    interpolation.

    :arg grid_T_hr: Hourly tracer results dataset from NEMO.
    :type grid_T_hr: :class:`netCDF4.Dataset

    :arg bathy: model bathymetry
    :type bathy: numpy array

    :arg route_name: name of a ferre route. HBDB, TWDP or TWSB.
    :type route_name: string

    :arg obs_sal: ferry data during route
    :type obs_sal: numpy array

    :return: model salinity array along the ferry route for two times
    """

    # Get the salinity data
    sal_a, sal_b = _get_nemo_salinity(route_name, grid_T_hr)

    sal_a_route = np.zeros(obs_sal.shape[1])
    sal_b_route = np.zeros(obs_sal.shape[1])

    # Perform the IDW on each data point and put them into an array for
    # the whole route.
    for i in np.arange(obs_sal.shape[1]):
        sal_a_route[i], sal_b_route[i] = _model_IDW(obs_sal[:, i], bathy,
                                                    grid_T_hr, sal_a, sal_b)

    # Convert to TEOS-10
    sal_a_t = teos_tools.psu_teos(sal_a_route)
    sal_b_t = teos_tools.psu_teos(sal_b_route)

    return sal_a_t, sal_b_t
Ejemplo n.º 3
0
def _prep_plot_data(grid_T_hr):
    si, ei = 200, 610
    sj, ej = 20, 370
    lons = grid_T_hr.variables["nav_lon"][si:ei, sj:ej]
    lats = grid_T_hr.variables["nav_lat"][si:ei, sj:ej]
    model_depth_level = 1  # 1.5 m
    ## TODO: model time step for salinity contour map should be calculated from
    ##       ferry route time
    model_time_step = 3  # 02:30 UTC
    sal_hr = grid_T_hr.variables["vosaline"]
    ## TODO: Use mesh mask instead of 0 for masking
    sal_masked = np.ma.masked_values(
        sal_hr[model_time_step, model_depth_level, si:ei, sj:ej], 0)
    timestamped_sal = namedtuple("timestamped_sal", "salinity, timestamp")
    sal_model = timestamped_sal(teos_tools.psu_teos(sal_masked),
                                nc_tools.timestamp(grid_T_hr, model_time_step))
    return lons, lats, sal_model, None
Ejemplo n.º 4
0
def ferry_salinity(ferry_data_dir, route_name, dmy, step=1):
    """Load ferry data and slice it to contain only the during route values.

    :arg str ferry_data_dir: storage file location for ONC ferry data.

    :arg str route_name: name of a ferre route. HBDB, TWDP or TWSB.

    :arg str dmy: today's date in :kbd:`ddmmmyy` format

    :arg int step: selecting every nth data point

    :returns: matrix containing time, lon, lat and salinity of ferry
              observations
    """
    # Load observation ferry salinity data with locations and time
    date = datetime.datetime.strptime(dmy, "%d%b%y")
    dayf = date - datetime.timedelta(days=1)
    dmyf = dayf.strftime("%d%b%y").lower()

    obs = _get_sal_data(ferry_data_dir, route_name, dmyf)

    # Create datetime object for start and end of route times
    date = datetime.datetime.strptime(dmy, "%d%b%y")
    start_time = date.replace(
        hour=FERRY_ROUTES[route_name]["start"]["hour"],
        minute=FERRY_ROUTES[route_name]["start"]["minute"],
    )
    end_time = date.replace(
        hour=FERRY_ROUTES[route_name]["end"]["hour"],
        minute=FERRY_ROUTES[route_name]["end"]["minute"],
    )

    # Slice the observational arrays to only have "during route" data
    time_obs = datenum2datetime(obs[0])
    df = pd.DataFrame(time_obs)
    j = np.logical_and(df >= start_time, df <= end_time)
    j = np.array(j)
    obs_route = obs[0:4, j]

    # High frequency ferry data, take every 20th value
    obs_slice = obs_route[:, 0:-1:step]

    # Convert to TEOS-10
    obs_slice[3] = teos_tools.psu_teos(obs_slice[3])

    return obs_slice
Ejemplo n.º 5
0
def onc_json_to_dataset(onc_json, teos=True):
    """Return an :py:class:`xarray.Dataset` object containing the data and
    metadata obtained from an Ocean Networks Canada (ONC) data web service API
    request.

    :arg dict onc_json: Data structure returned from an ONC data web service
                        API request.
                        Typically produces by calling the :py:meth:`json`
                        method on the :py:class:`~requests.Response` object
                        produced by calling :py:meth:`requests.get`.

    :arg boolean teos: Convert salinity data from PSU
                       (Practical Salinity  Units) to TEOS-10 reference
                       salinity in g/kg.
                       Defaults to :py:obj:`True`.

    :returns: Data structure containing data and metadata
    :rtype: :py:class:`xarray.Dataset`
    """
    data_vars = {}
    for sensor in onc_json['sensorData']:
        if sensor['sensorName'] == 'Practical Salinity' and teos:
            data = teos_tools.psu_teos([d['value'] for d in sensor['data']])
            sensor['sensorName'] = 'Reference Salinity'
            sensor['unitOfMeasure'] = 'g/kg'
        else:
            data = [d['value'] for d in sensor['data']]
        data_vars[sensor['sensor']] = xarray.DataArray(
            name=sensor['sensor'],
            data=data,
            coords={
                'sampleTime':
                [arrow.get(d['sampleTime']).naive for d in sensor['data']],
            },
            dims=('sampleTime', ),
            attrs={
                'qaqcFlag': np.array([d['qaqcFlag'] for d in sensor['data']]),
                'sensorName': sensor['sensorName'],
                'unitOfMeasure': sensor['unitOfMeasure'],
                'actualSamples': sensor['actualSamples'],
            })
    return xarray.Dataset(data_vars, attrs=onc_json['serviceMetadata'])
Ejemplo n.º 6
0
def salinity_ferry_route(
        ferry_data_dir,
        grid_T_hr,
        bathy,
        route_name,
        dmy,
        figsize=(20, 7.5),
):
    """Plot daily salinity comparisons between ferry observations and model
    results as well as ferry route with model salinity distribution.

    :arg str ferry_data_dir: storage file location for ONC ferry data.

    :arg grid_T_hr: Hourly tracer results dataset from NEMO.
    :type grid_T_hr: :class:`netCDF4.Dataset

    :arg bathy: model bathymetry
    :type bathy: numpy array

    :arg str route_name: route name of these three ferry routes respectively

    :arg str dmy: date in form ddmonyy

    :arg 2-tuple figsize: Figure size (width, height) in inches.

    :returns: matplotlib figure object instance (fig).
    """
    # Grid region to plot
    si, ei = 200, 610
    sj, ej = 20, 370
    lons = grid_T_hr.variables['nav_lon'][si:ei, sj:ej]
    lats = grid_T_hr.variables['nav_lat'][si:ei, sj:ej]
    # Salinity calculated by NEMO and observed by ONC ferry package
    model_depth_level = 1  # 1.5 m
    ## TODO: model time step for salinity contour map should be calculated from
    ##       ferry route time
    model_time_step = 3  # 02:30 UTC
    sal_hr = grid_T_hr.variables['vosaline']
    ## TODO: Use mesh mask instead of 0 for masking
    sal_masked = np.ma.masked_values(
        sal_hr[model_time_step, model_depth_level, si:ei, sj:ej], 0)
    sal_t = teos_tools.psu_teos(sal_masked)
    sal_obs = ferry_salinity(ferry_data_dir, route_name, dmy)
    nemo_a, nemo_b = nemo_sal_route(grid_T_hr, bathy, route_name, sal_obs)

    fig, axs = plt.subplots(1, 2, figsize=figsize)
    axs[1].set_axis_bgcolor("burlywood")
    viz_tools.set_aspect(axs[1], coords='map', lats=lats)
    cmap = plt.get_cmap('plasma')
    axs[1].set_xlim(-124.5, -122.5)
    axs[1].set_ylim(48.3, 49.6)

    # Plot model salinity
    mesh = axs[1].contourf(lons, lats, sal_t, 20, cmap=cmap)
    cbar = plt.colorbar(mesh, ax=axs[1])
    cbar.ax.axes.tick_params(labelcolor='w')
    cbar.set_label('Absolute Salinity [g/kg]', color='white', **axis_font)
    axs[1].set_title('Ferry Route: 3am[UTC] 1.5m model result ', **title_font)
    axs[1].set_xlabel('Longitude [°E]', **axis_font)
    axs[1].set_ylabel('Latitude [°N]', **axis_font)

    # Plot ferry route.
    axs[1].plot(sal_obs[1], sal_obs[2], 'black', linewidth=4)
    figures.axis_colors(axs[1], 'grey')

    # Add locations and markers on plot for orientation
    bbox_args = dict(boxstyle='square', facecolor='white', alpha=0.7)
    places = [
        FERRY_ROUTES[route_name]['start']['terminal'],
        FERRY_ROUTES[route_name]['end']['terminal'], 'Vancouver'
    ]
    label_offsets = [0.04, -0.4, 0.09]
    for stn, loc in zip(places, label_offsets):
        axs[1].plot(*PLACES[stn]['lon lat'],
                    marker='D',
                    color='white',
                    markersize=10,
                    markeredgewidth=2)
        axs[1].annotate(
            stn, (PLACES[stn]['lon lat'][0] + loc, PLACES[stn]['lon lat'][1]),
            fontsize=15,
            color='black',
            bbox=bbox_args)

    # Set up model part of salinity comparison plot
    axs[0].plot(sal_obs[1],
                nemo_a,
                'DodgerBlue',
                linewidth=2,
                label=f'{FERRY_ROUTES[route_name]["start"]["hour"]} am [UTC]')
    axs[0].plot(
        sal_obs[1],
        nemo_b,
        'MediumBlue',
        linewidth=2,
        label=f'{FERRY_ROUTES[route_name]["start"]["hour"]+1} am [UTC]')

    # Observational component of salinity comparisons plot
    axs[0].plot(sal_obs[1],
                sal_obs[3],
                'DarkGreen',
                linewidth=2,
                label="Observed")
    axs[0].text(0.25,
                -0.1,
                'Observations from Ocean Networks Canada',
                transform=axs[0].transAxes,
                color='white')

    axs[0].set_xlim(-124, -123)
    axs[0].set_ylim(10, 32)
    axs[0].set_title('Surface Salinity: ' + dmy, **title_font)
    axs[0].set_xlabel('Longitude', **axis_font)
    axs[0].set_ylabel('Absolute Salinity [g/kg]', **axis_font)
    axs[0].legend(loc=3)
    axs[0].grid(axis='both')

    fig.patch.set_facecolor('#2B3E50')
    figures.axis_colors(axs[0], 'grey')

    return fig
Ejemplo n.º 7
0
def test_psu_teos_polymorphic_sequence(psu, expected):
    teos = teos_tools.psu_teos(psu)
    np.testing.assert_allclose(teos, expected)
Ejemplo n.º 8
0
def test_psu_teos(psu, expected):
    np.testing.assert_allclose(teos_tools.psu_teos(psu), expected)