Source code for salishsea_tools.places

# Copyright 2013-2021 The Salish Sea MEOPAR contributors
# and The University of British Columbia

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#    http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Salish Sea NEMO model geographic places information.

It is recommended that library code that uses the :py:data:`PLACES` data
structure from this module should use :kbd:`try...except` to catch
:py:exc:`KeyError` exceptions and produce an error message that is more
informative than the default, for example:

.. code-block:: python

    try:
        max_tide_ssh = max(ttide.pred_all) + PLACES[site_name]['mean sea lvl']
        max_historic_ssh = PLACES[site_name]['hist max sea lvl']
    except KeyError as e:
        raise KeyError(
            'place name or info key not found in '
            'salishsea_tools.places.PLACES: {}'.format(e))
"""


#: Information about geographic places used in the analysis and
#: presentation of Salish Sea NEMO model results.
PLACES = {
    # Tide gauge stations
    'Campbell River': {
        # deg E, deg N
        'lon lat': (-125.24, 50.04),
        # Canadian Hydrographic Service (CHS) or NOAA
        'stn number': 8074,
        # m above chart datum
        'mean sea lvl': 2.916,
        # m above chart datum
        'hist max sea lvl': 5.35,
        # indices of nearest weather forcing grid point
        # j is the latitude (y) direction, i is the longitude (x) direction
        'wind grid ji': (190, 102),
        # indices of nearest NEMO model grid point
        # j is the latitude (y) direction, i is the longitude (x) direction
        'NEMO grid ji': (747, 125),
        # indices of nearest wave model grid point
        # j is the latitude (y) direction, i is the longitude (x) direction
        'ww3 grid ji': (453, 109)
    },
    'Cherry Point': {
        'lon lat': (-122.766667, 48.866667),
        'stn number': 9449424,
        'mean sea lvl': 3.543,
        'hist max sea lvl': 5.846,
        'wind grid ji': (122, 166),
        'NEMO grid ji': (343, 342),
        'ww3 grid ji': (193, 462),

    },
    'Friday Harbor': {
        'lon lat': (-123.016667, 48.55),
        'stn number': 9449880,
        'mean sea lvl': 2.561,
        'hist max sea lvl': 4.572,
        'wind grid ji': (108, 155),
        'NEMO grid ji': (300, 267),
        'ww3 grid ji': (124, 427),
    },
    'Halfmoon Bay': {
        'lon lat': (-123.912, 49.511),
        'stn number': 7830,
        'NEMO grid ji': (549, 254),
        'wind grid ji': (158, 136),
        'ww3 grid ji': (331, 297),
        'mean sea lvl': 3.14,
        'hist max sea lvl': 5.61,      # copied from Point Atkinson
    },
    'Nanaimo': {
        'lon lat': (-123.93, 49.16),
        'stn number': 7917,
        'mean sea lvl': 3.08,
        'hist max sea lvl': 5.47,
        'wind grid ji': (142, 133),
        'NEMO grid ji': (484, 208),  # current a little different
        'ww3 grid ji': (261, 298),

    },
    'Neah Bay': {
        'lon lat': (-124.6, 48.4),
        'stn number': 9443090,
        'mean sea lvl': 1.925,
        'hist max sea lvl': 4.359,
        'wind grid ji': (111, 105),
        'NEMO grid ji': (384, 15),
        'ww3 grid ji': (89, 200),
    },
    'New Westminster': {
        'lon lat': (-122.90535, 49.203683),
        'stn number': 7654,
        'mean sea lvl': 1.3,  # from Marlene Jefferies via 20mar18 email from Michael Dunphy
        'hist max sea lvl': 4.66,
        'NEMO grid ji': (423, 363),
        'wind grid ji': (138, 164),
        # no nearby waves
    },
    'Patricia Bay': {
        'lon lat': (-123.4515, 48.6536),
        'stn number': 7277,
        'mean sea lvl': 2.256,
        'hist max sea lvl': 4.38,
        'NEMO grid ji': (351, 214),
        'wind grid ji': (115, 143),
        'ww3 grid ji': (145, 363),
    },
    'Point Atkinson': {
        'lon lat': (-123.25, 49.33),
        'stn number': 7795,
        'mean sea lvl': 3.09,
        'hist max sea lvl': 5.61,
        'wind grid ji': (146, 155),
        'NEMO grid ji': (468, 329),
        'ww3 grid ji': (296, 393),
    },
    'Port Renfrew': {
        'lon lat': (-124.421, 48.555),
        'stn number': 8525,
        'mean sea lvl': 1.937,
        'hist max sea lvl': 4.359,  # from Neah Bay
        'NEMO grid ji': (401, 61),
        'wind grid ji': (117, 112),
        'ww3 grid ji': (123, 226),
    },
    'Sandy Cove': {
        'lon lat': (-123.23, 49.34),
        'stn number': 7786,
        'NEMO grid ji': (468, 333),
        'wind grid ji': (146, 155),
        'ww3 grid ji': (294, 396),
        'mean sea lvl': 3.1,  # from Marlene Jefferies via 20mar18 email from Michael Dunphy
        'hist max sea lvl': 5.61,  # from Pt. Atkinson
    },
    'Squamish': {
        'lon lat': (-123.155, 49.694),
        'stn number': 7811,
        'NEMO grid ji': (532, 389),
        'wind grid ji': (162, 160),
        'ww3 grid ji': (370, 404),
        'mean sea lvl': 3.14,
        'hist max sea lvl': 5.61  # from Pt. Atkkinson
    },
    'Victoria': {
        'lon lat': (-123.3707, 48.424666),
        'stn number': 7120,
        'mean sea lvl': 1.8810,
        'hist max sea lvl': 3.76,
        'wind grid ji': (104, 144),
        'NEMO grid ji': (302, 196),
        'ww3 grid ji': (90, 374),
    },
    'Woodwards Landing': {
        'lon lat': (-123.0754, 49.1251),
        'stn number': 7610,
        'hist max sea lvl': 4.66,  # based on New West
        'mean sea lvl': 1.84,  # from Marlene Jefferies via 20mar18 email from Michael Dunphy
        'NEMO grid ji': (414, 329),
        'wind grid ji': (135, 138),
    },
    'Boundary Bay': {
        'lon lat': (-122.925, 49.0),
        'stn number': None,
        'hist max sea lvl': 5.61,  # based on Point Atk
        'mean sea lvl': 3.09,  # based on Point Atk
        'NEMO grid ji': (380, 335),
        'wind grid ji': (129, 162),
        'ww3 grid ji': (222, 439),
    },

    # VHFR FVCOM model tide guage stations
    'Calamity Point': {
        'lon lat': (-123.1276, 49.31262),
        'stn number': 7724,
        'mean sea lvl': 3.001,  # same as Vancouver Harbour; from Marlene Jefferies via 20mar18 email from Michael Dunphy
        'NEMO grid ji': None,
        'wind grid ji': (456, 344),
        'ww3 grid ji': None,
    },
    'Vancouver Harbour': {
        'lon lat': (-123.1069, 49.28937),
        'stn number': 7735,
        'mean sea lvl': 3.001,  # from Marlene Jefferies via 20mar18 email from Michael Dunphy
        'NEMO grid ji': None,
        'wind grid ji': (143, 159),
        'ww3 grid ji': None,
    },
    'Port Moody': {
        'lon lat': (-122.8658, 49.28814),
        'stn number': 7755,
        'mean sea lvl': 3.143,  # from Marlene Jefferies via 20mar18 email from Michael Dunphy
        'NEMO grid ji': None,
        'wind grid ji': (142, 166),
        'ww3 grid ji': None,
    },
    'Indian Arm Head': {
        'lon lat': (-122.8864, 49.4615),
        'stn number': 7774,
        'mean sea lvl': 3.052,  # from Marlene Jefferies via 20mar18 email from Michael Dunphy
        'NEMO grid ji': None,
        'wind grid ji': (150, 167),
        'ww3 grid ji': None,
    },

    # VHFR FVCOM model HADCP station
    '2nd Narrows Rail Bridge': {
        'lon lat': (-123.0247222, 49.2938889),
        'stn number': 3160171,  # AIS MMSI (Maritime Mobile Service Identity)
        'mean sea lvl': None,
        'NEMO grid ji': None,
        'wind grid ji': (143, 161),
        'ww3 grid ji': None,
    },

    # Ferry terminals
    'Tsawwassen': {
        'lon lat': (-123.132722, 49.006165),
        'stn number': None,
        'mean sea lvl': None,
        'NEMO grid ji': (396, 305),
        'wind grid ji': (130, 155),
        'ww3 grid ji': None,
        'in berth radius': 0.0015,
    },
    'Duke Pt.': {
        'lon lat': (-123.89095676900132, 49.16340592936349),
        'stn number': None,
        'mean sea lvl': None,
        'NEMO grid ji': (481, 213),
        'wind grid ji': (142, 134),
        'ww3 grid ji': None,
        'in berth radius': 0.002,
    },
    'Horseshoe Bay': {
        'lon lat': (-123.2728, 49.3742),
        'stn number': None,
        'mean sea lvl': None,
        'NEMO grid ji': (478, 331),
        'wind grid ji': (148, 154),
        'ww3 grid ji': None,
    },
    'Departure Bay': {
        'lon lat': (-123.8909, 49.1632),
        'stn number': None,
        'mean sea lvl': None,
        'NEMO grid ji': (481, 213),
        'wind grid ji': (142, 134),
        'ww3 grid ji': None,
    },
    'Swartz Bay': {
        'lon lat': (-123.4102, 48.6882),
        'stn number': None,
        'mean sea lvl': None,
        'NEMO grid ji': (354, 225),
        'wind grid ji': (117, 144),
        'ww3 grid ji': None,
    },

    # Cities
    'Vancouver': {
        'lon lat': (-123.1207, 49.2827),
    },
    'Hope': {
        'lon lat': (-121.4419, 49.3858),
    },

    # Provinces and states
    'British Columbia': {
        'lon lat': (-123.6, 49.9),
    },
    'Washington State': {
        'lon lat': (-123.8, 47.8),
    },

    # Bodies of water
    'Pacific Ocean': {
        'lon lat': (-125.6, 48.1),
    },
    'Juan de Fuca Strait': {
        'lon lat': (-124.7, 48.47),
    },
    'Puget Sound': {
        'lon lat': (-122.67, 48),
    },
    'Strait of Georgia': {
        'lon lat': (-123.8, 49.3),
    },
    'Central SJDF': {
        'lon lat': (-123.9534, 48.281677),
        'NEMO grid ji': (315,95),
        'GEM2.5 grid ji': (101, 124),
    },
    # if you have a better location in mind for Baynes Sound, please update!
    # if not, I will after I hear from Debbie/Evie -EO
    'Baynes Sound': {
        'lon lat': (-124.86022, 49.60356),
        'NEMO grid ji': (635, 126),
    },
    # STRATOGEM STATION S3(lat,lon)=(49 7.5 N, 123 33.5 W)
    'S3': {
        'lon lat': (-123.558, 49.125),
        'NEMO grid ji': (450, 258),
        'GEM2.5 grid ji': (138, 144),
    },
    # Hakai STATION QU39 (lat,lon)=(50.0307 N, 125.0992 W)
    'QU39': {
        'lon lat': (-125.0992, 50.0307),
        'NEMO grid ji': (736, 144),
        'GEM2.5 grid ji': (189, 106),
    },
    # SJDF station for bloom timing 
    'SJDF': {
        'lon lat': (-124.07, 48.31),
        'NEMO grid ji': (329, 81),
        'GEM2.5 grid ji': (103, 121),
    },
    # Tereza's cluster stations, aligned with Vector Stations where possible.
    'Cluster_1': {
        'NEMO grid ji': (241, 212),
        'lon lat': (48.215, -123.099),
        'Vector Stn': '64'
    },
    'Cluster_2': {
        'NEMO grid ji': (294, 127),
        'lon lat': (48.261, -123.717),
        'Vector Stn': '69'
    },
    'Cluster_3': {
        'NEMO grid ji': (376, 291),
        'lon lat': (48.899, -123.138),
        'Vector Stn': '45'
    },
    'Cluster_4': {
        'NEMO grid ji': (282, 305),
        'lon lat': (48.555, -122.750),
        'Vector Stn': '53'
    },
    'Cluster_5': {
        'NEMO grid ji': (344, 271),
        'lon lat': (48.735, -123.135),
        'Vector Stn': '57'
    },
    'Cluster_6': {
        'NEMO grid ji': (320, 68),
        'lon lat': (48.249, -124.110),
        'Vector Stn': '73'
    },
    'Cluster_7': {
        'NEMO grid ji': (504, 246),
        'lon lat': (49.317, -123.801),
        'Vector Stn': '27'
    },
    'Cluster_8': {
        'NEMO grid ji': (646, 168),
        'lon lat': (49.726, -124.679),
        'Vector Stn': '12'
    },
    'Cluster_9': {
        'NEMO grid ji': (423, 300),
        'lon lat': (49.101, -123.249),
    },

    # VENUS
    'Central node': {
        # location from Ocean Networks Canada (ONC) website
        'lon lat': (-123.425825, 49.040066666),
        # depth in metres from ONC website
        'depth': 294,
        # corresponding python vertical grid index
        'NEMO grid k': 34,
        # NEMO python grid indices: j in y direction, i in x direction
        'NEMO grid ji': (424, 266),
        # HRDPS python grid indices: j in y direction, i in x direction
        'wind grid ji': (133, 147),
        # ONC data web services API station code
        'ONC stationCode': 'SCVIP',
    },
    'Delta BBL node': {
        # ONC's description is "Delta/Lower Slope/Bottom Boundary Layer"
        'lon lat': (-123.339633, 49.074766),
        'depth': 143,
        'NEMO grid k': 28,
        'NEMO grid ji': (424, 283),
        'wind grid ji': (134, 150),
        'ONC stationCode': 'LSBBL',
    },
    'Delta DDL node': {
        # ONC's description is "Delta/Upper Slope/Delta Dynamics Laboratory"
        'lon lat': (-123.32972, 49.08495),
        'depth': 107,
        'NEMO grid k': 27,
        'NEMO grid ji': (426, 286),
        'wind grid ji': (135, 150),
        'ONC stationCode': 'USDDL',
    },
    'East node': {
        'lon lat': (-123.316836666, 49.04316),
        'depth': 164,
        'NEMO grid k': 29,
        'NEMO grid ji': (417, 283),
        'wind grid ji': (133, 150),
        'ONC stationCode': 'SEVIP',
    },

    # Lightstations
    'Ballenas Islands': {
        'lon lat': (-124.160, 49.350),
        'NEMO grid ji': (536, 197),
        'wind grid ji': (152, 127),
    },
    'Discovery Island': {
        'lon lat': (-123.226, 48.425),
        'NEMO grid ji': (291, 219),
        'wind grid ji': (104, 148),
    },
    'Entrance Island': {
        'lon lat': (-123.811, 49.209),
        'NEMO grid ji': (484, 231),
        'wind grid ji': (143, 137),
    },
    'Race Rocks': {
        'lon lat': (-123.531, 48.298),
        'NEMO grid ji': (288, 159),
        'wind grid ji': (99, 137),
    },
    'Sand Heads': {
        'lon lat': (-123.30, 49.10),
        'stn number': 7594,  # Marlene's coordinates for Tide Station are slightly different.  Leaving as is.
        'NEMO grid ji': (426, 293),  # match Domain file
        'mean sea lvl': 2.875,
        'hist max sea lvl': 5.61-3.09+2.875,  # based on Point Atk.
        'GEM2.5 grid ji': (135, 151),
        'wind grid ji': (135, 151),
        'ww3 grid ji': (246, 385),
    },
    'Saturna Island': {
        'lon lat': (-123.045, 48.784),
        'NEMO grid ji': (347, 290),
        'wind grid ji': (119, 156),
    },
    'Sisters Islet': {
        'lon lat': (-124.43, 49.49),
        'NEMO grid ji': (582, 175),
        'GEM2.5 grid ji': (160, 120),
        'wind grid ji': (160, 120),
    },

    # Wind stations
    'Esquimalt': {
        'lon lat': (-123.439, 48.432),
        'NEMO grid ji': (307, 189),
        'wind grid ji': (105, 141),
    },
    'Pam Rocks': {
        'lon lat': (-123.299, 49.488),
        'NEMO grid ji': (502, 341),
        'wind grid ji': (153, 154),
    },

    # Wave buoys
    'Halibut Bank': {
        'lon lat': (-123.72, 49.34),
        'NEMO grid ji': (503, 261),
        'GEM2.5 grid ji': (149, 141),
        'wind grid ji': (149, 141),
        'EC buoy number': 46146,
    },
    'Sentry Shoal': {
        'lon lat': (-125.0, 49.92),
        'NEMO grid ji': (707, 145),
        'GEM2.5 grid ji': (183, 107),
        'wind grid ji': (183, 107),
        'EC buoy number': 46131,
    },

    # Seasonal Chl sensor at town dock
    'Egmont': {
        'lon lat': (-123.93, 49.75),
        'NEMO grid ji': (598,282),
    },

    # Airports
    'Comox Airport': {
        'lon lat': (-124.900, 49.717),
        'NEMO grid ji': (660, 134),
        'wind grid ji' : (173, 108),
    },
    'Squamish Airport': {
        'lon lat': (-123.161, 49.783),
        'wind grid ji' : (166, 161),
    },
    'YVR': {
        'lon lat': (-123.184, 49.195),
        'GEM2.5 grid ji' : (139, 155),
        'wind grid ji' : (139, 155),
    },
    # ORCA Buoys
    'Hoodsport': {
        'lon lat': (-123.1126, 47.4218),
        'NEMO grid ji': (89, 114),
    },
    'Twanoh': {
        'lon lat': (-123.0083, 47.3750),
        'NEMO grid ji': (72, 123),
    },
    'DabobBay': {
        'lon lat': (-122.8029, 47.8031),
        'NEMO grid ji': (141, 205),
    },
    'PointWells': {
        'lon lat': (-122.3972, 47.7612),
        'NEMO grid ji': (104, 259),
    },
    'CarrInlet': {
        'lon lat': (-122.7300, 47.2800),
        'NEMO grid ji': (34, 152),
    },
    'Hansville': {
        'lon lat': (-122.627, 47.90733),
        'NEMO grid ji': (148, 243),
    },
    'Dockton': {
        'lon lat': (-122.45722, 47.37611),
        'NEMO grid ji': (34, 204),
    },
    'PointWilliams': {
        'lon lat': (-122.40612, 47.53716),
        'NEMO grid ji': (62, 231),
    }
}
# Aliases:
PLACES['Sandheads'] = PLACES['Sand Heads']


#: Names of tide gauge sites,
#: ordered from south and west to north and east.
#: These names are keys of the :py:data:`~salishsea_tools.places.PLACES` dict.
TIDE_GAUGE_SITES = (
    'Neah Bay', 'Victoria', 'Cherry Point', 'Point Atkinson', 'Nanaimo',
    'Campbell River',
)
#: Other tide sites, no wind data at these (just to keep the number of arrows under control)
SUPP_TIDE_SITES = (
    'Friday Harbor', 'Halfmoon Bay', 'Patricia Bay', 'Port Renfrew',
    'Squamish', 'Boundary Bay', 'Sand Heads',
)


[docs] def DispGeoLocs(): """Display locations in map coordinates :returns: figure handle :rtype: :py:class:`matplotlib.figure.Figure` """ from mpl_toolkits.basemap import Basemap from matplotlib import pyplot as plt places2=PLACES.copy() places2.pop('Sandheads') places2.pop('Departure Bay') width = 300000; lon_0 = -124.3; lat_0 = 49 fig=plt.figure(figsize=(20,20)) m = Basemap(width=width,height=width,projection='aeqd', resolution='h', lat_0=lat_0,lon_0=lon_0) m.drawmapboundary() m.drawcoastlines(linewidth=0.5) m.drawrivers() m.drawparallels(range(40,60,2)) m.drawmeridians(range(-130,-110,2)) #plt.title('EC River Stations') # map stations: for pl in places2.keys(): if 'lon lat' in places2[pl].keys(): lon,lat=places2[pl]['lon lat'] if (47<lat<51) & (-128<lon<-120): if pl in ('Sandy Cove','Calamity Point','Port Moody','Vancouver','New Westminster','Delta DDL node','East node','Boundary Bay','Duke Pt.'): xpt, ypt = m(lon, lat) xpt2, ypt2 = m(lon+.03, lat) m.plot(xpt,ypt,'ro') plt.text(xpt2,ypt2,pl,fontsize=10,fontweight='bold', ha='left',va='center',color='r') else: xpt, ypt = m(lon, lat) xpt2, ypt2 = m(lon-.03, lat) m.plot(xpt,ypt,'ro') plt.text(xpt2,ypt2,pl,fontsize=10,fontweight='bold', ha='right',va='center',color='r') return fig
[docs] def DispGridLocs(mesh_mask='/ocean/eolson/MEOPAR/NEMO-forcing/grid/mesh_mask201702_noLPE.nc'): """Display locations in NEMO model grid coordinates :arg mesh_mask: string with path to the meshmask you would like to plot; 201702 default :type mesh_mask: str :returns: figure handle :rtype: :py:class:`matplotlib.figure.Figure` """ import numpy as np # only grid from mpl_toolkits.basemap import Basemap import netCDF4 as nc # only grid from matplotlib import pyplot as plt from salishsea_tools import viz_tools # only grid places2=PLACES.copy() places2.pop('Sandheads') places2.pop('Departure Bay') with nc.Dataset(mesh_mask) as fm: tmask=np.copy(fm.variables['tmask']) e3t_0=np.copy(fm.variables['e3t_0']) bathy=np.sum(e3t_0[0,:,:,:]*tmask[0,:,:,:],0) cm=plt.cm.get_cmap('Blues') cm.set_bad('lightgray') fig,ax=plt.subplots(1,2,figsize=(18,18)) viz_tools.set_aspect(ax[0]) viz_tools.set_aspect(ax[1]) ax[0].pcolormesh(np.ma.masked_where(tmask[0,0,:,:]==0,bathy),cmap=plt.cm.get_cmap('Blues')) # map stations: for pl in places2.keys(): if 'NEMO grid ji' in places2[pl].keys() and places2[pl]['NEMO grid ji'] is not None: j,i=places2[pl]['NEMO grid ji'] if pl in ('Sandy Cove','Calamity Point','Port Moody','Vancouver','New Westminster', 'East Node','Duke Pt.','Halibut Bank','Cherry Point','Central SJDF','Friday Harbor'): ax[0].plot(i,j,'ro') ax[0].text(i+4,j,pl,fontsize=10,fontweight='bold', ha='left',va='center',color='r') elif pl in ('Sand Heads','Delta DDL node','Central Node','Delta BBL node','Cluster_9', 'East Node','Woodwards Landing'): ax[0].plot(i,j,'ro') else: ax[0].plot(i,j,'ro') ax[0].text(i-4,j,pl,fontsize=10,fontweight='bold', ha='right',va='center',color='r') xl=(240,340) yl=(400,450) ax[1].pcolormesh(np.ma.masked_where(tmask[0,0,:,:]==0,bathy),cmap=plt.cm.get_cmap('Blues')) # map stations: for pl in places2.keys(): if 'NEMO grid ji' in places2[pl].keys() and places2[pl]['NEMO grid ji'] is not None: j,i=places2[pl]['NEMO grid ji'] if (xl[0]<i<xl[1]) & (yl[0]<j<yl[1]): if pl in ('Sandy Cove','Calamity Point','Port Moody','Vancouver','New Westminster','Friday Harbor', 'East Node','Duke Point','Halibut Bank','Cherry Point', 'Sand Heads','Cluster_9','Central SJDF'): ax[1].plot(i,j,'ro') ax[1].text(i+1,j,pl,fontsize=10,fontweight='bold', ha='left',va='center',color='r') elif pl in ('Delta BBL node'): ax[1].plot(i,j,'ro') ax[1].text(i,j-2,pl,fontsize=10,fontweight='bold', ha='center',va='center',color='r') elif pl in ('Delta DDL node'): ax[1].plot(i,j,'ro') ax[1].text(i,j+2,pl,fontsize=10,fontweight='bold', ha='right',va='center',color='r') else: ax[1].plot(i,j,'ro') ax[1].text(i-1,j,pl,fontsize=10,fontweight='bold', ha='right',va='center',color='r') ax[1].set_xlim(xl[0],xl[1]) ax[1].set_ylim(yl[0],yl[1]) return fig