Skip to content

Commit

Permalink
Merge branch 'master' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
knutfrode authored Jun 27, 2024
2 parents ea1a81d + 59bbd8f commit 07b943b
Show file tree
Hide file tree
Showing 29 changed files with 595 additions and 389 deletions.
19 changes: 11 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
# See https://opendrift.github.io for usage

FROM condaforge/mambaforge
# Use a minimal base image
FROM mambaorg/micromamba:1.4.2

ENV DEBIAN_FRONTEND noninteractive
ENV DEBIAN_FRONTEND=noninteractive
ENV MAMBA_DOCKERFILE_ACTIVATE=1

RUN mkdir /code
WORKDIR /code
RUN mkdir code
WORKDIR code

# Install opendrift environment into base conda environment
# Copy environment file
COPY environment.yml .
RUN mamba env update -n base -f environment.yml

# Install opendrift environment into base micromamba environment
RUN micromamba install -n base -f environment.yml

# Cache cartopy maps
RUN /bin/bash -c "echo -e \"import cartopy\nfor s in ('c', 'l', 'i', 'h', 'f'): cartopy.io.shapereader.gshhs(s)\" | python"

# Install opendrift
ADD . /code
ADD . .
RUN pip install -e .

# Test installation
RUN /bin/bash -c "echo -e \"import opendrift\" | python"

4 changes: 2 additions & 2 deletions examples/example_leeway_capsizing.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#%%
# Activating capsizing for high winds, with probability per hour given by
# p(windspeed) = 0.5 + 0.5*tanh((windspeed-wind_threshold)/sigma)
o.set_config('capsizing', True)
o.set_config('processes:capsizing', True)
o.set_config('capsizing:wind_threshold', 30)
o.set_config('capsizing:wind_threshold_sigma', 5)
o.set_config('capsizing:leeway_fraction', 0.4) # Reducing leeway coefficients to 40% of original after capsize
Expand Down Expand Up @@ -62,7 +62,7 @@
o = Leeway()
o.add_reader(reader_norkyst)
o.add_reader(reader_arome)
o.set_config('capsizing', True)
o.set_config('processes:capsizing', True)
o.seed_elements(lon=4.4, lat=61.0, radius=100, number=1000,
capsized=1, # now we seed all objects as already capsized
time=reader_arome.end_time, object_type=object_type)
Expand Down
2 changes: 1 addition & 1 deletion examples/example_long_global_thredds.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# - Ocean forecast from global HYCOM model
# - Weather forecast from NOAA/NCEP
o.add_readers_from_list([
'https://tds.hycom.org/thredds/dodsC/GLBy0.08/latest',
'https://www.ncei.noaa.gov/thredds-coastal/dodsC/hycom/hycom_sfc_agg/HYCOM_Surface_Aggregation_best.ncd',
'https://pae-paha.pacioos.hawaii.edu/thredds/dodsC/ncep_global/NCEP_Global_Atmospheric_Model_best.ncd'])

o.seed_elements(lat=24, lon=-81, time=datetime.utcnow(),
Expand Down
2 changes: 1 addition & 1 deletion examples/example_long_vietnam.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# - Ocean forecast from global Hycom
# - Weather forecast from NOAA/NCEP
o.add_readers_from_list([
'https://tds.hycom.org/thredds/dodsC/GLBy0.08/latest',
'https://www.ncei.noaa.gov/thredds-coastal/dodsC/hycom/hycom_sfc_agg/HYCOM_Surface_Aggregation_best.ncd',
'https://pae-paha.pacioos.hawaii.edu/thredds/dodsC/ncep_global/NCEP_Global_Atmospheric_Model_best.ncd'])

# Seed some particles
Expand Down
2 changes: 1 addition & 1 deletion examples/example_oilspill_seafloor_biodegradation.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#%%
# Current from HYCOM and wind from NCEP GFS
o.add_readers_from_list([
'https://tds.hycom.org/thredds/dodsC/GLBy0.08/expt_93.0/uv3z',
'https://www.ncei.noaa.gov/thredds-coastal/dodsC/hycom/hycom_sfc_agg/HYCOM_Surface_Aggregation_best.ncd',
'https://pae-paha.pacioos.hawaii.edu/thredds/dodsC/ncep_global/NCEP_Global_Atmospheric_Model_best.ncd'])
o.set_config('environment:constant:ocean_mixed_layer_thickness', 20)
o.set_config('drift', {'current_uncertainty': 0, 'wind_uncertainty': 0, 'horizontal_diffusivity': 20})
Expand Down
4 changes: 1 addition & 3 deletions examples/example_openoil.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@
#%%
# Seeding some particles
time = reader_arome.start_time
oil_type = 'GULLFAKS, EXXON'
oil_type = 'ARABIAN MEDIUM, API'
oil_type = 'ALGERIAN CONDENSATE, STATOIL'
oil_type = 'HEIDRUN AARE 2023'
o.seed_elements(lon=4.9, lat=60.1, radius=3000, number=2000,
time=time, z=0, oil_type=oil_type)

Expand Down
54 changes: 7 additions & 47 deletions examples/example_radionuclides.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,50 +22,27 @@

# Adjusting some configuration
o.set_config('drift:vertical_mixing', True)
#o.set_config('environment:constant:ocean_vertical_diffusivity', 0)
#o.set_config('vertical_mixing:diffusivitymodel','constant') # include settling without vertical turbulent mixing
o.set_config('vertical_mixing:diffusivitymodel','environment') # include settling without vertical turbulent mixing
o.set_config('vertical_mixing:diffusivitymodel','environment') # apply vertical diffusivity from ocean model
# Vertical mixing requires fast time step
o.set_config('vertical_mixing:timestep', 600.) # seconds
o.set_config('drift:horizontal_diffusivity', 10)

#%%
# Activate the desired species
#o.set_config('radionuclide:species:LMM', True)
#o.set_config('radionuclide:species:LMMcation', True)
#o.set_config('radionuclide:species:LMManion', True)
#o.set_config('radionuclide:species:Colloid', True)
#o.set_config('radionuclide:species:Humic_colloid', True)
#o.set_config('radionuclide:species:Polymer', True)
#o.set_config('radionuclide:species:Particle_reversible', True)
#o.set_config('radionuclide:species:Particle_irreversible', True)
#o.set_config('radionuclide:species:Particle_slowly_reversible', True)

#o.set_config('radionuclide:species:Sediment_reversible', True)
#o.set_config('radionuclide:species:Sediment_irreversible', True)
#o.set_config('radionuclide:species:Sediment_slowly_reversible', True)

o.set_config('radionuclide:particle_diameter',5.e-6) # m
#o.set_config('radionuclide:particle_diameter_uncertainty',1.e-7) # m
o.set_config('radionuclide:transformations:Kd',2.e0) # (m3/kg)
#o.set_config('radionuclide:transformations:slow_coeff',1.e-6)

o.set_config('radionuclide:sediment:resuspension_depth',2.)
o.set_config('radionuclide:sediment:resuspension_depth_uncert',0.1)
o.set_config('radionuclide:sediment:resuspension_critvel',0.15)


#
#o.set_config('radionuclide:transfer_setup','custom')
o.set_config('radionuclide:transfer_setup','Bokna_137Cs')
#o.set_config('radionuclide:transfer_setup','137Cs_rev')
#o.set_config('radionuclide:transfer_setup','Sandnesfj_Al')
o.set_config('radionuclide:isotope', '137Cs')
o.set_config('radionuclide:specie_setup','LMM + Rev')

# By default, radionuclides do not strand towards coastline
o.set_config('general:coastline_action', 'previous')
o.set_config('general:seafloor_action','lift_to_seafloor')
#o.set_config('general:seafloor_action','previous')
#o.set_config('general:use_auto_landmask',False)


o.set_config('seed:LMM_fraction',.45)
Expand All @@ -80,20 +57,13 @@
td=datetime.today()
time = datetime(td.year, td.month, td.day, 0)

#latseed= 61.2; lonseed= 4.3 # Sognesjen
#latseed= 59.0; lonseed= 10.75 # Hvaler/Koster
#latseed= 57.5; lonseed= 9.3 # Kattegat
latseed= 60.0; lonseed= 4.5 # Bergen (?)
latseed= 60.0; lonseed= 4.5

ntraj=5000
iniz=np.random.rand(ntraj) * -10. # seeding the radionuclides in the upper 10m

o.seed_elements(lonseed, latseed, z=iniz, radius=1000,number=ntraj,
time=time,
# LMM_fraction=0.25,
# particle_fraction=0.75
# diameter=99.e-6#diam,
#specie=init_speciation
)


Expand Down Expand Up @@ -137,17 +107,7 @@



# Postprocessing: write to concentration netcdf file
o.conc_lat = reader_norkyst.get_variables('latitude',
x=[reader_norkyst.xmin,reader_norkyst.xmax],
y=[reader_norkyst.ymin,reader_norkyst.ymax])['latitude'][:]
o.conc_lon = reader_norkyst.get_variables('longitude',
x=[reader_norkyst.xmin,reader_norkyst.xmax],
y=[reader_norkyst.ymin,reader_norkyst.ymax])['longitude'][:]
o.conc_topo = reader_norkyst.get_variables('sea_floor_depth_below_sea_level',
x=[reader_norkyst.xmin,reader_norkyst.xmax],
y=[reader_norkyst.ymin,reader_norkyst.ymax])['sea_floor_depth_below_sea_level'][:]
#o.conc_mask = reader_norkyst.land_binary_mask
# # Postprocessing: write to concentration netcdf file

#%%
#
Expand All @@ -160,8 +120,8 @@
smoothing_cells=1,
time_avg_conc=True,
deltat=2., # hours
llcrnrlon=4.4, llcrnrlat=59.9,
urcrnrlon=4.8, urcrnrlat=60.2,
# llcrnrlon=4.4, llcrnrlat=59.9,
# urcrnrlon=4.8, urcrnrlat=60.2,
)


Expand Down
9 changes: 3 additions & 6 deletions examples/example_wind_measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@

o.seed_elements(lon=lon, lat=lat, radius=radius, number=number, time=time_start, wind_drift_factor=wind_drift_factor)
o.run(end_time=time_end, time_step=time_step, time_step_output=time_step_output)
o.plot(fast = False, background=['x_sea_water_velocity', 'y_sea_water_velocity'], legend=['Norkyst onlyt', 'Gaussian measurment'], buffer = .023, markersize = 150, linewidth = 3, title = "", xlocs = mpl.ticker.MaxNLocator(5), ylocs = mpl.ticker.MaxNLocator(5), clabel = r"Wind speed $\mathrm{(m.s^{-1})}$", cpad = 0.08, text=text)

o.plot(fast = False, background=['x_sea_water_velocity', 'y_sea_water_velocity'], legend=['Norkyst only', 'Gaussian measurement'], buffer = .023, markersize = 150, linewidth = 3, title = "", xlocs = mpl.ticker.MaxNLocator(5), ylocs = mpl.ticker.MaxNLocator(5), clabel = r"Wind speed $\mathrm{(m.s^{-1})}$", cpad = 0.08, text=text)

#%%
# Measurement modified model simulation
Expand All @@ -139,8 +138,7 @@
o2.seed_elements(lon=lon, lat=lat, radius=radius, number=number, time=time_start, wind_drift_factor=wind_drift_factor)
o2.run(end_time=time_end, time_step=time_step, time_step_output=time_step_output)

o.plot(fast = False, compare=o2, background=['x_sea_water_velocity', 'y_sea_water_velocity'], legend=['Norkyst onlyt', 'Gaussian measurment'], buffer = .023, markersize = 150, linewidth = 3, title = "", xlocs = mpl.ticker.MaxNLocator(5), ylocs = mpl.ticker.MaxNLocator(5), clabel = r"Wind speed $\mathrm{(m.s^{-1})}$", cpad = 0.08, text=text)

o.plot(fast = False, compare=o2, background=['x_sea_water_velocity', 'y_sea_water_velocity'], legend=['Norkyst only', 'Gaussian measurement'], buffer = .023, markersize = 150, linewidth = 3, title = "", xlocs = mpl.ticker.MaxNLocator(5), ylocs = mpl.ticker.MaxNLocator(5), clabel = r"Wind speed $\mathrm{(m.s^{-1})}$", cpad = 0.08, text=text)

#%%
# Here, we generate more particles and look
Expand All @@ -161,8 +159,7 @@
o2.seed_elements(lon=lon, lat=lat, radius=radius, number=number, time=time_start, wind_drift_factor=wind_drift_factor)
o2.run(end_time=time_end, time_step=time_step, time_step_output=time_step_output)

o.plot(fast = False, compare=o2, background=['x_sea_water_velocity', 'y_sea_water_velocity'], legend=['Norkyst onlyt', 'Gaussian measurment'], buffer = .023, markersize = 70, linewidth = 1, title = "", xlocs = mpl.ticker.MaxNLocator(5), ylocs = mpl.ticker.MaxNLocator(5), clabel = r"Wind speed $\mathrm{(m.s^{-1})}$", cpad = 0.08, text=text)

o.plot(fast = False, compare=o2, background=['x_sea_water_velocity', 'y_sea_water_velocity'], legend=['Norkyst only', 'Gaussian measurement'], buffer = .023, markersize = 70, linewidth = 1, title = "", xlocs = mpl.ticker.MaxNLocator(5), ylocs = mpl.ticker.MaxNLocator(5), clabel = r"Wind speed $\mathrm{(m.s^{-1})}$", cpad = 0.08, text=text)

lon_drifters_1, lat_drifters_1 = o.get_lonlats()
lon_drifters_2, lat_drifters_2 = o2.get_lonlats()
Expand Down
55 changes: 55 additions & 0 deletions history.rst
Original file line number Diff line number Diff line change
@@ -1,14 +1,67 @@
History
=======

2024-06-27 / Release v1.11.9
----------------------------
* New feature to blend model field with point measurement (Ugo Martinez)
* Hack in generic reader to make sure wind from ECMWF files is at 10m height

* Raising now error if all elements are seeded on land
2024-06-26 / Release v1.11.8
----------------------------
* Raising now error if all elements are seeded on land

2024-06-25 / Release v1.11.7
----------------------------
* Decreased config_level of general:simulation_name to BASIC, due to wrong interpretation of config_level by Drifty

2024-06-24 / Release v1.11.6
----------------------------
* Credentials for copernicusmarine client can now be stored in environment variables COPERNICUSMARINE_USER and COPERNICUSMARINE_PASSWORD, as alternative to .netrc file
* Removed GRIB reader from list included in add_readers_from_list
* Replaced two obsolete URLS for HYCOM (tds.hycom.org) with new aggregate from ncei.noaa.gov
* Removed double quote from docstring, as giving problems for Drifty
* Updated max water content of new oils
* OpenDriftGUI now logs to file in addition to GUI window
* config general:simulation_name is now ESSENTIAL, meaning that it will appear on front page of GUI

2024-06-18 / Release v1.11.5
----------------------------
* Leeway config categori capsizing (bool) renamed to processes:capsizing
* adios<1.2 removed from pyproject.toml, as this it not found on conda

2024-06-14 / Release v1.11.4
----------------------------
* Updating requirements in pyproject.toml
* config setting general:simulation_name is now ESSENTIAL, to be on fron page of GUI

2024-06-14 / Release v1.11.3
----------------------------
* reader.plot() now takes time as optional argument for plotting background field at specific time
* Using now product_id instead of OPeNDAP URL for CMEMS datasets, and using copernicusmarineclient through new reader_copernicusmarine. username/password can be stored in netrc-file with machine name equal to *copernicusmarine* or *nrt.cmems-du.eu*
* Model property reguired_profiles_z_range is now replaced with config setting drift:profile_depth, and profiles are retrieved from surface to this depth. profiles_depth is now input parameter to get_environment, and not anymore a property of Environment class. prepare_run must now always call prepare_run of parent class, since profile_depth is copied to object in basemodel.prepare_run
* get_variables_along_trajectory now also takes depth (z) as input parameter
* updates to wetting/drying in ROMS reader (Kristin Thyng)
* Fill value in output netCDF files is now set to NaN for floats and -999 for integers
* Moving basereader.prepare() to variables.prepare(), as the former was overriding structured.prepare() due to multiple inheritance, and thus config *drift:max_speed* was not applied if config setting was made after reader was added. Also increasing *drift:max_speed* of OceanDrift from 1 to 2m/s
* Leeway model now allows capsizing (and un-capsizing for backwards runs), with given probability and reduction of leeway coefficients when wind exceeds given threshold
* New internal method simulation_direction() is 1 for forward runs, and -1 for backwards runs
* First version of gaussian merging of model and point measurements (Ugo Martinez)
* Added utility method open_mfdataset_overlap to create manual threds aggregates, and example_manual_aggregate to illustrate usage
* Added new config type 'str' with properties min_length and max_length (default 64). Added generic config 'general:simulation_name' (default empty)
* Changing >= to > in condition regarding at which timestep to export buffer to file
* Added new oil, HEIDRUN AARE 2023

2024-04-02 / Release v1.11.2
----------------------------
* Proper handling of sea_surface_height implemented by Kristin Thyng. All subclasses of OceanDrift now have `sea_surface_height` (default 0) as new parameter. z=0 is always sea surface (including sea_surface_height), and seafloor is now where z = -(sea_floor_depth + sea_surface_height)
* Improvements of ROMS reader by Kristin Thyng:

* Roppy-method `sdepth` (used by ROMS reader) now accounts for `sea_surface_height` (zeta).
* Improved handling of rotation of vectors.
* Interpolator can be saved/cached to file to save time on repeated simulations.
* Improved handling of landmasks, for wetting-drying-applications.

* Added alternative biodegradation to OpenOil by specifying half_tiome [days], which can be different for slick and submerged droplets.
* Memory usage is now logged once every timestep, and can be plotted after simulation with new method `o.plot_memory_usage()`
* Exporting directly to parquet file is now an alternative to netCDF (#1259, Achim Randelhoff)
Expand All @@ -17,9 +70,11 @@ History
* Bugfix for attibute of vertical coordinate in SCISM raeder (Calvin Quigley)
* Can make faster and smaller animation by selcting frames as range or list (Manuel Aghito)
* Updates to reader_netCDF_CF_generic:

* Now also rotating ensemble vectors from east/north to x/y
* Now using dynamic instead of hardcoded order of dimensions
* Removing unnecessary ensemble dimension for seafloor depth

* Now ending timer[total time] before finalizing output netCDF file, so that complete performance is included.

2024-01-25 / Release v1.11.1
Expand Down
12 changes: 12 additions & 0 deletions opendrift/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ def versions():
import matplotlib
import netCDF4
import xarray
try:
import adios_db
adios_version = adios_db.__version__
except:
adios_version = ': Not installed'
try:
import copernicusmarine
copernicus_version = copernicusmarine.__version__
except:
copernicus_version = ': Not installed'
import sys
s = '\n------------------------------------------------------\n'
s += 'Software and hardware:\n'
Expand All @@ -143,6 +153,8 @@ def versions():
s += ' Matplotlib version %s\n' % matplotlib.__version__
s += ' NetCDF4 version %s\n' % netCDF4.__version__
s += ' Xarray version %s\n' % xarray.__version__
s += ' ADIOS (adios_db) version %s\n' % adios_version
s += ' Copernicusmarine version %s\n' % copernicus_version
s += ' Python version %s\n' % sys.version.replace('\n', '')
s += '------------------------------------------------------\n'
return s
Expand Down
4 changes: 3 additions & 1 deletion opendrift/models/basemodel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
from opendrift.timer import Timeable
from opendrift.errors import WrongMode
from opendrift.models.physics_methods import PhysicsMethods
from opendrift.config import Configurable, CONFIG_LEVEL_BASIC, CONFIG_LEVEL_ADVANCED
from opendrift.config import Configurable, CONFIG_LEVEL_BASIC, CONFIG_LEVEL_ADVANCED, CONFIG_LEVEL_ESSENTIAL

Mode = Enum('Mode', ['Config', 'Ready', 'Run', 'Result'])

Expand Down Expand Up @@ -915,6 +915,8 @@ def closest_ocean_points(self, lon, lat):
time=land_reader.start_time)[0]['land_binary_mask']
if landgrid.min() == 1 or np.isnan(landgrid.min()):
logger.warning('No ocean pixels nearby, cannot move elements.')
if land.min() == 1:
raise ValueError('All elements seeded on land')
return lon, lat

oceangridlons = longrid[landgrid == 0]
Expand Down
6 changes: 3 additions & 3 deletions opendrift/models/leeway.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class LeewayObj(LagrangianArray):
('capsized', {
'dtype': np.uint8,
'units': '1',
'description': '0 is not capsized, changed to 1 after capsizing (irreversible). After capsizing, leeway coeffieiencts are reduced as given by config item "capsized:leeway_fraction"',
'description': '0 is not capsized, changed to 1 after capsizing (irreversible). After capsizing, leeway coeffieiencts are reduced as given by config item capsized:leeway_fraction',
'seed': True,
'default': 0
}),
Expand Down Expand Up @@ -231,7 +231,7 @@ def __init__(self, d=None, *args, **kwargs):
'units': 'probability',
'level': CONFIG_LEVEL_BASIC
},
'capsizing': {
'processes:capsizing': {
'type': 'bool',
'default': False,
'min': 0,
Expand Down Expand Up @@ -424,7 +424,7 @@ def update(self):
winddir = np.arctan2(self.environment.x_wind, self.environment.y_wind)

# Capsizing
if self.get_config('capsizing') is True:
if self.get_config('processes:capsizing') is True:
wind_threshold = self.get_config('capsizing:wind_threshold')
wind_threshold_sigma = self.get_config('capsizing:wind_threshold_sigma')
# For forward run, elements can be capsized, but for backwards run, only capsized elements can be un-capsized
Expand Down
3 changes: 1 addition & 2 deletions opendrift/models/openoil/adios/README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
The oils in oils.xz are scared from https://adios.orr.noaa.gov/oils using
harvest_oils.py. Re-run to update list.
The oils in oils.xz are downloaded from https://github.com/OpenDrift/noaa-oil-data using harvest_oils.py. Re-run to update list.
Loading

0 comments on commit 07b943b

Please sign in to comment.