def get_description(self): response = self._sender.send_entity_base_info_request( self.identifier, EntityTypes.SIMULATION.value) Timeout.hold_your_horses() self._handler.set_response(response) result = self._handler.handle_response_to_entity_base_info_request() return result.get("description")
def add_submodels(self, *submodels): """ Add new submodels to list of simulation submodels :param submodels: submodels to be added into current simulation :return: list of ALL simulation submodels """ assert all(isinstance(item, Submodel) for item in submodels) # First, get list of current submodels simulation_submodels = self.get_submodels() if not simulation_submodels: simulation_submodels = [] # Append new submodels to the list of existing submodels simulation_submodels.extend(submodels) # List of IDs of all updated submodels simulation_submodels_ids = [ submodel.identifier for submodel in simulation_submodels ] # Send request to update simulation submodels (that's how it works in CML-Bench) response = self._sender.send_simulation_submodels_update_request( self.identifier, simulation_submodels_ids) Timeout.hold_your_horses() self._handler.set_response(response) updated_simulation_submodels_ids = self._handler.handle_response_to_simulation_submodels_request( ) if updated_simulation_submodels_ids: submodels = [] for submodel_id in updated_simulation_submodels_ids: submodels.append(Submodel(self._app_session, submodel_id)) return submodels return None
def get_status(self): """ :return: current task status, or None, if error occurred """ response = self._sender.send_task_info_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) task_status = self._handler.handle_response_to_task_status_response() return task_status
def clone(self): """ Method for creating a new simulation, based on the current one :return: id of the new simulation, or None if failed to clone simulation """ response = self._sender.send_clone_simulation_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) return self._handler.handle_response_to_clone_simulation_request()
def _setup_attributes(self): if self.entity_type: response = self._sender.send_entity_base_info_request(self.identifier, self.entity_type.value) Timeout.hold_your_horses() self._handler.set_response(response) base_info = self._handler.handle_response_to_entity_base_info_request() self._name = base_info.get("name") self._parent_id = base_info.get("parent_id") self._tree_path = base_info.get("tree_path") self._tree_id = base_info.get("tree_id")
def get_time_estimation(self): """ :return: tuple of string representation of end waiting and end solving time, or (None, None) if error occurred """ response = self._sender.send_task_info_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) task_end_waiting, task_end_solving = self._handler.handle_response_to_task_estimations_response( ) return task_end_waiting, task_end_solving
def get_list_of_submodels(self): response = self._sender.send_simulation_submodels_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) simulation_submodels_list = self._handler.handle_response_to_simulation_submodels_request() if simulation_submodels_list: submodels = [] for submodel_id in simulation_submodels_list: submodels.append(Submodel(self._app_session, submodel_id)) return submodels return None
def get_list_of_submodels(self): response = self._sender.send_stype_submodels_request(self.tree_path) Timeout.hold_your_horses() self._handler.set_response(response) stype_submodels_list = self._handler.handle_response_to_stype_submodels_requests() if stype_submodels_list: submodels = [] for submodel_id in stype_submodels_list: submodels.append(Submodel(self._app_session, submodel_id)) return submodels return None
def erase_submodels(self): """ Removes all existing submodels from current simulation :return: true if success, false otherwise """ response = self._sender.send_simulation_submodels_update_request( self.identifier, []) Timeout.hold_your_horses() self._handler.set_response(response) status = self._handler.handle_response_to_simulation_submodels_erase_request( ) return status
def get_files(self): """ :return: return list of dictionaries like {id: fileName}, where fileName is a file belongs to current simulation, or None, if some error occurred during reading files """ response = self._sender.send_simulation_files_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) simulation_files_list_of_dicts = self._handler.handle_response_to_simulation_files_request( ) return simulation_files_list_of_dicts
def clone(self): """ Clone current simulation :return: return new simulation, or None, if some error occurred """ response = self._sender.send_clone_simulation_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) cloned_simulation_id = self._handler.handle_response_to_clone_simulation_request( ) if cloned_simulation_id: return Simulation(self._app_session, cloned_simulation_id) return None
def get_list_of_simulations(self): """ Method for getting a list of simulations, belonging to the loadcase :return: list of simulation objects, or None if some error occurred during reading simulations """ response = self._sender.send_loadcase_simulations_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) simulation_ids_list = self._handler.handle_response_to_loadcase_simulations_request() if simulation_ids_list: simulations = [] for simulation_id in simulation_ids_list: simulations.append(Simulation(self._app_session, simulation_id)) return simulations return None
def get_submodels(self): """ :return: list of existing submodels in current s|type, or None, if some error occurred """ response = self._sender.send_stype_submodels_request(self.tree_path) Timeout.hold_your_horses() self._handler.set_response(response) stype_submodels_list = self._handler.handle_response_to_stype_submodels_requests( ) if stype_submodels_list: submodels = [] for submodel_id in stype_submodels_list: submodels.append(Submodel(self._app_session, submodel_id)) return submodels return None
def get_list_of_tasks(self): """ Method for getting a list of tasks, belonging to the simulation :return: list of task objects, of None if some error occurred during reading tasks """ response = self._sender.send_simulation_tasks_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) simulation_tasks_list = self._handler.handle_response_to_simulation_tasks_request() if simulation_tasks_list: tasks = [] for task_id in simulation_tasks_list: tasks.append(Task(self._app_session, task_id)) return tasks return None
def delete_target(self, target): """ Removes target from loadcase :param target: Target object :return: removed target ID or None, if some error occurred """ assert isinstance(target, Target) response = self._sender.send_remove_loadcase_target_request( self.identifier, target.identifier) Timeout.hold_your_horses() self._handler.set_response(response) target_id = self._handler.handle_response_to_remove_loadcase_target_request( ) return target_id
def get_values(self): """ :return: return list of Values, or None, if some error occurred during reading """ response = self._sender.send_simulation_values_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) simulation_values_data = self._handler.handle_response_to_simulation_values_request( ) values = [] if simulation_values_data: for item_data in simulation_values_data: values.append(Value(item_data)) return values return None
def __get_defaults(self, base_simulation_id=None): """ Obtain default parameters for run/post-process task :param base_simulation_id: ID of base simulation for getting defaults :return: dictionary containing default task running parameters such as solver, cluster, etc. """ if base_simulation_id: response = self._sender.send_task_defaults_request( base_simulation_id) else: response = self._sender.send_task_defaults_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) task_startup_defaults = self._handler.handle_response_to_task_defaults_request( ) return task_startup_defaults
def get_tasks(self): """ :return: return list of tasks which belong to current simulation, or None, if some error occurred during reading tasks """ response = self._sender.send_simulation_tasks_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) simulation_tasks_list = self._handler.handle_response_to_simulation_tasks_request( ) if simulation_tasks_list: tasks = [] for task_id in simulation_tasks_list: tasks.append(Task(self._app_session, task_id)) return tasks return None
def get_submodels(self): """ :return: return list of current simulation submodels, or None, if some error occurred """ response = self._sender.send_simulation_submodels_request( self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) simulation_submodels_ids = self._handler.handle_response_to_simulation_submodels_request( ) if simulation_submodels_ids: submodels = [] for submodel_id in simulation_submodels_ids: submodels.append(Submodel(self._app_session, submodel_id)) return submodels return None
def get_targets(self): """ :return: list of targets which belong to current loadcase, or None, if some error occurred during reading targets """ response = self._sender.send_loadcase_targets_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) targets_data_list = self._handler.handle_response_to_loadcase_targets_request( ) if targets_data_list: targets = [] for target_data in targets_data_list: targets.append(Target(target_data)) return targets return None
def get_simulations(self): """ :return: list of simulations which belong to current loadcase, or None, if some error occurred during reading simulations """ response = self._sender.send_loadcase_simulations_request( self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) simulation_ids_list = self._handler.handle_response_to_loadcase_simulations_request( ) if simulation_ids_list: simulations = [] for simulation_id in simulation_ids_list: simulations.append(Simulation(self._app_session, simulation_id)) return simulations return None
def set_description(self, description): response = self._sender.send_entity_base_info_request( self.identifier, self.entity_type.value) Timeout.hold_your_horses() self._handler.set_response(response) payload = self._handler.get_full_server_base_response() if isinstance(payload, dict) and "description" in payload.keys(): payload["description"] = str(description) response = self._sender.send_modify_simulation_request( self.identifier, payload) Timeout.hold_your_horses() self._handler.set_response(response) result = self._handler.handle_response_to_update_simulation_request( description=description) return result else: terminal.show_error_message( "No description found in server response") return None
def upload_new_submodel(self, *files, **params): if "stype" in params.keys(): stype = SubmodelType(self._app_session, params.get("stype")) else: stype = SubmodelType(self._app_session, self._app_session.cfg.server_storage) if "add_to_clipboard" in params.keys(): add_to_clipboard = "on" if bool(params.get("add_to_clipboard")) else "off" else: add_to_clipboard = "off" submodels = [] for file in files: response = self._sender.send_upload_submodel_request(file, stype.tree_id, add_to_clipboard) Timeout.hold_your_horses() self._handler.set_response(response) sumbodel_id = self._handler.handle_response_to_upload_submodel_request() if sumbodel_id: submodels.append(Submodel(self._app_session, sumbodel_id)) return submodels
def add_new_sumbodels(self, new_submodel_ids): # First, get list of current submodels response = self._sender.send_simulation_submodels_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) simulation_submodels_list = self._handler.handle_response_to_simulation_submodels_request() if not simulation_submodels_list: simulation_submodels_list = [] # Append new submodel to the list of existing submodels simulation_submodels_list.extend(new_submodel_ids) # Send request to update simulation submodels (that's how it works in CML-Bench) response = self._sender.send_simulation_submodels_update_request(self.identifier, simulation_submodels_list) Timeout.hold_your_horses() self._handler.set_response(response) simulation_submodels_list = self._handler.handle_response_to_simulation_submodels_request() if simulation_submodels_list: submodels = [] for submodel_id in simulation_submodels_list: submodels.append(Submodel(self._app_session, submodel_id)) return submodels return None
def download_files(self, *files): """ Download chosen files to local directory :param files: files to be downloaded :return: return list of successfully downloaded files """ list_of_downloaded_files = [] simulation_files = self.get_files() list_of_simulation_file_ids = [ item.get("id") for item in simulation_files ] list_of_simulation_file_names = [ item.get("name") for item in simulation_files ] for file in files: # check if fileName is in simulation files if file in list_of_simulation_file_names: file_id = list_of_simulation_file_ids[ list_of_simulation_file_names.index(file)] response = self._sender.send_download_file_request( self.identifier, file_id) Timeout.hold_your_horses() self._handler.set_response(response) file_content = self._handler.handle_response_to_download_file_request( ) if file_content and isinstance(file_content, bytes): with open(self._app_session.cfg.local_storage + "\\" + file, mode="wb") as f: f.write(file_content) list_of_downloaded_files.append(file) else: terminal.show_warning_message( "Selected file \"{}\" not in simulation files".format( file)) return list_of_downloaded_files
def run(self, **parameters): """ Run or post-process current simulation :param parameters: keywords for identify run or post-processor commands "exec" - type of solver or post-processor to be run "stb" - storyboard id for "exec = VBA" "bsi" - base simulation ID :return: created Task or None if error occurred """ params = {} if "exec" in parameters.keys(): executable = parameters.get("exec") if executable == "Nastran 2017": params = { "parentType": { "name": "simulation" }, "solverName": "Nastran 2017", "solvingType": "Solving", "parentId": self.identifier } if executable == "VBA": if "stb" in parameters.keys(): storyboard_id = parameters.get("stb") params = { "parentType": { "name": "simulation" }, "postprocessorName": "Microsoft Office Postprocessing", "type": "postprocessing", "parentId": self.identifier, "storyboardId": storyboard_id } else: terminal.show_error_message( "No storyboard selected. Cannot execute post-processor" ) else: if "bsi" in parameters.keys(): base_simulation_id = parameters.get("bsi") received_params = self.__get_defaults(base_simulation_id) else: received_params = self.__get_defaults() if received_params is None: terminal.show_error_message("Failed to run simulation") return None # Modify `parentId` and `parentName` keys # __get_defaults() may return these parameters from another simulation # remove unnecessary parameters params["objectType"] = received_params.get("objectType") params["parentName"] = self.name params["owner"] = received_params.get("owner") params["ownerId"] = received_params.get("ownerId") params["id"] = received_params.get("id") params["numOfCores"] = received_params.get("numOfCores") params["memory"] = received_params.get("memory") params["storyboard"] = received_params.get("storyboard") params["storyboardId"] = received_params.get("storyboardId") params["solverName"] = received_params.get("solverName") params["solverDisplayName"] = received_params.get( "solverDisplayName") params["clusterName"] = received_params.get("clusterName") params["solverGroup"] = received_params.get("solverGroup") params["type"] = received_params.get("type") params["typeDisplayName"] = received_params.get("typeDisplayName") params["solvingType"] = received_params.get("solvingType") params["notified"] = received_params.get("notified") params["startupArguments"] = received_params.get( "startupArguments") params["autoCreateReport"] = received_params.get( "autoCreateReport") params["withPostprocessing"] = received_params.get( "withPostprocessing") params["postprocessorName"] = received_params.get( "postprocessorName") params["parentType"] = received_params.get("parentType") params["parentId"] = self.identifier params["cluster"] = received_params.get("cluster") params["clusterId"] = received_params.get("clusterId") params["expectedSolvingTime"] = received_params.get( "expectedSolvingTime") # terminal.show_info_dict("Run request payload parameters:", params) response = self._sender.send_run_request(params) Timeout.hold_your_horses() self._handler.set_response(response) task_id = self._handler.handle_response_to_run_request() if task_id: return Task(self._app_session, task_id) return None
def upload_submodel(self, *files, **params): """ :param files: paths to files to be uploaded into current s|type :param params: response parameters; `stype` - ID of s|type for uploading submodels; optional; default is current s|type `add_to_clipboard` - optional boolean parameter; default is False :return: list of uploaded submodels """ # FIXME wtf??? create instance of SubmodelType inside its method if "stype" in params.keys(): stype = SubmodelType(self._app_session, params.get("stype")) else: # stype = SubmodelType(self._app_session, self._app_session.cfg.server_storage) stype = self if "add_to_clipboard" in params.keys(): add_to_clipboard = "on" if bool( params.get("add_to_clipboard")) else "off" else: add_to_clipboard = "off" submodels = [] for file in files: response = self._sender.send_upload_submodel_request( file, stype.tree_id, add_to_clipboard) Timeout.hold_your_horses() self._handler.set_response(response) result = self._handler.handle_response_to_upload_submodel_request() if result is not None: submodel_ids_to_delete = result["to_delete"] submodel_ids_for_simulation = result["to_insert"] if len(submodel_ids_to_delete) == 0: terminal.show_info_message( "Uploaded submodel id to use in simulation: {}", submodel_ids_for_simulation[0]) submodels.append( Submodel(self._app_session, submodel_ids_for_simulation[0])) else: terminal.show_warning_message( "Uploaded submodel duplicates already existing submodel" ) terminal.show_warning_message( "Created submodel with id {} will be deleted", submodel_ids_to_delete[0]) response = self._sender.send_delete_submodel_from_server_request( submodel_ids_to_delete[0]) Timeout.hold_your_horses() self._handler.set_response(response) _ = self._handler.handle_response_to_delete_submodel_from_server_request( ) terminal.show_warning_message("Duplicate was deleted") terminal.show_info_message( "Already existing submodel id to use in simulation: {}", submodel_ids_for_simulation[0]) submodels.append( Submodel(self._app_session, submodel_ids_for_simulation[0])) return submodels
def get_status(self): response = self._sender.send_healthcheck_request() Timeout.hold_your_horses() self._handler.set_response(response) state = self._handler.handle_response_to_healthcheck_request() return state
def _run_all_tasks(self): """ Processing input JSON with behaviour `Solve` Run all simulations in graph vertices. :return: """ if self.json_type != JSONTypes.SOLVE.value: raise ValueError( "Method `run_all_tasks()` can not be called for JSON of type `{}`" .format(self.json_type)) @method_info def status_based_behaviour(vertex): """ Define main loop behaviour while walking through vertex basing on vertex status :param vertex: vertex in workflow graph :return terminate_loop: magic integer value: -1: error occurred and main loop shall be stopped 0: current simulation is not done yet, continue 1: current simulation is done """ assert isinstance(vertex, Vertex) terminal.show_info_message("Processing vertex with ID: {}", vertex.identifier) # if status is "New", # - clone base simulation # - upload submodels # - run cloned (current vertex) simulation # - update vertex status from simulation task status if vertex.status == "New": terminal.show_info_message("Vertex status: {}", vertex.status) terminal.show_info_message("Vertex base simulation ID: {}", vertex.base_simulation.identifier) base_simulation = vertex.base_simulation terminal.show_info_message( "Trying to clone base simulation...") current_simulation = base_simulation.clone() terminal.show_info_message( "Modify current simulation description...") current_simulation.set_description(vertex.description) terminal.show_info_message( "Update vertex current simulation...") vertex.current_simulation = current_simulation if current_simulation: # if cloned successfully, upload submodels terminal.show_info_message( "Cloned simulation ID: {}", vertex.current_simulation.identifier) terminal.show_info_message( "Uploading submodels for current simulation...") stype = vertex.stype uploaded_submodels = stype.upload_submodel( *vertex.submodels) # uploaded_submodels_ids = [submodel.identifier for submodel in uploaded_submodels] terminal.show_info_message( "Erasing current (cloned) simulation submodels...") status = current_simulation.erase_submodels() if status: terminal.show_info_message("Done") else: terminal.show_error_message("Failed") _ = current_simulation.add_submodels(*uploaded_submodels) terminal.show_info_message( "{} submodels added for current simulations", len(uploaded_submodels)) # start with default parameters terminal.show_info_message( "Trying to run current simulation...") # obtain default parameters to run tasks from base simulation current_task = current_simulation.run( bsi=base_simulation.identifier) vertex.current_task = current_task if current_task: # if task created successfully, get status terminal.show_info_message( f"Created task ID: {vertex.current_task.identifier}" ) vertex.status = current_task.get_status() return 0 terminal.show_error_message("Task has not been created.") return -1 terminal.show_error_message("Simulation has not been cloned.") return -1 # if status is "Finished", # - download vertex results # - save status; when all vertices will have the same status, loop can be stopped elif vertex.status == "Finished": terminal.show_info_message("Vertex status: {}", vertex.status) if len(vertex.results) == 0: terminal.show_info_message( "No results selected for download") else: terminal.show_info_message("Downloading results...") current_simulation = vertex.current_simulation lst = current_simulation.download_files(*vertex.results) terminal.show_info_message( "Successfully downloaded {} files", len(lst)) return 1 # if status is "Failed", # - terminate main loop elif vertex.status in ["Failed", "failed", "Error", "error"]: terminal.show_warning_message("Vertex status: {}", vertex.status) return -1 # if status is unknown, # - update vertex status from simulation task status else: terminal.show_info_message("Updating vertex status...") current_task = vertex.current_task if current_task: current_status = current_task.get_status() vertex.status = current_status task_end_waiting, task_end_solving = current_task.get_time_estimation( ) terminal.show_info_message( "Current task estimated end waiting time: {}", task_end_waiting) terminal.show_info_message( "Current task estimated end solving time: {}", task_end_solving) terminal.show_info_message("Vertex status: {}", vertex.status) return 0 # --- main section --- main section --- main section --- main section --- main section --- main section --- stop_main_loop = False # list of graph vertices to iterate over it with possibility to modify it vertices = list(self.graph.vertices.values()) assert all(isinstance(v, Vertex) for v in vertices) # initialize dictionary for saving loop results rs = {key: 0 for key in [v.identifier for v in vertices]} # terminal.show_info_dict("Initial state of results storage", rs) s = "" vals = [] for k, v in rs.items(): s += terminal.get_blank() + "{} → {}\n" vals.append(k) vals.append(v) terminal.show_info_message("Initial state of results storage:\n" + s, *vals) # main loop - while all tasks are done or some failure occurred while not stop_main_loop: # iterate over all workflow graph vertices # remove vertices wish status = "Finished" # modify original list, no list copies, only one pass: traditional solution is to iterate backwards for i in reversed(range(len(vertices))): v = vertices[i] # check vertex links # if links list is empty, vertex is at root level and it's simulation can be started if len(v.links) == 0: terminal.show_info_message( "Vertex {} has no linked vertices", v.identifier) r = status_based_behaviour(v) terminal.show_info_message( "Current vertex result status: {}", r) rs[v.identifier] = r # terminal.show_info_message(f"Current state of the list of vertices results status: {str(rs)}") if r == -1: terminal.show_error_message( "Failed while processing vertex {}", v.identifier) # stop_main_loop = True break if r == 1: terminal.show_info_message("Vertex {} is done", v.identifier) del vertices[i] # else, if links list is not empty, else: terminal.show_info_message( "Vertex {} has {} linked vertices", v.identifier, len(v.links)) terminal.show_info_message( "Checking status of linked vertices...") # check status of all linked vertices if all(l.status == "Finished" for l in v.links): # if all parent vertices successfully finished, # current vertex can run terminal.show_info_message( "All linked vertices successfully finished") r = status_based_behaviour(v) terminal.show_info_message( "Current vertex result status: {}", r) rs[v.identifier] = r # terminal.show_info_message(f"Current state of the list of vertices results status: {str(rs)}") if r == -1: terminal.show_error_message( "Failed while processing vertex {}", v.identifier) # stop_main_loop = True break if r == 1: terminal.show_info_message("Vertex {} is done", v.identifier) del vertices[i] else: terminal.show_info_message( "Some linked vertices is not finished yet...") stop_main_loop = all(item == 1 for item in rs.values()) or any( item == -1 for item in rs.values()) # terminal.show_info_message(f"List of vertices results status: {str(rs)}") # terminal.show_info_dict("Current state of results storage", rs) s = "" vals = [] for k, v in rs.items(): s += terminal.get_blank() + "{} → {}\n" vals.append(k) vals.append(v) terminal.show_info_message( "Initial state of results storage:\n" + s, *vals) if not stop_main_loop: terminal.show_info_message( f"Waiting for the next loop ... [{WorkFlow.WALK_INTERVAL} sec]" ) Timeout.pause(WorkFlow.WALK_INTERVAL) else: terminal.show_info_message("Terminating main loop ...")
def get_status(self): response = self._sender.send_task_status_request(self.identifier) Timeout.hold_your_horses() self._handler.set_response(response) return self._handler.handle_response_to_task_status_response()