h2lib 13.0.605__cp38-cp38-win_amd64.whl → 13.0.705__cp38-cp38-win_amd64.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.
h2lib/HAWC2Lib.dll CHANGED
Binary file
h2lib/_h2lib.py CHANGED
@@ -1,42 +1,34 @@
1
- import os
2
- import numpy as np
1
+ from contextlib import contextmanager
3
2
  from h2lib.dll_wrapper import DLLWrapper
4
3
  from h2lib.h2lib_signatures import H2LibSignatures
5
- from h2lib.utils import MultiProcessInterface, ProcessClass
6
- from contextlib import contextmanager
7
-
4
+ import os
5
+ import sys
8
6
 
9
- @contextmanager
10
- def set_LD_LIBRARY_PATH():
11
- old = os.environ.get('LD_LIBRARY_PATH', "")
12
- if '/lib/' in __file__: # pragma: no cover (only on linux)
13
- lib_path = __file__[:__file__.index("/lib/") + 5]
14
- os.environ['LD_LIBRARY_PATH'] = f'{lib_path}:{old}'
15
- try:
16
- yield
17
- finally:
18
- os.environ['LD_LIBRARY_PATH'] = old
7
+ from multiclass_interface.multiprocess_interface import MultiProcessClassInterface, ProcessClass
8
+ import numpy as np
19
9
 
20
10
 
21
11
  def H2Lib(suppress_output=False, subprocess=True):
22
- if subprocess:
23
- with set_LD_LIBRARY_PATH():
24
- return H2LibProcess(suppress_output=suppress_output)
25
- else:
26
- return H2LibThread(suppress_output=suppress_output)
12
+ H2 = [H2LibThread, H2LibProcess][subprocess]
13
+ return H2(suppress_output=suppress_output)
27
14
 
28
15
 
29
16
  class H2LibThread(H2LibSignatures, DLLWrapper):
30
17
  _model_path = '.'
31
18
  _aero_sections_data_shape = {}
32
19
 
33
- def __init__(self, filename=None, cwd='.', suppress_output=True):
20
+ def __init__(self, suppress_output=True, filename=None, cwd='.'):
34
21
  if filename is None:
35
22
  if os.name == 'nt':
36
23
  filename = os.path.dirname(__file__) + '/HAWC2Lib.dll'
37
24
  else:
38
25
  filename = os.path.dirname(__file__) + '/HAWC2Lib.so' # pragma: no cover
26
+ # doubles the speed of single instances and 2N of N instances on linux
27
+ os.environ['MKL_THREADING_LAYER'] = 'sequential'
39
28
  filename = os.path.abspath(filename)
29
+ library_bin = os.path.abspath(os.path.join(os.path.dirname(sys.executable), '../Library/bin'))
30
+ if os.path.isdir(library_bin): # pragma: no cover
31
+ os.add_dll_directory(library_bin)
40
32
  DLLWrapper.__init__(self, filename, cwd=cwd, cdecl=True)
41
33
  self.suppress_output = suppress_output
42
34
  self._initialized = False
@@ -56,13 +48,22 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
56
48
  if self._initialized:
57
49
  self.finalize()
58
50
  DLLWrapper.close(self)
51
+ return "closed h2lib"
59
52
 
60
53
  def getState(self):
61
54
  return H2LibSignatures.getState(self, restype=np.int32)[1]
62
55
 
56
+ def work(self, time):
57
+ """Return number of loops"""
58
+ return H2LibSignatures.work(self, np.float64(time), restype=np.int64)[1]
59
+
60
+ def loop(self, N):
61
+ """Return time to compute N loops"""
62
+ return H2LibSignatures.loop(self, int(N), restype=np.float64)[1]
63
+
63
64
  def get_version(self):
64
65
  s = " " * 255
65
- return H2LibSignatures.get_version(self, s)[0][0]
66
+ return H2LibSignatures.get_version(self, s)[0][0].strip()
66
67
 
67
68
  def get_wind_speed(self, pos_g):
68
69
  return self.get_lib_function('get_wind_speed')(np.asarray(pos_g, dtype=np.float64),
@@ -114,11 +115,11 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
114
115
  sensor_line += ";"
115
116
  index_start, index_stop = 0, 0
116
117
  index_start, index_stop = H2LibSignatures.add_sensor(self, sensor_line.lower(), index_start, index_stop)[0][1:]
117
- return list(range(index_start, index_stop + 1))
118
+ return tuple(range(index_start, index_stop + 1))
118
119
 
119
120
  def get_sensor_info(self, id):
120
121
  "return name, unit, description"
121
- if isinstance(id, list):
122
+ if isinstance(id, tuple):
122
123
  return [self.get_sensor_info(i) for i in id]
123
124
  return [s[:-1].strip() # remove null termination
124
125
  for s in H2LibSignatures.get_sensor_info(self, id, name=" " * 30, unit=" " * 10, desc=" " * 512)[0][1:]]
@@ -207,7 +208,7 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
207
208
  """
208
209
  if time is None:
209
210
  time = self.get_time()
210
- return H2LibSignatures.set_windfield(self, np.asarray(uvw, dtype=np.float64),
211
+ return H2LibSignatures.set_windfield(self, np.asarray(uvw, dtype=np.float32),
211
212
  np.float64(box_offset_x), np.float64(time))
212
213
 
213
214
  # ===================================================================================================================
@@ -236,7 +237,7 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
236
237
  return self._aero_sections_data_shape[rotor]
237
238
 
238
239
  def get_aerosections_position(self, rotor=0):
239
- position = np.zeros(self.aero_sections_data_shape(rotor), dtype=np.float64)
240
+ position = np.zeros(self.aero_sections_data_shape(rotor), dtype=np.float64, order='F')
240
241
  return H2LibSignatures.get_aerosections_position(self, rotor + 1, position)[0][1]
241
242
 
242
243
  def set_aerosections_windspeed(self, uvw, rotor=0):
@@ -244,12 +245,12 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
244
245
 
245
246
  def get_aerosections_forces(self, rotor=0):
246
247
  shape = self.aero_sections_data_shape(rotor)
247
- Fxyz = np.zeros(shape, dtype=np.float64)
248
+ Fxyz = np.zeros(shape, dtype=np.float64, order='F')
248
249
  return H2LibSignatures.get_aerosections_forces(self, rotor + 1, Fxyz)[0][1]
249
250
 
250
251
  def get_aerosections_moments(self, rotor=0):
251
252
  shape = self.aero_sections_data_shape(rotor)
252
- Mxyz = np.zeros(shape, dtype=np.float64)
253
+ Mxyz = np.zeros(shape, dtype=np.float64, order='F')
253
254
  return H2LibSignatures.get_aerosections_moments(self, rotor + 1, Mxyz)[0][1]
254
255
 
255
256
  def get_bem_grid_dim(self, rotor=0):
@@ -260,11 +261,12 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
260
261
  """returns azi, rad"""
261
262
  nazi, nrad = self.get_bem_grid_dim(rotor)
262
263
  return H2LibSignatures.get_bem_grid(self, rotor + 1,
263
- np.zeros(nazi, dtype=np.float64), np.zeros(nrad, dtype=np.float64))[0][1:]
264
+ np.zeros(nazi, dtype=np.float64, order='F'),
265
+ np.zeros(nrad, dtype=np.float64, order='F'))[0][1:]
264
266
 
265
267
  def get_induction_polargrid(self, rotor=0):
266
268
  nazi, nrad = self.get_bem_grid_dim(rotor)
267
- induction = np.zeros((nazi, nrad), dtype=np.float64)
269
+ induction = np.zeros((nazi, nrad), dtype=np.float64, order='F')
268
270
  return H2LibSignatures.get_induction_polargrid(self, rotor + 1, induction)[0][1]
269
271
 
270
272
  def get_induction_axisymmetric(self, rotor=0):
@@ -272,6 +274,10 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
272
274
  induction = np.zeros(nrad, dtype=np.float64)
273
275
  return H2LibSignatures.get_induction_axisymmetric(self, rotor + 1, induction)[0][1]
274
276
 
277
+ def get_induction_rotoravg(self, rotor=0):
278
+ induction = np.float64(0)
279
+ return H2LibSignatures.get_induction_rotoravg(self, rotor + 1, induction)[0][1]
280
+
275
281
  def get_rotor_orientation(self, rotor=0, deg=False):
276
282
  """return yaw, tilt, azi(of first blade) in rad(default) or deg"""
277
283
  r = H2LibSignatures.get_rotor_orientation(self, rotor=rotor + 1, yaw=0., tilt=0., azi=0.)[0][1:]
@@ -294,15 +300,47 @@ class H2LibThread(H2LibSignatures, DLLWrapper):
294
300
  return [vy, vx, -vz]
295
301
 
296
302
 
297
- class H2LibProcess(ProcessClass, H2LibThread):
298
- def __init__(self, suppress_output):
299
- ProcessClass.__init__(self, cls=H2LibThread, cls_attrs=set(dir(H2LibThread)) - set(dir(ProcessClass)))
300
- self(suppress_output=suppress_output)
303
+ @contextmanager
304
+ def set_LD_LIBRARY_PATH():
305
+ _file__ = np.__file__
306
+ old = os.environ.get('LD_LIBRARY_PATH', "")
307
+
308
+ if '/lib/' in _file__: # pragma: no cover (only on linux)
309
+ lib_path = _file__[:_file__.index("/lib/") + 5]
310
+ os.environ['LD_LIBRARY_PATH'] = f'{lib_path}:{old}'
311
+
312
+ try:
313
+ yield
314
+ finally:
315
+ os.environ['LD_LIBRARY_PATH'] = old
301
316
 
302
317
 
303
- class MultiH2Lib(MultiProcessInterface, H2LibThread):
304
- def __init__(self, N, filename=None, cwd='.', suppress_output=False):
305
- if not hasattr(suppress_output, '__len__'):
306
- suppress_output = [suppress_output] * N
318
+ class H2LibProcess(ProcessClass, H2LibThread):
319
+ def __init__(self, suppress_output, filename=None, cwd='.'):
307
320
  with set_LD_LIBRARY_PATH():
308
- MultiProcessInterface.__init__(self, H2LibThread, [(filename, cwd, suppress_output[i]) for i in range(N)])
321
+ ProcessClass.__init__(self, cls=H2LibThread, cls_attrs=set(dir(H2LibThread)) - set(dir(ProcessClass)))
322
+ self(suppress_output=suppress_output, filename=filename, cwd=cwd)
323
+
324
+
325
+ def MultiH2Lib(N, filename=None, cwd='.', suppress_output=False):
326
+
327
+ if not hasattr(suppress_output, '__len__'):
328
+ suppress_output = [suppress_output] * N
329
+ args = [(suppress_output[i], filename, cwd) for i in range(N)]
330
+
331
+ with set_LD_LIBRARY_PATH():
332
+ from multiclass_interface import mpi_interface
333
+ if mpi_interface.size > 1: # pragma: no cover
334
+ # try:
335
+ # with H2LibThread(filename):
336
+ # pass
337
+ # # LD_LIBRARY_PATH is set. Run H2LibThread directly in mpi processes
338
+ # cls = H2LibThread
339
+ # except OSError:
340
+ # # Set LD_LIBRARY_PATH in mpi workers and run H2LibThread from the workers via ProcessClass
341
+ # cls = H2LibProcess
342
+ from multiclass_interface.mpi_interface import MPIClassInterface
343
+ cls = H2LibProcess
344
+ return MPIClassInterface(cls, args)
345
+ else:
346
+ return MultiProcessClassInterface(H2LibThread, args)
h2lib/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # This file is autogenerated and should not be modified manually
2
- __version__ = '13.0.605'
3
- h2lib_version = '13.0.605'
4
- hawc2_version = '13.0.6+8-g2148dea'
2
+ __version__ = '13.0.705'
3
+ h2lib_version = '13.0.705'
4
+ hawc2_version = '13.0.9'
h2lib/dll_wrapper.py CHANGED
@@ -6,9 +6,7 @@ import platform
6
6
  import os
7
7
  import ctypes
8
8
  from _ctypes import POINTER
9
- from ctypes import c_int, c_double, c_char, c_char_p, c_long
10
- import tempfile
11
- import shutil
9
+ from ctypes import c_int, c_double, c_char, c_char_p, c_long, c_longlong
12
10
  from contextlib import contextmanager
13
11
  try:
14
12
  from ctypes import windll
@@ -21,6 +19,7 @@ c_int_p = POINTER(ctypes.c_long)
21
19
  c_long_p = POINTER(ctypes.c_longlong)
22
20
 
23
21
  c_double_p = POINTER(ctypes.c_double)
22
+ c_float_p = POINTER(ctypes.c_float)
24
23
 
25
24
  in_use = []
26
25
 
@@ -70,17 +69,88 @@ def cwd(f):
70
69
  return wrap
71
70
 
72
71
 
72
+ def wrap(self, f, *args, **kwargs):
73
+ c_args = []
74
+ args = list(args)
75
+ for i, arg in enumerate(args):
76
+ if isinstance(arg, (list, tuple)):
77
+ if all([isinstance(e, int) for e in arg]):
78
+ # default to int64 which is default on linux but not windows
79
+ args[i] = np.array(arg, dtype=np.int64)
80
+ else:
81
+ args[i] = np.array(arg)
82
+ if isinstance(args[i], np.ndarray):
83
+
84
+ if self.fortran:
85
+ if not args[i].flags.f_contiguous:
86
+ sys.stderr.write(f'argument {i} for {f.__name__} not f_contiguous\n')
87
+ else:
88
+ if not args[i].flags.c_contiguous:
89
+ sys.stderr.write(f'argument {i} for {f.__name__} not c_contiguous\n')
90
+
91
+ args[i] = np.require(args[i], requirements=['C', 'F'][self.fortran])
92
+
93
+ for arg in args:
94
+ if isinstance(arg, int):
95
+ c_args.append(c_long_p(c_longlong(arg)))
96
+ elif isinstance(arg, float):
97
+ c_args.append(c_double_p(c_double(arg)))
98
+ elif isinstance(arg, str):
99
+ c_args.append(c_char_p(arg.encode('cp1252')))
100
+ # c_args.append(c_int_p(c_int(len(arg))))
101
+
102
+ elif isinstance(arg, np.ndarray):
103
+ if arg.dtype in [np.int32]:
104
+ c_args.append(arg.ctypes.data_as(c_int_p))
105
+ elif arg.dtype in [np.int64]:
106
+ c_args.append(arg.ctypes.data_as(c_long_p))
107
+ elif arg.dtype == np.float64:
108
+ c_args.append(arg.ctypes.data_as(c_double_p))
109
+ elif arg.dtype == np.float32:
110
+ c_args.append(arg.ctypes.data_as(c_float_p))
111
+ else:
112
+ raise NotImplementedError(arg.dtype)
113
+
114
+ else:
115
+ # raise NotImplementedError(arg.__class__.__name__)
116
+ c_args.append(arg)
117
+ if 'restype' in kwargs:
118
+ restype = kwargs['restype']
119
+ if hasattr(restype, 'dtype'):
120
+ restype = np.ctypeslib.as_ctypes_type(restype)
121
+ f.restype = restype
122
+ with chdir(self.cwd):
123
+ if self.suppress_output:
124
+ with SuppressStream(sys.stdout), SuppressStream(sys.stderr):
125
+ res = f(*c_args)
126
+ else:
127
+ res = f(*c_args)
128
+ ret_args = []
129
+ for arg in args:
130
+ c_arg = c_args.pop(0)
131
+ if isinstance(arg, (int, float)):
132
+ ret_args.append(c_arg.contents.value)
133
+ elif isinstance(arg, (str)):
134
+ ret_args.append(c_arg.value.decode('cp1252'))
135
+ # c_args.pop(0)
136
+ elif isinstance(arg, np.ndarray):
137
+ ret_args.append(arg)
138
+ else:
139
+ raise NotImplementedError(arg.__class__.__name__)
140
+ return ret_args, res
141
+
142
+
73
143
  class DLLWrapper(object):
74
144
  def __init__(self, filename, cwd='.', cdecl=True, fortran=True):
75
145
  self.filename = str(filename)
76
146
  if os.path.abspath(self.filename) in in_use:
77
147
  raise Exception(f'{os.path.abspath(self.filename)} already in use in current process.')
78
- in_use.append(os.path.abspath(self.filename))
79
148
  self.cwd = cwd
80
149
  self.cdecl = cdecl
81
150
  self.fortran = fortran
82
151
  self.suppress_output = False
83
152
  self.open()
153
+ in_use.append(os.path.abspath(self.filename))
84
154
  atexit.register(self.close)
85
155
 
86
156
  @staticmethod
@@ -124,9 +194,10 @@ class DLLWrapper(object):
124
194
  def open(self):
125
195
  assert os.path.isfile(self.filename), os.path.abspath(self.filename)
126
196
  if self.cdecl:
127
- if tuple(map(int, platform.python_version().split('.'))) < (3, 8):
197
+ try:
198
+ # python < (3, 8) and > 3.10?:
128
199
  self.lib = ct.CDLL(self.filename)
129
- else:
200
+ except BaseException:
130
201
  self.lib = ct.CDLL(self.filename, winmode=ctypes.DEFAULT_MODE)
131
202
  else:
132
203
  self.lib = windll.LoadLibrary(self.filename)
@@ -148,82 +219,17 @@ class DLLWrapper(object):
148
219
  # self.close()
149
220
  # return False
150
221
 
151
- def __getattribute__(self, name):
152
- try:
153
- return object.__getattribute__(self, name)
154
- except AttributeError:
155
- if name == 'lib':
156
- raise Exception("DLL not loaded. Run using: 'with dll: ...'")
157
- return self.get_lib_function(name)
222
+ def __getattr__(self, name):
223
+ if name == 'lib':
224
+ raise Exception("DLL not loaded. Run using: 'with dll: ...'")
225
+ return self.get_lib_function(name)
158
226
 
159
227
  def get_lib_function(self, name):
160
228
  try:
161
229
  f = getattr(self.lib, name)
162
230
  except AttributeError as e:
163
231
  raise AttributeError("Attribute '%s' not found in dll ('%s')" % (name, self.filename))
164
-
165
- def wrap(*args, **kwargs):
166
- c_args = []
167
- args = list(args)
168
- for i, arg in enumerate(args):
169
- if isinstance(arg, (list, tuple)):
170
- if all([isinstance(e, int) for e in arg]):
171
- # default to int64 which is default on linux but not windows
172
- args[i] = np.array(arg, dtype=np.int64)
173
- else:
174
- args[i] = np.array(arg)
175
- if isinstance(args[i], np.ndarray):
176
- if self.fortran:
177
- args[i] = np.asfortranarray(args[i])
178
- else:
179
- args[i] = np.ascontiguousarray(args[i])
180
- for arg in args:
181
- if isinstance(arg, int):
182
- c_args.append(c_int_p(c_int(arg)))
183
- elif isinstance(arg, float):
184
- c_args.append(c_double_p(c_double(arg)))
185
- elif isinstance(arg, str):
186
- c_args.append(c_char_p(arg.encode('cp1252')))
187
- # c_args.append(c_int_p(c_int(len(arg))))
188
-
189
- elif isinstance(arg, np.ndarray):
190
- if arg.dtype in [np.int32]:
191
- c_args.append(arg.ctypes.data_as(c_int_p))
192
- elif arg.dtype in [np.int64]:
193
- c_args.append(arg.ctypes.data_as(c_long_p))
194
- elif arg.dtype == np.float64:
195
- c_args.append(arg.ctypes.data_as(c_double_p))
196
- else:
197
- raise NotImplementedError(arg.dtype)
198
-
199
- else:
200
- # raise NotImplementedError(arg.__class__.__name__)
201
- c_args.append(arg)
202
- if 'restype' in kwargs:
203
- restype = kwargs['restype']
204
- if hasattr(restype, 'dtype'):
205
- restype = np.ctypeslib.as_ctypes_type(restype)
206
- f.restype = restype
207
- with chdir(self.cwd):
208
- if self.suppress_output:
209
- with SuppressStream(sys.stdout), SuppressStream(sys.stderr):
210
- res = f(*c_args)
211
- else:
212
- res = f(*c_args)
213
- ret_args = []
214
- for arg in args:
215
- c_arg = c_args.pop(0)
216
- if isinstance(arg, (int, float)):
217
- ret_args.append(c_arg.contents.value)
218
- elif isinstance(arg, (str)):
219
- ret_args.append(c_arg.value.decode('cp1252'))
220
- # c_args.pop(0)
221
- elif isinstance(arg, np.ndarray):
222
- ret_args.append(arg)
223
- else:
224
- raise NotImplementedError(arg.__class__.__name__)
225
- return ret_args, res
226
- return wrap
232
+ return lambda *args, **kwargs: wrap(self, f, *args, **kwargs)
227
233
 
228
234
  def version(self, function_name='get_version'):
229
235
  try:
h2lib/h2lib_signatures.py CHANGED
@@ -33,6 +33,12 @@ end subroutine'''
33
33
  end subroutine'''
34
34
  return self.get_lib_function('extern_write_log')(c_msg, n, dll_name, error, warning)
35
35
 
36
+ def fail(self, str_arr): # pragma: no cover
37
+ '''subroutine fail(str_arr) bind(C, name='fail')
38
+ character(kind=c_char, len=1), intent(inout) :: str_arr(255)
39
+ end subroutine'''
40
+ return self.get_lib_function('fail')(str_arr)
41
+
36
42
  def finalize(self, ):
37
43
  '''SUBROUTINE finalize() bind(C, name="finalize")
38
44
  !DEC$ ATTRIBUTES DLLEXPORT :: finalize
@@ -115,6 +121,14 @@ END SUBROUTINE'''
115
121
  end subroutine'''
116
122
  return self.get_lib_function('get_induction_polargrid')(rotor, induction)
117
123
 
124
+ def get_induction_rotoravg(self, rotor, induction):
125
+ '''subroutine get_induction_rotoravg(rotor, induction) bind(C, name="get_induction_rotoravg")
126
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_induction_rotoravg
127
+ integer*8, intent(in) :: rotor
128
+ real(c_double), intent(out) :: induction
129
+ end subroutine'''
130
+ return self.get_lib_function('get_induction_rotoravg')(rotor, induction)
131
+
118
132
  def get_nSections(self, rotor, blade, restype):
119
133
  '''function get_nSections(rotor, blade) bind(C, name="get_nSections")
120
134
  !DEC$ ATTRIBUTES DLLEXPORT :: get_nSections
@@ -181,10 +195,8 @@ END SUBROUTINE'''
181
195
  return self.get_lib_function('get_sensor_values')(ids, values, n)
182
196
 
183
197
  def get_time(self, time):
184
- '''subroutine get_time(time) bind(C, name="get_time")
185
- !DEC$ ATTRIBUTES DLLEXPORT :: get_time
186
- double precision :: time ! time [s]
187
- end subroutine'''
198
+ '''subroutine
199
+ subroutine'''
188
200
  return self.get_lib_function('get_time')(time)
189
201
 
190
202
  def get_version(self, s):
@@ -206,6 +218,15 @@ END SUBROUTINE'''
206
218
  end subroutine'''
207
219
  return self.get_lib_function('init_windfield')(Nxyz, dxyz, box_offset_yz, transport_speed)
208
220
 
221
+ def loop(self, N, restype):
222
+ '''function loop(N) bind(C, Name='loop')
223
+ !DEC$ ATTRIBUTES DLLEXPORT :: loop
224
+ integer*8, intent(in) :: N
225
+ real(c_double) :: loop,a
226
+ integer*8 :: i, j
227
+ end function'''
228
+ return self.get_lib_function('loop')(N, restype=restype)
229
+
209
230
  def myfunction(self, int, dbl, restype):
210
231
  '''function myfunction(int, dbl) bind(C, name='myfunction')
211
232
  !DEC$ ATTRIBUTES DLLEXPORT :: myfunction
@@ -258,7 +279,7 @@ END SUBROUTINE'''
258
279
 
259
280
  def set_windfield(self, uvw, box_offset_x, time):
260
281
  '''subroutine set_windfield(uvw, box_offset_x, time) bind(C, name="set_windfield")
261
- real*8, intent(in) :: uvw(3, gwsd%TMOD%buffer_points_x,gwsd%TMOD%buffer_points_y,gwsd%TMOD%buffer_points_z)
282
+ real*4, intent(in) :: uvw(3, gwsd%TMOD%buffer_points_x,gwsd%TMOD%buffer_points_y,gwsd%TMOD%buffer_points_z)
262
283
  real*8, intent(in):: box_offset_x, time
263
284
  end subroutine'''
264
285
  return self.get_lib_function('set_windfield')(uvw, box_offset_x, time)
@@ -287,9 +308,11 @@ END SUBROUTINE'''
287
308
  end subroutine'''
288
309
  return self.get_lib_function('test_hdf5')()
289
310
 
290
- def work(self, time):
291
- '''subroutine work(time) bind(C, Name='work')
292
- integer*8, intent(in) :: time
293
- real*4 :: start_time
294
- end subroutine'''
295
- return self.get_lib_function('work')(time)
311
+ def work(self, time, restype):
312
+ '''function work(time) bind(C, Name='work')
313
+ !DEC$ ATTRIBUTES DLLEXPORT :: work
314
+ real(c_double), intent(in) :: time
315
+ real*4 :: start_time, t
316
+ integer*8 :: N, work
317
+ end function'''
318
+ return self.get_lib_function('work')(time, restype=restype)
@@ -1,12 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: h2lib
3
- Version: 13.0.605
4
- Summary: Python interface to HAWC2 (13.0.6+8-g2148dea)
3
+ Version: 13.0.705
4
+ Summary: Python interface to HAWC2 (13.0.9)
5
5
  Download-URL:
6
6
  Author: Mads M. Pedersen, S.G.Horcas and N.G.Ramos
7
7
  Author-email: mmpe@dtu.dk
8
8
  Maintainer:
9
9
  Maintainer-email:
10
+ Project-URL: Documentation, https://hawc2.pages.windenergy.dtu.dk/HAWC2Lib/
11
+ Project-URL: Source, https://gitlab.windenergy.dtu.dk/HAWC2/HAWC2Lib
12
+ Project-URL: Tracker, https://gitlab.windenergy.dtu.dk/HAWC2/HAWC2Lib/-/issues
10
13
  Requires-Dist: numpy
11
14
  Requires-Dist: intel-fortran-rt ==2021.3.0
12
15
  Requires-Dist: mkl ==2021.3.0
@@ -0,0 +1,14 @@
1
+ h2lib/HAWC2Lib.dll,sha256=GhnrcvnvBrC_KxHN2Asm1U7Ak6SW1axLhiBGPocwAvw,29301760
2
+ h2lib/__init__.py,sha256=f3fO4I6IEFRM9LaV2O3w9Pioj3GPI8qRl7P5Tg5ONtE,528
3
+ h2lib/_h2lib.py,sha256=PvXyuoVW6IDbjeYWYtCHRYcpLMlZh7aCiJkfLBl88gg,14938
4
+ h2lib/_version.py,sha256=xyyOn5ozEvCx53n7O9Ht13YA4b22VWeehuYZqCSUdEk,146
5
+ h2lib/dll_wrapper.py,sha256=vO7IGbnPTpzrbjsvm-jRnYabXM97gCukJDTPJHDLEpA,11824
6
+ h2lib/h2lib_signatures.py,sha256=uIcqvgVbm_L5C4jpHc9mBqz_6G5sLIk_6n2i-j1oA04,14500
7
+ multiclass_interface/mpi_interface.py,sha256=eGftiuyQ3QkcenpEmbZjy_3VomWoXADnQsGUCFoFBvs,6274
8
+ multiclass_interface/multi_object_list.py,sha256=5bEdwvtzQkPyBrS-W64i3EHJmuTfNGmRhGm5ToK7SXI,2072
9
+ multiclass_interface/multiprocess_interface.py,sha256=L5G7-EL5rXQtze5-4oSTBFs0AjswbD2diNtt0ynfWOM,7271
10
+ multiclass_interface/my_test_cls.py,sha256=7ZDsFkxrLfOY6q00U5Y-daxfuhATK-K5H04RP-VmQdE,850
11
+ h2lib-13.0.705.dist-info/METADATA,sha256=54FEPqcr2y_3vR70shyoAVXYpWfUwFdJcDNWW-EFR3M,623
12
+ h2lib-13.0.705.dist-info/WHEEL,sha256=3SeyPJ5-Us2Ct5GSftUVKtLSlm-bNefW4m5qd0GLzww,100
13
+ h2lib-13.0.705.dist-info/top_level.txt,sha256=CafRr3oTgH80oaQrp2SGKlPcX7cag5ag4EGKAZAy1ow,27
14
+ h2lib-13.0.705.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: bdist_wheel (0.42.0)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp38-cp38-win_amd64
5
5
 
@@ -0,0 +1,2 @@
1
+ h2lib
2
+ multiclass_interface
@@ -0,0 +1,184 @@
1
+ import numpy as np
2
+ import sys
3
+ import os
4
+ import subprocess
5
+ import traceback
6
+ import inspect
7
+ from enum import Enum
8
+
9
+ if 'SLURM_NTASKS' in os.environ:
10
+ mpi = int(os.environ['SLURM_NTASKS']) > 1
11
+ elif any([k in os.environ for k in ['MPI_LOCALNRANKS', 'OMPI_COMM_WORLD_SIZE']]):
12
+ mpi = True
13
+ else:
14
+ mpi = subprocess.run("python -c 'from mpi4py import MPI'", shell=True,
15
+ check=False, stderr=subprocess.PIPE).returncode == 0
16
+
17
+ if mpi:
18
+ from mpi4py import MPI
19
+ comm = MPI.COMM_WORLD
20
+ size = MPI.COMM_WORLD.Get_size()
21
+ rank = MPI.COMM_WORLD.Get_rank()
22
+ name = MPI.Get_processor_name()
23
+ else:
24
+ size = 1
25
+
26
+ MPIClassInterfaceAttributes = {'close', 'use_rank', 'cls', 'work_loop', 'object', '__class__','get_input','do_task', 'run_task', 'closed'}
27
+
28
+
29
+ LOOP_UNTIL_CLOSE=True
30
+ TERMINATE_ON_CLOSE=True
31
+
32
+
33
+ class MPIClassInterface():
34
+ def __init__(self, cls, args_lst):
35
+ if len(args_lst) > size:
36
+ if rank == 0:
37
+ raise Exception(f"Not enough mpi slots. Slots: {size}, Requested: {len(args_lst)}")
38
+ return
39
+ self.cls = cls
40
+ if rank < len(args_lst):
41
+ self.object = cls(*args_lst[rank])
42
+ else:
43
+ class Dummy():
44
+ def close(self):
45
+ pass
46
+ self.object = Dummy()
47
+ self.closed=False
48
+
49
+ if rank == 0:
50
+ self.use_rank = np.array([True] * size)
51
+ self.use_rank[len(args_lst):] = False
52
+ elif LOOP_UNTIL_CLOSE:
53
+ self.work_loop()
54
+
55
+ def __enter__(self):
56
+ return self
57
+
58
+ def __exit__(self, exc_type, exc_val, exc_tb):
59
+ self.close()
60
+
61
+ def work_loop(self):
62
+ while True:
63
+ method, args, kwargs = comm.scatter(None)
64
+ comm.gather(self.do_task(method, args, kwargs))
65
+ if LOOP_UNTIL_CLOSE:
66
+ if method == 'close':
67
+ if TERMINATE_ON_CLOSE:
68
+ #comm.gather(f'Exit, rank {rank}')
69
+ print ("sys.exit", rank, flush=True)
70
+ sys.exit(0)
71
+ else:
72
+ raise ChildProcessError('MPI worker done')
73
+ else:
74
+ break
75
+
76
+
77
+ def do_task(self, method, args, kwargs):
78
+ try:
79
+ if method == 'skip':
80
+ res = None
81
+ elif method=='setattr':
82
+ name, value = args
83
+ if hasattr(value, '__call__'):
84
+ def wrap(*args, func=value, **kwargs):
85
+ if inspect.getfullargspec(func).args[:1] == ['self']:
86
+ args = (self.object,) + args
87
+ return func(*args, **kwargs)
88
+ value = wrap
89
+ res = setattr(self.object, name, value)
90
+ else:
91
+ res = getattr(self.object, method)
92
+ if hasattr(res, '__call__'):
93
+ res = res(*args, **kwargs)
94
+ except BaseException as e:
95
+ res = (e, traceback.format_exc())
96
+ return res
97
+
98
+ def run_task(self, input_lst):
99
+ comm.scatter(input_lst, root=0)
100
+ if rank == 0:
101
+ method, args, kwargs = input_lst[0]
102
+ res = self.do_task(method, args, kwargs)
103
+ else:
104
+ res = None
105
+ use_rank = self.use_rank
106
+
107
+ res = [res for i, res in enumerate(comm.gather(res, root=0)) if use_rank[i]]
108
+ if rank==0:
109
+ for r in res:
110
+ if isinstance(r, tuple) and len(r) > 1 and isinstance(r[0], BaseException):
111
+ raise r[0].__class__(r[1])
112
+ return res
113
+
114
+
115
+ def get_input(self, name, i, args, kwargs):
116
+ use_rank = self.use_rank
117
+ N = np.sum(use_rank)
118
+ if use_rank[i]:
119
+ def get_arg(arg):
120
+ if isinstance(arg, list) and len(arg) == N:
121
+ return arg[np.where(use_rank)[0][i]]
122
+ else:
123
+ return arg
124
+ return (name, [get_arg(arg) for arg in args], {k: get_arg(v) for k, v in kwargs.items()})
125
+ else:
126
+ return ('skip', [], {})
127
+
128
+ def __getattribute__(self, name):
129
+ if name in MPIClassInterfaceAttributes:
130
+ return object.__getattribute__(self, name)
131
+ elif rank > 0:
132
+ self.work_loop()
133
+ return lambda *args, **kwargs:1
134
+
135
+ def wrap(*args, **kwargs):
136
+ inp = [self.get_input(name, i, args, kwargs) for i in range(size)]
137
+ return self.run_task(inp)
138
+
139
+ if hasattr(getattr(self.object, name), '__call__'):
140
+ return wrap
141
+ else:
142
+ return wrap()
143
+
144
+ def __setattr__(self, name, value):
145
+ if rank > 0 or name in MPIClassInterfaceAttributes:
146
+ return object.__setattr__(self, name, value)
147
+ else:
148
+ inp = [self.get_input('setattr', i, (name, value), {}) for i in range(size)]
149
+ return self.run_task(inp)
150
+
151
+
152
+ def __getitem__(self, slice):
153
+ use_rank = np.full_like(self.use_rank, False)
154
+ use_rank[slice] = True
155
+ if np.all(self.use_rank == use_rank):
156
+ return self
157
+ return SubsetMPIClassInterface(self.cls, self.object, use_rank)
158
+
159
+ def close(self):
160
+ if not self.closed:
161
+ if rank==0:
162
+ res = self.run_task([('close', [], {}) for _ in range(size)])
163
+ else:
164
+ self.work_loop()
165
+ res = None
166
+ self.closed=True
167
+
168
+
169
+
170
+
171
+ class SubsetMPIClassInterface(MPIClassInterface):
172
+ def __init__(self, cls, object, use_rank):
173
+ self.use_rank = use_rank
174
+ self.cls = cls
175
+ self.object = object
176
+
177
+ def __getitem__(self, slice):
178
+ l = np.arange(np.sum(self.use_rank))
179
+ if np.all(l == l[slice]):
180
+ return self
181
+ raise Exception('Cannot make subset of SubsetMPIClassInterface')
182
+
183
+ def close(self):
184
+ raise Exception('Cannot close SubsetMPIClassInterface. Please close all instances at once')
@@ -0,0 +1,57 @@
1
+ import numpy as np
2
+
3
+
4
+ class MultiObjectList():
5
+ def __init__(self, obj_lst, subset_cls=None):
6
+ self.obj_lst = np.atleast_1d(obj_lst)
7
+ self.subset_cls = subset_cls
8
+
9
+ def __str__(self):
10
+ return f'{self.__class__.__name__}({self.obj_lst})'
11
+
12
+ def get_obj_args_lst(self, args, kwargs):
13
+ N = len(self.obj_lst)
14
+
15
+ def get_obj_args(i):
16
+ def get_arg(arg):
17
+ if isinstance(arg, list) and len(arg) == N:
18
+ return arg[i]
19
+ else:
20
+ return arg
21
+ obj_args = [get_arg(arg) for arg in args]
22
+ obj_kwargs = {k: get_arg(v) for k, v in kwargs.items()}
23
+ return obj_args, obj_kwargs
24
+ return [get_obj_args(i) for i in range(N)]
25
+
26
+ def iscallable(self, name):
27
+ return hasattr(getattr(self.obj_lst[0], name), '__call__')
28
+
29
+ def __getitem__(self, s):
30
+ obj_lst = np.atleast_1d(self.obj_lst[s])
31
+ if len(obj_lst) == len(self.obj_lst) and np.all(obj_lst == self.obj_lst):
32
+ return self
33
+ subset_cls = self.subset_cls or MultiObjectList
34
+ return subset_cls(self.obj_lst[s])
35
+
36
+ def __getattr__(self, name):
37
+ att_lst = [getattr(obj, name) for obj in self.obj_lst]
38
+ if self.iscallable(name):
39
+ def wrap(*args, **kwargs):
40
+ return [att(*o_args, **o_kwargs)
41
+ for att, (o_args, o_kwargs) in zip(att_lst, self.get_obj_args_lst(args, kwargs))]
42
+ return wrap
43
+ else:
44
+ return att_lst
45
+
46
+ def __setattr__(self, name, value):
47
+ if name in {'obj_lst', 'subset_cls'}:
48
+ return object.__setattr__(self, name, value)
49
+ obj_lst = self.obj_lst
50
+ for obj, (o_args, _) in zip(obj_lst, self.get_obj_args_lst((value,), {})):
51
+ setattr(obj, name, *o_args)
52
+
53
+
54
+ class MultiClassInterface(MultiObjectList):
55
+ def __init__(self, cls, args_lst):
56
+ self.cls = cls
57
+ MultiObjectList.__init__(self, [cls(*args) for args in args_lst])
@@ -0,0 +1,184 @@
1
+ import multiprocessing
2
+ import atexit
3
+ import numpy as np
4
+ from threading import Thread
5
+ from functools import wraps
6
+ import traceback
7
+ from _queue import Empty
8
+ import os
9
+ from contextlib import contextmanager
10
+ import sys
11
+ import inspect
12
+ from multiclass_interface.multi_object_list import MultiObjectList
13
+
14
+
15
+ def run(cls, inputQueue, outputQueue, cls_args, **kwargs):
16
+ o = cls(*cls_args, **kwargs)
17
+ while True:
18
+ method, args, kwargs = inputQueue.get()
19
+ try:
20
+ if method == 'getattr':
21
+ name = args[0]
22
+ outputQueue.put(getattr(o, name))
23
+ elif method == 'setattr':
24
+ name, value = args
25
+ if hasattr(value, '__call__'): # pragma: no cover # cov not registered?
26
+
27
+ def wrap(*args, func=value, **kwargs):
28
+ if inspect.getfullargspec(func).args[:1] == ['self']:
29
+ args = (o,) + args
30
+ return func(*args, **kwargs)
31
+ outputQueue.put(setattr(o, name, wrap))
32
+ else:
33
+ outputQueue.put(setattr(o, name, value))
34
+ elif method == 'iscallable':
35
+ name = args[0]
36
+ outputQueue.put(hasattr(getattr(o, name), '__call__'))
37
+ else:
38
+ att = getattr(o, method)
39
+ outputQueue.put(att(*args, **kwargs))
40
+ if method == 'close':
41
+ outputQueue.put('Exit process')
42
+ return
43
+ except BaseException as e:
44
+ outputQueue.put((e, traceback.format_exc()))
45
+
46
+
47
+ class ProcessClass():
48
+ cls = None
49
+
50
+ def __init__(self, cls, cls_attrs={}):
51
+ self.cls_attrs = cls_attrs
52
+ self.cls = cls
53
+ self.ctx = multiprocessing.get_context('spawn')
54
+ self.inputQueue = self.ctx.Queue()
55
+ self.outputQueue = self.ctx.Queue()
56
+ atexit.register(self.close)
57
+ self.closed = False
58
+
59
+ def __call__(self, *args, **kwargs):
60
+ kwargs.update({'cls': self.cls, 'inputQueue': self.inputQueue, 'outputQueue': self.outputQueue,
61
+ 'cls_args': args})
62
+ s = 'vs_debug.py'
63
+ if s in "".join(traceback.format_stack()): # pragma: no cover
64
+ self.process = Thread(target=run, kwargs=kwargs) # use this to debug from Visual studio
65
+ else:
66
+ self.process = self.ctx.Process(target=run, kwargs=kwargs, daemon=True)
67
+
68
+ self.process.start()
69
+ return self
70
+
71
+ def __enter__(self):
72
+ return self
73
+
74
+ def __exit__(self, exc_type, exc_val, exc_tb):
75
+ self.close()
76
+
77
+ def __getattribute__(self, name):
78
+ try:
79
+ if name != 'cls_attrs' and name in self.cls_attrs:
80
+ raise AttributeError()
81
+ return object.__getattribute__(self, name)
82
+ except AttributeError:
83
+ if self.is_callable(name):
84
+ @wraps(getattr(self.cls, name, None))
85
+ def wrap(*args, wait_for_result=True, **kwargs):
86
+ self.inputQueue.put((name, args, kwargs))
87
+ if wait_for_result:
88
+ return self.get_result(raise_exception=True,
89
+ cmd=lambda: f'executing {name}({", ".join(list(map(str,args))+["%s=%s"%(k,v) for k,v in kwargs.items()])})')
90
+ return wrap
91
+ else:
92
+ self.inputQueue.put(('getattr', (name,), {}))
93
+ return self.get_result(raise_exception=True, cmd=lambda: f"getting attribute '{name}'")
94
+
95
+ def is_callable(self, name):
96
+ self.inputQueue.put(('iscallable', (name,), {}))
97
+ return self.get_result(raise_exception=True, cmd=lambda: f"checking if '{name}' is callable")
98
+
99
+ def __setattr__(self, name, value):
100
+ if name in {'cls', 'ctx', 'inputQueue', 'outputQueue', 'closed', 'process', 'cls_attrs'}:
101
+ return object.__setattr__(self, name, value)
102
+ else:
103
+ self.inputQueue.put(('setattr', (name, value), {}))
104
+ return self.get_result(raise_exception=True, cmd=lambda: f"setting attribute '{name}'")
105
+
106
+ def get_result(self, raise_exception, cmd):
107
+ while True:
108
+ if self.process.is_alive() or self.closed:
109
+ try:
110
+ res = self.outputQueue.get(timeout=2)
111
+ if isinstance(res, tuple) and len(res) > 1 and isinstance(res[0], BaseException):
112
+ res = res[0].__class__(res[1])
113
+ if raise_exception:
114
+ raise res
115
+ return res
116
+ except Empty:
117
+ pass # time out. Check process is alive and try again
118
+ else:
119
+ if hasattr(cmd, '__call__'):
120
+ cmd = cmd()
121
+ e = Exception(f'{self.cls.__name__} process died before or while {cmd}')
122
+ if raise_exception:
123
+ raise e
124
+ return e
125
+
126
+ def close(self, wait_for_result=False):
127
+ if not self.closed:
128
+ self.inputQueue.put(('close', [], {}))
129
+ r = self.get_result(False, 'close')
130
+ self.process.join()
131
+ self.inputQueue.close()
132
+ self.outputQueue.close()
133
+ self.closed = True
134
+ return r
135
+
136
+
137
+ class MultiProcessClassInterface(MultiObjectList):
138
+
139
+ def __init__(self, cls, args_lst, cls_attrs={}):
140
+ MultiObjectList.__init__(self, [ProcessClass(cls, cls_attrs)(*args) for args in args_lst], SubsetProcessWrapper)
141
+
142
+ def __getattr__(self, name):
143
+ obj_lst = self.obj_lst
144
+ if obj_lst[0].is_callable(name):
145
+ def wrap(*args, **kwargs):
146
+ for obj, (o_args, o_kwargs) in zip(obj_lst, self.get_obj_args_lst(args, kwargs)):
147
+ getattr(obj, name)(*o_args, wait_for_result=False, **o_kwargs)
148
+ res = [o.get_result(raise_exception=False, cmd=lambda: f"executing {name}(...)")
149
+ for o in obj_lst]
150
+ for r in res:
151
+ if isinstance(r, Exception):
152
+ raise r
153
+ return res
154
+ return wrap
155
+ else:
156
+ return [getattr(o, name) for o in obj_lst]
157
+
158
+ def __enter__(self):
159
+ return self
160
+
161
+ def __exit__(self, exc_type, exc_val, exc_tb):
162
+ self.close()
163
+
164
+ def close(self, wait_for_result=False):
165
+ for obj in self.obj_lst:
166
+ obj.inputQueue.put(('close', [], {}))
167
+ obj.process.join()
168
+ obj.closed = True
169
+
170
+
171
+ class SubsetProcessWrapper(MultiProcessClassInterface):
172
+ def __init__(self, obj_lst):
173
+ MultiObjectList.__init__(self, obj_lst)
174
+
175
+ def __getitem__(self, slice):
176
+ if np.all(np.atleast_1d(self.obj_lst[slice]) == self.obj_lst):
177
+ return self
178
+ raise Exception('Cannot make subset of SubsetProcessWrapper')
179
+
180
+ def __getattribute__(self, name):
181
+ if name == 'close':
182
+ raise Exception("Cannot close SubsetProcessWrapper. Please close all instances at once")
183
+
184
+ return MultiProcessClassInterface.__getattribute__(self, name)
@@ -0,0 +1,33 @@
1
+ import time
2
+ import os
3
+
4
+
5
+ class MyTest():
6
+ def __init__(self, id):
7
+ self.id = id
8
+ self.name = self.__class__.__name__
9
+
10
+ def get_id(self,):
11
+ return self.id
12
+
13
+ def work(self, t):
14
+ start_time = time.time()
15
+ s1 = f'{self.id} starts working for {t}s at t={start_time}. '
16
+ # print (s1)
17
+ while time.time() < start_time + t:
18
+ pass
19
+ s2 = f'{self.id} ends working at {time.time()}.'
20
+ # print (s2)
21
+ return s1 + s2
22
+
23
+ def return_input(self, *args, **kwargs):
24
+ return f"{self.id} got: {str(args)} and {str(kwargs)}"
25
+
26
+ def get_ld_library_path(self):
27
+ return os.environ['LD_LIBRARY_PATH']
28
+
29
+ def close(self):
30
+ return f"closing {self.get_id()}"
31
+
32
+ def raise_exception(self):
33
+ 1 / 0 # raise ZeroDivisionError
h2lib/utils.py DELETED
@@ -1,149 +0,0 @@
1
- import multiprocessing
2
- import atexit
3
- import numpy as np
4
- from threading import Thread
5
- from functools import wraps
6
- import traceback
7
-
8
-
9
- def run(cls, inputQueue, outputQueue, cls_args, **kwargs):
10
- o = cls(*cls_args, **kwargs)
11
- while True:
12
- method, args, kwargs = inputQueue.get()
13
- # if method == "Sentinel":
14
- # outputQueue.put(method)
15
- # else:
16
- # print(method, args, kwargs)
17
- att = getattr(o, method)
18
- if hasattr(att, '__call__'):
19
- outputQueue.put(att(*args, **kwargs))
20
- else:
21
- outputQueue.put(att)
22
- if method == 'close':
23
- outputQueue.put('Exit process')
24
- return
25
-
26
-
27
- class ProcessClass():
28
- cls = None
29
-
30
- def __init__(self, cls, cls_attrs={}):
31
- self.cls_attrs = cls_attrs
32
- self.cls = cls
33
- self.ctx = multiprocessing.get_context('spawn')
34
- self.inputQueue = self.ctx.Queue()
35
- self.outputQueue = self.ctx.Queue()
36
- atexit.register(self.close)
37
- self.closed = False
38
-
39
- def __call__(self, *args, **kwargs):
40
- kwargs.update({'cls': self.cls, 'inputQueue': self.inputQueue, 'outputQueue': self.outputQueue,
41
- 'cls_args': args})
42
- s = 'vs_debug.py'
43
- if s in "".join(traceback.format_stack()): # pragma: no cover
44
- self.process = Thread(target=run, kwargs=kwargs) # use this to debug from Visual studio
45
- else:
46
- self.process = self.ctx.Process(target=run, kwargs=kwargs, daemon=True)
47
-
48
- self.process.start()
49
- return self
50
-
51
- def __enter__(self):
52
- return self
53
-
54
- def __exit__(self, exc_type, exc_val, exc_tb):
55
- self.close()
56
-
57
- def __getattribute__(self, name):
58
- try:
59
- if name != 'cls_attrs' and name in self.cls_attrs:
60
- raise AttributeError()
61
- return object.__getattribute__(self, name)
62
- except AttributeError:
63
- if hasattr(self.cls, name):
64
- if hasattr(getattr(self.cls, name), '__call__'):
65
- @wraps(getattr(self.cls, name))
66
- def wrap(*args, wait_for_result=True, **kwargs):
67
- self.inputQueue.put((name, args, kwargs))
68
- if wait_for_result:
69
- return self.get_result()
70
- return wrap
71
- else:
72
- self.inputQueue.put((name, (), {}))
73
- return self.get_result()
74
- else:
75
- raise AttributeError(f"'{self.cls.__name__}' object has no attribute '{name}'")
76
-
77
- def get_result(self):
78
- if self.process.is_alive() or self.closed:
79
- return self.outputQueue.get()
80
- # self.inputQueue.put(('Sentinel', (), {}))
81
- # res_lst = []
82
- # print('get result')
83
- # while True:
84
- # print('get')
85
- # r = self.outputQueue.get()
86
- # print(' got')
87
- #
88
- # if isinstance(r, str):
89
- # if r == 'Exit process':
90
- # return r
91
- # elif r == 'Sentinel':
92
- # return res_lst[0]
93
- # else:
94
- # res_lst.append(r)
95
- # else:
96
- # res_lst.append(r)
97
-
98
- raise Exception(f'{self.cls.__name__} process died')
99
-
100
- def close(self, wait_for_result=False):
101
- self.inputQueue.put(('close', [], {}))
102
- self.process.join()
103
- self.closed = True
104
-
105
-
106
- class MultiProcessInterface():
107
- def __init__(self, cls, args_lst):
108
- self.cls = cls
109
- self.obj_lst = [ProcessClass(cls)(*args) for args in args_lst]
110
-
111
- def __getattribute__(self, name):
112
- if name in ['obj_lst']:
113
- return object.__getattribute__(self, name)
114
-
115
- a_lst = self.obj_lst
116
- if hasattr(getattr(self.obj_lst[0], name), '__call__'):
117
- def wrap(*args, **kwargs):
118
- for i, o in enumerate(self.obj_lst):
119
- def get_arg(arg):
120
- if isinstance(arg, list) and len(arg) == len(a_lst):
121
- return arg[i]
122
- else:
123
- return arg
124
- a_args = [get_arg(arg) for arg in args]
125
- a_kwargs = {k: get_arg(v) for k, v in kwargs.items()}
126
- getattr(o, name)(*a_args, wait_for_result=False, **a_kwargs)
127
- if isinstance(self, SubsetProcessWrapper) and len(self.obj_lst) == 1:
128
- return self.obj_lst[0].get_result()
129
- return [o.get_result() for o in self.obj_lst]
130
- return wrap
131
- else:
132
- if isinstance(self, SubsetProcessWrapper) and len(self.obj_lst) == 1:
133
- return getattr(self.obj_lst[0], name)
134
- return [getattr(o, name) for o in self.obj_lst]
135
-
136
- def __getitem__(self, slice):
137
- lst = np.atleast_1d(np.array(self.obj_lst)[slice]).tolist()
138
- return SubsetProcessWrapper(lst)
139
-
140
- def __enter__(self):
141
- return self
142
-
143
- def __exit__(self, exc_type, exc_val, exc_tb):
144
- self.close()
145
-
146
-
147
- class SubsetProcessWrapper(MultiProcessInterface):
148
- def __init__(self, obj_lst):
149
- self.obj_lst = obj_lst
@@ -1,11 +0,0 @@
1
- h2lib/HAWC2Lib.dll,sha256=ftWvOdfiMu78t0_vMiZca3e7lJ2nOIgUyOgmHD31bZY,29311488
2
- h2lib/__init__.py,sha256=f3fO4I6IEFRM9LaV2O3w9Pioj3GPI8qRl7P5Tg5ONtE,528
3
- h2lib/_h2lib.py,sha256=ZO2L9TWM3oJtkh3ixijw7o_8D1vyRd1fCIfNm2JdShA,13262
4
- h2lib/_version.py,sha256=fPq21FPnDoXOjYDsHMjXQQc1UKXkBMIKKOjGKNMZWh8,157
5
- h2lib/dll_wrapper.py,sha256=n--bPWNzJ2qR4F_kM8l2VI-impQRuAt7y8vA2cPF97c,11961
6
- h2lib/h2lib_signatures.py,sha256=KyhCNPmRoJasibDWQOOkUxganwXRFQBiwrus_iDGxpM,13579
7
- h2lib/utils.py,sha256=5EtSX4ByKg19TaI8EHtWa_C6A9jc6j5zGU1p0NHp6L0,5400
8
- h2lib-13.0.605.dist-info/METADATA,sha256=kYkdsl9WITSCHj8VZrGnco7P8oP_jj2vcO5OdsMGJ6Q,407
9
- h2lib-13.0.605.dist-info/WHEEL,sha256=KplWMgwSZbeAOumvxNxIrVbNPnn_LVzfBH7l38jDCVM,100
10
- h2lib-13.0.605.dist-info/top_level.txt,sha256=y_a-tUqphEZQ_0nsWSMaSb21P8Lsd8hUxUdE9g2Dcbk,6
11
- h2lib-13.0.605.dist-info/RECORD,,
@@ -1 +0,0 @@
1
- h2lib