Skip to content

Commit 03d8032

Browse files
authored
Merge pull request #1639 from knutfrode/dev
[run-ex] reader_oscillating now takes period as timedelta instead of …
2 parents 86a40e4 + 91825f8 commit 03d8032

10 files changed

Lines changed: 77 additions & 18 deletions

examples/example_river_runoff.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
o.set_config('general:coastline_action', 'previous')
2525
t1 = datetime.now()
2626
t2 = t1 + timedelta(hours=48)
27-
reader_x = reader_oscillating.Reader('x_sea_water_velocity', period_seconds=3600*24,
27+
reader_x = reader_oscillating.Reader('x_sea_water_velocity', period=timedelta(hours=24),
2828
amplitude=1, zero_time=t1)
29-
reader_y = reader_oscillating.Reader('y_sea_water_velocity', period_seconds=3600*72,
29+
reader_y = reader_oscillating.Reader('y_sea_water_velocity', period=timedelta(hours=72),
3030
amplitude=.5, zero_time=t2)
3131
o.add_reader([reader_x, reader_y])
3232
number = 25000

examples/example_seafloor_interaction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
# readers
2626
o = OceanDrift(loglevel=50)
2727
reader_norkyst = reader_netCDF_CF_generic.Reader(tdf + '14Jan2016_NorKyst_z_3d/NorKyst-800m_ZDEPTHS_his_00_3Dsubset.nc')
28-
reader_osc = reader_oscillating.Reader('x_sea_water_velocity', amplitude=10, period_seconds=3600)
28+
reader_osc = reader_oscillating.Reader('x_sea_water_velocity', amplitude=10, period=timedelta(hours=1))
2929

3030
runs = []
3131
seafloor_actions = ['previous', 'deactivate', 'lift_to_seafloor']

examples/example_sediments_resuspension.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
reader_oscx = reader_oscillating.Reader('x_sea_water_velocity',
1414
amplitude=0.6, zero_time=datetime.now())
1515
reader_oscy = reader_oscillating.Reader('y_sea_water_velocity',
16-
amplitude=.3, period_seconds=3600*5, zero_time=datetime.now())
16+
amplitude=.3, period=timedelta(hours=5), zero_time=datetime.now())
1717

1818
o = SedimentDrift(loglevel=50) # 0 for debug output
1919

opendrift/models/basemodel/__init__.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import sys
2525
import os
26+
import copy
2627
import types
2728
from typing import Union, List
2829
import traceback
@@ -241,8 +242,7 @@ def __init__(self,
241242
# List to store GeoJSON dicts of seeding commands
242243
self.seed_geojson = []
243244

244-
self.required_variables = self.required_variables.copy() # Avoid modifying the class variable
245-
245+
self.required_variables = copy.deepcopy(self.required_variables) # Avoid modifying the class variable
246246
self.env = Environment(self.required_variables, self._config)
247247

248248
# Make copies of dictionaries so that they are private to each instance
@@ -579,16 +579,26 @@ def post_run(self):
579579
def update_previous_state(self):
580580
"""Store some properties and variables, for access at next time step"""
581581

582-
# Retrieve previous from storage
582+
if self.newly_seeded_IDs is not None: # For newly seeded elements, we set previous equal to present
583+
newly_seeded_rel_indices = np.where(self.elements.age_seconds==self.time_step.total_seconds())[0]
584+
585+
# Environment variables
583586
if self._environment_previous is not None:
584587
# Update previous environment
588+
if self.newly_seeded_IDs is not None:
589+
for var in self._environment_previous:
590+
self._environment_previous[var][newly_seeded_rel_indices] = self.environment[var][newly_seeded_rel_indices]
585591
self.environment_previous = self._environment_previous.isel(trajectory=self.elements.ID)
586592
# Store present environment variables
587593
for var in self._environment_previous:
588594
self._environment_previous[var][self.elements.ID] = self.environment[var]
589595

596+
# Element properties
590597
if self._elements_previous is not None:
591598
# Update previous elements
599+
if self.newly_seeded_IDs is not None: # For new elements there is no previous, so using present
600+
for var in self._elements_previous:
601+
self._elements_previous[var][newly_seeded_rel_indices] = getattr(self.elements, var)[newly_seeded_rel_indices]
592602
self.elements_previous = self._elements_previous.isel(trajectory=self.elements.ID)
593603
# Store present element properties
594604
for var in self._elements_previous:
@@ -1722,16 +1732,26 @@ def run(self,
17221732
logger.info(f'Skipping environment variable {vn} because of condition {var["skip_if"]}')
17231733
self.required_variables.pop(vn)
17241734

1725-
####################################################################################
1726-
# Evaluate conditionals to determine if previous element properties shall be stored
1727-
####################################################################################
1735+
#########################################################################################
1736+
# Evaluate conditionals to determine if previous properties or variables shall be stored
1737+
#########################################################################################
1738+
# Element properties
17281739
for en, prop in self.elements.variables.copy().items():
17291740
if 'store_previous_if' in prop:
17301741
store = evaluate_conditional(*prop['store_previous_if'], self)
17311742
if store is True:
17321743
logger.info(f'Storing previous values of element property {en} because of condition {prop["store_previous_if"]}')
17331744
self.elements.variables[en]['store_previous'] = True
17341745
del self.elements.variables[en]['store_previous_if'] # To avoid writing this to netCDF metadata
1746+
# Environment variables
1747+
for en, var in self.required_variables.copy().items():
1748+
if 'store_previous_if' in var:
1749+
store = evaluate_conditional(*var['store_previous_if'], self)
1750+
if store is True:
1751+
logger.info(f'Storing previous values of environment variable {en} because of condition {var["store_previous_if"]}')
1752+
self.required_variables[en]['store_previous'] = True
1753+
del self.required_variables[en]['store_previous_if'] # To avoid writing this to netCDF metadata
1754+
17351755

17361756
########################
17371757
# Simulation time step

opendrift/models/oceandrift.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ class OceanDrift(OpenDriftSimulation):
7070
required_variables = {
7171
'x_sea_water_velocity': {'fallback': 0},
7272
'y_sea_water_velocity': {'fallback': 0},
73-
'sea_surface_height': {'fallback': 0},
73+
'sea_surface_height': {'fallback': 0,
74+
'store_previous_if': ['drift:vertical_advection', 'is', True]},
7475
'x_wind': {'fallback': 0},
7576
'y_wind': {'fallback': 0},
7677
'upward_sea_water_velocity': {'fallback': 0,
@@ -177,6 +178,8 @@ def __init__(self, *args, **kwargs):
177178
def update(self):
178179
"""Update positions and properties of elements."""
179180

181+
self.water_column_stretching()
182+
180183
# Simply move particles with ambient current
181184
self.advect_ocean_current()
182185

@@ -223,7 +226,6 @@ def simulate_trajectories(self, outfile, trajectories, number=1,
223226
if np.isnan(lo):
224227
continue
225228
self.seed_elements(lon=lo, lat=la, time=time, number=number, **kwargs)
226-
print(self)
227229
self.run(outfile=outfile, end_time=start_times[-1]+simulation_duration)
228230
# Simulate and save to file
229231

@@ -287,6 +289,12 @@ def prepare_vertical_mixing(self):
287289
def prepare_run(self):
288290
super(OceanDrift, self).prepare_run()
289291

292+
def water_column_stretching(self):
293+
"""If sea_water_level changes, adjust z for continuity"""
294+
295+
return # To be implemented
296+
delta_zeta = self.environment.sea_surface_height - self.environment_previous.sea_surface_height
297+
290298
def vertical_advection(self):
291299
"""Move particles vertically according to vertical ocean current
292300

opendrift/readers/reader_oscillating.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#
1515
# Copyright 2015, Knut-Frode Dagestad, MET Norway
1616

17-
from datetime import datetime
17+
from datetime import datetime, timedelta
1818
import numpy as np
1919

2020
from opendrift.readers.basereader import BaseReader, ContinuousReader
@@ -23,13 +23,15 @@
2323
class Reader(BaseReader, ContinuousReader):
2424
'''Returning values oscillating in time with given amplitude and period'''
2525

26-
def __init__(self, variable, amplitude, period_seconds=3600*24,
26+
def __init__(self, variable, amplitude, period=timedelta(hours=24), period_seconds=None,
2727
phase=0, zero_time=datetime(2017, 1, 1, 0)):
2828
'''init with '''
2929

3030
self.variables = [variable]
3131
self.amplitude = amplitude
32-
self.period_seconds = period_seconds
32+
if period_seconds is not None:
33+
raise ValueError('Input parameter "period_seconds" is deprecated, please use "period" (timedelta) instead')
34+
self.period_seconds = period.total_seconds()
3335
self.zero_time = zero_time
3436
self.proj4 = '+proj=latlong +datum=WGS84'
3537
self.xmin = -180

tests/models/test_basemodel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
def test_logging(tmpdir, capsys):
1111
# Accepting small variations in log output,
1212
# depending on machine, and from which folder test is run
13-
accepted = (220, 223)
13+
accepted = (221, 224)
1414

1515
# Logging to console
1616
logfile = None

tests/models/test_environment.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from datetime import datetime, timedelta
22
import pytest
3+
import numpy as np
34
from opendrift.models.basemodel.environment import Environment
45
from opendrift.models.oceandrift import OceanDrift
6+
from opendrift.readers import reader_oscillating
57
from opendrift.config import Configurable
68

79

@@ -28,6 +30,7 @@ def test_add_readers(test_data_roms):
2830
def test_previous():
2931
o = OceanDrift() # With coastline_action = none
3032
o.set_config('general:coastline_action', 'none')
33+
o.set_config('drift:vertical_advection', False)
3134
o.set_config('environment:constant:land_binary_mask', 0)
3235
o.set_config('environment:constant:x_sea_water_velocity', 1)
3336
o.seed_elements(lon=3, lat=60, time=datetime.now())
@@ -38,6 +41,7 @@ def test_previous():
3841

3942
o = OceanDrift() # With coastline_action = previous
4043
o.set_config('general:coastline_action', 'previous')
44+
o.set_config('drift:vertical_advection', False)
4145
o.set_config('environment:constant:land_binary_mask', 0)
4246
o.set_config('environment:constant:x_sea_water_velocity', 1)
4347
o.seed_elements(lon=3, lat=60, time=datetime.now())
@@ -47,6 +51,31 @@ def test_previous():
4751
assert o.elements_previous is not None
4852
assert o.environment_previous is None
4953

54+
o = OceanDrift() # For newly seeded, previous shall equal present
55+
o.seed_elements(lon=3, lat=60, time=[datetime.now(), datetime.now()+timedelta(hours=1)], number=10)
56+
o.run(steps=1, time_step=timedelta(minutes=30))
57+
assert len(o.environment.sea_surface_height) == 5
58+
assert len(o.environment_previous.sea_surface_height) == 5
59+
assert len(o._environment_previous.sea_surface_height) == 10
60+
assert o.environment_previous.sea_surface_height[0] == 0
61+
assert np.isnan(o._environment_previous.sea_surface_height[-1])
62+
63+
o = OceanDrift() # Check gradient
64+
time = datetime.now()
65+
reader_tidal = reader_oscillating.Reader('sea_surface_height', amplitude=1,
66+
period=timedelta(hours=6), phase=0, zero_time=time)
67+
o.add_reader(reader_tidal)
68+
o.seed_elements(lon=3, lat=60, time=[time, time+timedelta(hours=1)], number=10)
69+
o.run(steps=2, time_step=timedelta(minutes=30))
70+
assert len(o.environment.sea_surface_height) == 9
71+
assert len(o.environment_previous.sea_surface_height) == 9
72+
assert len(o._environment_previous.sea_surface_height) == 10
73+
assert o.environment.sea_surface_height[0] == pytest.approx(0.2588, 3)
74+
assert o.environment_previous.sea_surface_height[0] == 0
75+
assert np.isnan(o._environment_previous.sea_surface_height[-1])
76+
assert not np.isnan(o._environment_previous.sea_surface_height[-2])
77+
78+
5079
def test_skip_env_variable():
5180
o = OceanDrift()
5281
o.set_config('drift:vertical_mixing', True) # Diffusivity shall be included

tests/models/test_openberg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def test_grounding_and_degrounding():
8585
o = OpenBerg(loglevel=0)
8686
reader_osc = reader_oscillating.Reader('sea_surface_height',
8787
amplitude=2,
88-
period_seconds=3600 * 6,
88+
period=timedelta(hours=6),
8989
zero_time=datetime(2020,1,1))
9090
o.add_reader(reader_osc)
9191
o.set_config('environment:constant:x_sea_water_velocity', 0)

tests/models/test_stranding.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def test_stranding_roms(self):
9090
def test_stranding_options(self):
9191
reader_osc = reader_oscillating.Reader(
9292
'x_sea_water_velocity', amplitude=.5,
93-
period_seconds=3600*6,
93+
period=timedelta(hours=6),
9494
zero_time=datetime.now())
9595

9696
reader_global = reader_global_landmask.Reader()

0 commit comments

Comments
 (0)