ladim 2.0.4__py3-none-any.whl → 2.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ladim/__init__.py +1 -1
- ladim/__main__.py +1 -1
- ladim/config.py +5 -1
- ladim/forcing.py +14 -16
- ladim/grid.py +563 -8
- ladim/gridforce/ROMS.py +11 -4
- ladim/ibms/__init__.py +14 -9
- ladim/main.py +1 -1
- ladim/model.py +69 -70
- ladim/output.py +21 -23
- ladim/release.py +18 -21
- ladim/solver.py +6 -6
- ladim/state.py +12 -33
- ladim/tracker.py +8 -11
- {ladim-2.0.4.dist-info → ladim-2.0.6.dist-info}/METADATA +7 -5
- ladim-2.0.6.dist-info/RECORD +32 -0
- {ladim-2.0.4.dist-info → ladim-2.0.6.dist-info}/WHEEL +1 -1
- ladim-2.0.4.dist-info/RECORD +0 -32
- {ladim-2.0.4.dist-info → ladim-2.0.6.dist-info}/LICENSE +0 -0
- {ladim-2.0.4.dist-info → ladim-2.0.6.dist-info}/entry_points.txt +0 -0
- {ladim-2.0.4.dist-info → ladim-2.0.6.dist-info}/top_level.txt +0 -0
ladim/model.py
CHANGED
|
@@ -27,74 +27,72 @@ DEFAULT_MODULES = dict(
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class Model:
|
|
30
|
-
|
|
30
|
+
"""
|
|
31
|
+
The Model class represents the entire simulation model. The different
|
|
32
|
+
submodules control the simulation behaviour. In particular, the solver
|
|
33
|
+
submodule controls the execution flow while the other submodules are
|
|
34
|
+
called once every time step within the main simulation loop.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self, grid: "Grid", forcing: "Forcing", release: "Releaser",
|
|
39
|
+
state: "State", output: "Output", ibm: "IBM", tracker: "Tracker",
|
|
40
|
+
solver: "Solver",
|
|
41
|
+
):
|
|
42
|
+
self.grid = grid
|
|
43
|
+
self.forcing = forcing
|
|
44
|
+
self.release = release
|
|
45
|
+
self.state = state
|
|
46
|
+
self.output = output
|
|
47
|
+
self.ibm = ibm
|
|
48
|
+
self.tracker = tracker
|
|
49
|
+
self.solver = solver
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def from_config(config: dict) -> "Model":
|
|
53
|
+
"""
|
|
54
|
+
Initialize a model class by supplying the configuration parameters
|
|
55
|
+
of each submodule.
|
|
56
|
+
|
|
57
|
+
:param config: Configuration parameters for each submodule
|
|
58
|
+
:return: An initialized Model class
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
# Create new version of the config dict without the 'model' keyword
|
|
62
|
+
def remove_module_key(d: dict):
|
|
63
|
+
return {k: v for k, v in d.items() if k != 'module'}
|
|
64
|
+
|
|
65
|
+
# Initialize modules
|
|
31
66
|
module_names = (
|
|
32
67
|
'grid', 'forcing', 'release', 'state', 'output', 'ibm', 'tracker',
|
|
33
68
|
'solver',
|
|
34
69
|
)
|
|
35
|
-
|
|
36
|
-
self.modules = dict()
|
|
70
|
+
modules = dict()
|
|
37
71
|
for name in module_names:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
k: v for k, v in conf.items()
|
|
44
|
-
if k != 'module'
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
cls = load_class(module_name)
|
|
48
|
-
self.modules[name] = cls(self, **conf_without_module)
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def grid(self) -> "Grid":
|
|
52
|
-
# noinspection PyTypeChecker
|
|
53
|
-
return self.modules.get('grid', None)
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def forcing(self) -> "Forcing":
|
|
57
|
-
# noinspection PyTypeChecker
|
|
58
|
-
return self.modules.get('forcing', None)
|
|
59
|
-
|
|
60
|
-
@property
|
|
61
|
-
def release(self) -> "Releaser":
|
|
62
|
-
# noinspection PyTypeChecker
|
|
63
|
-
return self.modules.get('release', None)
|
|
72
|
+
subconf = config.get(name, dict())
|
|
73
|
+
modules[name] = Module.from_config(
|
|
74
|
+
conf=remove_module_key(subconf),
|
|
75
|
+
module=subconf.get('module', DEFAULT_MODULES[name]),
|
|
76
|
+
)
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
# noinspection PyTypeChecker
|
|
68
|
-
return self.modules.get('state', None)
|
|
69
|
-
|
|
70
|
-
@property
|
|
71
|
-
def output(self) -> "Output":
|
|
72
|
-
# noinspection PyTypeChecker
|
|
73
|
-
return self.modules.get('output', None)
|
|
78
|
+
# Initialize model
|
|
79
|
+
return Model(**modules)
|
|
74
80
|
|
|
75
81
|
@property
|
|
76
|
-
def
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# noinspection PyTypeChecker
|
|
88
|
-
return self.modules.get('solver', None)
|
|
89
|
-
|
|
90
|
-
def __getitem__(self, item):
|
|
91
|
-
return self.modules[item]
|
|
92
|
-
|
|
93
|
-
def __contains__(self, item):
|
|
94
|
-
return item in self.modules
|
|
82
|
+
def modules(self) -> dict:
|
|
83
|
+
return dict(
|
|
84
|
+
grid=self.grid,
|
|
85
|
+
forcing=self.forcing,
|
|
86
|
+
release=self.release,
|
|
87
|
+
state=self.state,
|
|
88
|
+
output=self.output,
|
|
89
|
+
ibm=self.ibm,
|
|
90
|
+
tracker=self.tracker,
|
|
91
|
+
solver=self.solver,
|
|
92
|
+
)
|
|
95
93
|
|
|
96
94
|
def run(self):
|
|
97
|
-
self.solver.run()
|
|
95
|
+
self.solver.run(self)
|
|
98
96
|
|
|
99
97
|
def close(self):
|
|
100
98
|
for m in self.modules.values():
|
|
@@ -127,18 +125,19 @@ def load_class(name):
|
|
|
127
125
|
|
|
128
126
|
|
|
129
127
|
class Module:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
128
|
+
@staticmethod
|
|
129
|
+
def from_config(conf: dict, module: str) -> "Module":
|
|
130
|
+
"""
|
|
131
|
+
Initialize a module using a configuration dict.
|
|
132
|
+
|
|
133
|
+
:param conf: The configuration parameters of the module
|
|
134
|
+
:param module: The fully qualified name of the module
|
|
135
|
+
:return: An initialized module
|
|
136
|
+
"""
|
|
137
|
+
cls = load_class(module)
|
|
138
|
+
return cls(**conf)
|
|
139
|
+
|
|
140
|
+
def update(self, model: Model):
|
|
142
141
|
pass
|
|
143
142
|
|
|
144
143
|
def close(self):
|
ladim/output.py
CHANGED
|
@@ -4,16 +4,14 @@ import numpy as np
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class Output(Module):
|
|
7
|
-
|
|
8
|
-
super().__init__(model)
|
|
7
|
+
pass
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
class RaggedOutput(Output):
|
|
12
|
-
def __init__(self,
|
|
11
|
+
def __init__(self, variables: dict, file: str, frequency):
|
|
13
12
|
"""
|
|
14
13
|
Writes simulation output to netCDF file in ragged array format
|
|
15
14
|
|
|
16
|
-
:param model: Parent model
|
|
17
15
|
:param variables: Simulation variables to include in output, and their formatting
|
|
18
16
|
:param file: Name of output file, or empty if a diskless dataset is desired
|
|
19
17
|
:param frequency: Output frequency in seconds. Alternatively, as a two-element
|
|
@@ -21,8 +19,6 @@ class RaggedOutput(Output):
|
|
|
21
19
|
unit.
|
|
22
20
|
|
|
23
21
|
"""
|
|
24
|
-
super().__init__(model)
|
|
25
|
-
|
|
26
22
|
# Convert output format specification from ladim.yaml config to OutputFormat
|
|
27
23
|
self._formats = {
|
|
28
24
|
k: OutputFormat.from_ladim_conf(v)
|
|
@@ -47,7 +43,7 @@ class RaggedOutput(Output):
|
|
|
47
43
|
freq_unit = 's'
|
|
48
44
|
self._write_frequency = np.timedelta64(freq_num, freq_unit).astype('timedelta64[s]').astype('int64')
|
|
49
45
|
|
|
50
|
-
self._dset = None
|
|
46
|
+
self._dset = None # type: nc.Dataset | None
|
|
51
47
|
self._num_writes = 0
|
|
52
48
|
self._last_write_time = np.int64(-4611686018427387904)
|
|
53
49
|
|
|
@@ -56,47 +52,48 @@ class RaggedOutput(Output):
|
|
|
56
52
|
"""Returns a handle to the netCDF dataset currently being written to"""
|
|
57
53
|
return self._dset
|
|
58
54
|
|
|
59
|
-
def update(self):
|
|
55
|
+
def update(self, model: Model):
|
|
60
56
|
if self._dset is None:
|
|
61
57
|
self._create_dset()
|
|
62
58
|
|
|
63
|
-
self._write_init_vars()
|
|
64
|
-
self._write_instance_vars()
|
|
59
|
+
self._write_init_vars(model)
|
|
60
|
+
self._write_instance_vars(model)
|
|
65
61
|
|
|
66
|
-
def _write_init_vars(self):
|
|
62
|
+
def _write_init_vars(self, model):
|
|
67
63
|
"""
|
|
68
64
|
Write the initial state of new particles
|
|
69
65
|
"""
|
|
70
66
|
|
|
71
67
|
# Check if there are any new particles
|
|
72
68
|
part_size = self._dset.dimensions['particle'].size
|
|
73
|
-
num_new =
|
|
69
|
+
num_new = model.state.released - part_size
|
|
74
70
|
if num_new == 0:
|
|
75
71
|
return
|
|
76
72
|
|
|
77
73
|
# Write variable data
|
|
78
|
-
idx =
|
|
79
|
-
pid =
|
|
74
|
+
idx = model.state['pid'] > part_size - 1
|
|
75
|
+
pid = model.state['pid'][idx]
|
|
80
76
|
for v in set(self._init_vars) - {'release_time'}:
|
|
81
77
|
# The idx array is not necessarily monotonically increasing by 1
|
|
82
78
|
# all the way. We therefore copy the data into a temporary,
|
|
83
79
|
# continuous array.
|
|
84
|
-
data_raw =
|
|
80
|
+
data_raw = model.state[v][idx]
|
|
85
81
|
data = np.zeros(num_new, dtype=data_raw.dtype)
|
|
86
82
|
data[pid - part_size] = data_raw
|
|
87
83
|
self._dset.variables[v][part_size:part_size + num_new] = data
|
|
88
84
|
|
|
89
85
|
# Write release time variable
|
|
90
|
-
data = np.broadcast_to(
|
|
86
|
+
data = np.broadcast_to(model.solver.time, shape=(num_new, ))
|
|
91
87
|
self._dset.variables['release_time'][part_size:part_size + num_new] = data
|
|
88
|
+
self._dset.sync()
|
|
92
89
|
|
|
93
|
-
def _write_instance_vars(self):
|
|
90
|
+
def _write_instance_vars(self, model):
|
|
94
91
|
"""
|
|
95
92
|
Write the current state of dynamic varaibles
|
|
96
93
|
"""
|
|
97
94
|
|
|
98
95
|
# Check if this is a write time step
|
|
99
|
-
current_time =
|
|
96
|
+
current_time = model.solver.time
|
|
100
97
|
elapsed_since_last_write = current_time - self._last_write_time
|
|
101
98
|
if elapsed_since_last_write < self._write_frequency:
|
|
102
99
|
return
|
|
@@ -109,16 +106,17 @@ class RaggedOutput(Output):
|
|
|
109
106
|
|
|
110
107
|
# Write variable values
|
|
111
108
|
inst_size = self._dset.dimensions['particle_instance'].size
|
|
112
|
-
inst_num =
|
|
113
|
-
inst_vars = {k:
|
|
109
|
+
inst_num = model.state.size
|
|
110
|
+
inst_vars = {k: model.state[k] for k in set(self._inst_vars) - {'lat', 'lon'}}
|
|
114
111
|
if {'lat', 'lon'}.intersection(self._inst_vars):
|
|
115
|
-
x, y =
|
|
116
|
-
inst_vars['lon'], inst_vars['lat'] =
|
|
112
|
+
x, y = model.state['X'], model.state['Y']
|
|
113
|
+
inst_vars['lon'], inst_vars['lat'] = model.grid.xy2ll(x, y)
|
|
117
114
|
for name, data in inst_vars.items():
|
|
118
115
|
self._dset.variables[name][inst_size:inst_size + inst_num] = data
|
|
119
116
|
|
|
120
117
|
# Write particle count
|
|
121
118
|
self._dset.variables['particle_count'][time_size] = inst_num
|
|
119
|
+
self._dset.sync()
|
|
122
120
|
|
|
123
121
|
def _create_dset(self):
|
|
124
122
|
default_formats = dict(
|
|
@@ -161,6 +159,7 @@ class RaggedOutput(Output):
|
|
|
161
159
|
)
|
|
162
160
|
|
|
163
161
|
self._dset.variables['instance_offset'][:] = 0
|
|
162
|
+
self._dset.sync()
|
|
164
163
|
|
|
165
164
|
def close(self):
|
|
166
165
|
if self._dset is not None:
|
|
@@ -242,5 +241,4 @@ def create_netcdf_file(fname: str, formats: dict[str, OutputFormat], diskless=Fa
|
|
|
242
241
|
dset.variables[varname].set_auto_mask(False)
|
|
243
242
|
dset.variables[varname].setncatts(item.attributes)
|
|
244
243
|
|
|
245
|
-
|
|
246
244
|
return dset
|
ladim/release.py
CHANGED
|
@@ -11,13 +11,12 @@ logger = logging.getLogger(__name__)
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class Releaser(Module):
|
|
14
|
-
|
|
15
|
-
super().__init__(model)
|
|
14
|
+
pass
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
class TextFileReleaser(Releaser):
|
|
19
18
|
def __init__(
|
|
20
|
-
self,
|
|
19
|
+
self, file, colnames: list = None, formats: dict = None,
|
|
21
20
|
frequency=(0, 's'), defaults=None,
|
|
22
21
|
):
|
|
23
22
|
"""
|
|
@@ -25,7 +24,6 @@ class TextFileReleaser(Releaser):
|
|
|
25
24
|
|
|
26
25
|
The text file must be a whitespace-separated csv file
|
|
27
26
|
|
|
28
|
-
:param model: Parent model
|
|
29
27
|
:param file: Release file
|
|
30
28
|
|
|
31
29
|
:param colnames: Column names, if the release file does not contain any
|
|
@@ -44,8 +42,6 @@ class TextFileReleaser(Releaser):
|
|
|
44
42
|
release.
|
|
45
43
|
"""
|
|
46
44
|
|
|
47
|
-
super().__init__(model)
|
|
48
|
-
|
|
49
45
|
# Release file
|
|
50
46
|
self._csv_fname = file # Path name
|
|
51
47
|
self._csv_column_names = colnames # Column headers
|
|
@@ -60,30 +56,31 @@ class TextFileReleaser(Releaser):
|
|
|
60
56
|
# Other parameters
|
|
61
57
|
self._defaults = defaults or dict()
|
|
62
58
|
|
|
63
|
-
def update(self):
|
|
64
|
-
self._add_new()
|
|
65
|
-
self._kill_old()
|
|
59
|
+
def update(self, model: Model):
|
|
60
|
+
self._add_new(model)
|
|
61
|
+
self._kill_old(model)
|
|
66
62
|
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
# noinspection PyMethodMayBeStatic
|
|
64
|
+
def _kill_old(self, model: Model):
|
|
65
|
+
state = model.state
|
|
69
66
|
if 'alive' in state:
|
|
70
67
|
alive = state['alive']
|
|
71
|
-
alive &=
|
|
68
|
+
alive &= model.grid.ingrid(state['X'], state['Y'])
|
|
72
69
|
state.remove(~alive)
|
|
73
70
|
|
|
74
|
-
def _add_new(self):
|
|
71
|
+
def _add_new(self, model: Model):
|
|
75
72
|
# Get the portion of the release dataset that corresponds to
|
|
76
73
|
# current simulation time
|
|
77
74
|
df = release_data_subset(
|
|
78
75
|
dataframe=self.dataframe,
|
|
79
|
-
start_time=
|
|
80
|
-
stop_time=
|
|
76
|
+
start_time=model.solver.time,
|
|
77
|
+
stop_time=model.solver.time + model.solver.step,
|
|
81
78
|
).copy(deep=True)
|
|
82
79
|
|
|
83
80
|
# If there are no new particles, but the state is empty, we should
|
|
84
81
|
# still initialize the state by adding the appropriate columns
|
|
85
|
-
if (len(df) == 0) and ('X' not in
|
|
86
|
-
|
|
82
|
+
if (len(df) == 0) and ('X' not in model.state):
|
|
83
|
+
model.state.append(df.to_dict(orient='list'))
|
|
87
84
|
self._last_release_dataframe = df
|
|
88
85
|
|
|
89
86
|
# If there are no new particles and we don't use continuous release,
|
|
@@ -94,14 +91,14 @@ class TextFileReleaser(Releaser):
|
|
|
94
91
|
|
|
95
92
|
# If we have continuous release, but there are no new particles and
|
|
96
93
|
# the last release is recent, we are also done
|
|
97
|
-
current_time =
|
|
94
|
+
current_time = model.solver.time
|
|
98
95
|
elapsed_since_last_write = current_time - self._last_release_time
|
|
99
96
|
last_release_is_recent = (elapsed_since_last_write < self._frequency)
|
|
100
97
|
if continuous_release and (len(df) == 0) and last_release_is_recent:
|
|
101
98
|
return
|
|
102
99
|
|
|
103
100
|
# If we are at the final time step, we should not release any more particles
|
|
104
|
-
if continuous_release and
|
|
101
|
+
if continuous_release and model.solver.time >= model.solver.stop:
|
|
105
102
|
return
|
|
106
103
|
|
|
107
104
|
# If we have continuous release, but there are no new particles and
|
|
@@ -119,7 +116,7 @@ class TextFileReleaser(Releaser):
|
|
|
119
116
|
logger.critical("Particle release must have position")
|
|
120
117
|
raise ValueError()
|
|
121
118
|
# else
|
|
122
|
-
X, Y =
|
|
119
|
+
X, Y = model.grid.ll2xy(df["lon"].values, df["lat"].values)
|
|
123
120
|
df.rename(columns=dict(lon="X", lat="Y"), inplace=True)
|
|
124
121
|
df["X"] = X
|
|
125
122
|
df["Y"] = Y
|
|
@@ -136,7 +133,7 @@ class TextFileReleaser(Releaser):
|
|
|
136
133
|
|
|
137
134
|
# Add new particles
|
|
138
135
|
new_particles = df.to_dict(orient='list')
|
|
139
|
-
state =
|
|
136
|
+
state = model.state
|
|
140
137
|
state.append(new_particles)
|
|
141
138
|
|
|
142
139
|
@property
|
ladim/solver.py
CHANGED
|
@@ -2,9 +2,8 @@ import numpy as np
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class Solver:
|
|
5
|
-
def __init__(self,
|
|
5
|
+
def __init__(self, start, stop, step, order=None, seed=None):
|
|
6
6
|
self.order = order or ('release', 'forcing', 'tracker', 'ibm', 'output')
|
|
7
|
-
self.modules = modules
|
|
8
7
|
self.start = np.datetime64(start, 's').astype('int64')
|
|
9
8
|
self.stop = np.datetime64(stop, 's').astype('int64')
|
|
10
9
|
self.step = np.timedelta64(step, 's').astype('int64')
|
|
@@ -13,11 +12,12 @@ class Solver:
|
|
|
13
12
|
if seed is not None:
|
|
14
13
|
np.random.seed(seed)
|
|
15
14
|
|
|
16
|
-
def run(self):
|
|
17
|
-
modules =
|
|
15
|
+
def run(self, model):
|
|
16
|
+
modules = model.modules
|
|
17
|
+
ordered_modules = [modules[k] for k in self.order if k in modules]
|
|
18
18
|
|
|
19
19
|
self.time = self.start
|
|
20
20
|
while self.time <= self.stop:
|
|
21
|
-
for m in
|
|
22
|
-
m.update()
|
|
21
|
+
for m in ordered_modules:
|
|
22
|
+
m.update(model)
|
|
23
23
|
self.time += self.step
|
ladim/state.py
CHANGED
|
@@ -4,19 +4,13 @@ from .model import Model, Module
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class State(Module):
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
The state module contains static and dynamic particle properties
|
|
10
|
-
|
|
11
|
-
The other modules interact with the state module mostly through
|
|
12
|
-
the getitem and setitem methods. For instance, to increase the
|
|
13
|
-
depth of all particles by 1, use
|
|
14
|
-
|
|
15
|
-
>>> model.state['Z'] += 1
|
|
7
|
+
"""
|
|
8
|
+
The state module contains static and dynamic particle properties
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
The other modules interact with the state module mostly through
|
|
11
|
+
the getitem and setitem methods. For instance, to increase the
|
|
12
|
+
depth of all particles by 1, use state['Z'] += 1
|
|
13
|
+
"""
|
|
20
14
|
|
|
21
15
|
@property
|
|
22
16
|
def size(self):
|
|
@@ -65,12 +59,9 @@ class State(Module):
|
|
|
65
59
|
|
|
66
60
|
|
|
67
61
|
class DynamicState(State):
|
|
68
|
-
def __init__(self
|
|
69
|
-
super().__init__(model)
|
|
70
|
-
|
|
62
|
+
def __init__(self):
|
|
71
63
|
self._num_released = 0
|
|
72
64
|
self._varnames = set()
|
|
73
|
-
|
|
74
65
|
self._data = pd.DataFrame()
|
|
75
66
|
|
|
76
67
|
@property
|
|
@@ -123,7 +114,11 @@ class DynamicState(State):
|
|
|
123
114
|
return self[item]
|
|
124
115
|
|
|
125
116
|
def __setattr__(self, item, value):
|
|
126
|
-
|
|
117
|
+
excepted_values = [
|
|
118
|
+
'_data', '_model', '_num_released', '_varnames', 'dt', 'timestep',
|
|
119
|
+
'timestamp'
|
|
120
|
+
]
|
|
121
|
+
if item in list(self.__dict__.keys()) + excepted_values:
|
|
127
122
|
super().__setattr__(item, value)
|
|
128
123
|
elif item in self._data:
|
|
129
124
|
self._data[item] = value
|
|
@@ -132,19 +127,3 @@ class DynamicState(State):
|
|
|
132
127
|
|
|
133
128
|
def __contains__(self, item):
|
|
134
129
|
return item in self._data
|
|
135
|
-
|
|
136
|
-
@property
|
|
137
|
-
def dt(self):
|
|
138
|
-
"""Backwards-compatibility function for returning model.solver.step"""
|
|
139
|
-
return self.model.solver.step
|
|
140
|
-
|
|
141
|
-
@property
|
|
142
|
-
def timestamp(self):
|
|
143
|
-
"""Backwards-compatibility function for returning solver time as numpy datetime"""
|
|
144
|
-
return np.int64(self.model.solver.time).astype('datetime64[s]')
|
|
145
|
-
|
|
146
|
-
@property
|
|
147
|
-
def timestep(self):
|
|
148
|
-
"""Backwards-compatibility function for returning solver time as timestep"""
|
|
149
|
-
elapsed = self.model.solver.time - self.model.solver.start
|
|
150
|
-
return elapsed // self.model.solver.step
|
ladim/tracker.py
CHANGED
|
@@ -3,28 +3,25 @@ import numpy as np
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class Tracker(Module):
|
|
6
|
-
|
|
7
|
-
super().__init__(model)
|
|
6
|
+
pass
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
class HorizontalTracker:
|
|
11
10
|
"""The physical particle tracking kernel"""
|
|
12
11
|
|
|
13
|
-
def __init__(self,
|
|
14
|
-
self.model = model
|
|
15
|
-
|
|
12
|
+
def __init__(self, method, diffusion) -> None:
|
|
16
13
|
if not diffusion:
|
|
17
14
|
method += "_nodiff"
|
|
18
15
|
self.integrator = StochasticDifferentialEquationIntegrator.from_keyword(method)
|
|
19
16
|
self.D = diffusion # [m2.s-1]
|
|
20
17
|
|
|
21
|
-
def update(self):
|
|
22
|
-
state =
|
|
23
|
-
grid =
|
|
24
|
-
forcing =
|
|
18
|
+
def update(self, model: Model):
|
|
19
|
+
state = model.state
|
|
20
|
+
grid = model.grid
|
|
21
|
+
forcing = model.forcing
|
|
25
22
|
|
|
26
|
-
t0 =
|
|
27
|
-
dt =
|
|
23
|
+
t0 = model.solver.time
|
|
24
|
+
dt = model.solver.step
|
|
28
25
|
|
|
29
26
|
act = state['active']
|
|
30
27
|
X, Y, Z = state['X'][act], state['Y'][act], state['Z'][act]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: ladim
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.6
|
|
4
4
|
Summary: Lagrangian Advection and Diffusion Model
|
|
5
5
|
Home-page: https://github.com/pnsaevik/ladim
|
|
6
6
|
Author: Bjørn Ådlandsvik
|
|
@@ -17,12 +17,14 @@ Classifier: Operating System :: OS Independent
|
|
|
17
17
|
Requires-Python: >=3.7
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
|
-
Requires-Dist: numpy
|
|
21
|
-
Requires-Dist: pyyaml
|
|
22
20
|
Requires-Dist: netCDF4
|
|
21
|
+
Requires-Dist: numpy
|
|
23
22
|
Requires-Dist: pandas
|
|
24
|
-
Requires-Dist: xarray
|
|
25
23
|
Requires-Dist: pyarrow
|
|
24
|
+
Requires-Dist: pyproj
|
|
25
|
+
Requires-Dist: pyyaml
|
|
26
|
+
Requires-Dist: scipy
|
|
27
|
+
Requires-Dist: xarray
|
|
26
28
|
|
|
27
29
|
LADiM – the Lagrangian Advection and Diffusion Model
|
|
28
30
|
====================================================
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
ladim/__init__.py,sha256=aQKGEYwOZyFPYOq2KX1uhUn41APv8PRIaY71yxI3Shg,51
|
|
2
|
+
ladim/__main__.py,sha256=I1AOHBQDwQNe3fVmDMyC84JcriqidOEURoeoJSOCTzg,24
|
|
3
|
+
ladim/config.py,sha256=p6swxS4yF0wHPNxE8psNtRxr4YGyhqnsrBs5kdYkUc0,5698
|
|
4
|
+
ladim/forcing.py,sha256=Wv9VPHTRLr_xgxKyNPINBXNwGTLfUVPRYoMcP9ObeNU,3037
|
|
5
|
+
ladim/grid.py,sha256=aZl8HUrY5oJSUKoVEY40reOfAEjClHuNlpzNO1GJK8k,20897
|
|
6
|
+
ladim/main.py,sha256=jsrJY7G37oCzQQDXLrlzc_I_jM7a1a-vmmQx9cuLRms,2906
|
|
7
|
+
ladim/model.py,sha256=zTGZtpXFsVlhT8OqaGFMteMc_nsCJEv3ENehhzKuG60,4221
|
|
8
|
+
ladim/output.py,sha256=1d7p2f3fP5flsRaMdGgGAMU3FaQJg-0OASBAF_cN1II,8317
|
|
9
|
+
ladim/release.py,sha256=lYpuwVYXHntW1Q-jFjkVbveGl7SSIb-EfsJfEZutbXs,8339
|
|
10
|
+
ladim/sample.py,sha256=n8wRGd_VsW_qyQe1ZoTpmfZcdcwB929vsM8PoKG6JTs,8292
|
|
11
|
+
ladim/solver.py,sha256=vOfVUzuQnAylPvtgdP6Ez7_pQGbYDCIYgYfXIbJJ-6M,765
|
|
12
|
+
ladim/state.py,sha256=RkKZQn1G9SbhdA3CTq4jpiN-8YIv1QXDRgI6RZlI7U0,3436
|
|
13
|
+
ladim/tracker.py,sha256=hSlCKlBRyLVEYP40QIGKub6mDYFOApyGhUypLrrP9w8,4977
|
|
14
|
+
ladim/utilities.py,sha256=r7-zShqJhh0cBctDUmtfw-GBOk1eTTYR4S72b0ouiSQ,994
|
|
15
|
+
ladim/gridforce/ROMS.py,sha256=yjEf6KM-nxSn4Hexr-5YctQ0rqjzxMDeL4mmQe3w7Vk,27788
|
|
16
|
+
ladim/gridforce/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
ladim/gridforce/analytical.py,sha256=qI-1LJdjmnwwanzOdrsDZqwGgo73bT75CB7pMaxbHKM,1094
|
|
18
|
+
ladim/gridforce/zROMS.py,sha256=4bnrmcXiWpCAUch9uqd_0XmyKRh-Ll6sFvIHiTbTOOg,23996
|
|
19
|
+
ladim/ibms/__init__.py,sha256=LLKhHJgEu-W6cbFjzg2apc-MPoY9wJF2z7S9W2EeWA0,698
|
|
20
|
+
ladim/ibms/light.py,sha256=POltHmKkX8-q3t9wXyfcseCKEq9Bq-kX1WEJYsr1lNQ,2737
|
|
21
|
+
ladim/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
postladim/__init__.py,sha256=ND-wa5_GNg01Tp0p_1zA1VD804zbfP3o4Cmd8pWU7OE,113
|
|
23
|
+
postladim/cellcount.py,sha256=nCFu9iJmprubn4YmPB4W0VO02GfEb90Iif7D49w1Kss,2054
|
|
24
|
+
postladim/kde_plot.py,sha256=GvMWzT6VxIeXKh1cnqaGzR-4jGG_WIHGMLPpRMXIpo4,1628
|
|
25
|
+
postladim/particlefile.py,sha256=0aif9wYUJ-VrpQKeCef8wB5VCiBB-gWY6sxNCUYviTA,4889
|
|
26
|
+
postladim/variable.py,sha256=-2aihoppYMMmpSpCqaF31XvpinTMaH3Y01-USDIkbBc,6587
|
|
27
|
+
ladim-2.0.6.dist-info/LICENSE,sha256=BgtXyjNr6Ly9nQ7ZLXKpV3r5kWRLnh5MiN0dxp0Bvfc,1085
|
|
28
|
+
ladim-2.0.6.dist-info/METADATA,sha256=Ijt1Va9KemQDmpaF8cG8EddY9VLftTU847irrlWSn58,1884
|
|
29
|
+
ladim-2.0.6.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
|
30
|
+
ladim-2.0.6.dist-info/entry_points.txt,sha256=JDlNJo87GJaOkH0-BpAzTPLCrZcuPSdSlHNQ4XmnoRg,41
|
|
31
|
+
ladim-2.0.6.dist-info/top_level.txt,sha256=TK8Gl7d6MsrAQvqKG4b6YJCbB4UL46Se3SzsI-sJAuc,16
|
|
32
|
+
ladim-2.0.6.dist-info/RECORD,,
|
ladim-2.0.4.dist-info/RECORD
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
ladim/__init__.py,sha256=1pOaNTt2-oJQ33nsnZyDsOulYErImxLErxjlfOb8Oyg,51
|
|
2
|
-
ladim/__main__.py,sha256=8f07EMfxQllDZSgpak5ECyYHnfQFy8LaHl2xdC-aO9c,23
|
|
3
|
-
ladim/config.py,sha256=tnTyKDeaDG1M9T5fiUGXG8Ezc_n7Xwm8l6--UpBJhaE,5449
|
|
4
|
-
ladim/forcing.py,sha256=f4PpSwyilSScXeNyorTWLMgVTiat9htSLkCwAkRlJVM,3048
|
|
5
|
-
ladim/grid.py,sha256=m6bQrGJ3cux7rqC8pbRXD86cOI-VQKF-XjP9m1jCIcY,2221
|
|
6
|
-
ladim/main.py,sha256=6_blu3PYnDXaYdPxfZoukWsjN0o9vh7O8_-W2-aguAI,2894
|
|
7
|
-
ladim/model.py,sha256=iXClvieChhipCSZ-dDrmnjqwS4cuM53VpJv7oaJyQ88,3794
|
|
8
|
-
ladim/output.py,sha256=Rz7iujvS7Z3LoABiJduQqyb3zPswNqhhFsywr3MLsBY,8373
|
|
9
|
-
ladim/release.py,sha256=1j__9Gj0BD0CqVCM2KLZhio1Ia-hz1gbUIhTsa0J3Rg,8451
|
|
10
|
-
ladim/sample.py,sha256=n8wRGd_VsW_qyQe1ZoTpmfZcdcwB929vsM8PoKG6JTs,8292
|
|
11
|
-
ladim/solver.py,sha256=sZvYgOxzJ-EItI-IB2y8_z8Tf-SJAQSrmydlhDRa7ZQ,755
|
|
12
|
-
ladim/state.py,sha256=4XNIIx5sGjlqkZ6bg-dGbqzp8ujFNkHHFL2D9qCQA2w,4119
|
|
13
|
-
ladim/tracker.py,sha256=VVX6T5CqiU6nGSCgLlSCC8w0UYhW273OGFE7ApPjdyI,5091
|
|
14
|
-
ladim/utilities.py,sha256=r7-zShqJhh0cBctDUmtfw-GBOk1eTTYR4S72b0ouiSQ,994
|
|
15
|
-
ladim/gridforce/ROMS.py,sha256=DF5CSR2iJsPWAmTOrqYavARVtqokQbtAWLSCDWb_9f0,27525
|
|
16
|
-
ladim/gridforce/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
ladim/gridforce/analytical.py,sha256=qI-1LJdjmnwwanzOdrsDZqwGgo73bT75CB7pMaxbHKM,1094
|
|
18
|
-
ladim/gridforce/zROMS.py,sha256=4bnrmcXiWpCAUch9uqd_0XmyKRh-Ll6sFvIHiTbTOOg,23996
|
|
19
|
-
ladim/ibms/__init__.py,sha256=GOG75jZDmNEiLr8brxrKqIlqVj-pNR7pnPP8FUKE6hU,565
|
|
20
|
-
ladim/ibms/light.py,sha256=POltHmKkX8-q3t9wXyfcseCKEq9Bq-kX1WEJYsr1lNQ,2737
|
|
21
|
-
ladim/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
-
postladim/__init__.py,sha256=ND-wa5_GNg01Tp0p_1zA1VD804zbfP3o4Cmd8pWU7OE,113
|
|
23
|
-
postladim/cellcount.py,sha256=nCFu9iJmprubn4YmPB4W0VO02GfEb90Iif7D49w1Kss,2054
|
|
24
|
-
postladim/kde_plot.py,sha256=GvMWzT6VxIeXKh1cnqaGzR-4jGG_WIHGMLPpRMXIpo4,1628
|
|
25
|
-
postladim/particlefile.py,sha256=0aif9wYUJ-VrpQKeCef8wB5VCiBB-gWY6sxNCUYviTA,4889
|
|
26
|
-
postladim/variable.py,sha256=-2aihoppYMMmpSpCqaF31XvpinTMaH3Y01-USDIkbBc,6587
|
|
27
|
-
ladim-2.0.4.dist-info/LICENSE,sha256=BgtXyjNr6Ly9nQ7ZLXKpV3r5kWRLnh5MiN0dxp0Bvfc,1085
|
|
28
|
-
ladim-2.0.4.dist-info/METADATA,sha256=9zVlHY1N0c5JKYGu9_ayPTmBVcPnzHaj9i8kJgLRgOU,1841
|
|
29
|
-
ladim-2.0.4.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
30
|
-
ladim-2.0.4.dist-info/entry_points.txt,sha256=JDlNJo87GJaOkH0-BpAzTPLCrZcuPSdSlHNQ4XmnoRg,41
|
|
31
|
-
ladim-2.0.4.dist-info/top_level.txt,sha256=TK8Gl7d6MsrAQvqKG4b6YJCbB4UL46Se3SzsI-sJAuc,16
|
|
32
|
-
ladim-2.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|