Bastien Sevajol vor 6 Jahren
Ursprung
Commit
a40912f7ba
3 geänderte Dateien mit 120 neuen und 31 gelöschten Zeilen
  1. 35 6
      synergine2/cycle.py
  2. 3 3
      synergine2/simulation.py
  3. 82 22
      tests/test_simulation.py

+ 35 - 6
synergine2/cycle.py Datei anzeigen

@@ -254,8 +254,11 @@ class CycleManager(BaseObject):
254 254
         self.logger.info('Subjects computing: {} subjects to compute'.format(str(len(subjects))))
255 255
 
256 256
         for subject in subjects:
257
-            mechanisms = subject.mechanisms.values()
257
+            subject_behaviours = self.get_active_subject_behaviors(subject)
258
+            if not subject_behaviours:
259
+                break
258 260
 
261
+            mechanisms = self.get_mechanisms_from_behaviors(subject_behaviours, subject)
259 262
             if mechanisms:
260 263
                 self.logger.info('Subject {}: {} mechanisms'.format(
261 264
                     str(subject.id),
@@ -291,16 +294,14 @@ class CycleManager(BaseObject):
291 294
                         str(mechanisms_data),
292 295
                     ))
293 296
 
294
-            subject_behaviours = subject.behaviours
295
-            if not subject_behaviours:
296
-                break
297
-
298 297
             self.logger.info('Subject {}: have {} behaviours'.format(
299 298
                 str(subject.id),
300 299
                 str(len(subject_behaviours)),
301 300
             ))
302 301
 
303
-            for behaviour_key, behaviour in list(subject_behaviours.items()):
302
+            for behaviour in subject_behaviours:
303
+                behaviour_key = type(behaviour)
304
+
304 305
                 self.logger.info('Subject {}: run {} behaviour'.format(
305 306
                     str(subject.id),
306 307
                     str(type(behaviour)),
@@ -411,3 +412,31 @@ class CycleManager(BaseObject):
411 412
 
412 413
     def stop(self) -> None:
413 414
         self.process_manager.terminate()
415
+
416
+    def get_active_subject_behaviors(
417
+        self,
418
+        subject: Subject,
419
+    ) -> typing.List[SubjectBehaviour]:
420
+        behaviours = []
421
+        for behaviour in subject.behaviours.values():
422
+            if behaviour.is_skip(self.current_cycle):
423
+                self.logger.debug('Simulation: behaviour {} skip'.format(
424
+                    str(type(behaviour)),
425
+                ))
426
+            else:
427
+                behaviours.append(behaviour)
428
+        return behaviours
429
+
430
+    def get_mechanisms_from_behaviors(
431
+        self,
432
+        subject_behaviours: typing.List[SubjectBehaviour],
433
+        subject: Subject,
434
+    ) -> typing.List[SubjectMechanism]:
435
+        # TODO BS 20180109: Not very optimized ... could be enhanced
436
+        mechanisms = set()
437
+        for subject_mechanism in subject.mechanisms.values():
438
+            for subject_behaviour in subject_behaviours:
439
+                for behaviour_mechanism_class in subject_behaviour.use:
440
+                    if isinstance(subject_mechanism, behaviour_mechanism_class):
441
+                        mechanisms.add(subject_mechanism)
442
+        return list(mechanisms)

+ 3 - 3
synergine2/simulation.py Datei anzeigen

@@ -158,7 +158,7 @@ class Subjects(list):
158 158
         super().remove(value)
159 159
         # Remove from start_collections
160 160
         for collection_name in value.collections:
161
-            self.simulation.collections[collection_name].remove(value)
161
+            self.simulation.collections[collection_name].remove(value.id)
162 162
         # Add to removed listing
163 163
         if self.track_changes:
164 164
             self.removes.append(value)
@@ -309,11 +309,11 @@ class Behaviour(BaseObject):
309 309
         """
310 310
         cycle_frequency = self.cycle_frequency
311 311
         if cycle_frequency is not None:
312
-            return not bool(cycle_number % cycle_frequency)
312
+            return bool(cycle_number % cycle_frequency)
313 313
 
314 314
         seconds_frequency = self.seconds_frequency
315 315
         if seconds_frequency is not None:
316
-            return time.time() - self.last_execution_time <= seconds_frequency
316
+            return float(time.time() - self.last_execution_time) <= seconds_frequency
317 317
 
318 318
         return False
319 319
 

+ 82 - 22
tests/test_simulation.py Datei anzeigen

@@ -153,19 +153,15 @@ class TestBehaviours(BaseTest):
153 153
             process_manager=do_nothing_process_manager,
154 154
         )
155 155
 
156
-        # Cycle 0: behaviour NOT executed
156
+        # Cycle 0: behaviour IS executed
157 157
         cycle_manager.current_cycle = 0
158 158
         results_by_subjects = cycle_manager._job_subjects(worker_id=0, process_count=1)
159 159
         assert results_by_subjects
160
-        assert id(my_subject) in results_by_subjects
161
-        assert not results_by_subjects[id(my_subject)]
162 160
 
163
-        # Cycle 1: behaviour executed
161
+        # Cycle 1: behaviour IS NOT executed
164 162
         cycle_manager.current_cycle = 1
165 163
         results_by_subjects = cycle_manager._job_subjects(worker_id=0, process_count=1)
166
-        assert results_by_subjects
167
-        assert id(my_subject) in results_by_subjects
168
-        assert results_by_subjects[id(my_subject)]
164
+        assert not results_by_subjects
169 165
 
170 166
     def test_subject_behaviour_seconds_frequency(
171 167
         self,
@@ -199,23 +195,17 @@ class TestBehaviours(BaseTest):
199 195
         # Less second after: NOT executed
200 196
         with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 0, 500000)):
201 197
             data = cycle_manager._job_subjects(worker_id=0, process_count=1)
202
-            assert data
203
-            assert id(my_subject) in data
204
-            assert not data[id(my_subject)]
198
+            assert not data
205 199
 
206 200
         # Less second after: NOT executed
207 201
         with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 0, 700000)):
208 202
             data = cycle_manager._job_subjects(worker_id=0, process_count=1)
209
-            assert data
210
-            assert id(my_subject) in data
211
-            assert not data[id(my_subject)]
203
+            assert not data
212 204
 
213
-        # Less second after: NOT executed
205
+        # Less second after: IS executed
214 206
         with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 1, 500000)):
215 207
             data = cycle_manager._job_subjects(worker_id=0, process_count=1)
216 208
             assert data
217
-            assert id(my_subject) in data
218
-            assert data[id(my_subject)]
219 209
 
220 210
     def test_simulation_behaviour_cycle_frequency(
221 211
         self,
@@ -237,15 +227,15 @@ class TestBehaviours(BaseTest):
237 227
             process_manager=do_nothing_process_manager,
238 228
         )
239 229
 
240
-        # Cycle 0: behaviour NOT executed
230
+        # Cycle 0: behaviour IS executed
241 231
         cycle_manager.current_cycle = 0
242 232
         data = cycle_manager._job_simulation(worker_id=0, process_count=1)
243
-        assert not data
233
+        assert data
244 234
 
245
-        # Cycle 1: behaviour executed
235
+        # Cycle 1: behaviour IS NOT executed
246 236
         cycle_manager.current_cycle = 1
247 237
         data = cycle_manager._job_simulation(worker_id=0, process_count=1)
248
-        assert data
238
+        assert not data
249 239
 
250 240
     def test_simulation_behaviour_seconds_frequency(
251 241
         self,
@@ -468,12 +458,82 @@ class TestMechanisms(BaseTest):
468 458
         cycle_manager._job_simulation(worker_id=0, process_count=1)
469 459
         assert called == 0
470 460
 
471
-    def test_mechanism_not_called_if_subject_behavior_timebase_not_active_yet(self):
461
+    def test_mechanism_not_called_if_subject_behavior_cycled_not_active_yet(
462
+        self,
463
+        do_nothing_process_manager: ProcessManager,
464
+    ):
465
+        shared.reset()
466
+        called = 0
467
+        global called
468
+
469
+        class MySubjectMechanism(SubjectMechanism):
470
+            def run(self):
471
+                global called
472
+                called += 1
473
+                return {'foo': 42}
474
+
475
+        class MySubjectBehaviour1(SubjectBehaviour):
476
+            use = [MySubjectMechanism]
477
+
478
+            @property
479
+            def cycle_frequency(self):
480
+                return 2
481
+
482
+            def run(self, data):
483
+                return {'bar': data[MySubjectMechanism]['foo'] + 100}
484
+
485
+        class MySubject(Subject):
486
+            behaviours_classes = [MySubjectBehaviour1]
487
+
488
+        simulation = Simulation(config)
489
+        my_subject = MySubject(config, simulation)
490
+        subjects = Subjects(simulation=simulation)
491
+        subjects.append(my_subject)
492
+        simulation.subjects = subjects
493
+
494
+        cycle_manager = CycleManager(
495
+            config,
496
+            logger,
497
+            simulation=simulation,
498
+            process_manager=do_nothing_process_manager,
499
+        )
500
+
501
+        cycle_manager.current_cycle = 0
502
+        cycle_manager._job_subjects(worker_id=0, process_count=1)
503
+        assert called == 1
504
+
505
+        cycle_manager.current_cycle = 1
506
+        cycle_manager._job_subjects(worker_id=0, process_count=1)
507
+        assert called == 1
508
+
509
+        cycle_manager.current_cycle = 2
510
+        cycle_manager._job_subjects(worker_id=0, process_count=1)
511
+        assert called == 2
512
+
513
+        cycle_manager.current_cycle = 3
514
+        cycle_manager._job_subjects(worker_id=0, process_count=1)
515
+        assert called == 2
516
+
517
+    def test_mechanism_not_called_if_simulation_behavior_cycled_not_active_yet(
518
+        self,
519
+        do_nothing_process_manager: ProcessManager,
520
+    ):
472 521
         shared.reset()
473 522
 
474 523
         pass
475 524
 
476
-    def test_mechanism_not_called_if_simulation_behavior_timebase_not_active_yet(self):
525
+    def test_mechanism_not_called_if_subject_behavior_timebase_not_active_yet(
526
+        self,
527
+        do_nothing_process_manager: ProcessManager,
528
+    ):
529
+        shared.reset()
530
+
531
+        pass
532
+
533
+    def test_mechanism_not_called_if_simulation_behavior_timebase_not_active_yet(
534
+        self,
535
+        do_nothing_process_manager: ProcessManager,
536
+    ):
477 537
         shared.reset()
478 538
 
479 539
         pass