diff --git a/models/Application_examples/Application_Process.mp b/models/Application_examples/Application_Process.mp index 3498d330a04a0f072eb45ecb699842fbaaabe88e..852b1a5989d65066f593a410f65320af5b731890 100644 --- a/models/Application_examples/Application_Process.mp +++ b/models/Application_examples/Application_Process.mp @@ -3,16 +3,18 @@ │*│ │ Model of Application Process │ │ │*│ │ Created by Mikhail Auguston in 2018. │ │ │*│ │ Edited by Pamela Dyer in September, 2021. │ │ -│*│ │ Schedule analysis added by Kristin Giammarco in │ │ -│*│ │ December, 2021. │ │ +│*│ │ Probabilties and timing attributes, reports, │ │ +│*│ │ tables, and charts added by Kristin Giammarco in │ │ +│*│ │ January, 2022. │ │ │*│ └────────────────────────────────────────────────────┘ │ │*│ │ │*│ ┌─[ Purpose ]────────────────────────────────────────┠│ │*│ │ To provide a template for an application approval │ │ │*│ │ process involving multiple levels of approval, and │ │ -│*│ │ demonstrate an example of a schedule analyis. │ │ +│*│ │ demonstrate an example of a schedule analyis that │ │ +│*│ │ takes trace probability into account. │ │ │*│ └────────────────────────────────────────────────────┘ │ -│*│ │ +│*│ │ │*│ ┌─[ Description ]────────────────────────────────────┠│ │*│ │ An applicant submits application and needs to get │ │ │*│ │ it approved by the bureaucratic chain of two │ │ @@ -50,7 +52,7 @@ │*│ │ Run for Scopes 1 and up. │ │ │*│ ├─[ Run Statistics ]─────────────────────────────────┤ │ │*│ │ Scope 1: 21 traces in less than 1 sec. | │ -│*│ │ Scope 2: 273 traces in 4.6 sec. │ │ +│*│ │ Scope 2: 273 traces in 4.6 sec. │ │ │*│ │ Scope 3: 2730 traces in 379 sec. │ │ │*│ └────────────────────────────────────────────────────┘ │ └*┴───────────────────────────────────────────────────────*/ @@ -70,18 +72,19 @@ ROOT Official_1: (+ Receive_application_from_Applicant In_Queue_for_Review Review_application - ( Approve_and_forward_to_Official_2 | - Request_rework | - Reject ) + ( <<0.7>> Approve_and_forward_to_Official_2 | + <<0.29>> Request_rework | + <<0.01>> Reject ) +) +/* The process stops if a rejection occurs */ BUILD{ ENSURE #Reject <= 1; ENSURE FOREACH $r: Reject #$$EVENT AFTER $r == 0; } ; - In_Queue_for_Review: ( Available_to_do_work | - Busy_with_other_work | - Out_of_office ); + In_Queue_for_Review: ( <<0.05>> Available_to_do_work | + <<0.75>> Busy_with_other_work | + <<0.20>> Out_of_office ); COORDINATE $s: Submit_application FROM Applicant, $r: Receive_application_from_Applicant FROM Official_1 @@ -92,11 +95,12 @@ ROOT Official_2: (* Receive_application_from_Official_1 In_Queue_for_Review Review_application - ( Approve_and_forward_to_Applicant | - Request_rework | - Reject ) + ( <<0.95>> Approve_and_forward_to_Applicant | + <<0.04>> Request_rework | + <<0.01>> Reject ) *) +/* The process stops if a rejection occurs */ BUILD{ ENSURE #Reject <= 1; ENSURE FOREACH $r: Reject #$$EVENT AFTER $r == 0; } ; @@ -120,7 +124,7 @@ COORDINATE $a: Approve_and_forward_to_Applicant FROM Official_2, DO ADD $a PRECEDES $aa; OD; -/* --------- Add duration attributes (hours) --------- */ +/* ------- Add duration attributes (hours) ------- */ COORDINATE $a1: Prepare_application DO SET $a1.duration AT LEAST 8; OD; @@ -150,7 +154,7 @@ COORDINATE $a5: Review_application FROM Official_1 COORDINATE $a7: Review_application FROM Official_2 DO SET $a7.duration AT LEAST 0.03; OD; -/* --------- Build trace tables and Gantt Charts --------- */ +/* --------- Build Gantt Charts on traces --------- */ TABLE Gantt_Table{ TABS string event_name, @@ -179,49 +183,150 @@ SHOW Gantt_Chart; SAY("Trace " trace_id " Total Time: " THIS.duration/8 " days"); -/* --------- Build global reports --------- */ +/* ---- Accumulate data from traces for global reports ---- */ -ATTRIBUTES {number accumulated_max, - accumulated_min, +ATTRIBUTES {number accumulated_max_duration, + accumulated_min_duration, accumulated_durations, - smallest_trace_id, - longest_trace_id; }; - -GLOBAL.accumulated_durations +:= THIS.duration.smallest; - -IF GLOBAL.accumulated_max < THIS.duration.largest THEN - GLOBAL.accumulated_max := THIS.duration.largest; + shortest_trace_id, + longest_trace_id, + trace_unique_id, + trace_duration, + weighted_duration, + count; + bool d_max, d_min; + }; + +/* Find the longest trace */ +IF GLOBAL.accumulated_max_duration < THIS.duration.largest THEN + GLOBAL.accumulated_max_duration := THIS.duration.largest; GLOBAL.longest_trace_id := trace_id; FI; -IF GLOBAL.accumulated_min >= THIS.duration.smallest OR - GLOBAL.accumulated_min == 0 THEN - GLOBAL.accumulated_min := THIS.duration.smallest; - GLOBAL.smallest_trace_id := trace_id; +/* Find the shortest trace */ +IF GLOBAL.accumulated_min_duration >= THIS.duration.smallest OR + GLOBAL.accumulated_min_duration == 0 THEN + GLOBAL.accumulated_min_duration := THIS.duration.smallest; + GLOBAL.shortest_trace_id := trace_id; FI; +/* Find the total of all trace durations for the denominator of + the average duration calculation */ +GLOBAL.accumulated_durations +:= THIS.duration.smallest; + +/* Store trace duration data in a graph container for later + accessing by GLOBAL section */ +GRAPH trace_data { }; +WITHIN trace_data{ + Node$x: NEW(THIS.duration.smallest); + Node$x.trace_unique_id := trace_id; + Node$x.trace_duration := THIS.duration.smallest; + }; + +/* Create and print global reports */ GLOBAL -REPORT Duration_Statistics_Report { TITLE ("Scope "$$scope" Duration Statistics"); - }; +/* Create table summarizing trace data */ +TABLE trace_data_summary { +TABS string Trace_Number, + string Trace_Probability, + string Trace_Duration_hours, + number Trace_Duration_days, + number Weighted_Duration_days, + string Maximum_Duration, + string Minimum_Duration; }; + +WITHIN trace_data{ + FOR Node$x + DO + weighted_duration +:= + Node$x.trace_duration/8 * #$$TP(Node$x.trace_unique_id); + IF Node$x.trace_duration == GLOBAL.accumulated_max_duration + THEN d_max:= true; + ELSE d_max:= false; FI; + IF Node$x.trace_duration == GLOBAL.accumulated_min_duration + THEN d_min:= true; + ELSE d_min:= false; FI; + + trace_data_summary <| + Trace_Number: SAY( Node$x.trace_unique_id ), + Trace_Probability: SAY( #$$TP(Node$x.trace_unique_id) ), + Trace_Duration_hours: SAY( Node$x ), + Trace_Duration_days: Node$x.trace_duration/8, + Weighted_Duration_days: weighted_duration, + Maximum_Duration: SAY( d_max ), + Minimum_Duration: SAY( d_min ); + OD; +}; + +/* Comment in the following SHOW statement to view table of trace data */ +/*SHOW trace_data_summary;*/ + + +/* Create summary report */ + +REPORT Duration_Statistics_Report { + TITLE ("Scope "$$scope" Duration Statistics"); }; CLEAR Duration_Statistics_Report; SAY("There are " #$$TRACE " traces total." ) => Duration_Statistics_Report; -SAY("Trace "longest_trace_id " has the max duration of " - accumulated_max/8" days." ) +SAY("Average duration assuming equal trace probabilities is: " + accumulated_durations/8/#$$TRACE" days.") => Duration_Statistics_Report; -SAY("Trace "smallest_trace_id " has the min duration of " - accumulated_min/8" days." ) +SAY ("Expected duration based on trace probabilities is: " + weighted_duration" days." ) => Duration_Statistics_Report; -SAY("The average duration across all traces (assuming equal probability) is " - accumulated_durations/8/#$$TRACE" days.") +SAY("Trace "longest_trace_id " has a max duration of " + accumulated_max_duration/8" days." ) + => Duration_Statistics_Report; + +SAY("Trace "shortest_trace_id " has a min duration of " + accumulated_min_duration/8" days." ) => Duration_Statistics_Report; SHOW Duration_Statistics_Report; -/*SHOW ACTIVITY DIAGRAM Applicant, Official_1, Official_2; -*/ + +/* Create probability histogram */ + +GRAPH trace_probability_histogram_data { }; + +WITHIN trace_probability_histogram_data{ + FOR Num$t: [1.. #$$TRACE] STEP 1 + DO FOR Num$n: [0 .. 1] STEP 0.1 + DO + Node$x: LAST("[" Num$n ".." Num$n + 0.1 ")"); + IF ( Num$n <= #$$TP(Num$t) AND + #$$TP(Num$t) < Num$n + 0.1) OR + ( #$$TRACE == 1 AND Num$n == 0.9 ) THEN + Node$x.count +:= 1; + FI; + OD; + OD; +}; + + +TABLE probability_histogram { TABS string probability_interval, + number trace_count; + }; + +BAR CHART probability_chart { TITLE("Trace Probabilities"); + FROM probability_histogram; + X_AXIS probability_interval; + }; + +WITHIN trace_probability_histogram_data { + FOR Node$n + DO probability_histogram <| + probability_interval: SAY( Node$n ), + trace_count: Node$n.count; + OD; +}; + +SHOW probability_chart SORT; + +SHOW ACTIVITY DIAGRAM Applicant, Official_1, Official_2;