Browse Source

add simulation behaviour tests

Bastien Sevajol 7 years ago
parent
commit
cc386e280c
2 changed files with 176 additions and 5 deletions
  1. 30 2
      synergine2/cycle.py
  2. 146 3
      tests/test_simulation.py

+ 30 - 2
synergine2/cycle.py View File

@@ -13,7 +13,9 @@ from synergine2.share import shared
13 13
 from synergine2.simulation import Subject
14 14
 from synergine2.simulation import Simulation
15 15
 from synergine2.simulation import SubjectBehaviour
16
+from synergine2.simulation import SimulationBehaviour
16 17
 from synergine2.simulation import SubjectMechanism
18
+from synergine2.simulation import SimulationMechanism
17 19
 from synergine2.simulation import Event
18 20
 from synergine2.utils import time_it
19 21
 
@@ -84,7 +86,8 @@ class CycleManager(BaseObject):
84 86
     def _job_simulation(self, worker_id: int, process_count: int) -> typing.Dict[int, typing.Dict[str, typing.Any]]:
85 87
         self.logger.info('Simulation computing (worker {})'.format(worker_id))
86 88
 
87
-        mechanisms = self.simulation.mechanisms.values()
89
+        behaviours = self.get_simulation_active_behaviours()
90
+        mechanisms = self.get_mechanisms_from_behaviours(behaviours)
88 91
         mechanisms_data = {}
89 92
         behaviours_data = {}
90 93
 
@@ -420,7 +423,8 @@ class CycleManager(BaseObject):
420 423
         behaviours = []
421 424
         for behaviour in subject.behaviours.values():
422 425
             if behaviour.is_skip(self.current_cycle):
423
-                self.logger.debug('Simulation: behaviour {} skip'.format(
426
+                self.logger.debug('Subject {}: behaviour {} skip'.format(
427
+                    str(subject.id),
424 428
                     str(type(behaviour)),
425 429
                 ))
426 430
             else:
@@ -440,3 +444,27 @@ class CycleManager(BaseObject):
440 444
                     if isinstance(subject_mechanism, behaviour_mechanism_class):
441 445
                         mechanisms.add(subject_mechanism)
442 446
         return list(mechanisms)
447
+
448
+    def get_simulation_active_behaviours(self) -> typing.List[SimulationBehaviour]:
449
+        behaviours = []
450
+        for behaviour in self.simulation.behaviours.values():
451
+            if behaviour.is_skip(self.current_cycle):
452
+                self.logger.debug('Simulation: behaviour {} skip'.format(
453
+                    str(type(behaviour)),
454
+                ))
455
+            else:
456
+                behaviours.append(behaviour)
457
+        return behaviours
458
+
459
+    def get_mechanisms_from_behaviours(
460
+        self,
461
+        behaviours: typing.List[SimulationBehaviour],
462
+    ) -> typing.List[SimulationMechanism]:
463
+        # TODO BS 20180109: Not very optimized ... could be enhanced
464
+        mechanisms = set()
465
+        for simulation_mechanism in self.simulation.mechanisms.values():
466
+            for simulation_behaviour in behaviours:
467
+                for simulation_mechanism_class in simulation_behaviour.use:
468
+                    if isinstance(simulation_mechanism, simulation_mechanism_class):
469
+                        mechanisms.add(simulation_mechanism)
470
+        return list(mechanisms)

+ 146 - 3
tests/test_simulation.py View File

@@ -519,24 +519,167 @@ class TestMechanisms(BaseTest):
519 519
         do_nothing_process_manager: ProcessManager,
520 520
     ):
521 521
         shared.reset()
522
+        global called
523
+        called = 0
524
+
525
+        class MySimulationMechanism(SimulationMechanism):
526
+            def run(self, process_number: int = None, process_count: int = None):
527
+                global called
528
+                called += 1
529
+                return {'foo': 42}
522 530
 
523
-        pass
531
+        class MySimulationBehaviour1(SimulationBehaviour):
532
+            use = [MySimulationMechanism]
533
+
534
+            @property
535
+            def cycle_frequency(self):
536
+                return 2
537
+
538
+            def run(self, data):
539
+                return {'bar': data[MySimulationMechanism]['foo'] + 100}
540
+
541
+        class MySimulation(Simulation):
542
+            behaviours_classes = [MySimulationBehaviour1]
543
+
544
+        simulation = MySimulation(config)
545
+        subjects = Subjects(simulation=simulation)
546
+        simulation.subjects = subjects
547
+
548
+        cycle_manager = CycleManager(
549
+            config,
550
+            logger,
551
+            simulation=simulation,
552
+            process_manager=do_nothing_process_manager,
553
+        )
554
+
555
+        cycle_manager.current_cycle = 0
556
+        cycle_manager._job_simulation(worker_id=0, process_count=1)
557
+        assert called == 1
558
+
559
+        cycle_manager.current_cycle = 1
560
+        cycle_manager._job_simulation(worker_id=0, process_count=1)
561
+        assert called == 1
562
+
563
+        cycle_manager.current_cycle = 2
564
+        cycle_manager._job_simulation(worker_id=0, process_count=1)
565
+        assert called == 2
566
+
567
+        cycle_manager.current_cycle = 3
568
+        cycle_manager._job_simulation(worker_id=0, process_count=1)
569
+        assert called == 2
524 570
 
525 571
     def test_mechanism_not_called_if_subject_behavior_timebase_not_active_yet(
526 572
         self,
527 573
         do_nothing_process_manager: ProcessManager,
528 574
     ):
529 575
         shared.reset()
576
+        global called
577
+        called = 0
578
+
579
+        class MySubjectMechanism(SubjectMechanism):
580
+            def run(self):
581
+                global called
582
+                called += 1
583
+                return {'foo': 42}
530 584
 
531
-        pass
585
+        class MySubjectBehaviour1(SubjectBehaviour):
586
+            use = [MySubjectMechanism]
587
+
588
+            @property
589
+            def seconds_frequency(self):
590
+                return 1.0
591
+
592
+            def run(self, data):
593
+                self.last_execution_time = time.time()
594
+                return {'bar': data[MySubjectMechanism]['foo'] + 100}
595
+
596
+        class MySubject(Subject):
597
+            behaviours_classes = [MySubjectBehaviour1]
598
+
599
+        simulation = Simulation(config)
600
+        my_subject = MySubject(config, simulation)
601
+        subjects = Subjects(simulation=simulation)
602
+        subjects.append(my_subject)
603
+        simulation.subjects = subjects
604
+
605
+        cycle_manager = CycleManager(
606
+            config,
607
+            logger,
608
+            simulation=simulation,
609
+            process_manager=do_nothing_process_manager,
610
+        )
611
+
612
+        with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 0)):
613
+            cycle_manager._job_subjects(worker_id=0, process_count=1)
614
+            assert called == 1
615
+
616
+        with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 0, 500000)):
617
+            cycle_manager._job_subjects(worker_id=0, process_count=1)
618
+            assert called == 1
619
+
620
+        with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 0, 700000)):
621
+            cycle_manager._job_subjects(worker_id=0, process_count=1)
622
+            assert called == 1
623
+
624
+        with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 1, 500000)):
625
+            cycle_manager._job_subjects(worker_id=0, process_count=1)
626
+            assert called == 2
532 627
 
533 628
     def test_mechanism_not_called_if_simulation_behavior_timebase_not_active_yet(
534 629
         self,
535 630
         do_nothing_process_manager: ProcessManager,
536 631
     ):
632
+
537 633
         shared.reset()
634
+        global called
635
+        called = 0
636
+
637
+        class MySimulationMechanism(SimulationMechanism):
638
+            def run(self, process_number: int = None, process_count: int = None):
639
+                global called
640
+                called += 1
641
+                return {'foo': 42}
642
+
643
+        class MySimulationBehaviour1(SimulationBehaviour):
644
+            use = [MySimulationMechanism]
645
+
646
+            @property
647
+            def seconds_frequency(self):
648
+                return 1.0
649
+
650
+            def run(self, data):
651
+                self.last_execution_time = time.time()
652
+                return {'bar': data[MySimulationMechanism]['foo'] + 100}
653
+
654
+        class MySimulation(Simulation):
655
+            behaviours_classes = [MySimulationBehaviour1]
656
+
657
+        simulation = MySimulation(config)
658
+        subjects = Subjects(simulation=simulation)
659
+        simulation.subjects = subjects
538 660
 
539
-        pass
661
+        cycle_manager = CycleManager(
662
+            config,
663
+            logger,
664
+            simulation=simulation,
665
+            process_manager=do_nothing_process_manager,
666
+        )
667
+
668
+        with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 0, 0)):
669
+            cycle_manager._job_simulation(worker_id=0, process_count=1)
670
+            assert called == 1
671
+
672
+        with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 0, 500000)):
673
+            cycle_manager._job_simulation(worker_id=0, process_count=1)
674
+            assert called == 1
675
+
676
+        with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 0, 700000)):
677
+            cycle_manager._job_simulation(worker_id=0, process_count=1)
678
+            assert called == 1
679
+
680
+        with freeze_time(datetime.datetime(2000, 12, 1, 0, 0, 1, 500000)):
681
+            cycle_manager._job_simulation(worker_id=0, process_count=1)
682
+            assert called == 2
540 683
 
541 684
 
542 685
 # TODO: Test Simulation mechanism parralelisation