1515from pix_framework .io .bpmn import get_activities_names_from_bpmn
1616
1717from simod .batching .discovery import discover_batching_rules
18- from simod .data_attributes .discovery import discover_data_attributes
18+ from simod .branch_rules .discovery import discover_branch_rules , map_branch_rules_to_flows
1919from simod .cli_formatter import print_section , print_subsection
2020from simod .control_flow .discovery import discover_process_model , add_bpmn_diagram_to_model
2121from simod .control_flow .optimizer import ControlFlowOptimizer
2222from simod .control_flow .settings import HyperoptIterationParams as ControlFlowHyperoptIterationParams
23+ from simod .data_attributes .discovery import discover_data_attributes
2324from simod .event_log .event_log import EventLog
2425from simod .extraneous_delays .optimizer import ExtraneousDelaysOptimizer
2526from simod .extraneous_delays .types import ExtraneousDelay
2829from simod .resource_model .optimizer import ResourceModelOptimizer
2930from simod .resource_model .repair import repair_with_missing_activities
3031from simod .resource_model .settings import HyperoptIterationParams as ResourceModelHyperoptIterationParams
32+ from simod .runtime_meter import RuntimeMeter
3133from simod .settings .simod_settings import SimodSettings
3234from simod .simulation .parameters .BPS_model import BPSModel
3335from simod .simulation .prosimos import simulate_and_evaluate
3436from simod .utilities import get_process_model_path , get_simulation_parameters_path
35- from simod .branch_rules .discovery import discover_branch_rules , map_branch_rules_to_flows
3637
3738
3839class Simod :
@@ -87,6 +88,10 @@ def run(self):
8788 Optimizes the BPS model with the given event log and settings.
8889 """
8990
91+ # Runtime object
92+ runtimes = RuntimeMeter ()
93+ runtimes .start (RuntimeMeter .TOTAL )
94+
9095 # Model activities might be different from event log activities if the model has been provided,
9196 # because we split the event log into train, test, and validation partitions.
9297 # We use model_activities to repair resource_model later after its discovery from a reduced event log.
@@ -96,6 +101,7 @@ def run(self):
96101
97102 # --- Discover Default Case Arrival and Resource Allocation models --- #
98103 print_section ("Discovering initial BPS Model" )
104+ runtimes .start (RuntimeMeter .INITIAL_MODEL )
99105 self ._best_bps_model .case_arrival_model = discover_case_arrival_model (
100106 self ._event_log .train_validation_partition , # No optimization process here, use train + validation
101107 self ._event_log .log_ids ,
@@ -115,43 +121,53 @@ def run(self):
115121 event_log = self ._event_log .train_validation_partition ,
116122 log_ids = self ._event_log .log_ids ,
117123 )
124+ runtimes .stop (RuntimeMeter .INITIAL_MODEL )
118125
119126 # --- Control-Flow Optimization --- #
120127 print_section ("Optimizing control-flow parameters" )
128+ runtimes .start (RuntimeMeter .CONTROL_FLOW_MODEL )
121129 best_control_flow_params = self ._optimize_control_flow ()
122130 self ._best_bps_model .process_model = self ._control_flow_optimizer .best_bps_model .process_model
123131 self ._best_bps_model .gateway_probabilities = self ._control_flow_optimizer .best_bps_model .gateway_probabilities
124132 self ._best_bps_model .branch_rules = self ._control_flow_optimizer .best_bps_model .branch_rules
133+ runtimes .stop (RuntimeMeter .CONTROL_FLOW_MODEL )
125134
126135 # --- Data Attributes --- #
127136 if (self ._settings .common .discover_data_attributes or
128137 self ._settings .resource_model .discover_prioritization_rules ):
129138 print_section ("Discovering data attributes" )
139+ runtimes .start (RuntimeMeter .DATA_ATTRIBUTES_MODEL )
130140 global_attributes , case_attributes , event_attributes = discover_data_attributes (
131141 self ._event_log .train_validation_partition ,
132142 self ._event_log .log_ids ,
133143 )
134144 self ._best_bps_model .global_attributes = global_attributes
135145 self ._best_bps_model .case_attributes = case_attributes
136146 self ._best_bps_model .event_attributes = event_attributes
147+ runtimes .stop (RuntimeMeter .DATA_ATTRIBUTES_MODEL )
137148
138149 # --- Resource Model Discovery --- #
139150 print_section ("Optimizing resource model parameters" )
151+ runtimes .start (RuntimeMeter .RESOURCE_MODEL )
140152 best_resource_model_params = self ._optimize_resource_model (model_activities )
141153 self ._best_bps_model .resource_model = self ._resource_model_optimizer .best_bps_model .resource_model
142154 self ._best_bps_model .calendar_granularity = self ._resource_model_optimizer .best_bps_model .calendar_granularity
143155 self ._best_bps_model .prioritization_rules = self ._resource_model_optimizer .best_bps_model .prioritization_rules
144156 self ._best_bps_model .batching_rules = self ._resource_model_optimizer .best_bps_model .batching_rules
157+ runtimes .stop (RuntimeMeter .RESOURCE_MODEL )
145158
146159 # --- Extraneous Delays Discovery --- #
147160 if self ._settings .extraneous_activity_delays is not None :
148161 print_section ("Discovering extraneous delays" )
162+ runtimes .start (RuntimeMeter .EXTRANEOUS_DELAYS )
149163 timers = self ._optimize_extraneous_activity_delays ()
150164 self ._best_bps_model .extraneous_delays = timers
151165 add_timers_to_bpmn_model (self ._best_bps_model .process_model , timers ) # Update BPMN model on disk
166+ runtimes .stop (RuntimeMeter .EXTRANEOUS_DELAYS )
152167
153168 # --- Discover final BPS model --- #
154169 print_section ("Discovering final BPS model" )
170+ runtimes .start (RuntimeMeter .FINAL_MODEL )
155171 self .final_bps_model = BPSModel ( # Bypass all models already discovered with train+validation
156172 process_model = get_process_model_path (self ._best_result_dir , self ._event_log .process_name ),
157173 case_arrival_model = self ._best_bps_model .case_arrival_model ,
@@ -187,19 +203,17 @@ def run(self):
187203 bpmn_graph = best_bpmn_graph ,
188204 discovery_method = best_control_flow_params .gateway_probabilities_method ,
189205 )
190-
191206 # Branch Rules
192207 if self ._settings .control_flow .discover_branch_rules :
193208 print_section ("Discovering branch conditions" )
194209 self .final_bps_model .branch_rules = discover_branch_rules (
195- best_bpmn_graph ,
196- self ._event_log .train_validation_partition ,
197- self ._event_log .log_ids ,
198- f_score = best_control_flow_params .f_score
199- )
210+ best_bpmn_graph ,
211+ self ._event_log .train_validation_partition ,
212+ self ._event_log .log_ids ,
213+ f_score = best_control_flow_params .f_score
214+ )
200215 self .final_bps_model .gateway_probabilities = \
201216 map_branch_rules_to_flows (self .final_bps_model .gateway_probabilities , self .final_bps_model .branch_rules )
202-
203217 # Resource model
204218 print_subsection ("Discovering best resource model" )
205219 self .final_bps_model .resource_model = discover_resource_model (
@@ -235,6 +249,9 @@ def run(self):
235249 self .final_bps_model .extraneous_delays = self ._best_bps_model .extraneous_delays
236250 add_timers_to_bpmn_model (self .final_bps_model .process_model , self ._best_bps_model .extraneous_delays )
237251 self .final_bps_model .replace_activity_names_with_ids ()
252+ runtimes .stop (RuntimeMeter .FINAL_MODEL )
253+ runtimes .stop (RuntimeMeter .TOTAL )
254+
238255 # Write JSON parameters to file
239256 json_parameters_path = get_simulation_parameters_path (self ._best_result_dir , self ._event_log .process_name )
240257 with json_parameters_path .open ("w" ) as f :
@@ -243,14 +260,18 @@ def run(self):
243260 # --- Evaluate final BPS model --- #
244261 if self ._settings .common .perform_final_evaluation :
245262 print_subsection ("Evaluate" )
263+ runtimes .start (RuntimeMeter .EVALUATION )
246264 simulation_dir = self ._best_result_dir / "evaluation"
247265 simulation_dir .mkdir (parents = True , exist_ok = True )
248266 self ._evaluate_model (self .final_bps_model .process_model , json_parameters_path , simulation_dir )
267+ runtimes .stop (RuntimeMeter .EVALUATION )
249268
250269 # --- Export settings and clean temporal files --- #
270+ print_section (f"Exporting canonical model, runtimes, settings and cleaning up intermediate files" )
251271 canonical_model_path = self ._best_result_dir / "canonical_model.json"
252- print_section (f"Exporting canonical model to { canonical_model_path } " )
253272 _export_canonical_model (canonical_model_path , best_control_flow_params , best_resource_model_params )
273+ runtimes_model_path = self ._best_result_dir / "runtimes.json"
274+ _export_runtimes (runtimes_model_path , runtimes )
254275 if self ._settings .common .clean_intermediate_files :
255276 self ._clean_up ()
256277 self ._settings .to_yaml (self ._best_result_dir )
@@ -342,14 +363,17 @@ def _export_canonical_model(
342363 control_flow_settings : ControlFlowHyperoptIterationParams ,
343364 calendar_settings : ResourceModelHyperoptIterationParams ,
344365):
345- structure = control_flow_settings .to_dict ()
346-
347- calendars = calendar_settings .to_dict ()
348-
349366 canon = {
350- "control_flow" : structure ,
351- "calendars" : calendars ,
367+ "control_flow" : control_flow_settings . to_dict () ,
368+ "calendars" : calendar_settings . to_dict () ,
352369 }
353-
354370 with open (file_path , "w" ) as f :
355371 json .dump (canon , f )
372+
373+
374+ def _export_runtimes (
375+ file_path : Path ,
376+ runtimes : RuntimeMeter
377+ ):
378+ with open (file_path , "w" ) as f :
379+ json .dump (runtimes .runtimes , f )
0 commit comments