h2lib 13.0.604__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 +0 -0
- h2lib/_h2lib.py +116 -46
- h2lib/_version.py +3 -3
- h2lib/dll_wrapper.py +83 -77
- h2lib/h2lib_signatures.py +85 -43
- h2lib-13.0.705.dist-info/METADATA +18 -0
- h2lib-13.0.705.dist-info/RECORD +14 -0
- {h2lib-13.0.604.dist-info → h2lib-13.0.705.dist-info}/WHEEL +1 -1
- h2lib-13.0.705.dist-info/top_level.txt +2 -0
- multiclass_interface/mpi_interface.py +184 -0
- multiclass_interface/multi_object_list.py +57 -0
- multiclass_interface/multiprocess_interface.py +184 -0
- multiclass_interface/my_test_cls.py +33 -0
- h2lib/utils.py +0 -149
- h2lib-13.0.604.dist-info/METADATA +0 -15
- h2lib-13.0.604.dist-info/RECORD +0 -11
- h2lib-13.0.604.dist-info/top_level.txt +0 -1
h2lib/h2lib_signatures.py
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
# noqa
|
2
|
+
|
1
3
|
from h2lib.dll_wrapper import DLLWrapper
|
4
|
+
|
5
|
+
|
2
6
|
class H2LibSignatures():
|
3
|
-
def add_sensor(self, sensor_line,
|
4
|
-
'''
|
5
|
-
|
6
|
-
integer*8 :: add_sensor
|
7
|
+
def add_sensor(self, sensor_line, index_start, index_stop):
|
8
|
+
'''subroutine add_sensor(sensor_line, index_start, index_stop) bind(C, name="add_sensor")
|
9
|
+
integer*8 :: index_start, index_stop
|
7
10
|
character(kind=c_char, len=1), intent(in) :: sensor_line(1024)
|
8
|
-
end
|
9
|
-
return self.get_lib_function('add_sensor')(sensor_line,
|
11
|
+
end subroutine'''
|
12
|
+
return self.get_lib_function('add_sensor')(sensor_line, index_start, index_stop)
|
10
13
|
|
11
14
|
def echo_version(self, ):
|
12
15
|
'''subroutine echo_version() BIND(C, NAME='echo_version')
|
@@ -30,9 +33,15 @@ end subroutine'''
|
|
30
33
|
end subroutine'''
|
31
34
|
return self.get_lib_function('extern_write_log')(c_msg, n, dll_name, error, warning)
|
32
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
|
+
|
33
42
|
def finalize(self, ):
|
34
43
|
'''SUBROUTINE finalize() bind(C, name="finalize")
|
35
|
-
!DEC$ ATTRIBUTES DLLEXPORT :: finalize
|
44
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: finalize
|
36
45
|
integer:: i
|
37
46
|
real*4:: T2
|
38
47
|
END SUBROUTINE'''
|
@@ -40,7 +49,7 @@ END SUBROUTINE'''
|
|
40
49
|
|
41
50
|
def getSquare(self, val, restype):
|
42
51
|
'''function getSquare(val) result(valSquared) BIND(C, NAME='getSquare')
|
43
|
-
|
52
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: getSquare
|
44
53
|
real(RK), intent(in) :: val
|
45
54
|
real(RK) :: valSquared
|
46
55
|
end function'''
|
@@ -48,7 +57,7 @@ END SUBROUTINE'''
|
|
48
57
|
|
49
58
|
def getState(self, restype):
|
50
59
|
'''function getState() result(val) BIND(C, NAME='getState')
|
51
|
-
|
60
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: getState
|
52
61
|
integer :: val
|
53
62
|
end function'''
|
54
63
|
return self.get_lib_function('getState')(restype=restype)
|
@@ -76,7 +85,7 @@ END SUBROUTINE'''
|
|
76
85
|
|
77
86
|
def get_bem_grid(self, rotor, azi, rad):
|
78
87
|
'''subroutine get_bem_grid(rotor, azi, rad) bind(C, name="get_bem_grid")
|
79
|
-
integer*8, intent(in) :: rotor
|
88
|
+
integer*8, intent(in) :: rotor
|
80
89
|
real(c_double), intent(out) :: azi(rotors_gl%rotor(rotor)%dyn_induc%bem%nazi)
|
81
90
|
real(c_double), intent(out) :: rad(rotors_gl%rotor(rotor)%dyn_induc%bem%nrad)
|
82
91
|
end subroutine'''
|
@@ -112,6 +121,14 @@ END SUBROUTINE'''
|
|
112
121
|
end subroutine'''
|
113
122
|
return self.get_lib_function('get_induction_polargrid')(rotor, induction)
|
114
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
|
+
|
115
132
|
def get_nSections(self, rotor, blade, restype):
|
116
133
|
'''function get_nSections(rotor, blade) bind(C, name="get_nSections")
|
117
134
|
!DEC$ ATTRIBUTES DLLEXPORT :: get_nSections
|
@@ -145,7 +162,7 @@ END SUBROUTINE'''
|
|
145
162
|
|
146
163
|
def get_rotor_orientation(self, rotor, yaw, tilt, azi):
|
147
164
|
'''subroutine get_rotor_orientation(rotor, yaw, tilt, azi) bind(C, name="get_rotor_orientation")
|
148
|
-
!DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_orientation
|
165
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_orientation
|
149
166
|
integer*8, intent(in) :: rotor
|
150
167
|
real(c_double), intent(out) :: yaw, tilt, azi
|
151
168
|
end subroutine'''
|
@@ -153,10 +170,10 @@ END SUBROUTINE'''
|
|
153
170
|
|
154
171
|
def get_rotor_position(self, rotor, position):
|
155
172
|
'''subroutine get_rotor_position(rotor, position) bind(C, name="get_rotor_position")
|
156
|
-
!DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_position
|
173
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_position
|
157
174
|
integer*8, intent(in) :: rotor
|
158
175
|
real(c_double), dimension(3), intent(out) :: position
|
159
|
-
!DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_avg_wsp
|
176
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_avg_wsp
|
160
177
|
integer*8, intent(in) :: rotor
|
161
178
|
integer*8, intent(in) :: coo ! 1: global, 2: rotor
|
162
179
|
end subroutine'''
|
@@ -169,19 +186,17 @@ END SUBROUTINE'''
|
|
169
186
|
end subroutine'''
|
170
187
|
return self.get_lib_function('get_sensor_info')(id, name, unit, desc)
|
171
188
|
|
172
|
-
def
|
173
|
-
'''
|
174
|
-
|
175
|
-
integer*8, intent(in) ::
|
176
|
-
real(c_double) ::
|
177
|
-
end
|
178
|
-
return self.get_lib_function('
|
189
|
+
def get_sensor_values(self, ids, values, n):
|
190
|
+
'''subroutine get_sensor_values(ids, values, n) bind(C, name="get_sensor_values")
|
191
|
+
integer*8, intent(in) :: n
|
192
|
+
integer*8, intent(in) :: ids(n)
|
193
|
+
real(c_double), intent(out) :: values(n)
|
194
|
+
end subroutine'''
|
195
|
+
return self.get_lib_function('get_sensor_values')(ids, values, n)
|
179
196
|
|
180
197
|
def get_time(self, time):
|
181
|
-
'''subroutine
|
182
|
-
|
183
|
-
double precision :: time ! time [s]
|
184
|
-
end subroutine'''
|
198
|
+
'''subroutine
|
199
|
+
subroutine'''
|
185
200
|
return self.get_lib_function('get_time')(time)
|
186
201
|
|
187
202
|
def get_version(self, s):
|
@@ -192,7 +207,7 @@ END SUBROUTINE'''
|
|
192
207
|
|
193
208
|
def init(self, ):
|
194
209
|
'''subroutine init() bind(C, name="init")
|
195
|
-
|
210
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: init
|
196
211
|
end subroutine'''
|
197
212
|
return self.get_lib_function('init')()
|
198
213
|
|
@@ -203,6 +218,31 @@ END SUBROUTINE'''
|
|
203
218
|
end subroutine'''
|
204
219
|
return self.get_lib_function('init_windfield')(Nxyz, dxyz, box_offset_yz, transport_speed)
|
205
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
|
+
|
230
|
+
def myfunction(self, int, dbl, restype):
|
231
|
+
'''function myfunction(int, dbl) bind(C, name='myfunction')
|
232
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: myfunction
|
233
|
+
integer*8, intent(in) :: int
|
234
|
+
real(c_double), intent(in) :: dbl
|
235
|
+
real(c_double) :: myfunction
|
236
|
+
end function'''
|
237
|
+
return self.get_lib_function('myfunction')(int, dbl, restype=restype)
|
238
|
+
|
239
|
+
def mysubroutine(self, str_arr, dbl_arr):
|
240
|
+
'''subroutine mysubroutine(str_arr, dbl_arr) bind(C, name='mysubroutine')
|
241
|
+
character(kind=c_char, len=1), intent(inout) :: str_arr(20)
|
242
|
+
real(c_double), intent(inout), dimension(2) :: dbl_arr
|
243
|
+
end subroutine'''
|
244
|
+
return self.get_lib_function('mysubroutine')(str_arr, dbl_arr)
|
245
|
+
|
206
246
|
def read_input(self, htc_path):
|
207
247
|
'''subroutine read_input(htc_path) bind(C, name="read_input")
|
208
248
|
character(kind=c_char, len=1), intent(in) :: htc_path(1024)
|
@@ -219,8 +259,8 @@ END SUBROUTINE'''
|
|
219
259
|
|
220
260
|
def setState(self, val):
|
221
261
|
'''subroutine setState(val) BIND(C, NAME='setState')
|
222
|
-
|
223
|
-
|
262
|
+
integer, intent(in) :: val
|
263
|
+
end subroutine'''
|
224
264
|
return self.get_lib_function('setState')(val)
|
225
265
|
|
226
266
|
def set_aerosections_windspeed(self, rotor, uvw):
|
@@ -239,15 +279,15 @@ END SUBROUTINE'''
|
|
239
279
|
|
240
280
|
def set_windfield(self, uvw, box_offset_x, time):
|
241
281
|
'''subroutine set_windfield(uvw, box_offset_x, time) bind(C, name="set_windfield")
|
242
|
-
real*
|
282
|
+
real*4, intent(in) :: uvw(3, gwsd%TMOD%buffer_points_x,gwsd%TMOD%buffer_points_y,gwsd%TMOD%buffer_points_z)
|
243
283
|
real*8, intent(in):: box_offset_x, time
|
244
284
|
end subroutine'''
|
245
285
|
return self.get_lib_function('set_windfield')(uvw, box_offset_x, time)
|
246
286
|
|
247
287
|
def sqr2(self, val):
|
248
288
|
'''subroutine sqr2(val) BIND(C, NAME='sqr2')
|
249
|
-
|
250
|
-
|
289
|
+
integer, intent(inout) :: val
|
290
|
+
end subroutine'''
|
251
291
|
return self.get_lib_function('sqr2')(val)
|
252
292
|
|
253
293
|
def step(self, restype):
|
@@ -259,18 +299,20 @@ END SUBROUTINE'''
|
|
259
299
|
|
260
300
|
def test_hdf5(self, ):
|
261
301
|
'''subroutine test_hdf5() BIND(C, NAME='test_hdf5')
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
302
|
+
!DEC$ ATTRIBUTES DLLEXPORT :: test_hdf5
|
303
|
+
INTEGER :: hdferr ! Error flag
|
304
|
+
CHARACTER(9) :: filename = 'test.hdf5'
|
305
|
+
INTEGER(HID_T) :: file_id ! File identifier
|
306
|
+
INTEGER(HID_T) :: H5_Create_file,H5_Open_file ! File identifier
|
307
|
+
type(c_ptr) :: x
|
308
|
+
end subroutine'''
|
269
309
|
return self.get_lib_function('test_hdf5')()
|
270
310
|
|
271
|
-
def work(self, time):
|
272
|
-
'''
|
273
|
-
|
274
|
-
real
|
275
|
-
|
276
|
-
|
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)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: h2lib
|
3
|
+
Version: 13.0.705
|
4
|
+
Summary: Python interface to HAWC2 (13.0.9)
|
5
|
+
Download-URL:
|
6
|
+
Author: Mads M. Pedersen, S.G.Horcas and N.G.Ramos
|
7
|
+
Author-email: mmpe@dtu.dk
|
8
|
+
Maintainer:
|
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
|
13
|
+
Requires-Dist: numpy
|
14
|
+
Requires-Dist: intel-fortran-rt ==2021.3.0
|
15
|
+
Requires-Dist: mkl ==2021.3.0
|
16
|
+
Provides-Extra: test
|
17
|
+
Requires-Dist: h2lib-tests ; extra == 'test'
|
18
|
+
|
@@ -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,,
|
@@ -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])
|