-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
194 lines (158 loc) · 7.33 KB
/
main.py
File metadata and controls
194 lines (158 loc) · 7.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import datetime
import time
from dataclasses import dataclass, field
from typing import Dict, List
import filters
from classes import Engin, Intervention, InterventionSimulee, Secteur
from data import get_data
from statistiques import combien_de_fois_on_envoie_un_vhl_diff, print_statistiques
from fonction_calcul_trajet import reset_stats as reset_trajet_stats
# -----------------------------------------------------------------------------
# SimulationResult — encapsule tout l'état d'une simulation
# -----------------------------------------------------------------------------
@dataclass
class SimulationResult:
"""Résultat complet d'une simulation. Remplace les anciennes variables globales."""
interventions_simulees: List[InterventionSimulee] = field(default_factory=list)
simulation_processing_time: float = 0.0
cs_match_count: int = 0
cs_total_count: int = 0
cs_mismatch_details: List[Dict] = field(default_factory=list)
def clear(self):
"""Réinitialise tous les résultats."""
self.interventions_simulees.clear()
self.simulation_processing_time = 0.0
self.cs_match_count = 0
self.cs_total_count = 0
self.cs_mismatch_details.clear()
# Instance globale unique — conserve la rétro-compatibilité avec le code
# existant qui accède à main_module.interventions_simulees etc.
_last_result = SimulationResult()
# Propriétés de rétro-compatibilité au niveau du module
interventions_simulees = _last_result.interventions_simulees
simulation_processing_time: float = 0.0
cs_match_count: int = 0
cs_total_count: int = 0
cs_mismatch_details: List[Dict] = []
def _sync_globals_from_result(result: SimulationResult):
"""Synchronise les anciennes variables globales depuis un SimulationResult."""
global interventions_simulees, simulation_processing_time
global cs_match_count, cs_total_count, cs_mismatch_details, _last_result
_last_result = result
interventions_simulees = result.interventions_simulees
simulation_processing_time = result.simulation_processing_time
cs_match_count = result.cs_match_count
cs_total_count = result.cs_total_count
cs_mismatch_details = result.cs_mismatch_details
# -----------------------------------------------------------------------------
# MAIN
# -----------------------------------------------------------------------------
# Configuration
LIMITE_INTERVENTIONS = None # Limite pour tests rapides (None = toutes)
def main(progress_callback=None, interventions=None, indisponibilites=None, engins=None, skip_cstc_priority=False):
"""
Lance la simulation et retourne (interventions, engins, result).
Le SimulationResult est aussi synchronisé vers les variables globales du module
pour la rétro-compatibilité (main_module.interventions_simulees, etc.).
"""
result = SimulationResult()
# Si interventions/indisponibilités non fournies, les charger
if interventions is None or indisponibilites is None:
interventions_tmp, secteurs, engins_tmp, indisponibilites_tmp = get_data()
if interventions is None:
interventions = interventions_tmp
if indisponibilites is None:
indisponibilites = indisponibilites_tmp
if engins is None:
engins = engins_tmp
else:
# Charger uniquement secteurs et engins si non fournis
from data import get_secteurs, get_engins, get_raw_interventions
from classes import Intervention, Secteur, Engin
# Assigner les attributs de classe nécessaires
Intervention.df = get_raw_interventions()
Secteur.df = None # Sera assigné par get_secteurs()
Engin.df = None # Sera assigné par get_engins()
secteurs = get_secteurs()
if engins is None:
engins = get_engins()
print(f"Nombre d'engins: {len(engins)}")
# --- Reset de l'état accumulé des simulations précédentes ---
for _, engin in engins.items():
engin.reset_simulation_state()
filters.reset_secteurs_proches()
reset_trajet_stats()
for _, engin in engins.items():
secteurs[engin.cs].add_engin(engin)
for indisponibilite in indisponibilites:
secteurs[indisponibilite.cs].ajouter_indisponibilite(indisponibilite)
for _, engin in engins.items():
engin.indisponibilites.set_up()
i = 0
print_every = 1000
start_time = time.time()
interventions_a_traiter = interventions[:LIMITE_INTERVENTIONS] if LIMITE_INTERVENTIONS else interventions
total_interventions = len(interventions_a_traiter)
for intervention in interventions_a_traiter:
if intervention.cstc == "NR":
print("Intervention avec cstc NR")
continue
engin = filters.attribuer(intervention, secteurs, skip_cstc_priority=skip_cstc_priority)
if engin is not None:
temps_aller, temps_retour = engin.attribuer_a(intervention)
result.interventions_simulees.append(
InterventionSimulee.from_Intervention(
intervention, engin, temps_aller, temps_retour
)
)
# Comparer le CS assigné avec le CS réel
cs_reel = getattr(intervention, "cs_vhl", None)
if cs_reel is not None:
result.cs_total_count += 1
if engin.cs == cs_reel:
result.cs_match_count += 1
else:
# Enregistrer les premiers 100 cas d'erreur pour diagnostic
if len(result.cs_mismatch_details) < 100:
result.cs_mismatch_details.append({
'intervention_id': getattr(intervention, 'id', i),
'date': intervention.date,
'cs_reel': cs_reel,
'cs_attribue': engin.cs,
'type_vhl_envoye': engin.type_engin,
'cstc': intervention.cstc,
'fem_mma': intervention.fem_mma,
'x': intervention.x,
'y': intervention.y,
})
i += 1
if i % print_every == 0:
print(datetime.datetime.now(), i)
# Callback pour la progression
if progress_callback and i % 100 == 0: # Mise à jour tous les 100 interventions
progress_callback(i, total_interventions)
result.simulation_processing_time = time.time() - start_time
# Synchroniser les variables globales pour la rétro-compatibilité
_sync_globals_from_result(result)
print("Fini.", i)
print(f"Temps de traitement: {result.simulation_processing_time:.1f}s")
return interventions, engins
if __name__ == "__main__":
# ---- Toggle profiling by setting USE_PROFILE = True ----
USE_PROFILE = True
if USE_PROFILE:
import cProfile
import io
import pstats
pr = cProfile.Profile()
pr.enable()
interventions_reelles, engins = main()
pr.disable()
print_statistiques(interventions_simulees, engins)
combien_de_fois_on_envoie_un_vhl_diff(interventions_simulees)
s = io.StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats("cumulative")
ps.print_stats(40) # top 40 hotspots
print(s.getvalue())
else:
main()