Skip to content

Commit 4ace059

Browse files
authored
Merge pull request #1675 from AchrefAO/form_skin_drags
formulation of skin and form drags
2 parents a7b402c + f527d72 commit 4ace059

1 file changed

Lines changed: 56 additions & 40 deletions

File tree

opendrift/models/openberg.py

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#
1515
# Copyright 2015, 2023, Knut-Frode Dagestad, MET Norway
1616
# Copyright 2024, Lenny Hucher, NERSC, Norway
17-
# Copyright 2023, 2024, 2025 Achref Othmani, NERSC, Norway
17+
# Copyright 2023, 2025 Achref Othmani, NERSC, Norway
1818

1919
"""
2020
This code is initiated from the following reference with posterior modifications.
@@ -68,59 +68,71 @@ class IcebergObj(LagrangianArray):
6868
'default': 30,
6969
'description': 'Width of iceberg)',
7070
'level': CONFIG_LEVEL_ESSENTIAL}),
71-
('weight_coeff', {'dtype': np.float32, # Relative to the shape of iceberg (e.g. 1 for tabular; 0.3 for pinnacle: It affects the mass only)
72-
'units': '1',
73-
'default': 1}),
74-
('water_drag_coeff', {'dtype': np.float32, # Ocean drag coeff.
75-
'units': '1',
76-
'default': 0.25}),
77-
('wind_drag_coeff', {'dtype': np.float32, # Wind/Air drag coeff.
78-
'units': '1',
79-
'default': 0.7}),
80-
("iceb_x_velocity", {"dtype": np.float32, # Iceberg velocity in the x-direction
81-
"units": "m/s",
82-
"default": 0.0}),
83-
("iceb_y_velocity", {"dtype": np.float32, # Iceberg velocity in the y-direction
84-
"units": "m/s",
85-
"default": 0.0}),
71+
('weight_coef', {'dtype': np.float32, #This parameter is relative to the shape of iceberg (e.g. 1 for tabular; 0.3 for pinnacle: It affects the mass only)
72+
'units': '1',
73+
'default': 1}),
74+
('water_form_drag_coef', {'dtype': np.float32, #Ocean form drag coef. (Cw, IK)
75+
'units': '1',
76+
'default': 0.25}),
77+
('water_skin_drag_coef', {'dtype': np.float32, #Ocean skin drag coef. (Cdw, IK)
78+
'units': '1',
79+
'default': 0.0055}),
80+
('wind_form_drag_coef', {'dtype': np.float32, #Wind/Air form drag coef. (Ca, IK)
81+
'units': '1',
82+
'default': 0.8}),
83+
('wind_skin_drag_coef', {'dtype': np.float32, #Wind/Air skin drag coef. (Cda, IK)
84+
'units': '1',
85+
'default': 0.0022}),
86+
("iceb_x_velocity", {'dtype': np.float32, #Iceberg velocity in the x-direction
87+
'units': "m/s",
88+
'default': 0.0}),
89+
("iceb_y_velocity", {'dtype': np.float32, #Iceberg velocity in the y-direction
90+
'units': "m/s",
91+
'default': 0.0}),
8692
])
8793

8894

8995
# Define the functions needed
90-
def ocean_force(iceb_vel, water_vel, Ao, rho_water, water_drag_coef):
96+
def ocean_force(iceb_vel, water_vel, Avo, Aho, rho_water, water_form_drag_coef, water_skin_drag_coef):
9197
""" Ocean force
9298
Args:
9399
iceb_vel : Iceberg's velocity at time t
94100
water_vel : Ocean current velocity
95-
Ao : Iceberg's area in contact with ocean (length x draft)
96101
rho_water : Water density
97-
water_drag_coef : Co is the drag coefficient applied on the iceberg's draft
102+
Avo : Vertical area of the iceberg in the ocean (length x draft)
103+
Aho : Horizontal area of the iceberg in contact with the ocean (width x draft)
104+
water_form_drag_coef : Co is the ocean form drag coefficient
105+
water_skin_drag_coef : Cdo is the ocean skin drag coefficient
98106
"""
99107
vxo, vyo = water_vel[0], water_vel[1]
100108
x_vel, y_vel = iceb_vel[0], iceb_vel[1]
101109
rel_water_x_vel = vxo - x_vel
102110
rel_water_y_vel = vyo - y_vel
103111
rel_water_norm = np.sqrt(rel_water_x_vel**2 + rel_water_y_vel**2)
104-
F_ocean_x = (0.5 * rho_water * water_drag_coef * Ao * rel_water_norm * rel_water_x_vel)
105-
F_ocean_y = (0.5 * rho_water * water_drag_coef * Ao * rel_water_norm * rel_water_y_vel)
112+
drag_factor_ocean = (0.5 * rho_water * water_form_drag_coef * Avo) + (rho_water * water_skin_drag_coef * Aho)
113+
F_ocean_x = drag_factor_ocean * rel_water_norm * rel_water_x_vel
114+
F_ocean_y = drag_factor_ocean * rel_water_norm * rel_water_y_vel
106115
return np.array([F_ocean_x, F_ocean_y])
107116

108117

109-
def wind_force(iceb_vel, wind_vel, Aa, wind_drag_coef):
118+
def wind_force(iceb_vel, wind_vel, Ava, Aha, wind_form_drag_coef, wind_skin_drag_coef):
110119
""" Wind force
111120
Args:
112121
iceb_vel : Iceberg's velocity at time t
113122
wind_vel : Wind velocity
114-
Aa : Iceberg's area in contact with wind (length x sail)
115-
wind_drag_coef : Ca is the drag coefficient applied on the iceberg's sail
123+
Ava : Vertical area of the iceberg in the air (length x sail)
124+
Aha : Horizontal area of the iceberg in contact with the air (width x sail)
125+
wind_form_drag_coef : Ca is the air form drag coefficient
126+
wind_skin_drag_coef : Cda is the air skin drag coefficient
116127
"""
117128
vxa, vya = wind_vel[0], wind_vel[1]
118129
x_vel, y_vel = iceb_vel[0], iceb_vel[1]
119130
rel_wind_x_vel = vxa - x_vel
120131
rel_wind_y_vel = vya - y_vel
121132
rel_wind_norm = np.sqrt(rel_wind_x_vel**2 + rel_wind_y_vel**2)
122-
F_wind_x = 0.5 * rho_air * wind_drag_coef * Aa * rel_wind_norm * rel_wind_x_vel
123-
F_wind_y = 0.5 * rho_air * wind_drag_coef * Aa * rel_wind_norm * rel_wind_y_vel
133+
drag_factor_wind = (0.5 * rho_air * wind_form_drag_coef * Ava) + (rho_air * wind_skin_drag_coef * Aha)
134+
F_wind_x = drag_factor_wind * rel_wind_norm * rel_wind_x_vel
135+
F_wind_y = drag_factor_wind * rel_wind_norm * rel_wind_y_vel
124136
return np.array([F_wind_x, F_wind_y])
125137

126138

@@ -402,10 +414,12 @@ def advect_iceberg(self):
402414
draft = self.elements.draft
403415
length = self.elements.length
404416
width = self.elements.width
405-
weight_coeff = self.elements.weight_coeff
417+
weight_coef = self.elements.weight_coef
406418
lat = self.elements.lat
407-
water_drag_coeff = self.elements.water_drag_coeff
408-
wind_drag_coeff = self.elements.wind_drag_coeff
419+
water_form_drag_coef = self.elements.water_form_drag_coef
420+
water_skin_drag_coef = self.elements.water_skin_drag_coef
421+
wind_form_drag_coef = self.elements.wind_form_drag_coef
422+
wind_skin_drag_coef = self.elements.wind_skin_drag_coef
409423

410424
T = self.environment.sea_water_temperature
411425
S = self.environment.sea_water_salinity
@@ -418,12 +432,14 @@ def advect_iceberg(self):
418432
sea_ice_thickness = self.environment.sea_ice_thickness
419433
sea_ice_conc = self.environment.sea_ice_area_fraction
420434
water_depth = self.environment.sea_floor_depth_below_sea_level
421-
422-
Ao = abs(draft) * length # (Alternatively: Ao = weight_coeff * length * width)
423-
Aa = sail * length
435+
Avo = length * abs(draft)
436+
Aho = width * abs(draft)
437+
Ava = length * sail
438+
Aha = width * sail
424439
Ai = sea_ice_thickness * length
425-
mass = width * (Aa + Ao) * rho_iceb * weight_coeff
426-
k = (rho_air * wind_drag_coeff * Aa / (rho_water * water_drag_coeff * Ao))
440+
441+
mass = width * (Ava + Avo) * rho_iceb * weight_coef
442+
k = (rho_air * wind_form_drag_coef * Ava / (rho_water * water_form_drag_coef * Avo))
427443
f = np.sqrt(k) / (1 + np.sqrt(k)) # (f is the wind drift factor, only used in the no acceleration model)
428444

429445
wave_rad = self.get_config('drift:wave_rad')
@@ -457,13 +473,13 @@ def advect_iceberg(self):
457473
sea_ice_vel = np.array([self.environment.sea_ice_x_velocity, self.environment.sea_ice_y_velocity])
458474

459475

460-
def dynamic(t,iceb_vel, water_vel, wind_vel, wave_height, wave_direction, Ao,
461-
Aa, rho_water, water_drag_coef, wind_drag_coef, iceb_length, mass,lat, sea_slope_x, sea_slope_y):
476+
def dynamic(t,iceb_vel, water_vel, wind_vel, wave_height, wave_direction, Avo, Aho,
477+
Ava, Aha, rho_water, water_form_drag_coef, water_skin_drag_coef, wind_form_drag_coef, wind_skin_drag_coef, iceb_length, mass,lat, sea_slope_x, sea_slope_y):
462478
""" Function required by solve_ivp. The t and iceb_vel parameters are required by solve_ivp, shouldn't be deleted """
463479
iceb_vel = iceb_vel.reshape((2, -1))
464480
# Individual forces
465-
ocean_force_val = ocean_force(iceb_vel, water_vel, Ao, rho_water, water_drag_coef)
466-
wind_force_val = wind_force(iceb_vel, wind_vel, Aa, wind_drag_coef)
481+
ocean_force_val = ocean_force(iceb_vel, water_vel, Avo, Aho, rho_water, water_form_drag_coef, water_skin_drag_coef)
482+
wind_force_val = wind_force(iceb_vel, wind_vel, Ava, Aha, wind_form_drag_coef, wind_skin_drag_coef)
467483
wave_radiation_force_val = int(wave_rad) * wave_radiation_force(rho_water, wave_height, wave_direction, iceb_length)
468484
coriolis_force_val = int(coriolis) * coriolis_force(iceb_vel, mass, lat)
469485
sea_surface_slope_val = int(sea_surface_slope) * sea_surface_slope_force(sea_slope_x, sea_slope_y, mass)
@@ -506,8 +522,8 @@ def dynamic(t,iceb_vel, water_vel, wind_vel, wave_height, wave_direction, Ao,
506522
logger.debug("Grounding process disabled in configuration")
507523

508524
sol = solve_ivp(dynamic, [0, self.time_step.total_seconds()], V0,
509-
args=(water_vel, wind_vel, wave_height, wave_direction, Ao, Aa, rho_water,
510-
water_drag_coeff, wind_drag_coeff, length, mass, lat, sea_slope_x, sea_slope_y),
525+
args=(water_vel, wind_vel, wave_height, wave_direction, Avo, Aho, Ava, Aha, rho_water,
526+
water_form_drag_coef, water_skin_drag_coef, wind_form_drag_coef, wind_skin_drag_coef,length, mass, lat, sea_slope_x, sea_slope_y),
511527
vectorized=True,
512528
t_eval=np.array([self.time_step.total_seconds()]))
513529
V = sol.y.reshape((2, -1))

0 commit comments

Comments
 (0)