def test_global_array(test_data): reader_global = reader_global_landmask.Reader() assert reader_global.extent is None reader_nordic = reader_ROMS_native.Reader( test_data + '2Feb2016_Nordic_sigma_3d/Nordic-4km_SLEVELS_avg_00_subset2Feb2016.nc') lon = np.array([15., 5.]) lat = np.array([65.6, 65.6]) # global oc = OceanDrift(loglevel=00) oc.add_reader([reader_nordic, reader_global]) en, en_prof, missing = oc.get_environment(['land_binary_mask'], reader_nordic.start_time, lon, lat, np.array([0, 0]), None) np.testing.assert_array_equal(en.land_binary_mask, np.array([True, False])) assert len( oc.readers) == 2 # make sure opendrift doesn't add default basemap
def test_density(self): """Test density""" outfile = 'test_xarray.nc' if os.path.exists(outfile): os.remove(outfile) o = OceanDrift(loglevel=20) o.set_config('environment:fallback:land_binary_mask', 0) t1 = datetime.now() t2 = t1 + timedelta(hours=6) o.seed_elements(time=t1, lon=4, lat=60, number=100, origin_marker=0) o.seed_elements(time=[t1, t2], lon=4.2, lat=60.2, number=100, origin_marker=1) o.seed_elements(time=[t1, t2], lon=4.1, lat=60.1, number=100, origin_marker=2) reader_x = reader_oscillating.Reader('x_sea_water_velocity', amplitude=1, zero_time=t1) reader_y = reader_oscillating.Reader('y_sea_water_velocity', amplitude=1, zero_time=t2) o.add_reader([reader_x, reader_y]) o.set_config('drift:horizontal_diffusivity', 10) o.run(duration=timedelta(hours=12), time_step=1800, outfile=outfile) #o.plot(fast=True) density_pixelsize_m=5000 H, Hsub, Hsurf, lon_array, lat_array = o.get_density_array(pixelsize_m=density_pixelsize_m) ox = opendrift.open_xarray(outfile) Hx = ox.get_histogram(pixelsize_m=density_pixelsize_m) self.assertAlmostEqual(lon_array[0], 3.94, 1) self.assertAlmostEqual(lon_array[-1], 4.76, 1) self.assertAlmostEqual(Hx.lon_bin[0].values, 3.90, 1) self.assertAlmostEqual(Hx.lon_bin[-1].values, 4.67, 1) self.assertEqual(Hx.sum(dim='origin_marker').shape, H.shape) Hsum = H.sum(axis=1).sum(axis=1) Hxsum = Hx.sum(('lon_bin', 'lat_bin', 'origin_marker')) self.assertEqual(Hsum[0], 118) self.assertEqual(Hxsum[0], 118) self.assertEqual(Hsum[-1], 300) self.assertEqual(Hxsum[-1], 300) os.remove(outfile)
def test_stranding_options(self): reader_osc = reader_oscillating.Reader('x_sea_water_velocity', amplitude=1, zero_time=datetime.now()) reader_basemap = reader_basemap_landmask.Reader(llcrnrlon=12, llcrnrlat=67.6, urcrnrlon=13.6, urcrnrlat=68.1, resolution='i', projection='merc') # Three different stranding options, with # expected final status and position options = ['stranding', 'previous', 'none'] status = ['stranded', 'active', 'active'] lons = [12.930, 13.348, 12.444] for i, option in enumerate(options): o = OceanDrift(loglevel=30) o.set_config('general:coastline_action', option) o.add_reader([reader_osc, reader_basemap]) # Adding northwards drift o.fallback_values['y_sea_water_velocity'] = .2 o.seed_elements(lon=12.2, lat=67.7, radius=0, time=reader_osc.zero_time) o.run(steps=28, time_step=3600 * 2) #o.plot() print('Testing stranding: %s' % option) if len(o.elements) == 1: el = o.elements else: el = o.elements_deactivated self.assertEqual(o.status_categories[int(el.status)], status[i]) self.assertIsNone( np.testing.assert_array_almost_equal(el.lon, lons[i], 2))
def test_outside_domain(self): o = OceanDrift(loglevel=50) reader_osc_x = reader_oscillating.Reader('x_sea_water_velocity', amplitude=1, zero_time=datetime.now()) reader_osc_y = reader_oscillating.Reader('y_sea_water_velocity', amplitude=1, zero_time=datetime.now()) o.add_reader([reader_osc_x, reader_osc_y]) o.set_config('drift:deactivate_east_of', 2.1) o.set_config('drift:deactivate_west_of', 1.9) o.set_config('drift:deactivate_south_of', 59.9) o.set_config('drift:deactivate_north_of', 60.1) o.set_config('environment:fallback:land_binary_mask', 0) o.seed_elements(lon=2, lat=60, number=1000, time=datetime.now(), radius=10000) o.run(duration=timedelta(hours=5)) self.assertEqual(o.num_elements_deactivated(), 768) self.assertEqual(o.num_elements_active(), 232)
def test_config_constant_fallback(self): o = OceanDrift(loglevel=0) reader_arome = reader_netCDF_CF_generic.Reader(o.test_data_folder() + '16Nov2015_NorKyst_z_surface/arome_subset_16Nov2015.nc') reader_norkyst = reader_netCDF_CF_generic.Reader(o.test_data_folder() + '16Nov2015_NorKyst_z_surface/norkyst800_subset_16Nov2015.nc') print(reader_norkyst, reader_arome) o.add_reader([reader_norkyst, reader_arome]) o.seed_elements(lon=4, lat=60, time=reader_arome.end_time - timedelta(hours=3), number=1) o.set_config('environment:fallback:land_binary_mask', 0) o.set_config('environment:fallback:x_sea_water_velocity', 1) o.set_config('environment:fallback:y_sea_water_velocity', 0) o.set_config('environment:constant:x_wind', 0) o.set_config('environment:constant:y_wind', 5) o.run(duration=timedelta(hours=6)) y_wind = np.array(o.get_property('y_wind')[0][:,0]) x_current = np.array(o.get_property('x_sea_water_velocity')[0][:,0]) # Check that constant wind is used for whole simulation self.assertAlmostEqual(y_wind[0], 5, 2) self.assertAlmostEqual(y_wind[-1], 5, 2) # Check that fallback current is used only after end of reader self.assertAlmostEqual(x_current[0], 0.155, 2) self.assertAlmostEqual(x_current[-1], 1, 2)
def test_global_array(test_data): shpfilename = shpreader.natural_earth(resolution='110m', category='cultural', name='admin_0_countries') reader_landmask = reader_shape.Reader.from_shpfiles(shpfilename) reader_nordic = reader_ROMS_native.Reader( test_data + '2Feb2016_Nordic_sigma_3d/Nordic-4km_SLEVELS_avg_00_subset2Feb2016.nc') lon = np.array([15., 5.]) lat = np.array([65.6, 65.6]) # global oc = OceanDrift(loglevel=00) oc.add_reader([reader_nordic, reader_landmask]) en, en_prof, missing = oc.get_environment(['land_binary_mask'], reader_nordic.start_time, lon, lat, np.array([0, 0]), None) np.testing.assert_array_equal(en.land_binary_mask, np.array([True, False])) assert len( oc.readers) == 2 # make sure opendrift doesn't add default basemap
def test_config_seed(self): #o = Leeway(loglevel=20) o = OceanDrift(loglevel=20) o.list_configspec()
#!/usr/bin/env python """ Drifter ================================== """ from datetime import timedelta import numpy as np from opendrift.readers import reader_netCDF_CF_generic from opendrift.models.oceandrift import OceanDrift o = OceanDrift( loglevel=20) # Basic drift model suitable for passive tracers or drifters #%% # Preparing Readers reader_current = reader_netCDF_CF_generic.Reader( o.test_data_folder() + '16Nov2015_NorKyst_z_surface/norkyst800_subset_16Nov2015.nc') reader_wind = reader_netCDF_CF_generic.Reader( o.test_data_folder() + '16Nov2015_NorKyst_z_surface/arome_subset_16Nov2015.nc') o.add_reader([reader_current, reader_wind]) #%% # Seeding elements # # Elements are moved with the ocean current, in addition to a fraction of # the wind speed (wind_drift_factor). This factor depends on the properties
#!/usr/bin/env python """ Thredds resources for GUI ========================= """ from datetime import datetime from opendrift.models.oceandrift import OceanDrift from opendrift.readers.reader_netCDF_CF_generic import Reader o = OceanDrift(loglevel=0) thredds_resources = open( o.test_data_folder() + '../../opendrift/scripts/data_sources.txt').readlines() times = {} #%% # Open each thredds dataset to check contents and spatial coverage for t in thredds_resources: if t.startswith('http') and 'nrt.cmems' not in t: start = datetime.now() print('\n#%%\n%s\n' % t) r = Reader(t) print(r) ts = str(datetime.now() - start) times[t] = ts print('Time to open reader: ', ts) if r.global_coverage(): lscale = 'coarse' else:
def test_invalid_config(self): o = OceanDrift(loglevel=20) with self.assertRaises(ValueError): o.set_config('seed:number_of_elements', 0) o.set_config('seed:number_of_elements', 100) self.assertEqual(o.get_config('seed:number_of_elements'), 100)
def test_automatic_landmask(self): o = OceanDrift(loglevel=20) self.assertRaises(ValueError, o.run) o.seed_elements(lon=4, lat=60, time=datetime(2016,9,1)) o.run(steps=2)
def test_output_time_step(self): o1 = OceanDrift(loglevel=30) norkyst = reader_netCDF_CF_generic.Reader( o1.test_data_folder() + '16Nov2015_NorKyst_z_surface/norkyst800_subset_16Nov2015.nc') basemap = reader_basemap_landmask.Reader(llcrnrlon=4.5, llcrnrlat=60.0, urcrnrlon=5.2, urcrnrlat=60.5, resolution='i', projection='merc') o1.add_reader([basemap, norkyst]) o1.seed_elements(4.96, 60.1, radius=3000, number=100, time=norkyst.start_time) o1.run(duration=timedelta(hours=12), time_step=timedelta(minutes=30), time_step_output=timedelta(minutes=30), outfile='test_time_step30.nc') # Check length of time array and output array time = o1.get_time_array()[0] self.assertEqual(o1.history.shape[1], len(time)) self.assertEqual(o1.start_time, time[0]) self.assertEqual(o1.time, time[-1]) # Second run, with larger output time step o2 = OceanDrift(loglevel=30) o2.add_reader([basemap, norkyst]) o2.seed_elements(4.96, 60.1, radius=3000, number=100, time=norkyst.start_time) o2.run(duration=timedelta(hours=12), time_step=timedelta(minutes=30), time_step_output=timedelta(minutes=60), outfile='test_time_step60.nc') self.assertEqual(o1.history.shape, (100, 25)) self.assertEqual(o2.history.shape, (100, 13)) # Check that start and end conditions (longitudes) are idential self.assertItemsEqual(o1.history['lon'][:, 24].compressed(), o2.history['lon'][:, 12].compressed()) self.assertItemsEqual(o1.history['lon'][:, 0].compressed(), o2.history['lon'][:, 0].compressed()) # Check that also run imported from file is identical o1i = OceanDrift(loglevel=20) o1i.io_import_file('test_time_step30.nc') o2i = OceanDrift(loglevel=20) o2i.io_import_file('test_time_step60.nc') os.remove('test_time_step30.nc') os.remove('test_time_step60.nc') self.assertItemsEqual(o2i.history['lon'][:, 12].compressed(), o2.history['lon'][:, 12].compressed()) # Check number of activated elements self.assertEqual(o1.num_elements_total(), o2.num_elements_total()) self.assertEqual(o1.num_elements_total(), o1i.num_elements_total()) self.assertEqual(o1.num_elements_total(), o2i.num_elements_total()) # Check number of deactivated elements self.assertEqual(o1.num_elements_deactivated(), o2.num_elements_deactivated()) self.assertEqual(o1.num_elements_deactivated(), o1i.num_elements_deactivated()) self.assertEqual(o1.num_elements_deactivated(), o2i.num_elements_deactivated())
def test_seed_cone(self): # Some cases with expected outcome lon0 = 3 lon1 = 4 lon2 = 5 lat0 = 60 lat1 = 60.2 lat2 = 60.4 lon_vec = np.array([lon0, lon1, lon2]) lat_vec = np.array([lat0, lat1, lat2]) t0 = datetime.now() t1 = t0 + timedelta(hours=6) t2 = t1 + timedelta(hours=6) t_vec = [t0, t1, t2] r0 = 1000 r1 = 2000 number_config = 222 cases = [ { 'lon': lon0, 'lat': lat0, 'time': t0, 'number': None, 'expected': number_config }, { 'lon': lon0, 'lat': lat0, 'time': t0, 'number': 12, 'expected': 12, 'maxlat': lat0 }, { 'lon': lon0, 'lat': lat0, 'time': t0, 'radius': 1000, 'number': 12, 'expected': 12, 'maxlat': lat0 + .013 }, { 'lon': lon0, 'lat': lat0, 'time': [t0, t1], 'maxtime': t1, 'number': 12, 'expected': 12 }, { 'lon': lon0, 'lat': lat0, 'time': t_vec, 'number': 12, 'expected': 'error' }, { 'lon': lon_vec, 'lat': lat_vec, 'time': t0, 'number': None, 'expected': 'error' }, { 'lon': lon0, 'lat': lat0, 'time': t0, 'wind_drift_factor': .05, 'number': None, 'expected': number_config }, { 'lon': [lon0, lon1], 'lat': [lat0, lat1], 'time': t0, 'number': None, 'expected': number_config }, { 'lon': [lon0, lon1], 'lat': [lat0, lat1], 'time': t0, 'number': 12, 'expected': 12 }, { 'lon': [lon0, lon1], 'lat': [lat0, lat1], 'time': t0, 'radius': 0, 'number': 200, 'expected': 200, 'maxlat': lat1 }, { 'lon': [lon0, lon1], 'lat': [lat0, lat1], 'time': t0, 'radius': 2000, 'number': 200, 'expected': 200, 'maxlat': lat1 + .024 }, { 'lon': [lon0, lon1], 'lat': [lat0, lat1], 'time': t0, 'radius': [1000, 2000], 'number': 200, 'expected': 200, 'maxlat': lat1 + .024 }, { 'lon': [lon0, lon1], 'lat': [lat0, lat1], 'time': t0, 'radius': [1000, 2000, 3000], 'number': 200, 'expected': 'error' }, #'wind_drift_factor': [.01, .02, .03], { 'lon': [lon0, lon1], 'lat': [lat0, lat1], 'time': [t0, t1], 'number': None, 'expected': number_config, 'maxtime': t1 }, { 'lon': [lon0, lon1], 'lat': [lat0, lat1], 'time': [t0, t1], 'radius': [r0, r1], 'number': None, 'expected': number_config, 'maxtime': t1 }, { 'lon': [lon0, lon1], 'lat': [lat0, lat1], 'time': [t0, t1], 'radius': [r0, r0], 'number': None, 'expected': number_config, 'maxtime': t1 }, ] for case in cases: o = OceanDrift(loglevel=50) o._set_config_default('seed:number', number_config) expected = case['expected'] del case['expected'] if 'maxlat' in case: maxlat = case['maxlat'] del case['maxlat'] else: maxlat = None if 'maxtime' in case: maxtime = case['maxtime'] del case['maxtime'] else: maxtime = None if expected == 'error': with self.assertRaises(ValueError): n = o.seed_cone(**case) else: o.seed_cone(**case) self.assertEqual(o.num_elements_total(), expected) if maxlat is not None: self.assertAlmostEqual(o.elements_scheduled.lat.max(), maxlat, 2) if maxtime is not None: self.assertEqual( o.elements_scheduled_time.max().replace(microsecond=0), maxtime.replace(microsecond=0)) if 'wind_drift_factor' in case: self.assertEqual( np.array(case['wind_drift_factor']).max().astype( np.float32), o.elements_scheduled.wind_drift_factor.max())
def test_vertical_mixing_profiles(self): # Testing an isolated mixing timestep cases = [ # Some cases with expected outcome { 'vt': 0, 'K': 0, 'K_below': .01, 'T': 60, # No mixing 'zmin': -10, 'zmax': -10, 'zmean': -10 }, { 'vt': -.005, 'K': 0, 'K_below': .01, 'T': 60, # Sinking #'zmin': -74.0, 'zmax': -21.4, 'zmean': -50.2}, # With old seed_elements 'zmin': -74.79, 'zmax': -21.6, 'zmean': -49.97 }, { 'vt': 0, 'K': .01, 'K_below': .01, 'T': 60, # Mixing #'zmin': -39.8, 'zmax': -0.1, 'zmean': -14.5}, 'zmin': -42.76, 'zmax': -0.02, 'zmean': -14.38 }, { 'vt': .005, 'K': .01, 'K_below': .01, 'T': 60, # Mixing and rising #'zmin': -8.1, 'zmax': -0.01, 'zmean': -2.1}, 'zmin': -7.86, 'zmax': -0.01, 'zmean': -2.1 }, { 'vt': -0.005, 'K': .01, 'K_below': .01, 'T': 60, # Mixing and sinking #'zmin': -75.8, 'zmax': -20.7, 'zmean': -48.1}, 'zmin': -78.76, 'zmax': -19.74, 'zmean': -48.0 }, { 'vt': 0, 'K': .02, 'K_below': .001, 'T': 60, # Mixing in mixed layer #'zmin': -22.8, 'zmax': -0.1, 'zmean': -9.8}, 'zmin': -21.3, 'zmax': -0.1, 'zmean': -9.55 }, ] N = 100 z = np.arange(0, -30, -2) time = datetime.now() for case in cases: diffusivity = np.ones(z.shape) * case['K'] diffusivity[z < -15] = case['K_below'] o = OceanDrift(loglevel=20) o.set_config('drift:vertical_mixing', True) o.set_config('vertical_mixing:diffusivitymodel', 'environment') o.set_config('vertical_mixing:timestep', case['T']) o.seed_elements(lon=4, lat=60, z=-10, time=time, number=N, terminal_velocity=case['vt']) o.time = time o.time_step = timedelta(hours=2) o.release_elements() o.set_config('environment:fallback:land_binary_mask', 0) o.environment = np.array(np.ones(N) * 100, dtype=[('sea_floor_depth_below_sea_level', np.float32)]).view(np.recarray) o.environment_profiles = { 'z': z, 'ocean_vertical_diffusivity': np.tile(diffusivity, (N, 1)).T } o.set_fallback_values() o.vertical_mixing() self.assertAlmostEqual(o.elements.z.min(), case['zmin'], 1) self.assertAlmostEqual(o.elements.z.max(), case['zmax'], 1) self.assertAlmostEqual(o.elements.z.mean(), case['zmean'], 1)
def test_automatic_basemap(self): o = OceanDrift(loglevel=20) self.assertRaises(ValueError, o.run) o.seed_elements(lon=4, lat=60, time=datetime(2016, 9, 1)) o.set_config('general:basemap_resolution', 'c') # To make test fast o.run(steps=2)
""" Convolve input ============== Decreasing the spatial resolution of fields from a reader by convolution. This may improve accuracy, see: https://doi.org/10.1016/j.rse.2019.01.001 """ from datetime import datetime, timedelta import matplotlib.pyplot as plt from opendrift.readers import reader_netCDF_CF_generic from opendrift.models.oceandrift import OceanDrift lon = 4.9 lat = 60.0 o = OceanDrift(loglevel=20) reader_norkyst = reader_netCDF_CF_generic.Reader( o.test_data_folder() + '16Nov2015_NorKyst_z_surface/norkyst800_subset_16Nov2015.nc') time = reader_norkyst.start_time o.add_reader([reader_norkyst]) o.seed_elements(lon, lat, radius=1000, number=1000, time=time) o.run(steps=20) #%% # Store final field of x-component of current original_current = reader_norkyst.var_block_after[list( reader_norkyst.var_block_after.keys( ))[0]].data_dict['x_sea_water_velocity'].copy()
import os import sys import numpy as np from datetime import datetime, timedelta from opendrift.readers import reader_global_landmask from opendrift.readers import reader_ROMS_native_MOANA from opendrift.models.oceandrift import OceanDrift #from opendrift.models.pelagicplankton_moana import PelagicPlanktonDrift #from opendrift.models.sedimentdrift import SedimentDrift ############################### # MODEL SELECTION ############################### o = OceanDrift(loglevel=100) #o = SedimentDrift(loglevel=100) # 0 for debug output #o = PelagicPlanktonDrift(loglevel=50) # Set loglevel to 0 for debug information o.max_speed = 3.0 # ############################### # READERS ############################### thredds_path_1 = 'http://thredds.moanaproject.org:8080/thredds/dodsC/moana/ocean/NZB/v1.9/raw_3D/nz5km_his_201709.nc?ntimes,dt,hc,grid,s_rho[5:1:12],Cs_r[5:1:12],h[0:1:466][0:1:396],lon_rho[0:1:466][0:1:396],lat_rho[0:1:466][0:1:396],lon_u[0:1:466][0:1:395],lat_u[0:1:466][0:1:395],lon_v[0:1:465][0:1:396],lat_v[0:1:465][0:1:396],lon_psi[0:1:465][0:1:395],angle[0:1:466][0:1:396],mask_rho[0:1:466][0:1:396],mask_u[0:1:466][0:1:395],mask_v[0:1:465][0:1:396],ocean_time[0:1:240],z_rho[0:1:240][5:1:12][0:1:466][0:1:396],u_eastward[0:1:240][5:1:12][0:1:466][0:1:396],v_northward[0:1:240][5:1:12][0:1:466][0:1:396]' # Limit to selected depths (raw data: [0:1:39])#'http://thredds.moanaproject.org:8080/thredds/dodsC/moana/ocean/NZB/v1.9/raw_3D/nz5km_his_201710.nc' reader_moana_v19_1 = reader_ROMS_native_MOANA.Reader( [thredds_path_1]) #load data for that year reader_moana_v19_1.multiprocessing_fail = True # bypass the use of multi core for coordinates conversion and seems to make the model run much faster. thredds_path_2 = 'http://thredds.moanaproject.org:8080/thredds/dodsC/moana/ocean/NZB/v1.9/raw_3D/nz5km_his_201708.nc?ntimes,dt,hc,grid,s_rho[5:1:12],Cs_r[5:1:12],h[0:1:466][0:1:396],lon_rho[0:1:466][0:1:396],lat_rho[0:1:466][0:1:396],lon_u[0:1:466][0:1:395],lat_u[0:1:466][0:1:395],lon_v[0:1:465][0:1:396],lat_v[0:1:465][0:1:396],lon_psi[0:1:465][0:1:395],angle[0:1:466][0:1:396],mask_rho[0:1:466][0:1:396],mask_u[0:1:466][0:1:395],mask_v[0:1:465][0:1:396],ocean_time[0:1:248],z_rho[0:1:248][5:1:12][0:1:466][0:1:396],u_eastward[0:1:248][5:1:12][0:1:466][0:1:396],v_northward[0:1:248][5:1:12][0:1:466][0:1:396]' # to finish the run in the previous month reader_moana_v19_2 = reader_ROMS_native_MOANA.Reader([thredds_path_2]) #
""" Convolve input ============= Demonstrating how the spatial resolution of fields from a reader may be reduced. """ from datetime import datetime, timedelta import matplotlib.pyplot as plt from opendrift.readers import reader_netCDF_CF_generic from opendrift.models.oceandrift import OceanDrift lon = 4.9; lat = 60.0 o = OceanDrift() reader_norkyst = reader_netCDF_CF_generic.Reader(o.test_data_folder() + '16Nov2015_NorKyst_z_surface/norkyst800_subset_16Nov2015.nc') time = reader_norkyst.start_time o.add_reader([reader_norkyst]) o.seed_elements(lon, lat, radius=1000, number=1000, time=time) o.run(steps=20) # Store final field of x-component of current original_current = reader_norkyst.var_block_after[list(reader_norkyst.var_block_after.keys())[0]].data_dict['x_sea_water_velocity'].copy() # For the second run, the NorKyst currents are convolved with a kernel, # effectively lowering the spatial resolution. # <reader>.convolve may also be given as an array (kernel) directly N = 10 # Convolusion kernel size
def test_seed_cone(self): o = OceanDrift(loglevel=20) o.seed_cone(time=[datetime.now(), datetime.now() + timedelta(hours=3)], number=100, lat=[60.5, 60.6], lon=[4.4, 4.5]) self.assertAlmostEqual(o.elements_scheduled.lon[50], 4.450, 2)
def make_OceanDrift_object(self): self.o = OceanDrift(loglevel=30) self.fake_eddy = reader_ArtificialOceanEddy.Reader(2, 62) self.reader_landmask = reader_global_landmask.Reader( extent=[-1.5, 59, 7, 64]) self.o.add_reader([self.fake_eddy, self.reader_landmask])
def test_dateline(self): # Make synthetic netCDF file with currents from 0 to 360 deg longitude fc = 'opendrift_test_current_0_360.nc' lon = np.arange(0, 360) lat = np.arange(-88, 89) start_time = datetime(2021, 1, 1) time = [start_time + i * timedelta(hours=24) for i in range(3)] t, xcurr, ycurr = np.meshgrid(time, np.zeros(lat.shape), np.zeros(lon.shape), indexing='ij') xcurr[:, :, 0:180] = 1 # eastward xcurr[:, :, 180:] = -1 # westward, i.e. current divergence at lon=0 ds = xr.Dataset( { "xcurr": (("time", "lat", "lon"), xcurr, { 'standard_name': 'x_sea_water_velocity' }), "ycurr": (("time", "lat", "lon"), ycurr, { 'standard_name': 'y_sea_water_velocity' }) }, coords={ "lon": lon, "lat": lat, "time": time }) ds.to_netcdf(fc) # Make synthetic netCDF file with winds from -180 to 180 deg longitude fw = 'opendrift_test_winds_180_180.nc' lon = np.arange(-180, 180) t, xwind, ywind = np.meshgrid(time, np.zeros(lat.shape), np.zeros(lon.shape), indexing='ij') ywind[:, :, 0:180] = 1 # northward ywind[:, :, 180:] = -1 # southward, i.e. wind divergence at lon=180 ds = xr.Dataset( { "xwind": (("time", "lat", "lon"), xwind, { 'standard_name': 'x_wind' }), "ywind": (("time", "lat", "lon"), ywind, { 'standard_name': 'y_wind' }) }, coords={ "lon": lon, "lat": lat, "time": time }) ds.to_netcdf(fw) reader_current = reader_netCDF_CF_generic.Reader(fc) reader_wind = reader_netCDF_CF_generic.Reader(fw) # Simulation across 0 meridian o = OceanDrift(loglevel=30) o.add_readers_from_list([fc, fw]) o.seed_elements(lon=[-2, 2], lat=[60, 60], time=start_time, wind_drift_factor=.1) o.run(steps=2) # Check that current give divergence, and that # wind is northwards east of 0 and southwards to the east np.testing.assert_array_almost_equal(o.elements.lon, [-2.129, 2.129], decimal=3) np.testing.assert_array_almost_equal(o.elements.lat, [60.006, 59.994], decimal=3) # Simulation across dateline (180 E/W) o = OceanDrift(loglevel=30) o.add_readers_from_list([fc, fw]) o.seed_elements(lon=[-175, 175], lat=[60, 60], time=start_time, wind_drift_factor=.1) o.run(steps=2) #o.plot(fast=True) # Check that current give convergence, and that # wind is northwards east of 180 and southwards to the west np.testing.assert_array_almost_equal(o.elements.lon, [-175.129, 175.129], decimal=3) np.testing.assert_array_almost_equal(o.elements.lat, [60.006, 59.994], decimal=3) # Cleaning up os.remove(fw) os.remove(fc)
# # Copyright 2015, Knut-Frode Dagestad, MET Norway import unittest from datetime import datetime, timedelta import numpy as np from opendrift.models.oceandrift import OceanDrift from opendrift.readers import reader_netCDF_CF_generic from opendrift.readers import reader_ROMS_native from opendrift.readers import reader_basemap_landmask from opendrift.models.pelagicegg import PelagicEggDrift o = OceanDrift() basemap = reader_basemap_landmask.Reader( llcrnrlon=-1.5, llcrnrlat=59, urcrnrlon=7, urcrnrlat=64, resolution='c') class TestReaders(unittest.TestCase): """Tests for readers""" def test_adding_readers(self): o = OceanDrift() r = reader_ROMS_native.Reader(o.test_data_folder() + '2Feb2016_Nordic_sigma_3d/Nordic-4km_SLEVELS_avg_00_subset2Feb2016.nc') o.add_reader([r, basemap]) self.assertEqual(o.priority_list['land_binary_mask'], ['roms native', 'basemap_landmask']) self.assertEqual(o.priority_list['x_sea_water_velocity'],
#!/usr/bin/env python from datetime import timedelta import numpy as np from opendrift.readers import reader_netCDF_CF_generic from opendrift.models.oceandrift import OceanDrift o = OceanDrift() # Basic drift model suitable for passive tracers or drifters ####################### # Preparing Readers ####################### reader_current = reader_netCDF_CF_generic.Reader( o.test_data_folder() + '16Nov2015_NorKyst_z_surface/norkyst800_subset_16Nov2015.nc') reader_wind = reader_netCDF_CF_generic.Reader( o.test_data_folder() + '16Nov2015_NorKyst_z_surface/arome_subset_16Nov2015.nc') o.add_reader([reader_current, reader_wind]) ####################### # Seeding elements ####################### # Elements are moved with the ocean current, in addition to a fraction of # the wind speed (wind_drift_factor). This factor depends on the properties # of the elements. Typical empirical values are: # - 0.035 (3.5 %) for oil and iSphere driftes
def test_seed_elements(self): # Some cases with expected outcome lon_vec = np.array([3, 4, 5]) lat_vec = np.array([63, 64, 65]) lon0 = 3 lat0 = 60 t0 = datetime.now() t1 = t0 + timedelta(hours=6) t2 = t1 + timedelta(hours=6) t_vec = [t0, t1, t2] number_config = 222 cases = [ { 'lon': lon0, 'lat': lat0, 'time': t0, 'number': None, 'expected': number_config }, { 'lon': lon0, 'lat': lat0, 'time': t0, 'number': 12, 'expected': 12, 'maxlat': lat0 }, { 'lon': lon0, 'lat': lat0, 'time': t0, 'radius': 1000, 'number': 12, 'expected': 12, 'maxlat': lat0 + .013 }, { 'lon': lon0, 'lat': lat0, 'time': [t0, t1], 'maxtime': t1, 'number': 12, 'expected': 12 }, { 'lon': lon0, 'lat': lat0, 'time': t_vec, # Time series 'maxtime': t2, 'number': None, 'expected': len(t_vec) }, { 'lon': lon0, 'lat': lat0, 'time': t_vec, 'number': 12, 'expected': 'error' }, { 'lon': lon_vec, 'lat': lat_vec, 'time': t0, 'number': None, 'expected': 3 }, { 'lon': lon_vec, 'lat': lat_vec, 'time': t0, 'wind_drift_factor': .05, 'number': None, 'expected': 3 }, { 'lon': lon_vec, 'lat': lat_vec, 'time': t0, 'wind_drift_factor': [.01, .02, .03], 'number': None, 'expected': 3 }, { 'lon': lon_vec, 'lat': lat_vec, 'time': t0, 'number': 4, 'expected': 'error' }, { 'lon': lon_vec, 'lat': lat_vec, 'time': t_vec, 'number': None, 'expected': 3, 'maxtime': t_vec[-1] }, ] for case in cases: o = OceanDrift(loglevel=50) o._set_config_default('seed:number', number_config) expected = case['expected'] del case['expected'] if 'maxlat' in case: maxlat = case['maxlat'] del case['maxlat'] else: maxlat = None if 'maxtime' in case: maxtime = case['maxtime'] del case['maxtime'] else: maxtime = None if expected == 'error': with self.assertRaises(ValueError): n = o.seed_elements(**case) else: o.seed_elements(**case) self.assertEqual(o.num_elements_total(), expected) if maxlat is not None: self.assertAlmostEqual(o.elements_scheduled.lat.max(), maxlat, 2) if maxtime is not None: self.assertEqual( o.elements_scheduled_time.max().replace(microsecond=0), maxtime.replace(microsecond=0)) if 'wind_drift_factor' in case: self.assertEqual( np.array(case['wind_drift_factor']).max().astype( np.float32), o.elements_scheduled.wind_drift_factor.max())
def test_plot(tmpdir): anifile = os.path.join(tmpdir, 'anim.mp4') plotfile = os.path.join(tmpdir, 'plot.png') #anifile = None #plotfile = None o = OceanDrift(loglevel=30) rn = reader_netCDF_CF_generic.Reader( o.test_data_folder() + '16Nov2015_NorKyst_z_surface/norkyst800_subset_16Nov2015.nc') o.add_reader(rn) o.seed_elements(lon=4.8, lat=60.0, number=10, radius=1000, time=rn.start_time) o.run(steps=5) # Making figures/animations o.plot(filename=plotfile, fast=True, background=['x_sea_water_velocity', 'y_sea_water_velocity']) o.animation(color='lat', filename=anifile, show_trajectories=True, fast=True) o.animation(density=True, filename=anifile, show_trajectories=True, fast=True) o.animation(filename=anifile, show_trajectories=True, fast=True) o.animation(filename=anifile, fast=True, background=['x_sea_water_velocity', 'y_sea_water_velocity']) o.plot(filename=plotfile, fast=True, linecolor='lat') o.plot(filename=plotfile, fast=False) # Second run for comparison o2 = OceanDrift(loglevel=30) o2.add_reader(rn) o2.fallback_values['x_wind'] = 15 # Adding wind o2.fallback_values['y_wind'] = 0 o2.seed_elements(lon=4.8, lat=60.0, number=10, radius=1000, time=rn.start_time) o2.run(steps=5) o.animation(filename=anifile, compare=o2, fast=True, legend=['No wind', '10 m/s wind']) o.plot(filename=plotfile, compare=o2, fast=True, legend=['No wind', '10 m/s wind']) # Check that files have been written assert os.path.exists(anifile) assert os.path.exists(plotfile)
Double gyre ============= Illustrating the difference between Euler and Runge-Kutta propagation schemes, using an idealised (analytical) eddy current field. Double gyre current field from http://shaddenlab.berkeley.edu/uploads/LCS-tutorial/examples.html """ from datetime import datetime, timedelta from opendrift.readers import reader_double_gyre from opendrift.models.oceandrift import OceanDrift o = OceanDrift(loglevel=20) # Set loglevel to 0 for debug information o.fallback_values['land_binary_mask'] = 0 o.set_config('drift:scheme', 'runge-kutta4') double_gyre = reader_double_gyre.Reader(epsilon=.25, omega=0.628, A=0.1) print(double_gyre) o.add_reader(double_gyre) x = [.9] y = [.5] lon, lat = double_gyre.xy2lonlat(x, y) o.seed_elements(lon, lat, radius=.1,
""" from datetime import datetime, timedelta from opendrift.models.oceandrift import OceanDrift from opendrift.readers.reader_constant import Reader as ConstantReader #%% # Mixed Layer Depth of 20m West of 3 deg E, and 50m to the east r1 = ConstantReader({'ocean_mixed_layer_thickness': 20}) r2 = ConstantReader({'ocean_mixed_layer_thickness': 50}) r1.xmax = 3 r2.xmin = 3 #%% # First with Sundby1983 parameterization of diffusivity, based on wind and MLD o = OceanDrift(loglevel=50) o.seed_cone(lon=[2, 4], lat=[60, 60], time=datetime.now(), number=5000) o.add_reader([r1, r2]) o.set_config('environment:constant:y_wind', 8) # Some wind for mixing o.set_config('drift:vertical_mixing', True) o.set_config('vertical_mixing:diffusivitymodel', 'windspeed_Sundby1983') # Increasing background diffusivity beyond default (1.2e-5) to avoid artefact due to sharp gradient at MLD o.set_config('vertical_mixing:background_diffusivity', 0.001) o.run(duration=timedelta(hours=48)) o.animation_profile() #%% # .. image:: /gallery/animations/example_mixed_layer_depth_0.gif #%% # Same, but with Large1994 parameterization of diffusivity