mijtsma3 commited on
Commit
0441cef
·
verified ·
1 Parent(s): 405c837

Upload script.py

Browse files
Files changed (1) hide show
  1. script.py +381 -0
script.py ADDED
@@ -0,0 +1,381 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from core import networkdata as nd
2
+ from core.parsing.jsonparser import JSONParser
3
+ from core.parsing.jsonencoder import JSONEncoder
4
+ from cytoapp.cytoscapeapp import CytoscapeApp
5
+ from userapps.rovercase.roverdatahandler import RoverDataHandler
6
+ import itertools
7
+ import copy
8
+ import webbrowser
9
+ from core.visualization.tikzstandard import StandardTikzVisualizer as s
10
+ from core.visualization.tikzlayer import LayeredTikzVisualizer as l
11
+ ### HRT Metrics Script
12
+
13
+ ''' The folder containing the JSON data.
14
+ '''
15
+ directory: str = "data/RevisedWMC/"
16
+
17
+ ''' The JSON files in the given folder
18
+ '''
19
+ data_sets: list[str] = [
20
+ "initial_model"
21
+ ]
22
+
23
+
24
+ # Define a dictionary with edges as keys and lists of QOS values as values
25
+ # edge_qos_values = {
26
+ # # ("PP", "NWS"): [30, 31, 42, 43],
27
+ # ("PP", "NWS"): [10, 15, 20, 25, 30, 31, 42, 43],
28
+ # # ("PP", "NWS"): [0, 10, 15, 20],
29
+ # ("Confirmation-BLM", "BLM"): [0, 20, 30, 40]
30
+ # }
31
+ edge_qos_values = {
32
+ # "PP_NWS": [30, 31, 42, 43],
33
+ # ("PP", "NWS"): [10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 110, 130, 150, 180, 210, 240, 270],
34
+ ("PP", "NWS"): [10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70],
35
+ # ("PP", "NWS"): [1, 2, 3, 5, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 160, 200, 240, 320],
36
+ # ("Confirmation-BLM", "BLM"): [0, 20, 30, 40, 50, 60, 80]
37
+ # ("confirmation", ""): [0]
38
+ ("confirmation", ""): [0,10,20,30,40,50,60,70,80,90,100]
39
+ }
40
+
41
+
42
+ # Class for user data
43
+ class UserData:
44
+ def __init__(self, QOS=1000000): # Default value set to 1000000
45
+ self.QOS = QOS
46
+
47
+ # Custom edge_user_data processor
48
+ def custom_user_parse(user_data):
49
+ ''' The default behavior for parsing user data. These types of
50
+ functions recieve the data tied to the "UserData" entries in
51
+ JSON files and return what user_data within the network model
52
+ elements should be set to.
53
+ '''
54
+
55
+ QOS = user_data["QOS"]
56
+ # user_data = lambda: None
57
+ if QOS != "":
58
+ user_data = UserData(float(QOS))
59
+ else:
60
+ user_data = UserData(1000000) # Assumption for missing data
61
+
62
+ return user_data
63
+
64
+ ''' Store the parsed network models in a dictionary.
65
+ '''
66
+ data_dict: dict[str, nd.NetworkModel] = {}
67
+ for name in data_sets:
68
+ data_dict[name] = JSONParser.parse(directory + name + ".json", e_user_data_func = custom_user_parse)
69
+
70
+
71
+ # Main network
72
+ main_net = data_dict["initial_model"]
73
+
74
+ # Define roles for both human and operator (is there a way to do this through the JSON?)
75
+ operator: nd.Agent = nd.Agent("Operator")
76
+ rover: nd.Agent = nd.Agent("Robot")
77
+
78
+ operator.add_action(main_net.get_node("LAA"), operator.allocation_types.Authority)
79
+ operator.add_action(main_net.get_node("OLL"), operator.allocation_types.Authority)
80
+ operator.add_action(main_net.get_node("CAM"), operator.allocation_types.Authority)
81
+ # Obstacle size estimation?
82
+
83
+ rover.add_action(main_net.get_node("BLM"), rover.allocation_types.Authority)
84
+ rover.add_action(main_net.get_node("TMP"), rover.allocation_types.Authority)
85
+ rover.add_action(main_net.get_node("RPP"), rover.allocation_types.Authority)
86
+ rover.add_action(main_net.get_node("NWS"), rover.allocation_types.Authority)
87
+ rover.add_action(main_net.get_node("IC"), rover.allocation_types.Authority)
88
+ rover.add_action(main_net.get_node("RM"), rover.allocation_types.Authority) # Remove this function?
89
+
90
+ # Responsibility
91
+ operator.add_action(main_net.get_node("BLM"), operator.allocation_types.Responsibility)
92
+ operator.add_action(main_net.get_node("TMP"), operator.allocation_types.Responsibility)
93
+ operator.add_action(main_net.get_node("RPP"), operator.allocation_types.Responsibility)
94
+ operator.add_action(main_net.get_node("NWS"), operator.allocation_types.Responsibility)
95
+ operator.add_action(main_net.get_node("IC"), operator.allocation_types.Responsibility)
96
+ operator.add_action(main_net.get_node("RM"), operator.allocation_types.Responsibility) # Remove this function?
97
+
98
+
99
+ # # Identify the shared resources
100
+ # shared_resources = []
101
+
102
+ # # Loop over all nodes in the graph
103
+ # for node_id in main_net.get_graph().nodes():
104
+
105
+ # node = main_net.get_node(node_id)
106
+
107
+ # # Check if WorkDomainResource
108
+ # if issubclass (node.__class__, nd.WorkDomainResource):
109
+
110
+ # # Get all neighboring nodes (actionNodes)
111
+ # functions_that_set = main_net.get_graph().predecessors(node_id)
112
+ # functions_that_get = main_net.get_graph().successors(node_id)
113
+
114
+ # # A list of all function pairs that are connected through this resources
115
+ # interdependent_functions = list(itertools.product(functions_that_get,functions_that_set))
116
+
117
+ # # For each pair, check whether roles is the same
118
+ # for pair in interdependent_functions:
119
+ # agent_setting = main_net.get_node(pair[0]).get_authorized_agent()
120
+ # agent_getting = main_net.get_node(pair[1]).get_authorized_agent()
121
+
122
+ # if agent_setting.id != agent_getting.id:
123
+ # shared_resources.append((node_id,pair))
124
+
125
+
126
+ # # For each of the shared resources, do something!
127
+ # # Current rule: When an information resource is shared between agents at the taskwork level,
128
+ # # then a function must be created at the teamwork level to show the relaying of information,
129
+ # # such that a shared awareness is formed at the social organizational level.
130
+ # for element in shared_resources:
131
+
132
+ # # print("There is a shared resource",element[0],"between ", element[1][0], "and", element[1][1])
133
+
134
+ # # Create a shared resources node and a teamwork function node
135
+ # soc_org_node = main_net.add_node(nd.Node("shared_"+element[0])) # TODO: Specify the node type/class
136
+ # teamwork_node = main_net.add_node(nd.ActionNode("sharing_"+element[0]))
137
+
138
+ # # Add edge going from teamwork node to shared_resource node
139
+ # main_net.add_edge("sharing_"+element[0],"shared_"+element[0])
140
+
141
+ # # Add edge going from original resource to the teamwork node
142
+ # main_net.add_edge(element[0],"sharing_"+element[0])
143
+
144
+ # # Add QOS to each edge (making an assumption that this needs to updated always but can change!)
145
+ # user_data = lambda: None
146
+ # user_data.QOS = 0
147
+ # # main_net.get_edge("sharing_"+element[0],"shared_"+element[0]).user_data = user_data # No QOS needed--because is set relationship
148
+ # main_net.get_edge(element[0],"sharing_"+element[0]).user_data = user_data
149
+
150
+
151
+ # Identify the shared resources
152
+ shared_actions = []
153
+
154
+ # Loop over all nodes in the graph
155
+ for node_id in main_net.get_graph().nodes():
156
+
157
+ node = main_net.get_node(node_id)
158
+
159
+ # Check if TaskworkAction
160
+ if issubclass (node.__class__, nd.TaskworkAction):
161
+
162
+ # Get all neighboring nodes (actionNodes)
163
+ authorized_agent = node.get_authorized_agent()
164
+ # responsible_agent = node.get_responsible_agent()
165
+
166
+ # For each pair, check whether roles is the same
167
+ if authorized_agent != operator:
168
+ shared_actions.append(node_id)
169
+
170
+ # For each of the shared action, do something!
171
+ # Current rule: When authority-responsibility mismatch, create a confirmation resources and an a confirmation
172
+ # action that is allocated to the operator
173
+ for node_id in shared_actions:
174
+
175
+ if node_id == "RM":
176
+ continue
177
+
178
+ # Create a coordination resource and a teamwork function node
179
+ soc_org_node = main_net.add_node(nd.CoordinationResource("Confirmation-"+node_id)) # TODO: Specify the node type/class
180
+ main_net.get_node("Confirmation-"+node_id).user_data = "Confirmation-"+node_id # Need to fill these for WMC parsing
181
+ teamwork_node = main_net.add_node(nd.TeamworkAction("Confirming-"+node_id))
182
+ main_net.get_node("Confirming-"+node_id).user_data = "Confirming-"+node_id # Need to fill these for WMC parsing
183
+
184
+ # Add edge going from teamwork node to coordination resource
185
+ main_net.add_edge("Confirming-"+node_id,"Confirmation-"+node_id)
186
+ main_net.get_edge("Confirming-"+node_id,"Confirmation-"+node_id).user_data = UserData(100000)
187
+
188
+ # Add edges going from coordination resource to original node
189
+ main_net.add_edge("Confirmation-"+node_id,node_id)
190
+
191
+ # Add edge going from work domain resources set by shared action to teamwork node
192
+ for wd_resource in main_net.get_graph().successors(node_id):
193
+ main_net.add_edge(wd_resource,"Confirming-"+node_id)
194
+
195
+ # Add QOS to each edge (making an assumption that this needs to updated always but can change!)
196
+ main_net.get_edge(wd_resource,"Confirming-"+node_id).user_data = UserData(1000000)
197
+
198
+ # Allocate authority and responsibility to human
199
+ operator.add_action(main_net.get_node("Confirming-"+node_id), operator.allocation_types.Authority)
200
+ operator.add_action(main_net.get_node("Confirming-"+node_id), operator.allocation_types.Responsibility)
201
+
202
+ # Add QOS to each edge (making an assumption that this needs to updated always but can change!)
203
+ main_net.get_edge("Confirmation-"+node_id,node_id).user_data = UserData(0)
204
+
205
+
206
+ # We want to write this new graph to an output JSON file.
207
+ # Create a custom encoder for the user data that should fill the QOS
208
+ def custom_user_encode(user_data):
209
+
210
+ user_data = {
211
+ "QOS": user_data.QOS,
212
+ }
213
+
214
+ return user_data
215
+
216
+
217
+ # Create all combinations of QOS values for the edges
218
+ qos_combinations = list(itertools.product(*edge_qos_values.values()))
219
+
220
+ # Loop over each combination to create copies of the main_net with these QOS values
221
+ for qos_combo in qos_combinations:
222
+ # Create a deep copy of the main_net to modify
223
+ temp_net = copy.deepcopy(main_net)
224
+
225
+ # Set the QOS values for the edges in the temp_net
226
+ for edge, qos_value in zip(edge_qos_values.keys(), qos_combo):
227
+ if edge[0] == "confirmation":
228
+ confirmation_nodes = [node for node in temp_net.get_node_ids() if node.startswith("Confirmation-")]
229
+ for full_node_id in confirmation_nodes:
230
+ node_id_after_dash = full_node_id.split("-", 1)[1]
231
+ print(full_node_id,node_id_after_dash)
232
+ temp_net.get_edge(full_node_id, node_id_after_dash).user_data = UserData(qos_value)
233
+ else:
234
+ print(edge[0])
235
+ temp_net.get_edge(*edge).user_data = UserData(qos_value)
236
+
237
+ # Write the data to a JSON file using the JSONEncoder and custom_user_encode
238
+ # The file name includes the QOS values for identification
239
+ file_name = "data/ForWMCreading/PPtoNWS_{}_conf_{}.json".format(*qos_combo)
240
+ JSONEncoder.encode(file_name, temp_net, e_user_data_func=custom_user_encode)
241
+
242
+
243
+
244
+ # Manually set the QOS for NWP to RM to 0. This is necessary because WMC schedules NWS but for
245
+ # the network analysis, this edge must be triggered
246
+ main_net.get_edge("NWP","RM").user_data = UserData(0)
247
+
248
+
249
+ # Now add attributes that represent when each WorkDomainResource and OrgResource was last updated
250
+ for node_id in main_net.get_node_ids():
251
+
252
+ node = main_net.get_node(node_id)
253
+
254
+ # Check if WorkDomainResource
255
+ if issubclass (node.__class__, nd.WorkDomainResource) or issubclass (node.__class__, nd.CoordinationResource):
256
+
257
+ user_data = lambda: None # Lambda function that we can add attributes to, could use to set last_update_time to zero.
258
+ user_data.last_update_time = 0#-1000000 # Something really small so that it updates the first time we run it.
259
+ node.user_data = user_data
260
+
261
+ # Check that previous is actually working
262
+ # for node_id in main_net.get_node_ids():
263
+
264
+ # node = main_net.get_node(node_id)
265
+
266
+ # # Check if WorkDomainResource
267
+ # if issubclass (node.__class__, nd.WorkDomainResource) or issubclass (node.__class__, nd.CoordinationResource):
268
+
269
+ # print(node.user_data.last_update_time)
270
+
271
+ # Check that QOS is loaded properly
272
+ # for edge_id in main_net.get_edge_ids():
273
+
274
+ # edge = main_net.get_edge(edge_id[0],edge_id[1])
275
+
276
+ # print(edge.user_data.QOS)
277
+
278
+ # Now we can do some funky things with the QOS requirements...
279
+ # First want to find edges that need updating based on when resources were last updated.
280
+ current_time = 32 #Needs something different here
281
+
282
+ # Manually change when resources were last updated
283
+ # Strategy for NWS without updating PP
284
+ # main_net.get_node("PP").user_data.last_update_time = current_time
285
+
286
+ # Strategy without cross-checking
287
+ # main_net.get_node("Confirmation-NWS").user_data.last_update_time = current_time
288
+ # main_net.get_node("Confirmation-BLM").user_data.last_update_time = current_time
289
+ # main_net.get_node("Confirmation-TMP").user_data.last_update_time = current_time
290
+ # main_net.get_node("Confirmation-RPP").user_data.last_update_time = current_time
291
+
292
+ # Strategy without obstacle location
293
+ # main_net.get_node("OL").user_data.last_update_time = current_time
294
+
295
+ # Strategy without battery level and temperature measurement
296
+ # main_net.get_node("OST").user_data.last_update_time = current_time
297
+ # main_net.get_node("OBL").user_data.last_update_time = current_time
298
+
299
+
300
+ out_of_bound_edges = []
301
+
302
+ # Identify which edges are out of QOS bound
303
+ for edge_id in main_net.get_edge_ids():
304
+
305
+ edge = main_net.get_edge(edge_id[0],edge_id[1])
306
+
307
+ # Check if the target is a function node
308
+ target_node = main_net.get_node(edge_id[1])
309
+ if issubclass (target_node.__class__, nd.ActionNode):
310
+
311
+ # Check when resource was last updated
312
+ source_node = main_net.get_node(edge_id[0])
313
+ last_update_time = source_node.user_data.last_update_time
314
+ QOS = edge.user_data.QOS
315
+
316
+ if float(current_time) - float(last_update_time) > float(QOS):
317
+ print("QOS for",source_node.id,"to",target_node.id,"is out of bounds with QOS",float(QOS),"and last update time",last_update_time)
318
+
319
+ out_of_bound_edges.append(edge_id)
320
+
321
+ # This function is used to identify functional nodes are predependencies for a target function
322
+ # based on QOS bounds and when resources were last updated.
323
+ # This function takes in a node id of a FUNCTION node that is the target
324
+ # It returns a list of function and resource nodes that need to be updated/executed to abide by QOS requirements
325
+ def add_predecessors_to_strategy(node_id, out_of_bound_edges, strategy_list, main_net):
326
+
327
+ # Get the node handle
328
+ node = main_net.get_node(node_id)
329
+
330
+ # If this node is not yet in the strategy, add it!
331
+ if node not in strategy_list:
332
+ strategy_list.append(node)
333
+
334
+ # Now loop over all incoming edges
335
+ for pred_node_id in main_net.get_graph().predecessors(node_id):
336
+
337
+ # And check whether it is within QOS bound
338
+ if (pred_node_id, node_id) in out_of_bound_edges:
339
+
340
+ # If out of QOS bound, need to add to our strategy (in need for an update)
341
+ strategy_list.append(main_net.get_node(pred_node_id))
342
+
343
+ # We need to add each of the functions that is linked to set this predecessor node
344
+ # and perform the same check to see if we need to add their predecessors
345
+ for pred_pred_node_id in main_net.get_graph().predecessors(pred_node_id):
346
+
347
+ if main_net.get_node(pred_pred_node_id) not in strategy_list:
348
+ add_predecessors_to_strategy(pred_pred_node_id, out_of_bound_edges, strategy_list, main_net)
349
+
350
+ return strategy_list
351
+
352
+ # Identify the strategy
353
+ strategy_list = add_predecessors_to_strategy('RM', out_of_bound_edges, [], main_net)
354
+
355
+ # # Identify edges to highlight (that are connecting the nodes in the strategy)
356
+ # connecting_edges = []
357
+ # for node in strategy_list:
358
+ # for neighbor in main_net.get_graph().neighbors(node.id):
359
+ # if main_net.get_node(neighbor) in strategy_list:
360
+ # edge = (node.id, neighbor) if (node.id, neighbor) in main_net.get_edge_ids() else (neighbor, node.id)
361
+ # if edge not in connecting_edges:
362
+ # connecting_edges.append(edge)
363
+
364
+ # Identify all incoming edges for every node in the strategy_list
365
+ connecting_edges = []
366
+ for node in strategy_list:
367
+ print(node.id)
368
+ for incoming_edge in main_net.get_graph().in_edges(node.id):
369
+ if incoming_edge not in connecting_edges:
370
+ connecting_edges.append(incoming_edge)
371
+
372
+ # Let's output as a TikZ graph
373
+ l.visualize(main_net, "tikzout3.tex")
374
+
375
+ ''' Alter networks after they have been read
376
+ from JSON.
377
+ '''
378
+ # app = CytoscapeApp(data_dict, RoverDataHandler, connecting_edges)
379
+ app = CytoscapeApp(data_dict, RoverDataHandler)
380
+ webbrowser.open_new("http://127.0.0.1:8050")
381
+ app.run()