diff --git a/backend/app/connect.py b/backend/app/connect.py index 63eebf6..d8ac1ee 100644 --- a/backend/app/connect.py +++ b/backend/app/connect.py @@ -175,7 +175,7 @@ def nodes_in_bfs_order(self): # create the dictionary for node in self.canvas: # create node - nodes_list[node["id"]] = Node(node["id"], node["queueType"], node["priorityFunction"], node["numberOfActors"], + nodes_list[node["id"]] = Node(node["id"], node["queueType"], node["priorityFunction"], node["numberOfActors"], node["distributionFunction"], process_name=node["elementType"], distribution_name=node["distribution"], distribution_parameters=node["distributionParameters"], output_process_ids=node["children"], rules=[], priority_type=node["priorityType"]) diff --git a/backend/app/models/node.py b/backend/app/models/node.py index ddee256..5027ec9 100644 --- a/backend/app/models/node.py +++ b/backend/app/models/node.py @@ -11,6 +11,8 @@ from flask import Flask import os import random +import numpy as np + app = Flask(__name__) @@ -20,7 +22,7 @@ class Node: node_dict = {} environment = os.environ.get("DEV_ENV") '''rules is a list of Rule Objects''' - def __init__(self, id, queue_type, priority_function, num_actors, + def __init__(self, id, queue_type, priority_function, num_actors, distribution_function, process_name=None, distribution_name=None, distribution_parameters=None, output_process_ids=None, rules=[], priority_type=""): @@ -36,6 +38,12 @@ def __init__(self, id, queue_type, priority_function, num_actors, self.priority_type = None else: self.priority_type = priority_type + + if distribution_function == "": + self.distribution_function = None + else: + self.distribution_function = distribution_function + self.queue = self._set_queue() # create num actors and resource dict based on num actors @@ -50,6 +58,24 @@ def __init__(self, id, queue_type, priority_function, num_actors, Node.node_dict[self.id] = self self.node_rules = rules[:] + if self.distribution_name == "define_your_own": + self._parse_d_func() + + def _parse_d_func(self): + """ + Helper function to help fix spacing and remove empty lines + Assign self.d_func to be the parse string + """ + split = self.distribution_function.split("\n") + new_split = [] + for line in split: + line = line.strip() + if line: + new_split.append(line + "\n") + self.distribution_function = "".join(new_split) + app.logger.info("parsed distribution_function func") + app.logger.info(self.distribution_function) + def set_id(self, id): self.id = id @@ -114,9 +140,19 @@ def _set_queue(self): else: raise Exception("This type of queue is not implemented yet") - def generate_finish_time(self): + def generate_finish_time(self, patient): if self.get_distribution_name() is None: duration = 0 + elif self.distribution_name == "define_your_own": + app.logger.info("d_type define your own") + app.logger.info(self.distribution_function) + duration = 0 + l = locals() + # executes input code string + # need to pass in locals and globals to mutate _p_value + exec(self.distribution_function, globals(), l) + app.logger.info(l['duration']) + duration = l['duration'] else: duration = Distributions.class_distributions[self.get_distribution_name()]( *self.get_distribution_parameters()) @@ -349,7 +385,7 @@ def insert_patient_to_resource_and_heap(self, patient, resource): finish_time = patient.get_start_time() duration = finish_time - GlobalTime.time else: - finish_time, duration = self.generate_finish_time() + finish_time, duration = self.generate_finish_time(patient) resource.insert_patient(patient, self.id, finish_time, duration) # record event of patient joining resource self.add_patient_join_resource_event(patient, resource) diff --git a/backend/app/run.py b/backend/app/run.py index 25b6c5a..6ee7190 100644 --- a/backend/app/run.py +++ b/backend/app/run.py @@ -78,7 +78,7 @@ def run(self) -> None: node_rules = rule_creator.create_rules(type="node", node_rules= node["nodeRules"], node_id=node["id"], canvas=canvas) # create node - nodes_list[node["id"]] = Node(node["id"], node["queueType"], node["priorityFunction"], node["numberOfActors"], + nodes_list[node["id"]] = Node(node["id"], node["queueType"], node["priorityFunction"], node["numberOfActors"], node["distributionFunction"], process_name=node["elementType"], distribution_name=node["distribution"], distribution_parameters=node["distributionParameters"], output_process_ids=node["children"], rules=node_rules, priority_type=node["priorityType"]) @@ -93,7 +93,7 @@ def run(self) -> None: # create patient_loader node when reception is found if node["elementType"] == "reception": - nodes_list[-1] = Node(-1, "queue", None, 1, process_name="patient_loader", + nodes_list[-1] = Node(-1, "queue", None, 1, None, process_name="patient_loader", distribution_name="fixed", distribution_parameters=[0], output_process_ids=[node["id"]], priority_type="") diff --git a/backend/test.csv b/backend/test.csv index aa32313..73c9a19 100644 --- a/backend/test.csv +++ b/backend/test.csv @@ -1,4 +1,4 @@ patient_id,time,patient_acuity,patient_admitted,xray,pxray -1,2019-01-01 00:00:00.958845,1,TRUE,0,1 -2,2019-01-01 00:00:00.958845,1,TRUE,0,1 -3,2019-01-01 00:00:00.958845,1,TRUE,0,1 \ No newline at end of file +1,2019-01-01 00:00:00.958845,1,TRUE,1,0 +2,2019-01-01 00:00:00.958845,1,TRUE,1,0 +3,2019-01-01 00:00:00.958845,1,TRUE,1,1 \ No newline at end of file diff --git a/frontend/src/components/JSONEntrySidebarContent.js b/frontend/src/components/JSONEntrySidebarContent.js index 4aa83ed..b5c2c0d 100644 --- a/frontend/src/components/JSONEntrySidebarContent.js +++ b/frontend/src/components/JSONEntrySidebarContent.js @@ -11,6 +11,7 @@ const nodeSchema = { "elementType": { "type": "string"}, "distribution": {"type": "string"}, "distributionParameters": {"type": "array", "items": {"type": "integer"}}, + "distributionFunction": { "type": "string"}, "numberOfActors": { "type": "integer"}, "queueType": { "type": "string"}, "priorityFunction": { "type": "string"}, @@ -104,7 +105,7 @@ export class JSONEntrySidebarContent extends Component { validatedJSON[i].patients = [] validatedJSON[i].processing = [] } - const requiredKeys = ["id", "elementType", "distribution", "distributionParameters", "numberOfActors", "queueType", "priorityFunction", "children", "priorityType"]; + const requiredKeys = ["id", "elementType", "distribution", "distributionParameters", "distributionFunction", "numberOfActors", "queueType", "priorityFunction", "children", "priorityType"]; // console.log(this.state.valid); for (let i = 0; i < validatedJSON.length; i++) { diff --git a/frontend/src/components/NodeSidebarContent.js b/frontend/src/components/NodeSidebarContent.js index 023a6a8..1c87cee 100644 --- a/frontend/src/components/NodeSidebarContent.js +++ b/frontend/src/components/NodeSidebarContent.js @@ -43,6 +43,14 @@ export class NodeSidebarContent extends React.Component { new_node.priorityType = "" } + if(new_node.distribution !== "define_your_own"){ + new_node.distributionFunction = "" + } + + if(new_node.distribution === "define_your_own"){ + new_node.distributionParameters = [] + } + // Empty the text inside the "other" field if (name === "elementType" && value === "other") { this.setState({ tempText: "" }); @@ -280,16 +288,46 @@ export class NodeSidebarContent extends React.Component { + + {this.state.node.distribution === 'define_your_own' && +
+

+
+ """
+ Set a custom duration for the patient at this node

+ Attributes available:
+ patient.get_acuity()
Returns a integer value of the patient's acuity

+ patient.get_start_time()
Returns the number of minutes it took for patient to enter the simulation + after the simulation started.

+ patient.get_attribute(attribute)
Returns the value of the attribute for the patient as indicated by the uploaded CSV +

+ """ +
+
+
+ duration = 0
+
# Set duration to the amount of time you want the patient to take
+ # DO NOT RETURN ANYTHING IN THE CODE
+
+ +
+ } -
{/* could indicate what parameters required */} -
- -
+ {this.state.node.distribution !== 'define_your_own' && +
{/* could indicate what parameters required */} +
+ +
+ }
diff --git a/frontend/src/models/ProcessNode.js b/frontend/src/models/ProcessNode.js index 629b798..0502b59 100644 --- a/frontend/src/models/ProcessNode.js +++ b/frontend/src/models/ProcessNode.js @@ -1,5 +1,5 @@ class ProcessNode { - constructor(id, elementType, distribution, distributionParameters, + constructor(id, elementType, distribution, distributionParameters, distributionFunction, numberOfActors, queueType, priorityFunction, children = [], patients = {}, priorityType, processing = {}, predictedChildren = [], nodeRules = [], resourceRules = []) { @@ -8,6 +8,7 @@ class ProcessNode { this.elementType = elementType; this.distribution = distribution; this.distributionParameters = distributionParameters; + this.distributionFunction = distributionFunction; this.numberOfActors = numberOfActors; this.queueType = queueType; this.priorityFunction = priorityFunction; diff --git a/frontend/src/redux/reducers.js b/frontend/src/redux/reducers.js index c515bfd..d3e5a28 100644 --- a/frontend/src/redux/reducers.js +++ b/frontend/src/redux/reducers.js @@ -17,13 +17,13 @@ const initialState = { linkBeingBuilt: [], // the ID's of 2 nodes between which a link is being constructed. nodeCount: 5, // max ID of any node nodes: [ - new ProcessNode(0, "reception", "fixed", [5], 1, + new ProcessNode(0, "reception", "fixed", [5], "", 1, "priority queue", "", [1], [], "acuity", [], []), - new ProcessNode(1, "triage", "fixed", [3], 2, + new ProcessNode(1, "triage", "fixed", [3], "", 2, "priority queue", "", [2, 3], [], "acuity", [], []), - new ProcessNode(2, "doctor", "fixed", [10], 3, + new ProcessNode(2, "doctor", "fixed", [10], "", 3, "priority queue", "", [3], [], "acuity", [], []), - new ProcessNode(3, "x-ray", "binomial", [1, 1], 2, + new ProcessNode(3, "x-ray", "binomial", [1, 1], "", 2, "priority queue", "", [], [], "acuity", [], []) ], // Intial state of the acuity colors