Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f20f41d
#52 - Implement one iteration of the experiment run
ira-halenok Mar 3, 2023
40b6f85
#52 - Add conditions for adding events to the model, remove obsolete …
ira-halenok Mar 4, 2023
e02d7eb
#52 - Return back mistakenly removed code
ira-halenok Mar 5, 2023
d75fcf8
#52 - Show the plot of results, run experiment for the same number of…
ira-halenok Mar 5, 2023
2881f44
#52 - Save final results in a file
ira-halenok Mar 6, 2023
1b9d815
#52 - Provide the default parameter for number_generated_events
ira-halenok Mar 6, 2023
364d006
#52 - Push missed file, load files for a test once
ira-halenok Mar 6, 2023
059d935
#52 - Prettify the script for experiments
ira-halenok Mar 6, 2023
1ab6825
#52 - Adjust the visualised plot
ira-halenok Mar 6, 2023
52f9f18
#52 - Preserve folder structure, update process files setup
ira-halenok Mar 6, 2023
4e09a37
#53 - Run experiments with adding diifferent number of priority levels
ira-halenok Mar 6, 2023
1b1e287
#52 - Refactor event runner for performance testing, clarify the para…
ira-halenok Mar 7, 2023
8acb523
#52 - Add bpmn and sim scenario for BPI 2012, events
ira-halenok Mar 7, 2023
1ed4878
#52 - Save fig as a file instead of showing it
ira-halenok Mar 7, 2023
2a7a9a8
#52 - Add new BPI input for events, allow running multiple examples o…
ira-halenok Mar 8, 2023
6d87b25
#53 - Extract general method to run the experiment, add bpi setup for…
ira-halenok Mar 8, 2023
ff7a407
#52 - Add option for normalising the sim time by the total number of …
ira-halenok Mar 9, 2023
3a46689
#54 - Run performance test for different number of batched task toget…
ira-halenok Mar 17, 2023
59e7b14
#54 - Name axis correctly for the first version of the plot
ira-halenok Mar 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ bimp_test_examples/
*.egg-info
.pymon
.DS_Store
.vscode/
.vscode/
performance_exp/*/*/results
performance_exp/events/generated_events
16 changes: 16 additions & 0 deletions bpdfr_simulation_engine/control_flow_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ def is_start_or_end_event(self):
def is_event(self):
return self.type in [BPMN.START_EVENT, BPMN.END_EVENT, BPMN.INTERMEDIATE_EVENT]

def delete_incoming_flow(self, flow_id):
"Delete incoming flow if it exists"
if flow_id in self.incoming_flows:
self.incoming_flows.remove(flow_id)

def delete_outgoing_flow(self, flow_id):
"Delete outgoing flow if it exists"
if flow_id in self.outgoing_flows:
self.outgoing_flows.remove(flow_id)


class ProcessState:
def __init__(self, bpmn_graph):
Expand Down Expand Up @@ -171,6 +181,12 @@ def add_bpmn_element(self, element_id, element_info):
self.from_name[element_info.name] = element_id
self.nodes_bitset[element_id] = (1 << len(self.element_info))

def remove_incoming_flow(self, element_id, flow_id):
self.element_info[element_id].delete_incoming_flow(flow_id)

def remove_outgoing_flow(self, element_id, flow_id):
self.element_info[element_id].delete_outgoing_flow(flow_id)

def add_flow_arc(self, flow_id, source_id, target_id):
for node_id in [source_id, target_id]:
if node_id not in self.element_info:
Expand Down
72 changes: 72 additions & 0 deletions bpdfr_simulation_engine/events_performance_experiments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import os
import string

from bpdfr_simulation_engine.control_flow_manager import (
BPMN,
EVENT_TYPE,
BPMNGraph,
ElementInfo,
)


def _add_events(
bpmn_graph: BPMNGraph,
sequence_flow_list,
element_probability,
num_inserted_events: int,
):
if len(sequence_flow_list) < num_inserted_events:
raise ValueError(
"A number of inserted events should not be higher than a number of sequence flows present in the BPMN model."
)

# keep track of the added events to the model
inserted_events_logs: string = ""

for i in range(num_inserted_events):
# the flow arc to be replaced
to_be_deleted_flow_arc = sequence_flow_list[i]
to_be_deleted_flow_arc_id = to_be_deleted_flow_arc.attrib["id"]

source_id = to_be_deleted_flow_arc.attrib["sourceRef"]
target_id = to_be_deleted_flow_arc.attrib["targetRef"]

new_event_id = f"event_{i}"

# log info about the newly added event
inserted_events_logs += f"{new_event_id} between {source_id} and {target_id}.\n"

# add intermediate event
bpmn_graph.add_bpmn_element(
new_event_id,
ElementInfo(
BPMN.INTERMEDIATE_EVENT,
new_event_id,
new_event_id,
EVENT_TYPE.TIMER,
),
)

# remove previously referenced sequence flow in the source & target activity
bpmn_graph.remove_outgoing_flow(source_id, to_be_deleted_flow_arc_id)
bpmn_graph.remove_incoming_flow(target_id, to_be_deleted_flow_arc_id)

# add sequence flow to and from the newly added event
seq_flow_to_event = f"{source_id}_{new_event_id}"
bpmn_graph.add_flow_arc(seq_flow_to_event, source_id, new_event_id)
seq_flow_from_event = f"{new_event_id}_{target_id}"
bpmn_graph.add_flow_arc(seq_flow_from_event, new_event_id, target_id)

# duplicate the gateway probability if it existed before
if source_id in element_probability:
element_probability[source_id].update_candidate_key(
to_be_deleted_flow_arc_id, seq_flow_to_event
)

# save logs about events
logs_path = os.path.join(
os.path.dirname(__file__),
f"../performance_exp/events/generated_events/{num_inserted_events}_events_logs.txt",
)
with open(logs_path, "w+") as logs_file:
logs_file.write(inserted_events_logs)
14 changes: 14 additions & 0 deletions bpdfr_simulation_engine/probability_distributions.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,20 @@ def get_multiple_flows(self):
selected.append((self.candidates_list[i], None))
return selected if len(selected) > 0 else [(self.get_outgoing_flow(), None)]

def update_candidate_key(self, old_candidate_id, new_candidate_id):
"""
After inserting an event, we need to change the candidate id in the list of candidates
This needs to happen due to the fact that we removed one gateway and inserted a new one instead
"""

try:
candidate_index = self.candidates_list.index(old_candidate_id)
except ValueError:
# in case candidate is not on the list, not updating anything
return

self.candidates_list[candidate_index] = new_candidate_id


def random_uniform(start, end):
return numpy.random.uniform(low=start, high=end)
Expand Down
3 changes: 2 additions & 1 deletion bpdfr_simulation_engine/simulation_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,9 +644,10 @@ def run_simulation(
log_out_path=None,
starting_at=None,
is_event_added_to_log=False,
num_generated_events=None,
):
diffsim_info = SimDiffSetup(
bpmn_path, json_path, is_event_added_to_log, total_cases
bpmn_path, json_path, is_event_added_to_log, total_cases, num_generated_events
)

if not diffsim_info:
Expand Down
24 changes: 20 additions & 4 deletions bpdfr_simulation_engine/simulation_properties_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
BPMNGraph,
ElementInfo,
)
from bpdfr_simulation_engine.events_performance_experiments import _add_events
from bpdfr_simulation_engine.prioritisation import AllPriorityRules
from bpdfr_simulation_engine.prioritisation_parser import PrioritisationParser
from bpdfr_simulation_engine.probability_distributions import *
Expand All @@ -27,7 +28,7 @@
PRIORITISATION_RULES_SECTION = "prioritisation_rules"
ARRIVAL_TIME_CALENDAR = "arrival_time_calendar"
RESOURCE_CALENDARS = "resource_calendars"

TASK_RESOURCE_DISTR_SECTON = "task_resource_distribution"

def parse_json_sim_parameters(json_path):
with open(json_path) as json_file:
Expand All @@ -38,7 +39,7 @@ def parse_json_sim_parameters(json_path):
)
calendars_map = parse_resource_calendars(json_data[RESOURCE_CALENDARS])
task_resource_distribution = parse_task_resource_distributions(
json_data["task_resource_distribution"], res_pool
json_data[TASK_RESOURCE_DISTR_SECTON], res_pool
)

element_distribution = parse_arrival_branching_probabilities(
Expand Down Expand Up @@ -234,7 +235,13 @@ def parse_arrival_branching_probabilities(arrival_json, gateway_json):
return element_distribution


def parse_simulation_model(bpmn_path):
def parse_simulation_model(
bpmn_path, element_probability={}, num_generated_events=None
):
"""
element_probability parameter is only used for adding probability for newly inserted sequence flows
when inserting events
"""
tree = ET.parse(bpmn_path)
root = tree.getroot()

Expand Down Expand Up @@ -276,7 +283,8 @@ def parse_simulation_model(bpmn_path):

# Counting incoming/outgoing flow arcs to handle cases of multiple in/out arcs simultaneously
pending_flow_arcs = list()
for flow_arc in process.findall("xmlns:sequenceFlow", bpmn_element_ns):
sequence_flow_list = process.findall("xmlns:sequenceFlow", bpmn_element_ns)
for flow_arc in sequence_flow_list:
# Fixing the case in which a task may have multiple incoming/outgoing flow-arcs
pending_flow_arcs.append(flow_arc)
if flow_arc.attrib["sourceRef"] in elements_map:
Expand Down Expand Up @@ -332,6 +340,14 @@ def parse_simulation_model(bpmn_path):
target_id = join_gateways[target_id]
bpmn_graph.add_flow_arc(flow_arc.attrib["id"], source_id, target_id)

if num_generated_events != None:
_add_events(
bpmn_graph,
sequence_flow_list,
element_probability,
num_generated_events,
)

bpmn_graph.encode_or_join_predecesors()
bpmn_graph.validate_model()
return bpmn_graph
Expand Down
26 changes: 21 additions & 5 deletions bpdfr_simulation_engine/simulation_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,37 @@
from bpdfr_simulation_engine.control_flow_manager import ProcessState, ElementInfo, BPMN
from bpdfr_simulation_engine.probability_distributions import generate_number_from
from bpdfr_simulation_engine.resource_calendar import RCalendar
from bpdfr_simulation_engine.simulation_properties_parser import parse_simulation_model, parse_json_sim_parameters
from bpdfr_simulation_engine.simulation_properties_parser import (
parse_simulation_model,
parse_json_sim_parameters,
)


class SimDiffSetup:
def __init__(self, bpmn_path, json_path, is_event_added_to_log, total_cases):
def __init__(
self,
bpmn_path,
json_path,
is_event_added_to_log,
total_cases,
num_generated_events=None,
):
self.process_name = ntpath.basename(bpmn_path).split(".")[0]
self.start_datetime = datetime.datetime.now(pytz.utc)

self.resources_map, self.calendars_map, self.element_probability, self.task_resource, self.arrival_calendar, \
self.event_distibution, self.batch_processing, self.case_attributes, self.prioritisation_rules \
= parse_json_sim_parameters(json_path)

self.bpmn_graph = parse_simulation_model(bpmn_path)
self.bpmn_graph.set_additional_fields_from_json(self.element_probability, \
self.task_resource, self.event_distibution, self.batch_processing)
self.bpmn_graph = parse_simulation_model(
bpmn_path, self.element_probability, num_generated_events
)
self.bpmn_graph.set_additional_fields_from_json(
self.element_probability,
self.task_resource,
self.event_distibution,
self.batch_processing
)
if not self.arrival_calendar:
self.arrival_calendar = self.find_arrival_calendar()

Expand Down
Binary file added performance_exp/batching/bpi2012/input.zip
Binary file not shown.
Empty file.
Loading