Multiclass-interface 1.2__tar.gz → 1.4__tar.gz

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.
Files changed (23) hide show
  1. {multiclass_interface-1.2 → multiclass_interface-1.4/Multiclass_interface.egg-info}/PKG-INFO +1 -1
  2. {multiclass_interface-1.2/Multiclass_interface.egg-info → multiclass_interface-1.4}/PKG-INFO +1 -1
  3. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/mpi_interface.py +28 -17
  4. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/tests/test_mpi.py +22 -4
  5. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/version.py +2 -2
  6. {multiclass_interface-1.2 → multiclass_interface-1.4}/sequence_diagrams.md +49 -2
  7. {multiclass_interface-1.2 → multiclass_interface-1.4}/.gitignore +0 -0
  8. {multiclass_interface-1.2 → multiclass_interface-1.4}/.gitlab-ci.yml +0 -0
  9. {multiclass_interface-1.2 → multiclass_interface-1.4}/LICENSE +0 -0
  10. {multiclass_interface-1.2 → multiclass_interface-1.4}/Multiclass_interface.egg-info/SOURCES.txt +0 -0
  11. {multiclass_interface-1.2 → multiclass_interface-1.4}/Multiclass_interface.egg-info/dependency_links.txt +0 -0
  12. {multiclass_interface-1.2 → multiclass_interface-1.4}/Multiclass_interface.egg-info/requires.txt +0 -0
  13. {multiclass_interface-1.2 → multiclass_interface-1.4}/Multiclass_interface.egg-info/top_level.txt +0 -0
  14. {multiclass_interface-1.2 → multiclass_interface-1.4}/README.md +0 -0
  15. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/__init__.py +0 -0
  16. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/multi_object_list.py +0 -0
  17. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/multiprocess_interface.py +0 -0
  18. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/tests/__init__.py +0 -0
  19. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/tests/my_test_cls.py +0 -0
  20. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/tests/test_multiclass_list.py +0 -0
  21. {multiclass_interface-1.2 → multiclass_interface-1.4}/multiclass_interface/tests/test_multiprocessinterface.py +0 -0
  22. {multiclass_interface-1.2 → multiclass_interface-1.4}/pyproject.toml +0 -0
  23. {multiclass_interface-1.2 → multiclass_interface-1.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: Multiclass_interface
3
- Version: 1.2
3
+ Version: 1.4
4
4
  Summary: Multiclass interface
5
5
  Author-email: "Mads M. Pedersen" <mmpe@dtu.dk>
6
6
  Project-URL: Homepage, https://gitlab.windenergy.dtu.dk/DYNAMIKS/multiclass_interface
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: Multiclass_interface
3
- Version: 1.2
3
+ Version: 1.4
4
4
  Summary: Multiclass interface
5
5
  Author-email: "Mads M. Pedersen" <mmpe@dtu.dk>
6
6
  Project-URL: Homepage, https://gitlab.windenergy.dtu.dk/DYNAMIKS/multiclass_interface
@@ -7,17 +7,20 @@ comm = None
7
7
  size = 1
8
8
  rank = 0
9
9
  name = ""
10
- main = True
10
+ mpi = False
11
11
 
12
12
 
13
- def activate_mpi():
14
- global comm, size, rank, name, main
13
+ def activate_mpi(collective_mpi=True, loop_until_close=True, terminate_on_close=True):
14
+ global comm, size, rank, name, mpi, LOOP_UNTIL_CLOSE, TERMINATE_ON_CLOSE, COLLECTIVE_MPI
15
15
  from mpi4py import MPI
16
16
  comm = MPI.COMM_WORLD
17
17
  size = MPI.COMM_WORLD.Get_size()
18
18
  rank = MPI.COMM_WORLD.Get_rank()
19
19
  name = MPI.Get_processor_name()
20
- main = rank == 0
20
+ mpi = True
21
+ COLLECTIVE_MPI = collective_mpi
22
+ LOOP_UNTIL_CLOSE = loop_until_close
23
+ TERMINATE_ON_CLOSE = terminate_on_close
21
24
 
22
25
 
23
26
  MPIClassInterfaceAttributes = {
@@ -33,8 +36,9 @@ MPIClassInterfaceAttributes = {
33
36
  'closed'}
34
37
 
35
38
 
36
- LOOP_UNTIL_CLOSE = True
37
- TERMINATE_ON_CLOSE = True
39
+ LOOP_UNTIL_CLOSE = True # MPI workers (rank>0) will enter the work loop and wait for commands from rank 0
40
+ TERMINATE_ON_CLOSE = True # MPI workers (rank>0) will terminate (sys.exit) when the close command is called via rank0
41
+ COLLECTIVE_MPI = True # rank0 acts as a single point of contact (scatters command+arg and gathers results)
38
42
 
39
43
 
40
44
  class MPIClassInterface():
@@ -53,10 +57,9 @@ class MPIClassInterface():
53
57
  self.object = Dummy()
54
58
  self.closed = False
55
59
 
56
- if rank == 0:
57
- self.use_rank = np.array([True] * size)
58
- self.use_rank[len(args_lst):] = False
59
- elif LOOP_UNTIL_CLOSE:
60
+ self.use_rank = np.array([True] * size)
61
+ self.use_rank[len(args_lst):] = False
62
+ if rank > 0 and COLLECTIVE_MPI and LOOP_UNTIL_CLOSE:
60
63
  self.work_loop()
61
64
 
62
65
  def __enter__(self):
@@ -133,13 +136,18 @@ class MPIClassInterface():
133
136
  def __getattribute__(self, name):
134
137
  if name in MPIClassInterfaceAttributes:
135
138
  return object.__getattribute__(self, name)
136
- elif rank > 0:
139
+ elif COLLECTIVE_MPI and rank > 0:
137
140
  self.work_loop()
138
141
  return lambda *args, **kwargs: 1
142
+ elif not self.use_rank[rank]:
143
+ raise ChildProcessError('MPI worker not used')
139
144
 
140
145
  def wrap(*args, **kwargs):
141
- inp = [self.get_input(name, i, args, kwargs) for i in range(size)]
142
- return self.run_task(inp)
146
+ if COLLECTIVE_MPI:
147
+ inp = [self.get_input(name, i, args, kwargs) for i in range(size)]
148
+ return self.run_task(inp)
149
+ else:
150
+ return self.do_task(name, args, kwargs)
143
151
 
144
152
  if hasattr(getattr(self.object, name), '__call__'):
145
153
  return wrap
@@ -162,11 +170,14 @@ class MPIClassInterface():
162
170
 
163
171
  def close(self):
164
172
  if not self.closed:
165
- if rank == 0:
166
- res = self.run_task([('close', [], {}) for _ in range(size)])
173
+ if COLLECTIVE_MPI:
174
+ if rank == 0:
175
+ res = self.run_task([('close', [], {}) for _ in range(size)])
176
+ else:
177
+ self.work_loop()
178
+ res = None
167
179
  else:
168
- self.work_loop()
169
- res = None
180
+ res = self.do_task('close', [], {})
170
181
  self.closed = True
171
182
 
172
183
 
@@ -42,11 +42,28 @@ def mpitest_mpi_ProcessClass():
42
42
  with ProcessClass(MyTest) as cls:
43
43
  myTest = cls(1)
44
44
  assert myTest.get_id() == 1
45
- print("done, test_mpi_ProcessClass")
45
+ print("done, test_mpi_ProcessClass", flush=True)
46
+
47
+
48
+ def mpitest_non_collective_mpi():
49
+ mpi_interface.COLLECTIVE_MPI = False
50
+ rank = mpi_interface.rank
51
+ import time
52
+ N = 3
53
+ with MPIClassInterface(MyTest, [(i + 10,) for i in range(N)]) as m:
54
+
55
+ try:
56
+ assert m.get_id() == rank + 10
57
+ assert rank < N # rank > N will fail with ChildProcessError
58
+ except ChildProcessError:
59
+ pass
60
+
61
+ mpi_interface.COLLECTIVE_MPI = True
46
62
 
47
63
 
48
64
  def mpitest_all():
49
65
  mpi_interface.activate_mpi()
66
+
50
67
  mpi_interface.exit_mpi_on_close = False
51
68
  rank = mpi_interface.rank
52
69
  from multiclass_interface.tests.test_multiprocessinterface import test_attribute, test_missing_attribute, test_execption, test_setattr, test_setattr_method
@@ -67,13 +84,14 @@ def mpitest_all():
67
84
  run(f)
68
85
 
69
86
  try:
70
- with MPIClassInterface(MyTest, [(1,), (2,)]) as mpici:
87
+ with MPIClassInterface(MyTest, [(1,), (2,), (3,)]) as mpici:
71
88
  for f in [test_attribute, test_missing_attribute, test_execption, test_setattr, test_setattr_method]:
72
- break
89
+
73
90
  run(f, mpici)
74
91
 
75
92
  except ChildProcessError:
76
93
  pass
77
- mpi_interface.TERMINATE_ON_CLOSE = True
94
+
95
+ run(mpitest_non_collective_mpi)
78
96
 
79
97
  print(f"Rank {rank} Done test_all")
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.2'
16
- __version_tuple__ = version_tuple = (1, 2)
15
+ __version__ = version = '1.4'
16
+ __version_tuple__ = version_tuple = (1, 4)
@@ -1,3 +1,12 @@
1
+ # Sequence diagrams
2
+ - [ThreadClass](#threadclass)
3
+ - [ProcessClass](#processclass)
4
+ - [MultiThreadClassInterface](#multithreadclassinterface)
5
+ - [MultiProcessClassInterface](#multiprocessclassinterface)
6
+ - [MPIClassInterface](#mpiclassinterface)
7
+ - [MPIClassInterface(LOOP_UNTIL_CLOSE=False)](#mpiclassinterfaceloop_until_closefalse)
8
+ - [MPIClassInterface(COLLECTIVE_MPI=False)](#mpiclassinterfacecollective_mpifalse)
9
+
1
10
  ## ThreadClass
2
11
  ```mermaid
3
12
  sequenceDiagram
@@ -42,7 +51,7 @@ This means:
42
51
  - Libraries (dll/so) will have their own memory space (important if multiple instances are launched)
43
52
  - Multiple processes allows parallel execution
44
53
 
45
- ## MultiProcessClassInterface
54
+ ## MultiThreadClassInterface
46
55
 
47
56
  ```mermaid
48
57
  sequenceDiagram
@@ -166,7 +175,7 @@ sequenceDiagram
166
175
  MPI2->>-MPI2:
167
176
  ```
168
177
 
169
- ## MPIClassInterface
178
+ ## MPIClassInterface(LOOP_UNTIL_CLOSE=False)
170
179
 
171
180
  Setting `mpi_interface.LOOP_UNTIL_CLOSE=False` results in the following workflow
172
181
 
@@ -226,3 +235,41 @@ sequenceDiagram
226
235
  ```
227
236
 
228
237
 
238
+ ## MPIClassInterface(COLLECTIVE_MPI=False)
239
+ Setting `mpi_interface.COLLECTIVE_MPI=False` results in the following workflow
240
+
241
+ ```mermaid
242
+ sequenceDiagram
243
+
244
+ participant MPI0 as MPI,rank0<br>MPIClassInterface
245
+
246
+
247
+ MPI0->>+MPI0: cls=A, [(args0),(args1)]
248
+
249
+
250
+ create participant A0
251
+ MPI0->>+A0: args0
252
+
253
+ participant MPI1 as MPI,rank1<br>MPIClassInterface
254
+ MPI1->>+MPI1: cls=A, [(args0),(args1)]
255
+ create participant A1
256
+ MPI1->>A1: args1
257
+ participant MPI2 as MPI,rank2<br>MPIClassInterface
258
+ MPI2->>MPI2: cls=A, [(args0),(args1)]
259
+
260
+ MPI0->>+MPI0:~a.f([args0,args1])
261
+ MPI1->>+MPI1:~a.f([args0,args1])
262
+ MPI2->>+MPI2:~a.f([args0,args1])
263
+
264
+
265
+ MPI0->>+A0: f(args0)
266
+ MPI1->>+A1: f(args1)
267
+ MPI2->>-MPI2: ChildProcessError
268
+ A0->>-MPI0: res0
269
+ A1->>-MPI1: res1
270
+
271
+ MPI0->>-MPI0: res0
272
+ MPI1->>-MPI1: res1
273
+
274
+ ```
275
+