Skip to content

Commit

Permalink
Merge pull request #1140 from GilesFearon/dsd_options
Browse files Browse the repository at this point in the history
Adding normal and lognormal droplet size distributions for subsea blowout
  • Loading branch information
knutfrode authored Jul 12, 2023
2 parents f2f9bac + ef81dc9 commit 5a14658
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 15 deletions.
16 changes: 11 additions & 5 deletions examples/example_oilspill_seafloor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,24 @@
o.set_config('environment:fallback:y_wind', 7)
o.set_config('drift:vertical_mixing', True)

#%%
# Setting the range of droplet sizes for the seafloor release
o.set_config('seed:droplet_size_distribution','uniform')
o.set_config('seed:droplet_diameter_min_subsea', 0.0001)
o.set_config('seed:droplet_diameter_max_subsea', 0.0005)

# 'normal' and 'lognormal' distributions can also be specified
# o.set_config('seed:droplet_size_distribution','lognormal')
# o.set_config('seed:droplet_diameter_mu',0.001) # 1 mm
# o.set_config('seed:droplet_diameter_sigma',0.0008) # 0.8 mm

#%%
# Seeding some particles
time = [reader_norkyst.start_time,
reader_norkyst.start_time + timedelta(hours=1)]
o.seed_elements(lon=4.5, lat=62.0, z='seafloor', radius=0, number=3000,
time=time, oil_type='GENERIC DIESEL')

#%%
# Setting the range of droplet sizes for the seafloor release
o.set_config('seed:droplet_diameter_min_subsea', 0.0001)
o.set_config('seed:droplet_diameter_max_subsea', 0.0005)

#%%
# Running model with a small timestep to resolve the boyant rising
o.run(duration=timedelta(hours=2), time_step=60, time_step_output=60)
Expand Down
92 changes: 82 additions & 10 deletions opendrift/models/openoil/openoil.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@
o.set_config('seed:droplet_diameter_min_subsea', 0.0005) # 0.5 mm
o.set_config('seed:droplet_diameter_max_subsea', 0.005) # 5 mm
Alternatively, the user can specify normal or lognormal initial subsea droplet size distributions, which are later modified by wave breaking events. In these cases the user must specify the mean and standard deviation of the distribution::
.. code::
o.set_config('seed:droplet_size_distribution','lognormal')
o.set_config('seed:droplet_diameter_mu',0.001) # 1 mm
o.set_config('seed:droplet_diameter_sigma',0.0008) # 0.8 mm
Note that these config settings must be adjusted before the seeding call.
After each wave breaking event, a new droplet diameter will be chosen based on the config setting for droplet size distribution.
"""
Expand Down Expand Up @@ -338,14 +346,45 @@ def __init__(self, weathering_model='noaa', *args, **kwargs):
'The amount (volume) of oil released per hour (or total amount if release is instantaneous)',
'level': self.CONFIG_LEVEL_ESSENTIAL
},
'seed:droplet_size_distribution': {
'type':
'enum',
'enum': ['uniform', 'normal', 'lognormal'],
'default':
'uniform',
'level':
self.CONFIG_LEVEL_ADVANCED,
'description':
'Droplet size distribution used for subsea release.'
},
'seed:droplet_diameter_mu': {
'type': 'float',
'default': 0.001,
'min': 1e-8,
'max': 1,
'units': 'meters',
'description':
'The mean diameter of oil droplet for a subsea release, used in normal/lognormal distributions.',
'level': self.CONFIG_LEVEL_BASIC
},
'seed:droplet_diameter_sigma': {
'type': 'float',
'default': 0.0005,
'min': 1e-8,
'max': 1,
'units': 'meters',
'description':
'The standard deviation in diameter of oil droplet for a subsea release, used in normal/lognormal distributions.',
'level': self.CONFIG_LEVEL_BASIC
},
'seed:droplet_diameter_min_subsea': {
'type': 'float',
'default': 0.0005,
'min': 1e-8,
'max': 1,
'units': 'meters',
'description':
'The minimum diameter of oil droplet for a subsea release.',
'The minimum diameter of oil droplet for a subsea release, used in unifrom distribution.',
'level': self.CONFIG_LEVEL_BASIC
},
'seed:droplet_diameter_max_subsea': {
Expand All @@ -355,7 +394,7 @@ def __init__(self, weathering_model='noaa', *args, **kwargs):
'max': 1,
'units': 'meters',
'description':
'The maximum diameter of oil droplet for a subsea release.',
'The maximum diameter of oil droplet for a subsea release, used in uniform distribution.',
'level': self.CONFIG_LEVEL_BASIC
},
'processes:dispersion': {
Expand Down Expand Up @@ -956,7 +995,7 @@ def get_wave_breaking_droplet_diameter(self):
elif dm == 'Li et al. (2017)':
return self.get_wave_breaking_droplet_diameter_liz2017()
else:
raise Exception("no droplet size distribution specified")
raise Exception("no wave entrainment droplet size distribution specified")

def get_wave_breaking_droplet_diameter_liz2017(self):
# Li,Zhengkai, M. Spaulding, D. French-McCay, D. Crowley, J.R. Payne: "Development of a unified oil droplet size distribution model
Expand Down Expand Up @@ -1551,13 +1590,46 @@ def seed_elements(self, *args, **kwargs):
z = z * np.ones(number) # Convert scalar z to array
subsea = z < 0
if np.sum(subsea) > 0 and 'diameter' not in kwargs:
# Droplet min and max for particles seeded below sea surface
sub_dmin = self.get_config('seed:droplet_diameter_min_subsea')
sub_dmax = self.get_config('seed:droplet_diameter_max_subsea')
logger.info('Using particle diameters between %s and %s m for '
'elements seeded below sea surface.' %
(sub_dmin, sub_dmax))
kwargs['diameter'] = np.random.uniform(sub_dmin, sub_dmax, number)
dsd = self.get_config('seed:droplet_size_distribution')
if dsd == 'uniform':
# Droplet min and max for particles seeded below sea surface
sub_dmin = self.get_config('seed:droplet_diameter_min_subsea')
sub_dmax = self.get_config('seed:droplet_diameter_max_subsea')
logger.info('Using uniform droplet size distribution between %s and %s m for '
'elements seeded below sea surface.' %
(sub_dmin, sub_dmax))
kwargs['diameter'] = np.random.uniform(sub_dmin, sub_dmax, number)
elif dsd == 'normal':
# Droplet mu and sigma for particles seeded below sea surface
sub_mu = self.get_config('seed:droplet_diameter_mu')
sub_sigma = self.get_config('seed:droplet_diameter_sigma')
logger.info('Using normal droplet size distribution with '
'mu = %s and sigma = %s m for elements seeded below sea surface.' %
(sub_mu, sub_sigma))
kwargs['diameter'] = np.random.normal(sub_mu, sub_sigma, number)
elif dsd == 'lognormal':
# Droplet mu and sigma for particles seeded below sea surface
sub_mu = self.get_config('seed:droplet_diameter_mu')
sub_sigma = self.get_config('seed:droplet_diameter_sigma')
logger.info('Using lognormal droplet size distribution with '
'mu = %s and sigma = %s m for elements seeded below sea surface.' %
(sub_mu, sub_sigma))
# From numpy.random.lognormal:
# "Note that the mean and standard deviation are not the values for the
# distribution itself, but of the underlying normal distribution it is derived from."
# So we need to compute the input to the function from the mean and
# standard deviation of the data we want to generate (assumed as input)
sub_sigma2 = sub_sigma**2
sub_sigma2_lognormal = np.log(sub_sigma2/sub_mu**2 + 1)
sub_mu_lognormal = np.log(sub_mu) - sub_sigma2_lognormal/2
sub_sigma_lognormal = sub_sigma2_lognormal**0.5
kwargs['diameter'] = np.random.lognormal(sub_mu_lognormal, sub_sigma_lognormal, number)
# check it worked
# print('median = '+str(np.median(kwargs['diameter'])))
# print('mean = '+str(np.mean(kwargs['diameter'])))
# print('sigma = '+str(np.std(kwargs['diameter'])))
else:
raise Exception("no valid initial subsea droplet size distribution specified")

if 'oiltype' in kwargs:
logger.warning(
Expand Down

0 comments on commit 5a14658

Please sign in to comment.