ladim 2.0.2__py3-none-any.whl → 2.0.3__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 CHANGED
@@ -1,3 +1,3 @@
1
- __version__ = '2.0.2'
1
+ __version__ = '2.0.3'
2
2
 
3
3
  from .main import main, run
ladim/config.py CHANGED
@@ -28,98 +28,118 @@ def configure(module_conf):
28
28
 
29
29
  def _versioned_configure(config_dict):
30
30
  if config_dict['version'] == 1:
31
- config_dict = _convert_1_to_2(config_dict)
31
+ config_dict = convert_1_to_2(config_dict)
32
32
 
33
33
  return config_dict
34
34
 
35
35
 
36
- def _convert_1_to_2(c):
36
+ def dict_get(d, items, default=None):
37
+ if isinstance(items, str):
38
+ items = [items]
39
+
40
+ for item in items:
41
+ try:
42
+ return dict_get_single(d, item)
43
+ except KeyError:
44
+ pass
45
+
46
+ return default
47
+
48
+
49
+ def dict_get_single(d, item):
50
+ tokens = str(item).split(sep='.')
51
+ sub_dict = d
52
+ for t in tokens:
53
+ if t in sub_dict:
54
+ sub_dict = sub_dict[t]
55
+ else:
56
+ raise KeyError
57
+
58
+ return sub_dict
59
+
60
+
61
+ def convert_1_to_2(c):
62
+
63
+ out = {}
64
+
37
65
  # Read timedelta
38
- dt_value, dt_unit = c['numerics']['dt']
39
- dt_sec = np.timedelta64(dt_value, dt_unit).astype('timedelta64[s]').astype('int64')
66
+ dt_sec = None
67
+ if 'numerics' in c:
68
+ if 'dt' in c['numerics']:
69
+ dt_value, dt_unit = c['numerics']['dt']
70
+ dt_sec = np.timedelta64(dt_value, dt_unit).astype('timedelta64[s]').astype('int64')
71
+
72
+ out['version'] = 2
73
+
74
+ out['solver'] = {}
75
+ out['solver']['start'] = dict_get(c, 'time_control.start_time')
76
+ out['solver']['stop'] = dict_get(c, 'time_control.stop_time')
77
+ out['solver']['step'] = dt_sec
78
+ out['solver']['seed'] = dict_get(c, 'numerics.seed')
79
+ out['solver']['order'] = ['release', 'forcing', 'output', 'tracker', 'ibm', 'state']
80
+
81
+ out['grid'] = {}
82
+ out['grid']['file'] = dict_get(c, [
83
+ 'files.grid_file', 'gridforce.grid_file',
84
+ 'files.input_file', 'gridforce.input_file'])
85
+ out['grid']['legacy_module'] = dict_get(c, 'gridforce.module', '') + '.Grid'
86
+ out['grid']['start_time'] = np.datetime64(dict_get(c, 'time_control.start_time', '1970'), 's')
87
+
88
+ out['forcing'] = {}
89
+ out['forcing']['file'] = dict_get(c, ['gridforce.input_file', 'files.input_file'])
90
+ out['forcing']['legacy_module'] = dict_get(c, 'gridforce.module', '') + '.Forcing'
91
+ out['forcing']['start_time'] = np.datetime64(dict_get(c, 'time_control.start_time', '1970'), 's')
92
+ out['forcing']['stop_time'] = np.datetime64(dict_get(c, 'time_control.stop_time', '1970'), 's')
93
+ out['forcing']['dt'] = dt_sec
94
+ out['forcing']['ibm_forcing'] = dict_get(c, 'gridforce.ibm_forcing', [])
40
95
 
41
- # Read output variables
42
- outvars = dict()
43
- outvar_names = c['output_variables'].get('particle', []) + c['output_variables'].get('instance', [])
96
+ out['output'] = {}
97
+ out['output']['file'] = dict_get(c, 'files.output_file')
98
+ out['output']['frequency'] = dict_get(c, 'output_variables.outper')
99
+ out['output']['variables'] = {}
100
+
101
+ # Convert output variable format spec
102
+ outvar_names = dict_get(c, 'output_variables.particle', []).copy()
103
+ outvar_names += dict_get(c, 'output_variables.instance', [])
44
104
  for v in outvar_names:
45
- outvars[v] = c['output_variables'][v].copy()
46
- for v in c['output_variables'].get('particle', []):
47
- outvars[v]['kind'] = 'initial'
48
- if 'release_time' in outvars and 'units' in outvars['release_time']:
49
- outvars['release_time']['units'] = 'seconds since 1970-01-01'
105
+ out['output']['variables'][v] = c['output_variables'][v].copy()
106
+ if v == 'release_time' and 'units' in c['output_variables'][v]:
107
+ out['output']['variables'][v]['units'] = 'seconds since 1970-01-01'
108
+ for v in dict_get(c, 'output_variables.particle', []):
109
+ out['output']['variables'][v]['kind'] = 'initial'
110
+
111
+ out['tracker'] = {}
112
+ out['tracker']['method'] = dict_get(c, 'numerics.advection')
113
+ out['tracker']['diffusion'] = dict_get(c, 'numerics.diffusion')
50
114
 
51
115
  # Read release config
52
- relconf = dict(
53
- file=c['files']['particle_release_file'],
54
- frequency=c['particle_release'].get('release_frequency', [0, 's']),
55
- colnames=c['particle_release']['variables'],
56
- formats={
57
- c['particle_release'][v]: v
58
- for v in c['particle_release']['variables']
59
- if v in c['particle_release'].keys()
60
- },
61
- )
62
- if c['particle_release'].get('release_type', '') != 'continuous':
63
- del relconf['frequency']
64
- ibmvars = c.get('state', dict()).get('ibm_variables', [])
65
- ibmvars += c.get('ibm', dict()).get('variables', [])
66
- relconf['defaults'] = {
116
+ out['release'] = {}
117
+ out['release']['file'] = dict_get(c, 'files.particle_release_file')
118
+ out['release']['colnames'] = dict_get(c, 'particle_release.variables', [])
119
+ if dict_get(c, 'particle_release.release_type', '') == 'continuous':
120
+ out['release']['frequency'] = dict_get(c, 'particle_release.release_frequency', [0, 's'])
121
+ out['release']['formats'] = {
122
+ c.get('particle_release', {})[v]: v
123
+ for v in dict_get(c, 'particle_release.variables', [])
124
+ if v in c.get('particle_release', {}).keys()
125
+ }
126
+ out['release']['defaults'] = {
67
127
  k: np.float64(0)
68
- for k in ibmvars
69
- if k not in relconf['colnames']
128
+ for k in dict_get(c, 'state.ibm_variables', []) + dict_get(c, 'ibm.variables', [])
129
+ if k not in out['release']['colnames']
70
130
  }
71
131
 
72
- # Read ibm config
73
- ibmconf_legacy = c.get('ibm', dict()).copy()
74
- if 'module' in ibmconf_legacy:
75
- ibmconf_legacy['ibm_module'] = ibmconf_legacy.pop('module')
76
- ibmconf = dict()
77
- if 'ibm_module' in ibmconf_legacy:
78
- ibmconf['module'] = 'ladim.ibms.LegacyIBM'
79
- ibmconf['legacy_module'] = ibmconf_legacy['ibm_module']
80
- ibmconf['conf'] = dict(
81
- dt=dt_sec,
82
- output_instance=c.get('output_variables', {}).get('instance', []),
83
- nc_attributes={k: v for k, v in outvars.items()}
84
- )
85
- ibmconf['conf']['ibm'] = {
132
+ out['ibm'] = {}
133
+ if 'ibm' in c:
134
+ out['ibm']['module'] = 'ladim.ibms.LegacyIBM'
135
+ out['ibm']['legacy_module'] = dict_get(c, ['ibm.ibm_module', 'ibm.module'])
136
+ out['ibm']['conf'] = {}
137
+ out['ibm']['conf']['dt'] = dt_sec
138
+ out['ibm']['conf']['output_instance'] = dict_get(c, 'output_variables.instance', [])
139
+ out['ibm']['conf']['nc_attributes'] = {
86
140
  k: v
87
- for k, v in ibmconf_legacy.items()
88
- if k != 'ibm_module'
141
+ for k, v in out['output']['variables'].items()
89
142
  }
143
+ out['ibm']['conf']['ibm'] = {k: v for k, v in c['ibm'].items() if k != 'ibm_module'}
90
144
 
91
- config_dict = dict(
92
- version=2,
93
- solver=dict(
94
- start=c['time_control']['start_time'],
95
- stop=c['time_control']['stop_time'],
96
- step=dt_sec,
97
- seed=c['numerics'].get('seed', None),
98
- order=['release', 'forcing', 'output', 'tracker', 'ibm', 'state'],
99
- ),
100
- grid=dict(
101
- file=c['gridforce']['input_file'],
102
- legacy_module=c['gridforce']['module'] + '.Grid',
103
- start_time=np.datetime64(c['time_control']['start_time'], 's'),
104
- ),
105
- forcing=dict(
106
- file=c['gridforce']['input_file'],
107
- legacy_module=c['gridforce']['module'] + '.Forcing',
108
- start_time=np.datetime64(c['time_control']['start_time'], 's'),
109
- stop_time=np.datetime64(c['time_control']['stop_time'], 's'),
110
- dt=dt_sec,
111
- ibm_forcing=c['gridforce'].get('ibm_forcing', []),
112
- ),
113
- release=relconf,
114
- output=dict(
115
- file=c['files']['output_file'],
116
- frequency=c['output_variables']['outper'],
117
- variables=outvars,
118
- ),
119
- tracker=dict(
120
- method=c['numerics']['advection'],
121
- diffusion=c['numerics']['diffusion'],
122
- ),
123
- ibm=ibmconf,
124
- )
125
- return config_dict
145
+ return out
ladim/gridforce/ROMS.py CHANGED
@@ -182,6 +182,8 @@ class Grid:
182
182
  """Return the depth of grid cells"""
183
183
  I = X.round().astype(int) - self.i0
184
184
  J = Y.round().astype(int) - self.j0
185
+ I = np.minimum(np.maximum(I, 0), self.H.shape[1] - 1)
186
+ J = np.minimum(np.maximum(J, 0), self.H.shape[0] - 1)
185
187
  return self.H[J, I]
186
188
 
187
189
  def lonlat(self, X, Y, method="bilinear"):
@@ -191,6 +193,8 @@ class Grid:
191
193
  # else: containing grid cell, less accurate
192
194
  I = X.round().astype("int") - self.i0
193
195
  J = Y.round().astype("int") - self.j0
196
+ I = np.minimum(np.maximum(I, 0), self.lon.shape[1] - 1)
197
+ J = np.minimum(np.maximum(J, 0), self.lon.shape[0] - 1)
194
198
  return self.lon[J, I], self.lat[J, I]
195
199
 
196
200
  def ingrid(self, X: np.ndarray, Y: np.ndarray) -> np.ndarray:
@@ -206,6 +210,11 @@ class Grid:
206
210
  """Returns True for points on land"""
207
211
  I = X.round().astype(int) - self.i0
208
212
  J = Y.round().astype(int) - self.j0
213
+
214
+ # Constrain to valid indices
215
+ I = np.minimum(np.maximum(I, 0), self.M.shape[-1] - 1)
216
+ J = np.minimum(np.maximum(J, 0), self.M.shape[-2] - 1)
217
+
209
218
  return self.M[J, I] < 1
210
219
 
211
220
  # Error if point outside
@@ -802,6 +811,11 @@ def sample3D(F, X, Y, K, A, method="bilinear"):
802
811
  # else: method == 'nearest'
803
812
  I = X.round().astype("int")
804
813
  J = Y.round().astype("int")
814
+
815
+ # Constrain to valid indices
816
+ I = np.minimum(np.maximum(I, 0), F.shape[-1] - 1)
817
+ J = np.minimum(np.maximum(J, 0), F.shape[-2] - 1)
818
+
805
819
  return F[K, J, I]
806
820
 
807
821
 
ladim/gridforce/zROMS.py CHANGED
@@ -37,12 +37,23 @@ class Grid:
37
37
  def __init__(self, config):
38
38
 
39
39
  logger.info("Initializing zROMS grid object")
40
+
41
+ # Grid file
42
+ if "grid_file" in config["gridforce"]:
43
+ grid_file = config["gridforce"]["grid_file"]
44
+ elif "input_file" in config["gridforce"]:
45
+ files = glob.glob(config["gridforce"]["input_file"])
46
+ files.sort()
47
+ grid_file = files[0]
48
+ else:
49
+ logger.error("No grid file specified")
50
+ raise SystemExit(1)
51
+
40
52
  try:
41
- ncid = Dataset(config["gridforce"]["grid_file"])
53
+ ncid = Dataset(grid_file)
54
+ ncid.set_auto_mask(False)
42
55
  except OSError:
43
- logger.error(
44
- "Grid file {} not found".format(config["gridforce"]["grid_file"])
45
- )
56
+ logger.error("Could not open grid file " + grid_file)
46
57
  raise SystemExit(1)
47
58
 
48
59
  # Subgrid, only considers internal grid cells
@@ -247,7 +258,7 @@ class Forcing:
247
258
  num_frames = [] # Available time frames in each file
248
259
  # change_times = [] # Times for change of file
249
260
  for fname in files:
250
- print(fname)
261
+ logging.info(f'Load {fname}')
251
262
  with Dataset(fname) as nc:
252
263
  # new_times = nc.variables['ocean_time'][:]
253
264
  new_times = nc.variables["time"][:]
ladim/main.py CHANGED
@@ -47,7 +47,9 @@ def run():
47
47
 
48
48
  logging.basicConfig(
49
49
  level=logging.INFO,
50
- format='%(levelname)s:%(module)s - %(message)s')
50
+ format='%(asctime)s %(levelname)s:%(module)s - %(message)s',
51
+ datefmt='%Y-%m-%d %H:%M:%S',
52
+ )
51
53
 
52
54
  # ====================
53
55
  # Parse command line
ladim/model.py CHANGED
@@ -1,4 +1,7 @@
1
1
  import importlib
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
2
5
 
3
6
  from typing import TYPE_CHECKING
4
7
  if TYPE_CHECKING:
@@ -101,7 +104,26 @@ class Model:
101
104
 
102
105
  def load_class(name):
103
106
  pkg, cls = name.rsplit(sep='.', maxsplit=1)
104
- return getattr(importlib.import_module(pkg), cls)
107
+
108
+ # Check if "pkg" is an existing file
109
+ spec = None
110
+ module_name = None
111
+ file_name = pkg + '.py'
112
+ if Path(file_name).exists():
113
+ # This can return None if there were import errors
114
+ module_name = pkg
115
+ spec = importlib.util.spec_from_file_location(module_name, file_name)
116
+
117
+ # If pkg can not be interpreted as a file, use regular import
118
+ if spec is None:
119
+ return getattr(importlib.import_module(pkg), cls)
120
+
121
+ # File import
122
+ else:
123
+ module = importlib.util.module_from_spec(spec)
124
+ sys.modules[module_name] = module
125
+ spec.loader.exec_module(module)
126
+ return getattr(module, cls)
105
127
 
106
128
 
107
129
  class Module:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ladim
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Summary: Lagrangian Advection and Diffusion Model
5
5
  Home-page: https://github.com/pnsaevik/ladim
6
6
  Author: Bjørn Ådlandsvik
@@ -1,10 +1,10 @@
1
- ladim/__init__.py,sha256=0i7KXjW3S0HuMuJqk69XKrsqQE9QUVTrXRDo6jNiFEM,51
1
+ ladim/__init__.py,sha256=Vn8lFql5FOG5tGQ1TDaKybIZLoYlLHVXvLcitN1QO04,51
2
2
  ladim/__main__.py,sha256=8f07EMfxQllDZSgpak5ECyYHnfQFy8LaHl2xdC-aO9c,23
3
- ladim/config.py,sha256=6b0ikBrBnq_sSElgO2YcVtJHjQU0nyZsVyPV3q9fy5I,4233
3
+ ladim/config.py,sha256=AAmQflh_u8T-0Qudij_cGpuc_WHOKouoLTBtMZw_Bh0,5075
4
4
  ladim/forcing.py,sha256=f4PpSwyilSScXeNyorTWLMgVTiat9htSLkCwAkRlJVM,3048
5
5
  ladim/grid.py,sha256=m6bQrGJ3cux7rqC8pbRXD86cOI-VQKF-XjP9m1jCIcY,2221
6
- ladim/main.py,sha256=EwBkmWwQG7I0_i-xjthSTeGsoALHH-MdQ1Vvf64lv_A,2838
7
- ladim/model.py,sha256=jpjq_ZSh7ULpwi3_RqDb-p5SG8WcdgCPaBkSpnNWblU,3137
6
+ ladim/main.py,sha256=6_blu3PYnDXaYdPxfZoukWsjN0o9vh7O8_-W2-aguAI,2894
7
+ ladim/model.py,sha256=iXClvieChhipCSZ-dDrmnjqwS4cuM53VpJv7oaJyQ88,3794
8
8
  ladim/output.py,sha256=Rz7iujvS7Z3LoABiJduQqyb3zPswNqhhFsywr3MLsBY,8373
9
9
  ladim/release.py,sha256=1j__9Gj0BD0CqVCM2KLZhio1Ia-hz1gbUIhTsa0J3Rg,8451
10
10
  ladim/sample.py,sha256=n8wRGd_VsW_qyQe1ZoTpmfZcdcwB929vsM8PoKG6JTs,8292
@@ -12,10 +12,10 @@ ladim/solver.py,sha256=sZvYgOxzJ-EItI-IB2y8_z8Tf-SJAQSrmydlhDRa7ZQ,755
12
12
  ladim/state.py,sha256=4XNIIx5sGjlqkZ6bg-dGbqzp8ujFNkHHFL2D9qCQA2w,4119
13
13
  ladim/tracker.py,sha256=VVX6T5CqiU6nGSCgLlSCC8w0UYhW273OGFE7ApPjdyI,5091
14
14
  ladim/utilities.py,sha256=r7-zShqJhh0cBctDUmtfw-GBOk1eTTYR4S72b0ouiSQ,994
15
- ladim/gridforce/ROMS.py,sha256=6y8ZIkAQgVPgK-zG53SKxFms4lJdkTCaP1doz7zuSyo,26965
15
+ ladim/gridforce/ROMS.py,sha256=DF5CSR2iJsPWAmTOrqYavARVtqokQbtAWLSCDWb_9f0,27525
16
16
  ladim/gridforce/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  ladim/gridforce/analytical.py,sha256=qI-1LJdjmnwwanzOdrsDZqwGgo73bT75CB7pMaxbHKM,1094
18
- ladim/gridforce/zROMS.py,sha256=t88mow91orUP-kMQiqmQ0_SnJKKG9xfycM5MMmdVljI,22853
18
+ ladim/gridforce/zROMS.py,sha256=217lDAHY0H7vbez6iLgIHQxK6MrNaZlAtWo6MteKVxU,23225
19
19
  ladim/ibms/__init__.py,sha256=GOG75jZDmNEiLr8brxrKqIlqVj-pNR7pnPP8FUKE6hU,565
20
20
  ladim/ibms/light.py,sha256=POltHmKkX8-q3t9wXyfcseCKEq9Bq-kX1WEJYsr1lNQ,2737
21
21
  ladim/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -24,9 +24,9 @@ postladim/cellcount.py,sha256=nCFu9iJmprubn4YmPB4W0VO02GfEb90Iif7D49w1Kss,2054
24
24
  postladim/kde_plot.py,sha256=GvMWzT6VxIeXKh1cnqaGzR-4jGG_WIHGMLPpRMXIpo4,1628
25
25
  postladim/particlefile.py,sha256=0aif9wYUJ-VrpQKeCef8wB5VCiBB-gWY6sxNCUYviTA,4889
26
26
  postladim/variable.py,sha256=-2aihoppYMMmpSpCqaF31XvpinTMaH3Y01-USDIkbBc,6587
27
- ladim-2.0.2.dist-info/LICENSE,sha256=BgtXyjNr6Ly9nQ7ZLXKpV3r5kWRLnh5MiN0dxp0Bvfc,1085
28
- ladim-2.0.2.dist-info/METADATA,sha256=sjw274vLpD7oaf1g96Ik4VEI0c2grbLVml7nVXTVfoU,1841
29
- ladim-2.0.2.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
30
- ladim-2.0.2.dist-info/entry_points.txt,sha256=JDlNJo87GJaOkH0-BpAzTPLCrZcuPSdSlHNQ4XmnoRg,41
31
- ladim-2.0.2.dist-info/top_level.txt,sha256=TK8Gl7d6MsrAQvqKG4b6YJCbB4UL46Se3SzsI-sJAuc,16
32
- ladim-2.0.2.dist-info/RECORD,,
27
+ ladim-2.0.3.dist-info/LICENSE,sha256=BgtXyjNr6Ly9nQ7ZLXKpV3r5kWRLnh5MiN0dxp0Bvfc,1085
28
+ ladim-2.0.3.dist-info/METADATA,sha256=QjbEu8Z5DysRolgZ7RuuvAT4CZ0S_8bWPP49ByNIQIE,1841
29
+ ladim-2.0.3.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
30
+ ladim-2.0.3.dist-info/entry_points.txt,sha256=JDlNJo87GJaOkH0-BpAzTPLCrZcuPSdSlHNQ4XmnoRg,41
31
+ ladim-2.0.3.dist-info/top_level.txt,sha256=TK8Gl7d6MsrAQvqKG4b6YJCbB4UL46Se3SzsI-sJAuc,16
32
+ ladim-2.0.3.dist-info/RECORD,,
File without changes
File without changes