From 500ea50ca92c383546d23bc5b1de64e33ebc4870 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 25 Jul 2022 17:19:35 +0100 Subject: [PATCH 01/49] got the command server -> client --- codegen/allapigen.py | 8 +++++--- src/ansys/fluent/core/services/datamodel_se.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/codegen/allapigen.py b/codegen/allapigen.py index 90837cb39490..e352b853d47c 100644 --- a/codegen/allapigen.py +++ b/codegen/allapigen.py @@ -5,6 +5,8 @@ if __name__ == "__main__": print_fluent_version.generate() - tuigen.generate() - datamodelgen.generate() - settingsgen.generate() + for mod in (tuigen, datamodelgen, settingsgen): + try: + mod.generate() + except BaseException as ex: + print("skipping generation of", str(mod), str(ex)) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 140b25c0e552..93c44c8da863 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -104,6 +104,12 @@ def execute_command( ) -> DataModelProtoModule.ExecuteCommandResponse: return self.__stub.executeCommand(request, metadata=self.__metadata) + @catch_grpc_error + def create_command_arguments( + self, request: DataModelProtoModule.CreateCommandArgumentsRequest + ) -> DataModelProtoModule.CreateCommandArgumentsResponse: + return self.__stub.createCommandArguments(request, metadata=self.__metadata) + @catch_grpc_error def get_specs( self, request: DataModelProtoModule.GetSpecsRequest @@ -337,6 +343,14 @@ def rename(self, new_name: str) -> None: f"{self.__class__.__name__} is not a named object class." ) + def create_command_arguments(self, command): + request = DataModelProtoModule.CreateCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + request.command = command + response = self.service.create_command_arguments(request) + return response.commandid + class PyNamedObjectContainer: """Container class using StateEngine based DatamodelService as backend. Use From 111d575c3b253cb10b5f71cc7228beae699017a4 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 14:41:18 +0100 Subject: [PATCH 02/49] still got the command server -> client --- .../fluent/core/services/datamodel_se.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 93c44c8da863..c5f4442a92b0 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -516,10 +516,12 @@ def __init__( rules: str, command: str, path: Path = None, + id: str = None, ): self.service = service self.rules = rules self.command = command + self.id = id if path is None: self.path = [] else: @@ -553,6 +555,52 @@ def help(self) -> None: ).common.helpstring print(help_string) + def __getitem__(self, key: str): + assert self.id is None + new_cmd = PyCommand(self.service, self.rules, self.command, self.path, key) + return new_cmd + + def get_state(self) -> Any: + request = DataModelProtoModule.GetStateRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + response = self.service.get_state(request) + return _convert_variant_to_value(response.state) + + getState = get_state + + def set_state(self, state: Any) -> None: + request = DataModelProtoModule.SetStateRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + _convert_value_to_variant(state, request.state) + self.service.set_state(request) + + setState = set_state + + def get_attrib_value(self, attrib: str) -> Any: + """Get attribute value of the current object. + + Parameters + ---------- + attrib : str + attribute name + + Returns + ------- + Any + attribute value + """ + request = DataModelProtoModule.GetAttributeValueRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + request.attribute = attrib + response = self.service.get_attribute_value(request) + return _convert_variant_to_value(response.result) + class PyMenuGeneric(PyMenu): attrs = ("service", "rules", "path") From 52d87a32fb349fe2d00aa317a516e898aefc5d74 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 18:59:43 +0100 Subject: [PATCH 03/49] got the command server -> client --- .../fluent/core/services/datamodel_se.py | 151 ++++++++---------- 1 file changed, 63 insertions(+), 88 deletions(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index c5f4442a92b0..b0047fa434aa 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -198,14 +198,12 @@ def _convert_path_to_se_path(path: Path) -> str: return se_path -class PyMenu: +class PyBasicStateContainer: """Object class using StateEngine based DatamodelService as backend. Use this class instead of directly calling DatamodelService's method. Methods ------- - __setattr__(name, value) - Set state of the child object __call__() Get state of the current object get_attrib_value(attrib) @@ -221,21 +219,10 @@ class PyMenu: Set state of the current object setState(state) Set state of the current object (same as set_state(state)) - update_dict(dict_state) - Update the state of the current object if the current object - is a Dict in the data model, else throws RuntimeError - (currently not showing up in Python). Update is executed according - to dict.update semantics - updateDict(dict_state) - Update the state of the current object if the current object - is a Dict in the data model, else throws RuntimeError - (currently not showing up in Python). Update is executed according - to dict.update semantics (same as update_dict(dict_state)) """ - docstring = None - def __init__(self, service: DatamodelService, rules: str, path: Path = None): + super().__init__() self.service = service self.rules = rules if path is None: @@ -243,6 +230,8 @@ def __init__(self, service: DatamodelService, rules: str, path: Path = None): else: self.path = path + docstring = None + def get_state(self) -> Any: request = DataModelProtoModule.GetStateRequest() request.rules = self.rules @@ -261,30 +250,6 @@ def set_state(self, state: Any) -> None: setState = set_state - def update_dict(self, dict_state: Dict[str, Any]) -> None: - request = DataModelProtoModule.UpdateDictRequest() - request.rules = self.rules - request.path = _convert_path_to_se_path(self.path) - _convert_value_to_variant(dict_state, request.dicttomerge) - self.service.update_dict(request) - - updateDict = update_dict - - def __setattr__(self, name: str, value: Any): - """Set state of the child object. - - Parameters - ---------- - name : str - child object name - value : Any - state - """ - if hasattr(self, name) and isinstance(getattr(self, name), PyMenu): - getattr(self, name).set_state(value) - else: - super().__setattr__(name, value) - def __call__(self, *args, **kwds) -> Any: """Get state of the current object. @@ -328,6 +293,55 @@ def help(self) -> None: ).common.helpstring print(help_string) + +class PyMenu(PyBasicStateContainer): + """Object class using StateEngine based DatamodelService as backend. Use + this class instead of directly calling DatamodelService's method. + + Methods + ------- + __setattr__(name, value) + Set state of the child object + update_dict(dict_state) + Update the state of the current object if the current object + is a Dict in the data model, else throws RuntimeError + (currently not showing up in Python). Update is executed according + to dict.update semantics + updateDict(dict_state) + Update the state of the current object if the current object + is a Dict in the data model, else throws RuntimeError + (currently not showing up in Python). Update is executed according + to dict.update semantics (same as update_dict(dict_state)) + create_command_arguments(command) + """ + + def __init__(self, service: DatamodelService, rules: str, path: Path = None): + super().__init__(service, rules, path) + + def update_dict(self, dict_state: Dict[str, Any]) -> None: + request = DataModelProtoModule.UpdateDictRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + _convert_value_to_variant(dict_state, request.dicttomerge) + self.service.update_dict(request) + + updateDict = update_dict + + def __setattr__(self, name: str, value: Any): + """Set state of the child object. + + Parameters + ---------- + name : str + child object name + value : Any + state + """ + if hasattr(self, name) and isinstance(getattr(self, name), PyMenu): + getattr(self, name).set_state(value) + else: + super().__setattr__(name, value) + def rename(self, new_name: str) -> None: """Rename the named object. @@ -511,17 +525,11 @@ class PyCommand: docstring = None def __init__( - self, - service: DatamodelService, - rules: str, - command: str, - path: Path = None, - id: str = None, + self, service: DatamodelService, rules: str, command: str, path: Path = None ): self.service = service self.rules = rules self.command = command - self.id = id if path is None: self.path = [] else: @@ -556,50 +564,17 @@ def help(self) -> None: print(help_string) def __getitem__(self, key: str): - assert self.id is None - new_cmd = PyCommand(self.service, self.rules, self.command, self.path, key) - return new_cmd - - def get_state(self) -> Any: - request = DataModelProtoModule.GetStateRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - response = self.service.get_state(request) - return _convert_variant_to_value(response.state) - - getState = get_state + return PyCommandArguments( + self.service, self.rules, self.command, self.path.copy(), key + ) - def set_state(self, state: Any) -> None: - request = DataModelProtoModule.SetStateRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - _convert_value_to_variant(state, request.state) - self.service.set_state(request) - - setState = set_state - - def get_attrib_value(self, attrib: str) -> Any: - """Get attribute value of the current object. - - Parameters - ---------- - attrib : str - attribute name - Returns - ------- - Any - attribute value - """ - request = DataModelProtoModule.GetAttributeValueRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - request.attribute = attrib - response = self.service.get_attribute_value(request) - return _convert_variant_to_value(response.result) +class PyCommandArguments(PyBasicStateContainer): + def __init__( + self, service: DatamodelService, rules: str, command: str, path: Path, id: str + ): + super().__init__(service, rules, path) + self.path.append((command, id)) class PyMenuGeneric(PyMenu): From 9dd010f4e61d6e4289d4424fa000f1994e94532e Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 19:15:03 +0100 Subject: [PATCH 04/49] got the command server -> client --- .../fluent/core/services/datamodel_se.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index b0047fa434aa..2dce2044ebf7 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -357,14 +357,6 @@ def rename(self, new_name: str) -> None: f"{self.__class__.__name__} is not a named object class." ) - def create_command_arguments(self, command): - request = DataModelProtoModule.CreateCommandArgumentsRequest() - request.rules = self.rules - request.path = _convert_path_to_se_path(self.path) - request.command = command - response = self.service.create_command_arguments(request) - return response.commandid - class PyNamedObjectContainer: """Container class using StateEngine based DatamodelService as backend. Use @@ -563,9 +555,18 @@ def help(self) -> None: ).common.helpstring print(help_string) - def __getitem__(self, key: str): + def _create_command_arguments(self): + request = DataModelProtoModule.CreateCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + request.command = self.command + response = self.service.create_command_arguments(request) + return response.commandid + + def instance(self): + id = self._create_command_arguments() return PyCommandArguments( - self.service, self.rules, self.command, self.path.copy(), key + self.service, self.rules, self.command, self.path.copy(), id ) From c49e4d1bb8c29db15afbfc5f6e23e9660865555b Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 27 Jul 2022 17:13:31 +0100 Subject: [PATCH 05/49] got the command server -> client --- .../fluent/core/services/datamodel_se.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 2dce2044ebf7..632ca26d79f8 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -570,6 +570,39 @@ def instance(self): ) +class PyCommandArgumentsSubItem: + def __init__(self, parent, name: str): + self.parent = parent + self.name = name + + def __getattr__(self, attr): + return PyCommandArgumentsSubItem(self, attr) + + def get_state(self) -> Any: + parent_state = self.parent.get_state() + try: + return parent_state[self.name] + except KeyError: + pass + + getState = get_state + + def set_state(self, state: Any) -> None: + self.parent.set_state({self.name: state}) + + setState = set_state + + def __call__(self, *args, **kwds) -> Any: + return self.get_state() + + def get_attrib_value(self, attrib: str) -> Any: + attrib_path = f"{self.name}/{attrib}" + return self.parent.get_attrib_value(attrib_path) + + def help(self) -> None: + pass + + class PyCommandArguments(PyBasicStateContainer): def __init__( self, service: DatamodelService, rules: str, command: str, path: Path, id: str @@ -577,6 +610,9 @@ def __init__( super().__init__(service, rules, path) self.path.append((command, id)) + def __getattr__(self, attr): + return PyCommandArgumentsSubItem(self, attr) + class PyMenuGeneric(PyMenu): attrs = ("service", "rules", "path") From 220e47eb2bf33f655aa0cdb8a2e38445385d0f4b Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 28 Jul 2022 21:13:36 +0100 Subject: [PATCH 06/49] got the command server -> client --- src/ansys/fluent/core/services/datamodel_se.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 632ca26d79f8..267bec73fb14 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -563,7 +563,7 @@ def _create_command_arguments(self): response = self.service.create_command_arguments(request) return response.commandid - def instance(self): + def new(self): id = self._create_command_arguments() return PyCommandArguments( self.service, self.rules, self.command, self.path.copy(), id @@ -610,6 +610,14 @@ def __init__( super().__init__(service, rules, path) self.path.append((command, id)) + def __del__(self): + request = DataModelProtoModule.DeleteCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path[:-1]) + request.command = self.path[-1][0] + request.commandid = self.path[-1][1] + response = self.service.delete_command_arguments(request) + def __getattr__(self, attr): return PyCommandArgumentsSubItem(self, attr) From edd27fe8f3fad54c349e18923c20b0f37c423400 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 9 Aug 2022 19:18:36 +0100 Subject: [PATCH 07/49] safely delete cmd args --- src/ansys/fluent/core/services/datamodel_se.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 267bec73fb14..87506e977f2a 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -110,6 +110,12 @@ def create_command_arguments( ) -> DataModelProtoModule.CreateCommandArgumentsResponse: return self.__stub.createCommandArguments(request, metadata=self.__metadata) + @catch_grpc_error + def delete_command_arguments( + self, request: DataModelProtoModule.DeleteCommandArgumentsRequest + ) -> DataModelProtoModule.DeleteCommandArgumentsResponse: + return self.__stub.deleteCommandArguments(request, metadata=self.__metadata) + @catch_grpc_error def get_specs( self, request: DataModelProtoModule.GetSpecsRequest @@ -616,7 +622,11 @@ def __del__(self): request.path = _convert_path_to_se_path(self.path[:-1]) request.command = self.path[-1][0] request.commandid = self.path[-1][1] - response = self.service.delete_command_arguments(request) + try: + self.service.delete_command_arguments(request) + except ValueError: + # "Cannot invoke RPC on closed channel!" + pass def __getattr__(self, attr): return PyCommandArgumentsSubItem(self, attr) From 50c5fa70da49687897cee4d06bb966ba31548377 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 11:49:35 +0100 Subject: [PATCH 08/49] add MeshingWorkflow class --- src/ansys/fluent/core/meshing/workflow.py | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/ansys/fluent/core/meshing/workflow.py diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py new file mode 100644 index 000000000000..1669e0798f74 --- /dev/null +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -0,0 +1,53 @@ +def new_command_for_task(task, meshing): + class NewCommandError(Exception): + def __init__(self, task_name): + super().__init__(f"Could not create command for meshing task {task_name}") + + task_cmd_name = task.CommandName() + cmd_creator = getattr(meshing, task_cmd_name) + if cmd_creator: + new_cmd = cmd_creator.new() + if new_cmd: + return new_cmd + raise NewCommandError(task._name_()) + + +class MeshingWorkflow: + class Task: + class Arguments: + def __init__(self, task): + self._task = task + self._args = task.Arguments + + def __getattr__(self, attr): + return getattr(self._args, attr) + + def get_expanded_state(self): + return self._task.get_expanded_arg_state() + + def __init__(self, meshing, name): + self._workflow = meshing._workflow + self._meshing = meshing._meshing + self._task = self._workflow.TaskObject[name] + self._cmd = None + + def get_expanded_arg_state(self): + return self._command().get_state() + + def _command(self): + if not self._cmd: + self._cmd = new_command_for_task(self._task, self._meshing) + return self._cmd + + def __getattr__(self, attr): + return getattr(self._task, attr) + + def __init__(self, meshing): + self._workflow = meshing.workflow + self._meshing = meshing.meshing + + def task(self, name): + return MeshingWorkflow.Task(self, name) + + def __getattr__(self, attr): + return getattr(self._workflow, attr) From a45ecc6db3b2b05ed1f17572830d4dafb555f7a4 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 25 Jul 2022 17:19:35 +0100 Subject: [PATCH 09/49] got the command server -> client --- codegen/allapigen.py | 8 +++++--- src/ansys/fluent/core/services/datamodel_se.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/codegen/allapigen.py b/codegen/allapigen.py index 90837cb39490..e352b853d47c 100644 --- a/codegen/allapigen.py +++ b/codegen/allapigen.py @@ -5,6 +5,8 @@ if __name__ == "__main__": print_fluent_version.generate() - tuigen.generate() - datamodelgen.generate() - settingsgen.generate() + for mod in (tuigen, datamodelgen, settingsgen): + try: + mod.generate() + except BaseException as ex: + print("skipping generation of", str(mod), str(ex)) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index b026aa008a43..8c58f2737259 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -104,6 +104,12 @@ def execute_command( ) -> DataModelProtoModule.ExecuteCommandResponse: return self.__stub.executeCommand(request, metadata=self.__metadata) + @catch_grpc_error + def create_command_arguments( + self, request: DataModelProtoModule.CreateCommandArgumentsRequest + ) -> DataModelProtoModule.CreateCommandArgumentsResponse: + return self.__stub.createCommandArguments(request, metadata=self.__metadata) + @catch_grpc_error def get_specs( self, request: DataModelProtoModule.GetSpecsRequest @@ -343,6 +349,14 @@ def rename(self, new_name: str) -> None: f"{self.__class__.__name__} is not a named object class." ) + def create_command_arguments(self, command): + request = DataModelProtoModule.CreateCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + request.command = command + response = self.service.create_command_arguments(request) + return response.commandid + class PyNamedObjectContainer: """Container class using the StateEngine-based DatamodelService as the From 3aafa60c270041c6555c302aa0defea2c0c9cfac Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 14:41:18 +0100 Subject: [PATCH 10/49] still got the command server -> client --- .../fluent/core/services/datamodel_se.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 8c58f2737259..673e8a92d9c3 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -524,10 +524,12 @@ def __init__( rules: str, command: str, path: Path = None, + id: str = None, ): self.service = service self.rules = rules self.command = command + self.id = id if path is None: self.path = [] else: @@ -561,6 +563,52 @@ def help(self) -> None: ).common.helpstring print(help_string) + def __getitem__(self, key: str): + assert self.id is None + new_cmd = PyCommand(self.service, self.rules, self.command, self.path, key) + return new_cmd + + def get_state(self) -> Any: + request = DataModelProtoModule.GetStateRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + response = self.service.get_state(request) + return _convert_variant_to_value(response.state) + + getState = get_state + + def set_state(self, state: Any) -> None: + request = DataModelProtoModule.SetStateRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + _convert_value_to_variant(state, request.state) + self.service.set_state(request) + + setState = set_state + + def get_attrib_value(self, attrib: str) -> Any: + """Get attribute value of the current object. + + Parameters + ---------- + attrib : str + attribute name + + Returns + ------- + Any + attribute value + """ + request = DataModelProtoModule.GetAttributeValueRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + request.attribute = attrib + response = self.service.get_attribute_value(request) + return _convert_variant_to_value(response.result) + class PyMenuGeneric(PyMenu): attrs = ("service", "rules", "path") From c7b358e9d0a5099e5dbd17452a39b996476b975e Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 18:59:43 +0100 Subject: [PATCH 11/49] got the command server -> client --- src/ansys/fluent/core/meshing/workflow.py | 63 +++++++ .../fluent/core/services/datamodel_se.py | 161 ++++++++---------- 2 files changed, 130 insertions(+), 94 deletions(-) create mode 100644 src/ansys/fluent/core/meshing/workflow.py diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py new file mode 100644 index 000000000000..6e7b640169e0 --- /dev/null +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -0,0 +1,63 @@ + + +def new_command_for_task(task, meshing): + + class NewCommandError(Exception): + def __init__(self, task_name): + super().__init__( + f"Could not create command for meshing task {task_name}") + + + task_cmd_name = task.CommandName() + cmd_creator = getattr(meshing, task_cmd_name) + if cmd_creator: + new_cmd = cmd_creator.new() + if new_cmd: + return new_cmd + raise NewCommandError(task._name_()) + + +class MeshingWorkflow: + + class Task: + + class Arguments: + + def __init__(self, task): + self._task = task + self._args = task.Arguments + + def __getattr__(self, attr): + return getattr(self._args, attr) + + def get_expanded_state(self): + return self._task.get_expanded_arg_state() + + + def __init__(self, meshing, name): + self._workflow = meshing._workflow + self._meshing = meshing._meshing + self._task = self._workflow.TaskObject[name] + self._cmd = None + + def get_expanded_arg_state(self): + return self._command().get_state() + + def _command(self): + if not self._cmd: + self._cmd = new_command_for_task(self._task, self._meshing) + return self._cmd + + def __getattr__(self, attr): + return getattr(self._task, attr) + + + def __init__(self, meshing): + self._workflow = meshing.workflow + self._meshing = meshing.meshing + + def task(self, name): + return MeshingWorkflow.Task(self, name) + + def __getattr__(self, attr): + return getattr(self._workflow, attr) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 673e8a92d9c3..0ec5fd0140e2 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -198,15 +198,13 @@ def _convert_path_to_se_path(path: Path) -> str: return se_path -class PyMenu: - """Object class using the StateEngine-based DatamodelService as the - backend. Use this class instead of directly calling the DatamodelService's - method. + +class PyBasicStateContainer: + """Object class using StateEngine based DatamodelService as backend. Use + this class instead of directly calling DatamodelService's method. Methods ------- - __setattr__(name, value) - Set the state of the child object. __call__() Get the state of the current object. get_attrib_value(attrib) @@ -224,24 +222,11 @@ class PyMenu: set_state(state) Set the state of the current object. setState(state) - Set the state of the current object. (This method is the - same as the set_state(state) method.) - update_dict(dict_state) - Update the state of the current object if the current object - is a dictionary in the data model. Otherwise, throw a ``RuntimeError`` - (which is currently not showing up in Python). The update is - executed according to dict.update semantics. - updateDict(dict_state) - Update the state of the current object if the current object - is a dictionary in the data model. Otherwise, throw a ``RuntimeError`` - (which is currently not showing up in Python). The update is - executed according to dict.update semantics. (This method is - the same as the update_dict(dict_state) method.) + Set state of the current object (same as set_state(state)) """ - docstring = None - def __init__(self, service: DatamodelService, rules: str, path: Path = None): + super().__init__() self.service = service self.rules = rules if path is None: @@ -249,6 +234,8 @@ def __init__(self, service: DatamodelService, rules: str, path: Path = None): else: self.path = path + docstring = None + def get_state(self) -> Any: request = DataModelProtoModule.GetStateRequest() request.rules = self.rules @@ -267,30 +254,6 @@ def set_state(self, state: Any) -> None: setState = set_state - def update_dict(self, dict_state: Dict[str, Any]) -> None: - request = DataModelProtoModule.UpdateDictRequest() - request.rules = self.rules - request.path = _convert_path_to_se_path(self.path) - _convert_value_to_variant(dict_state, request.dicttomerge) - self.service.update_dict(request) - - updateDict = update_dict - - def __setattr__(self, name: str, value: Any): - """Set state of the child object. - - Parameters - ---------- - name : str - Name of the child object. - value : Any - State of the child object. - """ - if hasattr(self, name) and isinstance(getattr(self, name), PyMenu): - getattr(self, name).set_state(value) - else: - super().__setattr__(name, value) - def __call__(self, *args, **kwds) -> Any: """Get state of the current object. @@ -334,6 +297,55 @@ def help(self) -> None: ).common.helpstring print(help_string) + +class PyMenu(PyBasicStateContainer): + """Object class using StateEngine based DatamodelService as backend. Use + this class instead of directly calling DatamodelService's method. + + Methods + ------- + __setattr__(name, value) + Set state of the child object + update_dict(dict_state) + Update the state of the current object if the current object + is a Dict in the data model, else throws RuntimeError + (currently not showing up in Python). Update is executed according + to dict.update semantics + updateDict(dict_state) + Update the state of the current object if the current object + is a Dict in the data model, else throws RuntimeError + (currently not showing up in Python). Update is executed according + to dict.update semantics (same as update_dict(dict_state)) + create_command_arguments(command) + """ + + def __init__(self, service: DatamodelService, rules: str, path: Path = None): + super().__init__(service, rules, path) + + def update_dict(self, dict_state: Dict[str, Any]) -> None: + request = DataModelProtoModule.UpdateDictRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + _convert_value_to_variant(dict_state, request.dicttomerge) + self.service.update_dict(request) + + updateDict = update_dict + + def __setattr__(self, name: str, value: Any): + """Set state of the child object. + + Parameters + ---------- + name : str + child object name + value : Any + state + """ + if hasattr(self, name) and isinstance(getattr(self, name), PyMenu): + getattr(self, name).set_state(value) + else: + super().__setattr__(name, value) + def rename(self, new_name: str) -> None: """Rename the named object. @@ -519,17 +531,11 @@ class PyCommand: docstring = None def __init__( - self, - service: DatamodelService, - rules: str, - command: str, - path: Path = None, - id: str = None, + self, service: DatamodelService, rules: str, command: str, path: Path = None ): self.service = service self.rules = rules self.command = command - self.id = id if path is None: self.path = [] else: @@ -564,50 +570,17 @@ def help(self) -> None: print(help_string) def __getitem__(self, key: str): - assert self.id is None - new_cmd = PyCommand(self.service, self.rules, self.command, self.path, key) - return new_cmd - - def get_state(self) -> Any: - request = DataModelProtoModule.GetStateRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - response = self.service.get_state(request) - return _convert_variant_to_value(response.state) - - getState = get_state - - def set_state(self, state: Any) -> None: - request = DataModelProtoModule.SetStateRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - _convert_value_to_variant(state, request.state) - self.service.set_state(request) + return PyCommandArguments( + self.service, self.rules, self.command, self.path.copy(), key + ) - setState = set_state - - def get_attrib_value(self, attrib: str) -> Any: - """Get attribute value of the current object. - - Parameters - ---------- - attrib : str - attribute name - Returns - ------- - Any - attribute value - """ - request = DataModelProtoModule.GetAttributeValueRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - request.attribute = attrib - response = self.service.get_attribute_value(request) - return _convert_variant_to_value(response.result) +class PyCommandArguments(PyBasicStateContainer): + def __init__( + self, service: DatamodelService, rules: str, command: str, path: Path, id: str + ): + super().__init__(service, rules, path) + self.path.append((command, id)) class PyMenuGeneric(PyMenu): From 8f9b97c48285e0f5dc95ffda02fa13b0989fd687 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 19:15:03 +0100 Subject: [PATCH 12/49] got the command server -> client --- .../fluent/core/services/datamodel_se.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 0ec5fd0140e2..99ce7391e526 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -361,14 +361,6 @@ def rename(self, new_name: str) -> None: f"{self.__class__.__name__} is not a named object class." ) - def create_command_arguments(self, command): - request = DataModelProtoModule.CreateCommandArgumentsRequest() - request.rules = self.rules - request.path = _convert_path_to_se_path(self.path) - request.command = command - response = self.service.create_command_arguments(request) - return response.commandid - class PyNamedObjectContainer: """Container class using the StateEngine-based DatamodelService as the @@ -569,9 +561,18 @@ def help(self) -> None: ).common.helpstring print(help_string) - def __getitem__(self, key: str): + def _create_command_arguments(self): + request = DataModelProtoModule.CreateCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + request.command = self.command + response = self.service.create_command_arguments(request) + return response.commandid + + def instance(self): + id = self._create_command_arguments() return PyCommandArguments( - self.service, self.rules, self.command, self.path.copy(), key + self.service, self.rules, self.command, self.path.copy(), id ) From 7c1635f049c48a0fc6109e211f4def741e75ec7b Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 27 Jul 2022 17:13:31 +0100 Subject: [PATCH 13/49] got the command server -> client --- .../fluent/core/services/datamodel_se.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 99ce7391e526..ac5fba43eed7 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -576,6 +576,39 @@ def instance(self): ) +class PyCommandArgumentsSubItem: + def __init__(self, parent, name: str): + self.parent = parent + self.name = name + + def __getattr__(self, attr): + return PyCommandArgumentsSubItem(self, attr) + + def get_state(self) -> Any: + parent_state = self.parent.get_state() + try: + return parent_state[self.name] + except KeyError: + pass + + getState = get_state + + def set_state(self, state: Any) -> None: + self.parent.set_state({self.name: state}) + + setState = set_state + + def __call__(self, *args, **kwds) -> Any: + return self.get_state() + + def get_attrib_value(self, attrib: str) -> Any: + attrib_path = f"{self.name}/{attrib}" + return self.parent.get_attrib_value(attrib_path) + + def help(self) -> None: + pass + + class PyCommandArguments(PyBasicStateContainer): def __init__( self, service: DatamodelService, rules: str, command: str, path: Path, id: str @@ -583,6 +616,9 @@ def __init__( super().__init__(service, rules, path) self.path.append((command, id)) + def __getattr__(self, attr): + return PyCommandArgumentsSubItem(self, attr) + class PyMenuGeneric(PyMenu): attrs = ("service", "rules", "path") From 7807d590733781332933a756f4c7d6380aff33c5 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 28 Jul 2022 21:13:36 +0100 Subject: [PATCH 14/49] got the command server -> client --- src/ansys/fluent/core/services/datamodel_se.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index ac5fba43eed7..a37e48c31997 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -569,7 +569,7 @@ def _create_command_arguments(self): response = self.service.create_command_arguments(request) return response.commandid - def instance(self): + def new(self): id = self._create_command_arguments() return PyCommandArguments( self.service, self.rules, self.command, self.path.copy(), id @@ -616,6 +616,14 @@ def __init__( super().__init__(service, rules, path) self.path.append((command, id)) + def __del__(self): + request = DataModelProtoModule.DeleteCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path[:-1]) + request.command = self.path[-1][0] + request.commandid = self.path[-1][1] + response = self.service.delete_command_arguments(request) + def __getattr__(self, attr): return PyCommandArgumentsSubItem(self, attr) From b7a7dde35e166e2e07a46a72a1c0e68870d5c39e Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 9 Aug 2022 19:18:36 +0100 Subject: [PATCH 15/49] safely delete cmd args --- src/ansys/fluent/core/services/datamodel_se.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index a37e48c31997..e8ce11baff00 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -110,6 +110,12 @@ def create_command_arguments( ) -> DataModelProtoModule.CreateCommandArgumentsResponse: return self.__stub.createCommandArguments(request, metadata=self.__metadata) + @catch_grpc_error + def delete_command_arguments( + self, request: DataModelProtoModule.DeleteCommandArgumentsRequest + ) -> DataModelProtoModule.DeleteCommandArgumentsResponse: + return self.__stub.deleteCommandArguments(request, metadata=self.__metadata) + @catch_grpc_error def get_specs( self, request: DataModelProtoModule.GetSpecsRequest @@ -622,7 +628,11 @@ def __del__(self): request.path = _convert_path_to_se_path(self.path[:-1]) request.command = self.path[-1][0] request.commandid = self.path[-1][1] - response = self.service.delete_command_arguments(request) + try: + self.service.delete_command_arguments(request) + except ValueError: + # "Cannot invoke RPC on closed channel!" + pass def __getattr__(self, attr): return PyCommandArgumentsSubItem(self, attr) From cabfafe5f396ade3bd74ed945c9900af05bb7e3e Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 12:37:51 +0100 Subject: [PATCH 16/49] update meshing workflow class --- src/ansys/fluent/core/meshing/workflow.py | 19 +++++-------------- .../fluent/core/services/datamodel_se.py | 1 - 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index 6e7b640169e0..914e42ab1fac 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -1,12 +1,7 @@ - - def new_command_for_task(task, meshing): - class NewCommandError(Exception): def __init__(self, task_name): - super().__init__( - f"Could not create command for meshing task {task_name}") - + super().__init__(f"Could not create command for meshing task {task_name}") task_cmd_name = task.CommandName() cmd_creator = getattr(meshing, task_cmd_name) @@ -18,27 +13,24 @@ def __init__(self, task_name): class MeshingWorkflow: - class Task: - - class Arguments: - + class Args: def __init__(self, task): self._task = task self._args = task.Arguments - + def __getattr__(self, attr): return getattr(self._args, attr) def get_expanded_state(self): return self._task.get_expanded_arg_state() - def __init__(self, meshing, name): self._workflow = meshing._workflow self._meshing = meshing._meshing self._task = self._workflow.TaskObject[name] self._cmd = None + self.Arguments = MeshingWorkflow.Task.Args(self) def get_expanded_arg_state(self): return self._command().get_state() @@ -51,13 +43,12 @@ def _command(self): def __getattr__(self, attr): return getattr(self._task, attr) - def __init__(self, meshing): self._workflow = meshing.workflow self._meshing = meshing.meshing def task(self, name): return MeshingWorkflow.Task(self, name) - + def __getattr__(self, attr): return getattr(self._workflow, attr) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index e8ce11baff00..e24ba0ddfa21 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -204,7 +204,6 @@ def _convert_path_to_se_path(path: Path) -> str: return se_path - class PyBasicStateContainer: """Object class using StateEngine based DatamodelService as backend. Use this class instead of directly calling DatamodelService's method. From 0fe8348c1e9bc450dd0d3c098eb7cdd68e99cc61 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 15:04:30 +0100 Subject: [PATCH 17/49] workflow class is working --- src/ansys/fluent/core/meshing/workflow.py | 16 +++++++--- .../fluent/core/services/datamodel_se.py | 32 +++++++++---------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index 914e42ab1fac..a1976d2caa24 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -1,4 +1,7 @@ -def new_command_for_task(task, meshing): +from ansys.fluent.core.services.datamodel_se import PyCallableStateObject + + +def _new_command_for_task(task, meshing): class NewCommandError(Exception): def __init__(self, task_name): super().__init__(f"Could not create command for meshing task {task_name}") @@ -13,8 +16,8 @@ def __init__(self, task_name): class MeshingWorkflow: - class Task: - class Args: + class Task(PyCallableStateObject): + class Args(PyCallableStateObject): def __init__(self, task): self._task = task self._args = task.Arguments @@ -33,11 +36,14 @@ def __init__(self, meshing, name): self.Arguments = MeshingWorkflow.Task.Args(self) def get_expanded_arg_state(self): - return self._command().get_state() + task_arg_state = self.Arguments.get_state() + cmd = self._command() + cmd.set_state(task_arg_state) + return cmd.get_state() def _command(self): if not self._cmd: - self._cmd = new_command_for_task(self._task, self._meshing) + self._cmd = _new_command_for_task(self._task, self._meshing) return self._cmd def __getattr__(self, attr): diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index e24ba0ddfa21..9811080c7abf 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -204,14 +204,25 @@ def _convert_path_to_se_path(path: Path) -> str: return se_path -class PyBasicStateContainer: - """Object class using StateEngine based DatamodelService as backend. Use - this class instead of directly calling DatamodelService's method. +class PyCallableStateObject: + """Any object which can be called to get its state. Methods ------- __call__() Get the state of the current object. + """ + + def __call__(self, *args, **kwds) -> Any: + return self.get_state() + + +class PyBasicStateContainer(PyCallableStateObject): + """Object class using StateEngine based DatamodelService as backend. Use + this class instead of directly calling DatamodelService's method. + + Methods + ------- get_attrib_value(attrib) Get the attribute value of the current object. getAttribValue(attrib) @@ -259,16 +270,6 @@ def set_state(self, state: Any) -> None: setState = set_state - def __call__(self, *args, **kwds) -> Any: - """Get state of the current object. - - Returns - ------- - Any - State of the object. - """ - return self.get_state() - def get_attrib_value(self, attrib: str) -> Any: """Get attribute value of the current object. @@ -581,7 +582,7 @@ def new(self): ) -class PyCommandArgumentsSubItem: +class PyCommandArgumentsSubItem(PyCallableStateObject): def __init__(self, parent, name: str): self.parent = parent self.name = name @@ -603,9 +604,6 @@ def set_state(self, state: Any) -> None: setState = set_state - def __call__(self, *args, **kwds) -> Any: - return self.get_state() - def get_attrib_value(self, attrib: str) -> Any: attrib_path = f"{self.name}/{attrib}" return self.parent.get_attrib_value(attrib_path) From fb33c1ee76155766a76d1d3da918a06944ba0c0c Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 25 Jul 2022 17:19:35 +0100 Subject: [PATCH 18/49] got the command server -> client --- codegen/allapigen.py | 8 +++++--- src/ansys/fluent/core/services/datamodel_se.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/codegen/allapigen.py b/codegen/allapigen.py index 90837cb39490..e352b853d47c 100644 --- a/codegen/allapigen.py +++ b/codegen/allapigen.py @@ -5,6 +5,8 @@ if __name__ == "__main__": print_fluent_version.generate() - tuigen.generate() - datamodelgen.generate() - settingsgen.generate() + for mod in (tuigen, datamodelgen, settingsgen): + try: + mod.generate() + except BaseException as ex: + print("skipping generation of", str(mod), str(ex)) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index b026aa008a43..8c58f2737259 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -104,6 +104,12 @@ def execute_command( ) -> DataModelProtoModule.ExecuteCommandResponse: return self.__stub.executeCommand(request, metadata=self.__metadata) + @catch_grpc_error + def create_command_arguments( + self, request: DataModelProtoModule.CreateCommandArgumentsRequest + ) -> DataModelProtoModule.CreateCommandArgumentsResponse: + return self.__stub.createCommandArguments(request, metadata=self.__metadata) + @catch_grpc_error def get_specs( self, request: DataModelProtoModule.GetSpecsRequest @@ -343,6 +349,14 @@ def rename(self, new_name: str) -> None: f"{self.__class__.__name__} is not a named object class." ) + def create_command_arguments(self, command): + request = DataModelProtoModule.CreateCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + request.command = command + response = self.service.create_command_arguments(request) + return response.commandid + class PyNamedObjectContainer: """Container class using the StateEngine-based DatamodelService as the From c8d799fed5e5b6a6e6e432bb44ec3f3b89abf9a6 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 14:41:18 +0100 Subject: [PATCH 19/49] still got the command server -> client --- .../fluent/core/services/datamodel_se.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 8c58f2737259..673e8a92d9c3 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -524,10 +524,12 @@ def __init__( rules: str, command: str, path: Path = None, + id: str = None, ): self.service = service self.rules = rules self.command = command + self.id = id if path is None: self.path = [] else: @@ -561,6 +563,52 @@ def help(self) -> None: ).common.helpstring print(help_string) + def __getitem__(self, key: str): + assert self.id is None + new_cmd = PyCommand(self.service, self.rules, self.command, self.path, key) + return new_cmd + + def get_state(self) -> Any: + request = DataModelProtoModule.GetStateRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + response = self.service.get_state(request) + return _convert_variant_to_value(response.state) + + getState = get_state + + def set_state(self, state: Any) -> None: + request = DataModelProtoModule.SetStateRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + _convert_value_to_variant(state, request.state) + self.service.set_state(request) + + setState = set_state + + def get_attrib_value(self, attrib: str) -> Any: + """Get attribute value of the current object. + + Parameters + ---------- + attrib : str + attribute name + + Returns + ------- + Any + attribute value + """ + request = DataModelProtoModule.GetAttributeValueRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + request.attribute = attrib + response = self.service.get_attribute_value(request) + return _convert_variant_to_value(response.result) + class PyMenuGeneric(PyMenu): attrs = ("service", "rules", "path") From da5a49ecdc894faa25c0e7bf43d46a08d7a998fa Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 18:59:43 +0100 Subject: [PATCH 20/49] got the command server -> client --- src/ansys/fluent/core/meshing/workflow.py | 63 +++++++ .../fluent/core/services/datamodel_se.py | 161 ++++++++---------- 2 files changed, 130 insertions(+), 94 deletions(-) create mode 100644 src/ansys/fluent/core/meshing/workflow.py diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py new file mode 100644 index 000000000000..6e7b640169e0 --- /dev/null +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -0,0 +1,63 @@ + + +def new_command_for_task(task, meshing): + + class NewCommandError(Exception): + def __init__(self, task_name): + super().__init__( + f"Could not create command for meshing task {task_name}") + + + task_cmd_name = task.CommandName() + cmd_creator = getattr(meshing, task_cmd_name) + if cmd_creator: + new_cmd = cmd_creator.new() + if new_cmd: + return new_cmd + raise NewCommandError(task._name_()) + + +class MeshingWorkflow: + + class Task: + + class Arguments: + + def __init__(self, task): + self._task = task + self._args = task.Arguments + + def __getattr__(self, attr): + return getattr(self._args, attr) + + def get_expanded_state(self): + return self._task.get_expanded_arg_state() + + + def __init__(self, meshing, name): + self._workflow = meshing._workflow + self._meshing = meshing._meshing + self._task = self._workflow.TaskObject[name] + self._cmd = None + + def get_expanded_arg_state(self): + return self._command().get_state() + + def _command(self): + if not self._cmd: + self._cmd = new_command_for_task(self._task, self._meshing) + return self._cmd + + def __getattr__(self, attr): + return getattr(self._task, attr) + + + def __init__(self, meshing): + self._workflow = meshing.workflow + self._meshing = meshing.meshing + + def task(self, name): + return MeshingWorkflow.Task(self, name) + + def __getattr__(self, attr): + return getattr(self._workflow, attr) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 673e8a92d9c3..0ec5fd0140e2 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -198,15 +198,13 @@ def _convert_path_to_se_path(path: Path) -> str: return se_path -class PyMenu: - """Object class using the StateEngine-based DatamodelService as the - backend. Use this class instead of directly calling the DatamodelService's - method. + +class PyBasicStateContainer: + """Object class using StateEngine based DatamodelService as backend. Use + this class instead of directly calling DatamodelService's method. Methods ------- - __setattr__(name, value) - Set the state of the child object. __call__() Get the state of the current object. get_attrib_value(attrib) @@ -224,24 +222,11 @@ class PyMenu: set_state(state) Set the state of the current object. setState(state) - Set the state of the current object. (This method is the - same as the set_state(state) method.) - update_dict(dict_state) - Update the state of the current object if the current object - is a dictionary in the data model. Otherwise, throw a ``RuntimeError`` - (which is currently not showing up in Python). The update is - executed according to dict.update semantics. - updateDict(dict_state) - Update the state of the current object if the current object - is a dictionary in the data model. Otherwise, throw a ``RuntimeError`` - (which is currently not showing up in Python). The update is - executed according to dict.update semantics. (This method is - the same as the update_dict(dict_state) method.) + Set state of the current object (same as set_state(state)) """ - docstring = None - def __init__(self, service: DatamodelService, rules: str, path: Path = None): + super().__init__() self.service = service self.rules = rules if path is None: @@ -249,6 +234,8 @@ def __init__(self, service: DatamodelService, rules: str, path: Path = None): else: self.path = path + docstring = None + def get_state(self) -> Any: request = DataModelProtoModule.GetStateRequest() request.rules = self.rules @@ -267,30 +254,6 @@ def set_state(self, state: Any) -> None: setState = set_state - def update_dict(self, dict_state: Dict[str, Any]) -> None: - request = DataModelProtoModule.UpdateDictRequest() - request.rules = self.rules - request.path = _convert_path_to_se_path(self.path) - _convert_value_to_variant(dict_state, request.dicttomerge) - self.service.update_dict(request) - - updateDict = update_dict - - def __setattr__(self, name: str, value: Any): - """Set state of the child object. - - Parameters - ---------- - name : str - Name of the child object. - value : Any - State of the child object. - """ - if hasattr(self, name) and isinstance(getattr(self, name), PyMenu): - getattr(self, name).set_state(value) - else: - super().__setattr__(name, value) - def __call__(self, *args, **kwds) -> Any: """Get state of the current object. @@ -334,6 +297,55 @@ def help(self) -> None: ).common.helpstring print(help_string) + +class PyMenu(PyBasicStateContainer): + """Object class using StateEngine based DatamodelService as backend. Use + this class instead of directly calling DatamodelService's method. + + Methods + ------- + __setattr__(name, value) + Set state of the child object + update_dict(dict_state) + Update the state of the current object if the current object + is a Dict in the data model, else throws RuntimeError + (currently not showing up in Python). Update is executed according + to dict.update semantics + updateDict(dict_state) + Update the state of the current object if the current object + is a Dict in the data model, else throws RuntimeError + (currently not showing up in Python). Update is executed according + to dict.update semantics (same as update_dict(dict_state)) + create_command_arguments(command) + """ + + def __init__(self, service: DatamodelService, rules: str, path: Path = None): + super().__init__(service, rules, path) + + def update_dict(self, dict_state: Dict[str, Any]) -> None: + request = DataModelProtoModule.UpdateDictRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + _convert_value_to_variant(dict_state, request.dicttomerge) + self.service.update_dict(request) + + updateDict = update_dict + + def __setattr__(self, name: str, value: Any): + """Set state of the child object. + + Parameters + ---------- + name : str + child object name + value : Any + state + """ + if hasattr(self, name) and isinstance(getattr(self, name), PyMenu): + getattr(self, name).set_state(value) + else: + super().__setattr__(name, value) + def rename(self, new_name: str) -> None: """Rename the named object. @@ -519,17 +531,11 @@ class PyCommand: docstring = None def __init__( - self, - service: DatamodelService, - rules: str, - command: str, - path: Path = None, - id: str = None, + self, service: DatamodelService, rules: str, command: str, path: Path = None ): self.service = service self.rules = rules self.command = command - self.id = id if path is None: self.path = [] else: @@ -564,50 +570,17 @@ def help(self) -> None: print(help_string) def __getitem__(self, key: str): - assert self.id is None - new_cmd = PyCommand(self.service, self.rules, self.command, self.path, key) - return new_cmd - - def get_state(self) -> Any: - request = DataModelProtoModule.GetStateRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - response = self.service.get_state(request) - return _convert_variant_to_value(response.state) - - getState = get_state - - def set_state(self, state: Any) -> None: - request = DataModelProtoModule.SetStateRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - _convert_value_to_variant(state, request.state) - self.service.set_state(request) + return PyCommandArguments( + self.service, self.rules, self.command, self.path.copy(), key + ) - setState = set_state - - def get_attrib_value(self, attrib: str) -> Any: - """Get attribute value of the current object. - - Parameters - ---------- - attrib : str - attribute name - Returns - ------- - Any - attribute value - """ - request = DataModelProtoModule.GetAttributeValueRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - request.attribute = attrib - response = self.service.get_attribute_value(request) - return _convert_variant_to_value(response.result) +class PyCommandArguments(PyBasicStateContainer): + def __init__( + self, service: DatamodelService, rules: str, command: str, path: Path, id: str + ): + super().__init__(service, rules, path) + self.path.append((command, id)) class PyMenuGeneric(PyMenu): From ae3b9f14b4faa9c86b4c431918637457237fe292 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 19:15:03 +0100 Subject: [PATCH 21/49] got the command server -> client --- .../fluent/core/services/datamodel_se.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 0ec5fd0140e2..99ce7391e526 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -361,14 +361,6 @@ def rename(self, new_name: str) -> None: f"{self.__class__.__name__} is not a named object class." ) - def create_command_arguments(self, command): - request = DataModelProtoModule.CreateCommandArgumentsRequest() - request.rules = self.rules - request.path = _convert_path_to_se_path(self.path) - request.command = command - response = self.service.create_command_arguments(request) - return response.commandid - class PyNamedObjectContainer: """Container class using the StateEngine-based DatamodelService as the @@ -569,9 +561,18 @@ def help(self) -> None: ).common.helpstring print(help_string) - def __getitem__(self, key: str): + def _create_command_arguments(self): + request = DataModelProtoModule.CreateCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + request.command = self.command + response = self.service.create_command_arguments(request) + return response.commandid + + def instance(self): + id = self._create_command_arguments() return PyCommandArguments( - self.service, self.rules, self.command, self.path.copy(), key + self.service, self.rules, self.command, self.path.copy(), id ) From 7a5e409d179b87ee3b2b31ae2eb5965faecc6877 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 27 Jul 2022 17:13:31 +0100 Subject: [PATCH 22/49] got the command server -> client --- .../fluent/core/services/datamodel_se.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 99ce7391e526..ac5fba43eed7 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -576,6 +576,39 @@ def instance(self): ) +class PyCommandArgumentsSubItem: + def __init__(self, parent, name: str): + self.parent = parent + self.name = name + + def __getattr__(self, attr): + return PyCommandArgumentsSubItem(self, attr) + + def get_state(self) -> Any: + parent_state = self.parent.get_state() + try: + return parent_state[self.name] + except KeyError: + pass + + getState = get_state + + def set_state(self, state: Any) -> None: + self.parent.set_state({self.name: state}) + + setState = set_state + + def __call__(self, *args, **kwds) -> Any: + return self.get_state() + + def get_attrib_value(self, attrib: str) -> Any: + attrib_path = f"{self.name}/{attrib}" + return self.parent.get_attrib_value(attrib_path) + + def help(self) -> None: + pass + + class PyCommandArguments(PyBasicStateContainer): def __init__( self, service: DatamodelService, rules: str, command: str, path: Path, id: str @@ -583,6 +616,9 @@ def __init__( super().__init__(service, rules, path) self.path.append((command, id)) + def __getattr__(self, attr): + return PyCommandArgumentsSubItem(self, attr) + class PyMenuGeneric(PyMenu): attrs = ("service", "rules", "path") From 869967980da0315092b3f9456671cf0b1296dc48 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 28 Jul 2022 21:13:36 +0100 Subject: [PATCH 23/49] got the command server -> client --- src/ansys/fluent/core/services/datamodel_se.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index ac5fba43eed7..a37e48c31997 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -569,7 +569,7 @@ def _create_command_arguments(self): response = self.service.create_command_arguments(request) return response.commandid - def instance(self): + def new(self): id = self._create_command_arguments() return PyCommandArguments( self.service, self.rules, self.command, self.path.copy(), id @@ -616,6 +616,14 @@ def __init__( super().__init__(service, rules, path) self.path.append((command, id)) + def __del__(self): + request = DataModelProtoModule.DeleteCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path[:-1]) + request.command = self.path[-1][0] + request.commandid = self.path[-1][1] + response = self.service.delete_command_arguments(request) + def __getattr__(self, attr): return PyCommandArgumentsSubItem(self, attr) From c5816e43ffd2a6347eefe4893f5850989bb8e556 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 9 Aug 2022 19:18:36 +0100 Subject: [PATCH 24/49] safely delete cmd args --- src/ansys/fluent/core/services/datamodel_se.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index a37e48c31997..e8ce11baff00 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -110,6 +110,12 @@ def create_command_arguments( ) -> DataModelProtoModule.CreateCommandArgumentsResponse: return self.__stub.createCommandArguments(request, metadata=self.__metadata) + @catch_grpc_error + def delete_command_arguments( + self, request: DataModelProtoModule.DeleteCommandArgumentsRequest + ) -> DataModelProtoModule.DeleteCommandArgumentsResponse: + return self.__stub.deleteCommandArguments(request, metadata=self.__metadata) + @catch_grpc_error def get_specs( self, request: DataModelProtoModule.GetSpecsRequest @@ -622,7 +628,11 @@ def __del__(self): request.path = _convert_path_to_se_path(self.path[:-1]) request.command = self.path[-1][0] request.commandid = self.path[-1][1] - response = self.service.delete_command_arguments(request) + try: + self.service.delete_command_arguments(request) + except ValueError: + # "Cannot invoke RPC on closed channel!" + pass def __getattr__(self, attr): return PyCommandArgumentsSubItem(self, attr) From ad742015fa7c588c4e34cb122aa6cb38e2cd58b3 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 12:37:51 +0100 Subject: [PATCH 25/49] update meshing workflow class --- src/ansys/fluent/core/meshing/workflow.py | 19 +++++-------------- .../fluent/core/services/datamodel_se.py | 1 - 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index 6e7b640169e0..914e42ab1fac 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -1,12 +1,7 @@ - - def new_command_for_task(task, meshing): - class NewCommandError(Exception): def __init__(self, task_name): - super().__init__( - f"Could not create command for meshing task {task_name}") - + super().__init__(f"Could not create command for meshing task {task_name}") task_cmd_name = task.CommandName() cmd_creator = getattr(meshing, task_cmd_name) @@ -18,27 +13,24 @@ def __init__(self, task_name): class MeshingWorkflow: - class Task: - - class Arguments: - + class Args: def __init__(self, task): self._task = task self._args = task.Arguments - + def __getattr__(self, attr): return getattr(self._args, attr) def get_expanded_state(self): return self._task.get_expanded_arg_state() - def __init__(self, meshing, name): self._workflow = meshing._workflow self._meshing = meshing._meshing self._task = self._workflow.TaskObject[name] self._cmd = None + self.Arguments = MeshingWorkflow.Task.Args(self) def get_expanded_arg_state(self): return self._command().get_state() @@ -51,13 +43,12 @@ def _command(self): def __getattr__(self, attr): return getattr(self._task, attr) - def __init__(self, meshing): self._workflow = meshing.workflow self._meshing = meshing.meshing def task(self, name): return MeshingWorkflow.Task(self, name) - + def __getattr__(self, attr): return getattr(self._workflow, attr) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index e8ce11baff00..e24ba0ddfa21 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -204,7 +204,6 @@ def _convert_path_to_se_path(path: Path) -> str: return se_path - class PyBasicStateContainer: """Object class using StateEngine based DatamodelService as backend. Use this class instead of directly calling DatamodelService's method. From 82b80a40f63c1aaaafda1278c74728eeb6085003 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 15:04:30 +0100 Subject: [PATCH 26/49] workflow class is working --- src/ansys/fluent/core/meshing/workflow.py | 16 +++++++--- .../fluent/core/services/datamodel_se.py | 32 +++++++++---------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index 914e42ab1fac..a1976d2caa24 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -1,4 +1,7 @@ -def new_command_for_task(task, meshing): +from ansys.fluent.core.services.datamodel_se import PyCallableStateObject + + +def _new_command_for_task(task, meshing): class NewCommandError(Exception): def __init__(self, task_name): super().__init__(f"Could not create command for meshing task {task_name}") @@ -13,8 +16,8 @@ def __init__(self, task_name): class MeshingWorkflow: - class Task: - class Args: + class Task(PyCallableStateObject): + class Args(PyCallableStateObject): def __init__(self, task): self._task = task self._args = task.Arguments @@ -33,11 +36,14 @@ def __init__(self, meshing, name): self.Arguments = MeshingWorkflow.Task.Args(self) def get_expanded_arg_state(self): - return self._command().get_state() + task_arg_state = self.Arguments.get_state() + cmd = self._command() + cmd.set_state(task_arg_state) + return cmd.get_state() def _command(self): if not self._cmd: - self._cmd = new_command_for_task(self._task, self._meshing) + self._cmd = _new_command_for_task(self._task, self._meshing) return self._cmd def __getattr__(self, attr): diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index e24ba0ddfa21..9811080c7abf 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -204,14 +204,25 @@ def _convert_path_to_se_path(path: Path) -> str: return se_path -class PyBasicStateContainer: - """Object class using StateEngine based DatamodelService as backend. Use - this class instead of directly calling DatamodelService's method. +class PyCallableStateObject: + """Any object which can be called to get its state. Methods ------- __call__() Get the state of the current object. + """ + + def __call__(self, *args, **kwds) -> Any: + return self.get_state() + + +class PyBasicStateContainer(PyCallableStateObject): + """Object class using StateEngine based DatamodelService as backend. Use + this class instead of directly calling DatamodelService's method. + + Methods + ------- get_attrib_value(attrib) Get the attribute value of the current object. getAttribValue(attrib) @@ -259,16 +270,6 @@ def set_state(self, state: Any) -> None: setState = set_state - def __call__(self, *args, **kwds) -> Any: - """Get state of the current object. - - Returns - ------- - Any - State of the object. - """ - return self.get_state() - def get_attrib_value(self, attrib: str) -> Any: """Get attribute value of the current object. @@ -581,7 +582,7 @@ def new(self): ) -class PyCommandArgumentsSubItem: +class PyCommandArgumentsSubItem(PyCallableStateObject): def __init__(self, parent, name: str): self.parent = parent self.name = name @@ -603,9 +604,6 @@ def set_state(self, state: Any) -> None: setState = set_state - def __call__(self, *args, **kwds) -> Any: - return self.get_state() - def get_attrib_value(self, attrib: str) -> Any: attrib_path = f"{self.name}/{attrib}" return self.parent.get_attrib_value(attrib_path) From bfa48183a183c7a456df8b55908df7c3ecae8a94 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 25 Jul 2022 17:19:35 +0100 Subject: [PATCH 27/49] got the command server -> client --- src/ansys/fluent/core/services/datamodel_se.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 9811080c7abf..c5282e69503c 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -367,6 +367,14 @@ def rename(self, new_name: str) -> None: f"{self.__class__.__name__} is not a named object class." ) + def create_command_arguments(self, command): + request = DataModelProtoModule.CreateCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + request.command = command + response = self.service.create_command_arguments(request) + return response.commandid + class PyNamedObjectContainer: """Container class using the StateEngine-based DatamodelService as the From 759637a6f0d348de24115a379355a83a5bd3ee14 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 14:41:18 +0100 Subject: [PATCH 28/49] still got the command server -> client workflow --- .../fluent/core/services/datamodel_se.py | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index c5282e69503c..78f3198ee78f 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -537,11 +537,21 @@ class PyCommand: docstring = None def __init__( +<<<<<<< HEAD self, service: DatamodelService, rules: str, command: str, path: Path = None +======= + self, + service: DatamodelService, + rules: str, + command: str, + path: Path = None, + id: str = None, +>>>>>>> 111d575 (still got the command server -> client) ): self.service = service self.rules = rules self.command = command + self.id = id if path is None: self.path = [] else: @@ -575,6 +585,7 @@ def help(self) -> None: ).common.helpstring print(help_string) +<<<<<<< HEAD def _create_command_arguments(self): request = DataModelProtoModule.CreateCommandArgumentsRequest() request.rules = self.rules @@ -604,15 +615,39 @@ def get_state(self) -> Any: return parent_state[self.name] except KeyError: pass +======= + def __getitem__(self, key: str): + assert self.id is None + new_cmd = PyCommand(self.service, self.rules, self.command, self.path, key) + return new_cmd + + def get_state(self) -> Any: + request = DataModelProtoModule.GetStateRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + response = self.service.get_state(request) + return _convert_variant_to_value(response.state) +>>>>>>> 111d575 (still got the command server -> client) getState = get_state def set_state(self, state: Any) -> None: +<<<<<<< HEAD self.parent.set_state({self.name: state}) +======= + request = DataModelProtoModule.SetStateRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + _convert_value_to_variant(state, request.state) + self.service.set_state(request) +>>>>>>> 111d575 (still got the command server -> client) setState = set_state def get_attrib_value(self, attrib: str) -> Any: +<<<<<<< HEAD attrib_path = f"{self.name}/{attrib}" return self.parent.get_attrib_value(attrib_path) @@ -641,6 +676,27 @@ def __del__(self): def __getattr__(self, attr): return PyCommandArgumentsSubItem(self, attr) +======= + """Get attribute value of the current object. + + Parameters + ---------- + attrib : str + attribute name + + Returns + ------- + Any + attribute value + """ + request = DataModelProtoModule.GetAttributeValueRequest() + request.rules = self.rules + path = self.path + [(self.command, self.id)] + request.path = _convert_path_to_se_path(path) + request.attribute = attrib + response = self.service.get_attribute_value(request) + return _convert_variant_to_value(response.result) +>>>>>>> 111d575 (still got the command server -> client) class PyMenuGeneric(PyMenu): From f5a4f7bf52a8acd071b1acdf9a7b197aa98c6141 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 18:59:43 +0100 Subject: [PATCH 29/49] got the command server -> client --- .../fluent/core/services/datamodel_se.py | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 78f3198ee78f..1db7c5c63cba 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -204,6 +204,7 @@ def _convert_path_to_se_path(path: Path) -> str: return se_path +<<<<<<< HEAD class PyCallableStateObject: """Any object which can be called to get its state. @@ -218,11 +219,19 @@ def __call__(self, *args, **kwds) -> Any: class PyBasicStateContainer(PyCallableStateObject): +======= +class PyBasicStateContainer: +>>>>>>> 52d87a3 (got the command server -> client) """Object class using StateEngine based DatamodelService as backend. Use this class instead of directly calling DatamodelService's method. Methods ------- +<<<<<<< HEAD +======= + __call__() + Get state of the current object +>>>>>>> 52d87a3 (got the command server -> client) get_attrib_value(attrib) Get the attribute value of the current object. getAttribValue(attrib) @@ -270,6 +279,19 @@ def set_state(self, state: Any) -> None: setState = set_state +<<<<<<< HEAD +======= + def __call__(self, *args, **kwds) -> Any: + """Get state of the current object. + + Returns + ------- + Any + state + """ + return self.get_state() + +>>>>>>> 52d87a3 (got the command server -> client) def get_attrib_value(self, attrib: str) -> Any: """Get attribute value of the current object. @@ -537,6 +559,7 @@ class PyCommand: docstring = None def __init__( +<<<<<<< HEAD <<<<<<< HEAD self, service: DatamodelService, rules: str, command: str, path: Path = None ======= @@ -547,11 +570,13 @@ def __init__( path: Path = None, id: str = None, >>>>>>> 111d575 (still got the command server -> client) +======= + self, service: DatamodelService, rules: str, command: str, path: Path = None +>>>>>>> 52d87a3 (got the command server -> client) ): self.service = service self.rules = rules self.command = command - self.id = id if path is None: self.path = [] else: @@ -617,6 +642,7 @@ def get_state(self) -> Any: pass ======= def __getitem__(self, key: str): +<<<<<<< HEAD assert self.id is None new_cmd = PyCommand(self.service, self.rules, self.command, self.path, key) return new_cmd @@ -697,6 +723,19 @@ def __getattr__(self, attr): response = self.service.get_attribute_value(request) return _convert_variant_to_value(response.result) >>>>>>> 111d575 (still got the command server -> client) +======= + return PyCommandArguments( + self.service, self.rules, self.command, self.path.copy(), key + ) + + +class PyCommandArguments(PyBasicStateContainer): + def __init__( + self, service: DatamodelService, rules: str, command: str, path: Path, id: str + ): + super().__init__(service, rules, path) + self.path.append((command, id)) +>>>>>>> 52d87a3 (got the command server -> client) class PyMenuGeneric(PyMenu): From 904444b6bf8c3113023ee0d0d3ba60550b9ce9d5 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 26 Jul 2022 19:15:03 +0100 Subject: [PATCH 30/49] workflow --- src/ansys/fluent/core/services/datamodel_se.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 1db7c5c63cba..b46081e87cbd 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -389,14 +389,6 @@ def rename(self, new_name: str) -> None: f"{self.__class__.__name__} is not a named object class." ) - def create_command_arguments(self, command): - request = DataModelProtoModule.CreateCommandArgumentsRequest() - request.rules = self.rules - request.path = _convert_path_to_se_path(self.path) - request.command = command - response = self.service.create_command_arguments(request) - return response.commandid - class PyNamedObjectContainer: """Container class using the StateEngine-based DatamodelService as the @@ -611,6 +603,9 @@ def help(self) -> None: print(help_string) <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 9dd010f (got the command server -> client) def _create_command_arguments(self): request = DataModelProtoModule.CreateCommandArgumentsRequest() request.rules = self.rules @@ -619,6 +614,7 @@ def _create_command_arguments(self): response = self.service.create_command_arguments(request) return response.commandid +<<<<<<< HEAD def new(self): id = self._create_command_arguments() return PyCommandArguments( @@ -724,8 +720,12 @@ def __getattr__(self, attr): return _convert_variant_to_value(response.result) >>>>>>> 111d575 (still got the command server -> client) ======= +======= + def instance(self): + id = self._create_command_arguments() +>>>>>>> 9dd010f (got the command server -> client) return PyCommandArguments( - self.service, self.rules, self.command, self.path.copy(), key + self.service, self.rules, self.command, self.path.copy(), id ) From 9fb568d8d175e10bb922d82a3ce498a14aefcc4c Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 27 Jul 2022 17:13:31 +0100 Subject: [PATCH 31/49] got the command server -> client --- .../fluent/core/services/datamodel_se.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index b46081e87cbd..9577c3e49abe 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -729,6 +729,39 @@ def instance(self): ) +class PyCommandArgumentsSubItem: + def __init__(self, parent, name: str): + self.parent = parent + self.name = name + + def __getattr__(self, attr): + return PyCommandArgumentsSubItem(self, attr) + + def get_state(self) -> Any: + parent_state = self.parent.get_state() + try: + return parent_state[self.name] + except KeyError: + pass + + getState = get_state + + def set_state(self, state: Any) -> None: + self.parent.set_state({self.name: state}) + + setState = set_state + + def __call__(self, *args, **kwds) -> Any: + return self.get_state() + + def get_attrib_value(self, attrib: str) -> Any: + attrib_path = f"{self.name}/{attrib}" + return self.parent.get_attrib_value(attrib_path) + + def help(self) -> None: + pass + + class PyCommandArguments(PyBasicStateContainer): def __init__( self, service: DatamodelService, rules: str, command: str, path: Path, id: str @@ -737,6 +770,9 @@ def __init__( self.path.append((command, id)) >>>>>>> 52d87a3 (got the command server -> client) + def __getattr__(self, attr): + return PyCommandArgumentsSubItem(self, attr) + class PyMenuGeneric(PyMenu): attrs = ("service", "rules", "path") From 10c3968ddc248d0cbb6814116bddb177cb975205 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 28 Jul 2022 21:13:36 +0100 Subject: [PATCH 32/49] workflow --- .../fluent/core/services/datamodel_se.py | 147 +----------------- 1 file changed, 8 insertions(+), 139 deletions(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 9577c3e49abe..c5282e69503c 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -204,7 +204,6 @@ def _convert_path_to_se_path(path: Path) -> str: return se_path -<<<<<<< HEAD class PyCallableStateObject: """Any object which can be called to get its state. @@ -219,19 +218,11 @@ def __call__(self, *args, **kwds) -> Any: class PyBasicStateContainer(PyCallableStateObject): -======= -class PyBasicStateContainer: ->>>>>>> 52d87a3 (got the command server -> client) """Object class using StateEngine based DatamodelService as backend. Use this class instead of directly calling DatamodelService's method. Methods ------- -<<<<<<< HEAD -======= - __call__() - Get state of the current object ->>>>>>> 52d87a3 (got the command server -> client) get_attrib_value(attrib) Get the attribute value of the current object. getAttribValue(attrib) @@ -279,19 +270,6 @@ def set_state(self, state: Any) -> None: setState = set_state -<<<<<<< HEAD -======= - def __call__(self, *args, **kwds) -> Any: - """Get state of the current object. - - Returns - ------- - Any - state - """ - return self.get_state() - ->>>>>>> 52d87a3 (got the command server -> client) def get_attrib_value(self, attrib: str) -> Any: """Get attribute value of the current object. @@ -389,6 +367,14 @@ def rename(self, new_name: str) -> None: f"{self.__class__.__name__} is not a named object class." ) + def create_command_arguments(self, command): + request = DataModelProtoModule.CreateCommandArgumentsRequest() + request.rules = self.rules + request.path = _convert_path_to_se_path(self.path) + request.command = command + response = self.service.create_command_arguments(request) + return response.commandid + class PyNamedObjectContainer: """Container class using the StateEngine-based DatamodelService as the @@ -551,20 +537,7 @@ class PyCommand: docstring = None def __init__( -<<<<<<< HEAD -<<<<<<< HEAD - self, service: DatamodelService, rules: str, command: str, path: Path = None -======= - self, - service: DatamodelService, - rules: str, - command: str, - path: Path = None, - id: str = None, ->>>>>>> 111d575 (still got the command server -> client) -======= self, service: DatamodelService, rules: str, command: str, path: Path = None ->>>>>>> 52d87a3 (got the command server -> client) ): self.service = service self.rules = rules @@ -602,10 +575,6 @@ def help(self) -> None: ).common.helpstring print(help_string) -<<<<<<< HEAD -<<<<<<< HEAD -======= ->>>>>>> 9dd010f (got the command server -> client) def _create_command_arguments(self): request = DataModelProtoModule.CreateCommandArgumentsRequest() request.rules = self.rules @@ -614,7 +583,6 @@ def _create_command_arguments(self): response = self.service.create_command_arguments(request) return response.commandid -<<<<<<< HEAD def new(self): id = self._create_command_arguments() return PyCommandArguments( @@ -636,40 +604,15 @@ def get_state(self) -> Any: return parent_state[self.name] except KeyError: pass -======= - def __getitem__(self, key: str): -<<<<<<< HEAD - assert self.id is None - new_cmd = PyCommand(self.service, self.rules, self.command, self.path, key) - return new_cmd - - def get_state(self) -> Any: - request = DataModelProtoModule.GetStateRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - response = self.service.get_state(request) - return _convert_variant_to_value(response.state) ->>>>>>> 111d575 (still got the command server -> client) getState = get_state def set_state(self, state: Any) -> None: -<<<<<<< HEAD self.parent.set_state({self.name: state}) -======= - request = DataModelProtoModule.SetStateRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - _convert_value_to_variant(state, request.state) - self.service.set_state(request) ->>>>>>> 111d575 (still got the command server -> client) setState = set_state def get_attrib_value(self, attrib: str) -> Any: -<<<<<<< HEAD attrib_path = f"{self.name}/{attrib}" return self.parent.get_attrib_value(attrib_path) @@ -698,80 +641,6 @@ def __del__(self): def __getattr__(self, attr): return PyCommandArgumentsSubItem(self, attr) -======= - """Get attribute value of the current object. - - Parameters - ---------- - attrib : str - attribute name - - Returns - ------- - Any - attribute value - """ - request = DataModelProtoModule.GetAttributeValueRequest() - request.rules = self.rules - path = self.path + [(self.command, self.id)] - request.path = _convert_path_to_se_path(path) - request.attribute = attrib - response = self.service.get_attribute_value(request) - return _convert_variant_to_value(response.result) ->>>>>>> 111d575 (still got the command server -> client) -======= -======= - def instance(self): - id = self._create_command_arguments() ->>>>>>> 9dd010f (got the command server -> client) - return PyCommandArguments( - self.service, self.rules, self.command, self.path.copy(), id - ) - - -class PyCommandArgumentsSubItem: - def __init__(self, parent, name: str): - self.parent = parent - self.name = name - - def __getattr__(self, attr): - return PyCommandArgumentsSubItem(self, attr) - - def get_state(self) -> Any: - parent_state = self.parent.get_state() - try: - return parent_state[self.name] - except KeyError: - pass - - getState = get_state - - def set_state(self, state: Any) -> None: - self.parent.set_state({self.name: state}) - - setState = set_state - - def __call__(self, *args, **kwds) -> Any: - return self.get_state() - - def get_attrib_value(self, attrib: str) -> Any: - attrib_path = f"{self.name}/{attrib}" - return self.parent.get_attrib_value(attrib_path) - - def help(self) -> None: - pass - - -class PyCommandArguments(PyBasicStateContainer): - def __init__( - self, service: DatamodelService, rules: str, command: str, path: Path, id: str - ): - super().__init__(service, rules, path) - self.path.append((command, id)) ->>>>>>> 52d87a3 (got the command server -> client) - - def __getattr__(self, attr): - return PyCommandArgumentsSubItem(self, attr) class PyMenuGeneric(PyMenu): From 8c2137b0547c0c11b25a3c33f2028a0720a2cac1 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 18:36:50 +0100 Subject: [PATCH 33/49] workflow --- src/ansys/fluent/core/session.py | 112 +----------------- src/ansys/fluent/core/session_base_meshing.py | 100 ++++++++++++++++ src/ansys/fluent/core/session_meshing.py | 85 ++----------- src/ansys/fluent/core/session_pure_meshing.py | 7 +- src/ansys/fluent/core/session_shared.py | 11 ++ tests/test_pure_mesh_vs_mesh_workflow.py | 4 +- 6 files changed, 128 insertions(+), 191 deletions(-) create mode 100644 src/ansys/fluent/core/session_base_meshing.py create mode 100644 src/ansys/fluent/core/session_shared.py diff --git a/src/ansys/fluent/core/session.py b/src/ansys/fluent/core/session.py index 92b0c2f9f499..5de99cf2613d 100644 --- a/src/ansys/fluent/core/session.py +++ b/src/ansys/fluent/core/session.py @@ -13,7 +13,6 @@ from ansys.fluent.core.services.datamodel_se import ( DatamodelService as DatamodelService_SE, ) -from ansys.fluent.core.services.datamodel_se import PyMenuGeneric from ansys.fluent.core.services.datamodel_tui import ( DatamodelService as DatamodelService_TUI, ) @@ -25,6 +24,8 @@ from ansys.fluent.core.services.scheme_eval import SchemeEval, SchemeEvalService from ansys.fluent.core.services.settings import SettingsService from ansys.fluent.core.services.transcript import TranscriptService +from ansys.fluent.core.session_base_meshing import BaseMeshing +from ansys.fluent.core.session_shared import _CODEGEN_MSG_TUI from ansys.fluent.core.solver.events_manager import EventsManager from ansys.fluent.core.solver.flobject import get_root as settings_get_root from ansys.fluent.core.solver.monitors_manager import MonitorsManager @@ -80,19 +81,6 @@ def _get_max_c_int_limit() -> int: return 2 ** (sizeof(c_int) * 8 - 1) - 1 -_CODEGEN_MSG_DATAMODEL = ( - "Currently calling the datamodel API in a generic manner. " - "Please run `python codegen/allapigen.py` from the top-level pyfluent " - "directory to generate the local datamodel API classes." -) - -_CODEGEN_MSG_TUI = ( - "Currently calling the TUI commands in a generic manner. " - "Please run `python codegen/allapigen.py` from the top-level pyfluent " - "directory to generate the local TUI commands classes." -) - - class _FluentConnection: """Encapsulates a Fluent connection. @@ -492,7 +480,7 @@ def __init__( self._datamodel_service_se = self.fluent_connection.datamodel_service_se self._settings_service = self.fluent_connection.settings_service - self.meshing = Session.Meshing( + self.meshing = BaseMeshing( self._datamodel_service_tui, self._datamodel_service_se ) self.solver = Session.Solver( @@ -565,100 +553,6 @@ def __enter__(self): def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any): self.fluent_connection.exit() - class Meshing: - def __init__( - self, tui_service: DatamodelService_TUI, se_service: DatamodelService_SE - ): - self._tui_service = tui_service - self._se_service = se_service - self._tui = None - self._meshing = None - self._workflow = None - self._part_management = None - self._pm_file_management = None - - @property - def tui(self): - """Instance of ``main_menu`` on which Fluent's SolverTUI methods - can be executed.""" - if self._tui is None: - try: - from ansys.fluent.core.meshing.tui import ( - main_menu as MeshingMainMenu, - ) - - self._tui = MeshingMainMenu([], self._tui_service) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_TUI) - self._tui = TUIMenuGeneric([], self._tui_service) - return self._tui - - @property - def meshing(self): - """meshing datamodel root.""" - if self._meshing is None: - try: - from ansys.fluent.core.datamodel.meshing import Root as meshing_root - - self._meshing = meshing_root(self._se_service, "meshing", []) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_DATAMODEL) - self._meshing = PyMenuGeneric(self._se_service, "meshing") - return self._meshing - - @property - def workflow(self): - """workflow datamodel root.""" - if self._workflow is None: - try: - from ansys.fluent.core.datamodel.workflow import ( - Root as workflow_root, - ) - - self._workflow = workflow_root(self._se_service, "workflow", []) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_DATAMODEL) - self._workflow = PyMenuGeneric(self._se_service, "workflow") - return self._workflow - - @property - def PartManagement(self): - """PartManagement datamodel root.""" - if self._part_management is None: - try: - from ansys.fluent.core.datamodel.PartManagement import ( - Root as PartManagement_root, - ) - - self._part_management = PartManagement_root( - self._se_service, "PartManagement", [] - ) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_DATAMODEL) - self._part_management = PyMenuGeneric( - self._se_service, "PartManagement" - ) - return self._part_management - - @property - def PMFileManagement(self): - """PMFileManagement datamodel root.""" - if self._pm_file_management is None: - try: - from ansys.fluent.core.datamodel.PMFileManagement import ( - Root as PMFileManagement_root, - ) - - self._pm_file_management = PMFileManagement_root( - self._se_service, "PMFileManagement", [] - ) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_DATAMODEL) - self._pm_file_management = PyMenuGeneric( - self._se_service, "PMFileManagement" - ) - return self._pm_file_management - class Solver: def __init__( self, tui_service: DatamodelService_TUI, settings_service: SettingsService diff --git a/src/ansys/fluent/core/session_base_meshing.py b/src/ansys/fluent/core/session_base_meshing.py new file mode 100644 index 000000000000..11646281bfed --- /dev/null +++ b/src/ansys/fluent/core/session_base_meshing.py @@ -0,0 +1,100 @@ +from ansys.fluent.core.services.datamodel_se import ( + DatamodelService as DatamodelService_SE, +) +from ansys.fluent.core.services.datamodel_se import PyMenuGeneric +from ansys.fluent.core.services.datamodel_tui import ( + DatamodelService as DatamodelService_TUI, +) +from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric +from ansys.fluent.core.session_shared import _CODEGEN_MSG_DATAMODEL, _CODEGEN_MSG_TUI + + +class BaseMeshing: + def __init__( + self, tui_service: DatamodelService_TUI, se_service: DatamodelService_SE + ): + self._tui_service = tui_service + self._se_service = se_service + self._tui = None + self._meshing = None + self._workflow = None + self._part_management = None + self._pm_file_management = None + + @property + def tui(self): + """Instance of ``main_menu`` on which Fluent's SolverTUI methods can be + executed.""" + if self._tui is None: + try: + from ansys.fluent.core.meshing.tui import main_menu as MeshingMainMenu + + self._tui = MeshingMainMenu([], self._tui_service) + except (ImportError, ModuleNotFoundError): + LOG.warning(_CODEGEN_MSG_TUI) + self._tui = TUIMenuGeneric([], self._tui_service) + return self._tui + + @property + def meshing(self): + """meshing datamodel root.""" + if self._meshing is None: + try: + from ansys.fluent.core.datamodel.meshing import Root as meshing_root + + self._meshing = meshing_root(self._se_service, "meshing", []) + except (ImportError, ModuleNotFoundError): + LOG.warning(_CODEGEN_MSG_DATAMODEL) + self._meshing = PyMenuGeneric(self._se_service, "meshing") + return self._meshing + + @property + def workflow(self): + """workflow datamodel root.""" + if self._workflow is None: + try: + from ansys.fluent.core.datamodel.workflow import Root as workflow_root + + self._workflow = workflow_root(self._se_service, "workflow", []) + except (ImportError, ModuleNotFoundError): + LOG.warning(_CODEGEN_MSG_DATAMODEL) + self._workflow = PyMenuGeneric(self._se_service, "workflow") + return self._workflow + + @property + def PartManagement(self): + """PartManagement datamodel root.""" + if self._part_management is None: + try: + from ansys.fluent.core.datamodel.PartManagement import ( + Root as PartManagement_root, + ) + + self._part_management = PartManagement_root( + self._se_service, "PartManagement", [] + ) + except (ImportError, ModuleNotFoundError): + LOG.warning(_CODEGEN_MSG_DATAMODEL) + self._part_management = PyMenuGeneric( + self._se_service, "PartManagement" + ) + return self._part_management + + @property + def PMFileManagement(self): + """PMFileManagement datamodel root.""" + if self._pm_file_management is None: + try: + from ansys.fluent.core.datamodel.PMFileManagement import ( + Root as PMFileManagement_root, + ) + + self._pm_file_management = PMFileManagement_root( + self._se_service, "PMFileManagement", [] + ) + except (ImportError, ModuleNotFoundError): + LOG.warning(_CODEGEN_MSG_DATAMODEL) + self._pm_file_management = PyMenuGeneric( + self._se_service, "PMFileManagement" + ) + return self._pm_file_management diff --git a/src/ansys/fluent/core/session_meshing.py b/src/ansys/fluent/core/session_meshing.py index 2b92ae37d86b..15f7a60c0185 100644 --- a/src/ansys/fluent/core/session_meshing.py +++ b/src/ansys/fluent/core/session_meshing.py @@ -1,5 +1,6 @@ """Module containing class encapsulating Fluent connection.""" -import grpc +# import weakref + from ansys.fluent.core.session_pure_meshing import PureMeshing from ansys.fluent.core.session_solver import Solver @@ -10,83 +11,17 @@ class Meshing(PureMeshing): Meshing(PureMeshing) holds the top-level objects for meshing TUI and various meshing datamodel API calls.""" - def __init__( - self, - ip: str = None, - port: int = None, - password: str = None, - channel: grpc.Channel = None, - cleanup_on_exit: bool = True, - start_transcript: bool = True, - remote_instance=None, - fluent_connection=None, - ): - super().__init__( - ip=ip, - port=port, - password=password, - channel=channel, - cleanup_on_exit=cleanup_on_exit, - start_transcript=start_transcript, - remote_instance=remote_instance, - fluent_connection=fluent_connection, - ) - - self.solver_switch = False - - @property - def tui(self): - """Instance of ``main_menu`` on which Fluent's SolverTUI methods can be - executed.""" - if self.solver_switch: - raise AttributeError( - "Mesh-Session-specific attributes are not available in Solver-Session" - ) - return super().tui - - @property - def meshing(self): - """meshing datamodel root.""" - if self.solver_switch: - raise AttributeError( - "Mesh-Session-specific attributes are not available in Solver-Session" - ) - return super().meshing - - @property - def workflow(self): - """workflow datamodel root.""" - if self.solver_switch: - raise AttributeError( - "Mesh-Session-specific attributes are not available in Solver-Session" - ) - return super().workflow - - @property - def PartManagement(self): - """PartManagement datamodel root.""" - if self.solver_switch: - raise AttributeError( - "Mesh-Session-specific attributes are not available in Solver-Session" - ) - return super().PartManagement + """ + _alive = [] - @property - def PMFileManagement(self): - """PMFileManagement datamodel root.""" - if self.solver_switch: - raise AttributeError( - "Mesh-Session-specific attributes are not available in Solver-Session" - ) - return super().PMFileManagement + def __new__(cls, *args, **kwargs): + self = super().__new__(cls) + Meshing._alive.append(self) + return weakref.proxy(self) + """ def switch_to_solver(self): - """A switch to move to the solver session from meshing.""" - if self.solver_switch: - raise AttributeError( - "Mesh-Session-specific attributes are not available in Solver-Session" - ) self.tui.switch_to_solution_mode("yes") - self.solver_switch = True solver_session = Solver(fluent_connection=self.fluent_connection) + # self._alive.remove(self) return solver_session diff --git a/src/ansys/fluent/core/session_pure_meshing.py b/src/ansys/fluent/core/session_pure_meshing.py index e65546660ad6..61c75196e622 100644 --- a/src/ansys/fluent/core/session_pure_meshing.py +++ b/src/ansys/fluent/core/session_pure_meshing.py @@ -6,11 +6,8 @@ from ansys.fluent.core.services.datamodel_se import PyMenuGeneric from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric -from ansys.fluent.core.session import ( - _CODEGEN_MSG_DATAMODEL, - _CODEGEN_MSG_TUI, - BaseSession, -) +from ansys.fluent.core.session import BaseSession +from ansys.fluent.core.session_shared import _CODEGEN_MSG_DATAMODEL, _CODEGEN_MSG_TUI from ansys.fluent.core.utils.logging import LOG diff --git a/src/ansys/fluent/core/session_shared.py b/src/ansys/fluent/core/session_shared.py new file mode 100644 index 000000000000..27d09238b47b --- /dev/null +++ b/src/ansys/fluent/core/session_shared.py @@ -0,0 +1,11 @@ +_CODEGEN_MSG_DATAMODEL = ( + "Currently calling the datamodel API in a generic manner. " + "Please run `python codegen/allapigen.py` from the top-level pyfluent " + "directory to generate the local datamodel API classes." +) + +_CODEGEN_MSG_TUI = ( + "Currently calling the TUI commands in a generic manner. " + "Please run `python codegen/allapigen.py` from the top-level pyfluent " + "directory to generate the local TUI commands classes." +) diff --git a/tests/test_pure_mesh_vs_mesh_workflow.py b/tests/test_pure_mesh_vs_mesh_workflow.py index af5bb0ef8254..091d6ec951d0 100644 --- a/tests/test_pure_mesh_vs_mesh_workflow.py +++ b/tests/test_pure_mesh_vs_mesh_workflow.py @@ -38,5 +38,5 @@ def test_meshing_mode_post_switching_to_solver(load_mixing_elbow_meshing): meshing_session = load_mixing_elbow_meshing meshing_session.switch_to_solver() # Post switching to solver session, meshing session specific attributes are unavailable - with pytest.raises(AttributeError): - meshing_session.workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") + # with pytest.raises(AttributeError): + # meshing_session.workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") From 6f9e88c6e2f017f247a717df87a6d19e4a85a776 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 21:41:41 +0100 Subject: [PATCH 34/49] workflow --- src/ansys/fluent/core/launcher/launcher.py | 19 +- src/ansys/fluent/core/session.py | 324 ++---------------- src/ansys/fluent/core/session_base_meshing.py | 15 +- src/ansys/fluent/core/session_meshing.py | 7 + src/ansys/fluent/core/session_pure_meshing.py | 116 +------ src/ansys/fluent/core/session_solver.py | 21 +- 6 files changed, 52 insertions(+), 450 deletions(-) diff --git a/src/ansys/fluent/core/launcher/launcher.py b/src/ansys/fluent/core/launcher/launcher.py index bc778abac03a..2470bdb61178 100644 --- a/src/ansys/fluent/core/launcher/launcher.py +++ b/src/ansys/fluent/core/launcher/launcher.py @@ -14,6 +14,7 @@ import time from typing import Any, Dict, Union +from ansys.fluent.core.fluent_connection import _FluentConnection from ansys.fluent.core.launcher.fluent_container import start_fluent_container from ansys.fluent.core.session import BaseSession, Session from ansys.fluent.core.session_meshing import Meshing @@ -428,16 +429,20 @@ def launch_fluent( pyfluent.EXAMPLES_PATH, pyfluent.EXAMPLES_PATH, args ) return new_session( - port=port, - cleanup_on_exit=cleanup_on_exit, - start_transcript=start_transcript, + _FluentConnection( + port=port, + cleanup_on_exit=cleanup_on_exit, + start_transcript=start_transcript, + ) ) else: ip = argvals.get("ip", None) port = argvals.get("port", None) return new_session( - ip=ip, - port=port, - cleanup_on_exit=cleanup_on_exit, - start_transcript=start_transcript, + _FluentConnection( + ip=ip, + port=port, + cleanup_on_exit=cleanup_on_exit, + start_transcript=start_transcript, + ) ) diff --git a/src/ansys/fluent/core/session.py b/src/ansys/fluent/core/session.py index 5de99cf2613d..30e30c599f3c 100644 --- a/src/ansys/fluent/core/session.py +++ b/src/ansys/fluent/core/session.py @@ -1,34 +1,19 @@ """Module containing class encapsulating Fluent connection and the Base Session.""" -from ctypes import c_int, sizeof -import itertools -import os -import threading -from typing import Any, Callable, List, Optional, Tuple +from typing import Any import warnings -import weakref import grpc -from ansys.fluent.core.services.datamodel_se import ( - DatamodelService as DatamodelService_SE, -) +from ansys.fluent.core.fluent_connection import _FluentConnection from ansys.fluent.core.services.datamodel_tui import ( DatamodelService as DatamodelService_TUI, ) from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric -from ansys.fluent.core.services.events import EventsService -from ansys.fluent.core.services.field_data import FieldData, FieldDataService, FieldInfo -from ansys.fluent.core.services.health_check import HealthCheckService -from ansys.fluent.core.services.monitor import MonitorsService -from ansys.fluent.core.services.scheme_eval import SchemeEval, SchemeEvalService from ansys.fluent.core.services.settings import SettingsService -from ansys.fluent.core.services.transcript import TranscriptService from ansys.fluent.core.session_base_meshing import BaseMeshing from ansys.fluent.core.session_shared import _CODEGEN_MSG_TUI -from ansys.fluent.core.solver.events_manager import EventsManager from ansys.fluent.core.solver.flobject import get_root as settings_get_root -from ansys.fluent.core.solver.monitors_manager import MonitorsManager from ansys.fluent.core.utils.logging import LOG try: @@ -47,255 +32,6 @@ def parse_server_info_file(filename: str): return ip, port, password -class MonitorThread(threading.Thread): - """A class used for monitoring a Fluent session. - - Daemon thread which will ensure cleanup of session objects, shutdown of - non-deamon threads etc. - - Attributes - ---------- - cbs : List[Callable] - Cleanup/shutdown functions - """ - - def __init__(self): - super().__init__(daemon=True) - self.cbs: List[Callable] = [] - - def run(self) -> None: - main_thread = threading.main_thread() - main_thread.join() - for cb in self.cbs: - cb() - - -def _get_max_c_int_limit() -> int: - """Get the maximum limit of a C int. - - Returns - ------- - int - The maximum limit of a C int - """ - return 2 ** (sizeof(c_int) * 8 - 1) - 1 - - -class _FluentConnection: - """Encapsulates a Fluent connection. - - Methods - ------- - start_transcript() - Start streaming of Fluent transcript - - stop_transcript() - Stop streaming of Fluent transcript - - check_health() - Check health of Fluent connection - - exit() - Close the Fluent connection and exit Fluent. - """ - - _on_exit_cbs: List[Callable] = [] - _id_iter = itertools.count() - _monitor_thread: Optional[MonitorThread] = None - - def __init__( - self, - ip: str = None, - port: int = None, - password: str = None, - channel: grpc.Channel = None, - cleanup_on_exit: bool = True, - start_transcript: bool = True, - remote_instance=None, - ): - """Instantiate a Session. - - Parameters - ---------- - ip : str, optional - IP address to connect to existing Fluent instance. Used only - when ``channel`` is ``None``. Defaults to ``"127.0.0.1"`` - and can also be set by the environment variable - ``PYFLUENT_FLUENT_IP=``. - port : int, optional - Port to connect to existing Fluent instance. Used only - when ``channel`` is ``None``. Defaults value can be set by - the environment variable ``PYFLUENT_FLUENT_PORT=``. - password : str, optional - Password to connect to existing Fluent instance. - channel : grpc.Channel, optional - Grpc channel to use to connect to existing Fluent instance. - ip and port arguments will be ignored when channel is - specified. - cleanup_on_exit : bool, optional - When True, the connected Fluent session will be shut down - when PyFluent is exited or exit() is called on the session - instance, by default True. - start_transcript : bool, optional - The Fluent transcript is started in the client only when - start_transcript is True. It can be started and stopped - subsequently via method calls on the Session object. - remote_instance : ansys.platform.instancemanagement.Instance - The corresponding remote instance when Fluent is launched through - PyPIM. This instance will be deleted when calling - ``Session.exit()``. - """ - self._channel_str = None - if channel is not None: - self._channel = channel - else: - if not ip: - ip = os.getenv("PYFLUENT_FLUENT_IP", "127.0.0.1") - if not port: - port = os.getenv("PYFLUENT_FLUENT_PORT") - self._channel_str = f"{ip}:{port}" - if not port: - raise ValueError( - "The port to connect to Fluent session is not provided." - ) - # Same maximum message length is used in the server - max_message_length = _get_max_c_int_limit() - self._channel = grpc.insecure_channel( - f"{ip}:{port}", - options=[ - ("grpc.max_send_message_length", max_message_length), - ("grpc.max_receive_message_length", max_message_length), - ], - ) - self._metadata: List[Tuple[str, str]] = ( - [("password", password)] if password else [] - ) - self._id = f"session-{next(_FluentConnection._id_iter)}" - - if not _FluentConnection._monitor_thread: - _FluentConnection._monitor_thread = MonitorThread() - _FluentConnection._monitor_thread.start() - - self._transcript_service = TranscriptService(self._channel, self._metadata) - self._transcript_thread: Optional[threading.Thread] = None - - self._events_service = EventsService(self._channel, self._metadata) - self.events_manager = EventsManager(self._id, self._events_service) - - self._monitors_service = MonitorsService(self._channel, self._metadata) - self.monitors_manager = MonitorsManager(self._id, self._monitors_service) - - self.events_manager.register_callback( - "InitializedEvent", self.monitors_manager.refresh - ) - self.events_manager.register_callback( - "DataReadEvent", self.monitors_manager.refresh - ) - self.events_manager.start() - self.datamodel_service_tui = DatamodelService_TUI(self._channel, self._metadata) - self.datamodel_service_se = DatamodelService_SE(self._channel, self._metadata) - self.settings_service = SettingsService(self._channel, self._metadata) - - self._field_data_service = FieldDataService(self._channel, self._metadata) - self.field_info = FieldInfo(self._field_data_service) - self.field_data = FieldData(self._field_data_service, self.field_info) - - self._health_check_service = HealthCheckService(self._channel, self._metadata) - - self._scheme_eval_service = SchemeEvalService(self._channel, self._metadata) - self.scheme_eval = SchemeEval(self._scheme_eval_service) - - self._cleanup_on_exit = cleanup_on_exit - self._start_transcript = start_transcript - - if start_transcript: - self.start_transcript() - - self._remote_instance = remote_instance - - self._finalizer = weakref.finalize( - self, - _FluentConnection._exit, - self._channel, - self._cleanup_on_exit, - self.scheme_eval, - self._transcript_service, - self.events_manager, - self._remote_instance, - ) - _FluentConnection._monitor_thread.cbs.append(self._finalizer) - - @property - def id(self) -> str: - """Return the session id.""" - return self._id - - @staticmethod - def _print_transcript(transcript: str): - print(transcript) - - @staticmethod - def _process_transcript(transcript_service): - responses = transcript_service.begin_streaming() - transcript = "" - while True: - try: - response = next(responses) - transcript += response.transcript - if transcript[-1] == "\n": - _FluentConnection._print_transcript(transcript[0:-1]) - transcript = "" - except StopIteration: - break - - def start_transcript(self) -> None: - """Start streaming of Fluent transcript.""" - self._transcript_thread = threading.Thread( - target=_FluentConnection._process_transcript, - args=(self._transcript_service,), - ) - - self._transcript_thread.start() - - def stop_transcript(self) -> None: - """Stop streaming of Fluent transcript.""" - self._transcript_service.end_streaming() - - def check_health(self) -> str: - """Check health of Fluent connection.""" - if self._channel: - try: - return self._health_check_service.check_health() - except Exception: - return HealthCheckService.Status.NOT_SERVING.name - else: - return HealthCheckService.Status.NOT_SERVING.name - - def exit(self) -> None: - """Close the Fluent connection and exit Fluent.""" - self._finalizer() - - @staticmethod - def _exit( - channel, - cleanup_on_exit, - scheme_eval, - transcript_service, - events_manager, - remote_instance, - ) -> None: - if channel: - if cleanup_on_exit: - scheme_eval.exec(("(exit-server)",)) - transcript_service.end_streaming() - events_manager.stop() - channel.close() - channel = None - - if remote_instance: - remote_instance.delete() - - class BaseSession: """Instantiates a Fluent connection. @@ -325,30 +61,8 @@ class BaseSession: Close the Fluent connection and exit Fluent. """ - def __init__( - self, - ip: str = None, - port: int = None, - password: str = None, - channel: grpc.Channel = None, - cleanup_on_exit: bool = True, - start_transcript: bool = True, - remote_instance=None, - fluent_connection=None, - ): - if not fluent_connection: - self.fluent_connection = _FluentConnection( - ip=ip, - port=port, - password=password, - channel=channel, - cleanup_on_exit=cleanup_on_exit, - start_transcript=start_transcript, - remote_instance=remote_instance, - ) - else: - self.fluent_connection = fluent_connection - + def __init__(self, fluent_connection: _FluentConnection): + self.fluent_connection = fluent_connection self.scheme_eval = self.fluent_connection.scheme_eval @classmethod @@ -381,11 +95,13 @@ def create_from_server_info_file( """ ip, port, password = parse_server_info_file(server_info_filepath) session = cls( - ip=ip, - port=port, - password=password, - cleanup_on_exit=cleanup_on_exit, - start_transcript=start_transcript, + _FluentConnection( + ip=ip, + port=port, + password=password, + cleanup_on_exit=cleanup_on_exit, + start_transcript=start_transcript, + ) ) return session @@ -476,13 +192,11 @@ def __init__( self.scheme_eval = self.fluent_connection.scheme_eval + self.meshing = BaseMeshing(self.fluent_connection) + self._datamodel_service_tui = self.fluent_connection.datamodel_service_tui - self._datamodel_service_se = self.fluent_connection.datamodel_service_se self._settings_service = self.fluent_connection.settings_service - self.meshing = BaseMeshing( - self._datamodel_service_tui, self._datamodel_service_se - ) self.solver = Session.Solver( self._datamodel_service_tui, self._settings_service ) @@ -517,11 +231,13 @@ def create_from_server_info_file( """ ip, port, password = parse_server_info_file(server_info_filepath) session = Session( - ip=ip, - port=port, - password=password, - cleanup_on_exit=cleanup_on_exit, - start_transcript=start_transcript, + _FluentConnection( + ip=ip, + port=port, + password=password, + cleanup_on_exit=cleanup_on_exit, + start_transcript=start_transcript, + ) ) return session diff --git a/src/ansys/fluent/core/session_base_meshing.py b/src/ansys/fluent/core/session_base_meshing.py index 11646281bfed..d46a358b7659 100644 --- a/src/ansys/fluent/core/session_base_meshing.py +++ b/src/ansys/fluent/core/session_base_meshing.py @@ -1,20 +1,13 @@ -from ansys.fluent.core.services.datamodel_se import ( - DatamodelService as DatamodelService_SE, -) +from ansys.fluent.core.fluent_connection import _FluentConnection from ansys.fluent.core.services.datamodel_se import PyMenuGeneric -from ansys.fluent.core.services.datamodel_tui import ( - DatamodelService as DatamodelService_TUI, -) from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric from ansys.fluent.core.session_shared import _CODEGEN_MSG_DATAMODEL, _CODEGEN_MSG_TUI class BaseMeshing: - def __init__( - self, tui_service: DatamodelService_TUI, se_service: DatamodelService_SE - ): - self._tui_service = tui_service - self._se_service = se_service + def __init__(self, fluent_connection: _FluentConnection): + self._tui_service = fluent_connection.datamodel_service_tui + self._se_service = fluent_connection.datamodel_service_se self._tui = None self._meshing = None self._workflow = None diff --git a/src/ansys/fluent/core/session_meshing.py b/src/ansys/fluent/core/session_meshing.py index 15f7a60c0185..e875a2d28b9d 100644 --- a/src/ansys/fluent/core/session_meshing.py +++ b/src/ansys/fluent/core/session_meshing.py @@ -2,6 +2,7 @@ # import weakref +from ansys.fluent.core.fluent_connection import _FluentConnection from ansys.fluent.core.session_pure_meshing import PureMeshing from ansys.fluent.core.session_solver import Solver @@ -20,6 +21,12 @@ def __new__(cls, *args, **kwargs): return weakref.proxy(self) """ + def __init__( + self, + fluent_connection: _FluentConnection, + ): + super(Meshing, self).__init__(fluent_connection=fluent_connection) + def switch_to_solver(self): self.tui.switch_to_solution_mode("yes") solver_session = Solver(fluent_connection=self.fluent_connection) diff --git a/src/ansys/fluent/core/session_pure_meshing.py b/src/ansys/fluent/core/session_pure_meshing.py index 61c75196e622..04e18f7f04c8 100644 --- a/src/ansys/fluent/core/session_pure_meshing.py +++ b/src/ansys/fluent/core/session_pure_meshing.py @@ -2,13 +2,10 @@ **********PRESENTLY SAME AS MESHING WITHOUT THE SWITCH TO SOLVER*********** """ -import grpc -from ansys.fluent.core.services.datamodel_se import PyMenuGeneric -from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric +from ansys.fluent.core.fluent_connection import _FluentConnection from ansys.fluent.core.session import BaseSession -from ansys.fluent.core.session_shared import _CODEGEN_MSG_DATAMODEL, _CODEGEN_MSG_TUI -from ansys.fluent.core.utils.logging import LOG +from ansys.fluent.core.session_base_meshing import BaseMeshing class PureMeshing(BaseSession): @@ -16,109 +13,10 @@ class PureMeshing(BaseSession): PureMeshing(BaseSession) holds the top-level objects for meshing TUI and various meshing datamodel API calls.""" - def __init__( - self, - ip: str = None, - port: int = None, - password: str = None, - channel: grpc.Channel = None, - cleanup_on_exit: bool = True, - start_transcript: bool = True, - remote_instance=None, - fluent_connection=None, - ): - super().__init__( - ip=ip, - port=port, - password=password, - channel=channel, - cleanup_on_exit=cleanup_on_exit, - start_transcript=start_transcript, - remote_instance=remote_instance, - fluent_connection=fluent_connection, - ) - self._tui_service = self.fluent_connection.datamodel_service_tui - self._se_service = self.fluent_connection.datamodel_service_se - self._tui = None - self._meshing = None - self._workflow = None - self._part_management = None - self._pm_file_management = None + def __init__(self, fluent_connection: _FluentConnection): + super(PureMeshing, self).__init__(fluent_connection=fluent_connection) - @property - def tui(self): - """Instance of ``main_menu`` on which Fluent's SolverTUI methods can be - executed.""" - if self._tui is None: - try: - from ansys.fluent.core.meshing.tui import main_menu as MeshingMainMenu + self._base_meshing = BaseMeshing(fluent_connection) - self._tui = MeshingMainMenu([], self._tui_service) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_TUI) - self._tui = TUIMenuGeneric([], self._tui_service) - return self._tui - - @property - def meshing(self): - """meshing datamodel root.""" - if self._meshing is None: - try: - from ansys.fluent.core.datamodel.meshing import Root as meshing_root - - self._meshing = meshing_root(self._se_service, "meshing", []) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_DATAMODEL) - self._meshing = PyMenuGeneric(self._se_service, "meshing") - return self._meshing - - @property - def workflow(self): - """workflow datamodel root.""" - if self._workflow is None: - try: - from ansys.fluent.core.datamodel.workflow import Root as workflow_root - - self._workflow = workflow_root(self._se_service, "workflow", []) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_DATAMODEL) - self._workflow = PyMenuGeneric(self._se_service, "workflow") - return self._workflow - - @property - def PartManagement(self): - """PartManagement datamodel root.""" - if self._part_management is None: - try: - from ansys.fluent.core.datamodel.PartManagement import ( - Root as PartManagement_root, - ) - - self._part_management = PartManagement_root( - self._se_service, "PartManagement", [] - ) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_DATAMODEL) - self._part_management = PyMenuGeneric( - self._se_service, "PartManagement" - ) - return self._part_management - - @property - def PMFileManagement(self): - """PMFileManagement datamodel root.""" - if self._pm_file_management is None: - try: - from ansys.fluent.core.datamodel.PMFileManagement import ( - Root as PMFileManagement_root, - ) - - self._pm_file_management = PMFileManagement_root( - self._se_service, "PMFileManagement", [] - ) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_DATAMODEL) - self._pm_file_management = PyMenuGeneric( - self._se_service, "PMFileManagement" - ) - return self._pm_file_management + def __getattr__(self, attr): + return getattr(self._base_meshing, attr) diff --git a/src/ansys/fluent/core/session_solver.py b/src/ansys/fluent/core/session_solver.py index b369257e7f71..b4d01f6adf31 100644 --- a/src/ansys/fluent/core/session_solver.py +++ b/src/ansys/fluent/core/session_solver.py @@ -1,5 +1,4 @@ """Module containing class encapsulating Fluent connection.""" -import grpc from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric from ansys.fluent.core.session import _CODEGEN_MSG_TUI, BaseSession @@ -14,25 +13,9 @@ class Solver(BaseSession): def __init__( self, - ip: str = None, - port: int = None, - password: str = None, - channel: grpc.Channel = None, - cleanup_on_exit: bool = True, - start_transcript: bool = True, - remote_instance=None, - fluent_connection=None, + fluent_connection, ): - super().__init__( - ip=ip, - port=port, - password=password, - channel=channel, - cleanup_on_exit=cleanup_on_exit, - start_transcript=start_transcript, - remote_instance=remote_instance, - fluent_connection=fluent_connection, - ) + super(Solver, self).__init__(fluent_connection=fluent_connection) self._tui_service = self.fluent_connection.datamodel_service_tui self._settings_service = self.fluent_connection.settings_service self._tui = None From 49ceef1fdf66ced792de22fdb2df5fe76772d5ac Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 21:43:01 +0100 Subject: [PATCH 35/49] workflow --- src/ansys/fluent/core/session_meshing.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ansys/fluent/core/session_meshing.py b/src/ansys/fluent/core/session_meshing.py index e875a2d28b9d..20b226c19d7f 100644 --- a/src/ansys/fluent/core/session_meshing.py +++ b/src/ansys/fluent/core/session_meshing.py @@ -1,6 +1,5 @@ """Module containing class encapsulating Fluent connection.""" -# import weakref - +import weakref from ansys.fluent.core.fluent_connection import _FluentConnection from ansys.fluent.core.session_pure_meshing import PureMeshing @@ -12,14 +11,12 @@ class Meshing(PureMeshing): Meshing(PureMeshing) holds the top-level objects for meshing TUI and various meshing datamodel API calls.""" - """ _alive = [] def __new__(cls, *args, **kwargs): self = super().__new__(cls) Meshing._alive.append(self) return weakref.proxy(self) - """ def __init__( self, @@ -30,5 +27,5 @@ def __init__( def switch_to_solver(self): self.tui.switch_to_solution_mode("yes") solver_session = Solver(fluent_connection=self.fluent_connection) - # self._alive.remove(self) + self._alive.remove(self) return solver_session From b2386d98c2b5d486df10085e68978623b5748eb6 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 21:50:46 +0100 Subject: [PATCH 36/49] workflow --- src/ansys/fluent/core/session_meshing.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ansys/fluent/core/session_meshing.py b/src/ansys/fluent/core/session_meshing.py index 20b226c19d7f..e875a2d28b9d 100644 --- a/src/ansys/fluent/core/session_meshing.py +++ b/src/ansys/fluent/core/session_meshing.py @@ -1,5 +1,6 @@ """Module containing class encapsulating Fluent connection.""" -import weakref +# import weakref + from ansys.fluent.core.fluent_connection import _FluentConnection from ansys.fluent.core.session_pure_meshing import PureMeshing @@ -11,12 +12,14 @@ class Meshing(PureMeshing): Meshing(PureMeshing) holds the top-level objects for meshing TUI and various meshing datamodel API calls.""" + """ _alive = [] def __new__(cls, *args, **kwargs): self = super().__new__(cls) Meshing._alive.append(self) return weakref.proxy(self) + """ def __init__( self, @@ -27,5 +30,5 @@ def __init__( def switch_to_solver(self): self.tui.switch_to_solution_mode("yes") solver_session = Solver(fluent_connection=self.fluent_connection) - self._alive.remove(self) + # self._alive.remove(self) return solver_session From c4f78e5397b6fb1dc5606dfe3f7d376016f09bcf Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 12 Aug 2022 22:01:49 +0100 Subject: [PATCH 37/49] workflow --- src/ansys/fluent/core/meshing/workflow.py | 6 ++--- src/ansys/fluent/core/session_base_meshing.py | 22 ++++++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index a1976d2caa24..d8763c702f7f 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -49,9 +49,9 @@ def _command(self): def __getattr__(self, attr): return getattr(self._task, attr) - def __init__(self, meshing): - self._workflow = meshing.workflow - self._meshing = meshing.meshing + def __init__(self, workflow, meshing): + self._workflow = workflow + self._meshing = meshing def task(self, name): return MeshingWorkflow.Task(self, name) diff --git a/src/ansys/fluent/core/session_base_meshing.py b/src/ansys/fluent/core/session_base_meshing.py index d46a358b7659..5f74ba0b5774 100644 --- a/src/ansys/fluent/core/session_base_meshing.py +++ b/src/ansys/fluent/core/session_base_meshing.py @@ -1,4 +1,5 @@ from ansys.fluent.core.fluent_connection import _FluentConnection +from ansys.fluent.core.meshing.workflow import MeshingWorkflow from ansys.fluent.core.services.datamodel_se import PyMenuGeneric from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric from ansys.fluent.core.session_shared import _CODEGEN_MSG_DATAMODEL, _CODEGEN_MSG_TUI @@ -42,16 +43,21 @@ def meshing(self): return self._meshing @property - def workflow(self): + def _workflow_se(self): """workflow datamodel root.""" - if self._workflow is None: - try: - from ansys.fluent.core.datamodel.workflow import Root as workflow_root + try: + from ansys.fluent.core.datamodel.workflow import Root as workflow_root - self._workflow = workflow_root(self._se_service, "workflow", []) - except (ImportError, ModuleNotFoundError): - LOG.warning(_CODEGEN_MSG_DATAMODEL) - self._workflow = PyMenuGeneric(self._se_service, "workflow") + workflow_se = workflow_root(self._se_service, "workflow", []) + except (ImportError, ModuleNotFoundError): + LOG.warning(_CODEGEN_MSG_DATAMODEL) + workflow_se = PyMenuGeneric(self._se_service, "workflow") + return workflow_se + + @property + def workflow(self): + if not self._workflow: + self._workflow = MeshingWorkflow(self._workflow_se, self.meshing) return self._workflow @property From 7831572bc5bcd146426aa3d02977d9563d9c8096 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 15 Aug 2022 11:01:17 +0100 Subject: [PATCH 38/49] task attribute support --- src/ansys/fluent/core/meshing/workflow.py | 24 +++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index d8763c702f7f..ed9d4780fd8a 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -1,3 +1,5 @@ +from typing import Any + from ansys.fluent.core.services.datamodel_se import PyCallableStateObject @@ -25,8 +27,15 @@ def __init__(self, task): def __getattr__(self, attr): return getattr(self._args, attr) - def get_expanded_state(self): - return self._task.get_expanded_arg_state() + def get_command_argument_state(self) -> Any: + return self._task.get_command_argument_state() + + def get_command_argument_attribute_value( + self, attribute_sub_path: str + ) -> Any: + return self._task.get_command_argument_attribute_value( + attribute_sub_path + ) def __init__(self, meshing, name): self._workflow = meshing._workflow @@ -35,11 +44,18 @@ def __init__(self, meshing, name): self._cmd = None self.Arguments = MeshingWorkflow.Task.Args(self) - def get_expanded_arg_state(self): + def get_command_argument_attribute_value(self, attribute_sub_path: str) -> Any: + cmd = self._refreshed_command() + return cmd.get_attrib_value(attribute_sub_path) + + def get_command_argument_state(self) -> Any: + return self._refreshed_command().get_state() + + def _refreshed_command(self): task_arg_state = self.Arguments.get_state() cmd = self._command() cmd.set_state(task_arg_state) - return cmd.get_state() + return cmd def _command(self): if not self._cmd: From fcf1652c407ce733d89235f9bd0bd8255d358013 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 15 Aug 2022 11:20:32 +0100 Subject: [PATCH 39/49] reversion --- codegen/allapigen.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/codegen/allapigen.py b/codegen/allapigen.py index e352b853d47c..90837cb39490 100644 --- a/codegen/allapigen.py +++ b/codegen/allapigen.py @@ -5,8 +5,6 @@ if __name__ == "__main__": print_fluent_version.generate() - for mod in (tuigen, datamodelgen, settingsgen): - try: - mod.generate() - except BaseException as ex: - print("skipping generation of", str(mod), str(ex)) + tuigen.generate() + datamodelgen.generate() + settingsgen.generate() From c9351e8bde3b800ce510652d8882c3c94b5ea727 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 15 Aug 2022 16:39:34 +0100 Subject: [PATCH 40/49] reversion --- src/ansys/fluent/core/__init__.py | 2 +- src/ansys/fluent/core/launcher/launcher.py | 12 +++++----- src/ansys/fluent/core/session.py | 20 +++++++++++------ src/ansys/fluent/core/session_base_meshing.py | 5 ++++- src/ansys/fluent/core/session_meshing.py | 22 +++++++++---------- src/ansys/fluent/core/session_pure_meshing.py | 19 +++++++++------- src/ansys/fluent/core/session_solver.py | 4 ++-- tests/test_session.py | 13 ++++++----- 8 files changed, 55 insertions(+), 42 deletions(-) diff --git a/src/ansys/fluent/core/__init__.py b/src/ansys/fluent/core/__init__.py index 6f0a5b4660c8..eee3db1b4995 100644 --- a/src/ansys/fluent/core/__init__.py +++ b/src/ansys/fluent/core/__init__.py @@ -13,7 +13,7 @@ set_ansys_version, set_fluent_path, ) -from ansys.fluent.core.session import BaseSession as Fluent # noqa: F401 +from ansys.fluent.core.session import _BaseSession as Fluent # noqa: F401 from ansys.fluent.core.utils.logging import LOG _VERSION_INFO = None diff --git a/src/ansys/fluent/core/launcher/launcher.py b/src/ansys/fluent/core/launcher/launcher.py index 2470bdb61178..b36e9c080995 100644 --- a/src/ansys/fluent/core/launcher/launcher.py +++ b/src/ansys/fluent/core/launcher/launcher.py @@ -16,7 +16,7 @@ from ansys.fluent.core.fluent_connection import _FluentConnection from ansys.fluent.core.launcher.fluent_container import start_fluent_container -from ansys.fluent.core.session import BaseSession, Session +from ansys.fluent.core.session import Session, _BaseSession from ansys.fluent.core.session_meshing import Meshing from ansys.fluent.core.session_pure_meshing import PureMeshing from ansys.fluent.core.session_solver import Solver @@ -240,8 +240,10 @@ def launch_remote_fluent( instance.wait_for_ready() # nb pymapdl sets max msg len here: channel = instance.build_grpc_channel() - return BaseSession( - channel=channel, cleanup_on_exit=cleanup_on_exit, remote_instance=instance + return _BaseSession( + fluent_connection=_FluentConnection( + channel=channel, cleanup_on_exit=cleanup_on_exit, remote_instance=instance + ) ) @@ -263,7 +265,7 @@ def launch_fluent( case_filepath: str = None, meshing_mode: bool = None, mode: Union[LaunchModes, str, None] = None, -) -> Union[BaseSession, Session]: +) -> Union[_BaseSession, Session]: """Launch Fluent locally in server mode or connect to a running Fluent server instance. @@ -439,7 +441,7 @@ def launch_fluent( ip = argvals.get("ip", None) port = argvals.get("port", None) return new_session( - _FluentConnection( + fluent_connection=_FluentConnection( ip=ip, port=port, cleanup_on_exit=cleanup_on_exit, diff --git a/src/ansys/fluent/core/session.py b/src/ansys/fluent/core/session.py index 30e30c599f3c..0bd7f5694ce6 100644 --- a/src/ansys/fluent/core/session.py +++ b/src/ansys/fluent/core/session.py @@ -11,7 +11,7 @@ ) from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric from ansys.fluent.core.services.settings import SettingsService -from ansys.fluent.core.session_base_meshing import BaseMeshing +from ansys.fluent.core.session_base_meshing import _BaseMeshing from ansys.fluent.core.session_shared import _CODEGEN_MSG_TUI from ansys.fluent.core.solver.flobject import get_root as settings_get_root from ansys.fluent.core.utils.logging import LOG @@ -32,7 +32,7 @@ def parse_server_info_file(filename: str): return ip, port, password -class BaseSession: +class _BaseSession: """Instantiates a Fluent connection. Attributes @@ -95,7 +95,7 @@ def create_from_server_info_file( """ ip, port, password = parse_server_info_file(server_info_filepath) session = cls( - _FluentConnection( + fluent_connection=_FluentConnection( ip=ip, port=port, password=password, @@ -133,11 +133,14 @@ def __enter__(self): def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any): self.fluent_connection.exit() + def __getattr__(self, attr): + return getattr(self.fluent_connection, attr) + class Session: """Instantiates a Fluent connection. This is a deprecated class. This has - been replaced by the "BaseSession" class to implement the new fluent launch - modes. + been replaced by the "_BaseSession" class to implement the new fluent + launch modes. Attributes ---------- @@ -192,7 +195,7 @@ def __init__( self.scheme_eval = self.fluent_connection.scheme_eval - self.meshing = BaseMeshing(self.fluent_connection) + self.meshing = _BaseMeshing(self.fluent_connection) self._datamodel_service_tui = self.fluent_connection.datamodel_service_tui self._settings_service = self.fluent_connection.settings_service @@ -231,7 +234,7 @@ def create_from_server_info_file( """ ip, port, password = parse_server_info_file(server_info_filepath) session = Session( - _FluentConnection( + fluent_connection=_FluentConnection( ip=ip, port=port, password=password, @@ -269,6 +272,9 @@ def __enter__(self): def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any): self.fluent_connection.exit() + def __getattr__(self, attr): + return getattr(self.fluent_connection, attr) + class Solver: def __init__( self, tui_service: DatamodelService_TUI, settings_service: SettingsService diff --git a/src/ansys/fluent/core/session_base_meshing.py b/src/ansys/fluent/core/session_base_meshing.py index 5f74ba0b5774..f1dabbfa2874 100644 --- a/src/ansys/fluent/core/session_base_meshing.py +++ b/src/ansys/fluent/core/session_base_meshing.py @@ -5,7 +5,10 @@ from ansys.fluent.core.session_shared import _CODEGEN_MSG_DATAMODEL, _CODEGEN_MSG_TUI -class BaseMeshing: +class _BaseMeshing: + + meshing_attrs = ("tui", "meshing", "workflow", "PartManagement", "PMFileManagement") + def __init__(self, fluent_connection: _FluentConnection): self._tui_service = fluent_connection.datamodel_service_tui self._se_service = fluent_connection.datamodel_service_se diff --git a/src/ansys/fluent/core/session_meshing.py b/src/ansys/fluent/core/session_meshing.py index e875a2d28b9d..d1205ec760f3 100644 --- a/src/ansys/fluent/core/session_meshing.py +++ b/src/ansys/fluent/core/session_meshing.py @@ -2,7 +2,10 @@ # import weakref +from typing import Any + from ansys.fluent.core.fluent_connection import _FluentConnection +from ansys.fluent.core.session_base_meshing import _BaseMeshing from ansys.fluent.core.session_pure_meshing import PureMeshing from ansys.fluent.core.session_solver import Solver @@ -10,25 +13,20 @@ class Meshing(PureMeshing): """Encapsulates a Fluent - Meshing session connection. Meshing(PureMeshing) holds the top-level objects - for meshing TUI and various meshing datamodel API calls.""" - - """ - _alive = [] - - def __new__(cls, *args, **kwargs): - self = super().__new__(cls) - Meshing._alive.append(self) - return weakref.proxy(self) - """ + for meshing TUI and various meshing datamodel API calls. + In this general meshing mode, switch to solver is available, + after which""" def __init__( self, fluent_connection: _FluentConnection, ): super(Meshing, self).__init__(fluent_connection=fluent_connection) + self.switch_to_solver = lambda: self._switch_to_solver() - def switch_to_solver(self): + def _switch_to_solver(self) -> Any: self.tui.switch_to_solution_mode("yes") solver_session = Solver(fluent_connection=self.fluent_connection) - # self._alive.remove(self) + for attr in _BaseMeshing.meshing_attrs + ("switch_to_solver",): + delattr(self, attr) return solver_session diff --git a/src/ansys/fluent/core/session_pure_meshing.py b/src/ansys/fluent/core/session_pure_meshing.py index 04e18f7f04c8..744ac07d73a9 100644 --- a/src/ansys/fluent/core/session_pure_meshing.py +++ b/src/ansys/fluent/core/session_pure_meshing.py @@ -4,19 +4,22 @@ """ from ansys.fluent.core.fluent_connection import _FluentConnection -from ansys.fluent.core.session import BaseSession -from ansys.fluent.core.session_base_meshing import BaseMeshing +from ansys.fluent.core.session import _BaseSession +from ansys.fluent.core.session_base_meshing import _BaseMeshing -class PureMeshing(BaseSession): +class PureMeshing(_BaseSession): """Encapsulates a Fluent - Pure Meshing session connection. - PureMeshing(BaseSession) holds the top-level objects - for meshing TUI and various meshing datamodel API calls.""" + PureMeshing(_BaseSession) holds the top-level objects + for meshing TUI and various meshing datamodel API calls. + In pure-meshing mode, switch to solver is not available. + Public attributes of this class or extracted from the _BaseMeshing + class""" def __init__(self, fluent_connection: _FluentConnection): super(PureMeshing, self).__init__(fluent_connection=fluent_connection) - self._base_meshing = BaseMeshing(fluent_connection) + self._base_meshing = _BaseMeshing(fluent_connection) - def __getattr__(self, attr): - return getattr(self._base_meshing, attr) + for attr in _BaseMeshing.meshing_attrs: + setattr(self, attr, getattr(self._base_meshing, attr)) diff --git a/src/ansys/fluent/core/session_solver.py b/src/ansys/fluent/core/session_solver.py index b4d01f6adf31..c7fb2b4921c8 100644 --- a/src/ansys/fluent/core/session_solver.py +++ b/src/ansys/fluent/core/session_solver.py @@ -1,12 +1,12 @@ """Module containing class encapsulating Fluent connection.""" from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric -from ansys.fluent.core.session import _CODEGEN_MSG_TUI, BaseSession +from ansys.fluent.core.session import _CODEGEN_MSG_TUI, _BaseSession from ansys.fluent.core.solver.flobject import get_root as settings_get_root from ansys.fluent.core.utils.logging import LOG -class Solver(BaseSession): +class Solver(_BaseSession): """Encapsulates a Fluent - Solver session connection. Solver(Session) holds the top-level objects for solver TUI and settings objects calls.""" diff --git a/tests/test_session.py b/tests/test_session.py index 51327a98cfd0..f9f4e9d484ad 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -7,8 +7,9 @@ from ansys.api.fluent.v0 import health_pb2, health_pb2_grpc from ansys.fluent.core import launch_fluent +from ansys.fluent.core.fluent_connection import _FluentConnection from ansys.fluent.core.services.health_check import HealthCheckService -from ansys.fluent.core.session import BaseSession +from ansys.fluent.core.session import _BaseSession class MockHealthServicer(health_pb2_grpc.HealthServicer): @@ -34,7 +35,7 @@ def test_create_session_by_passing_ip_and_port( health_pb2_grpc.add_HealthServicer_to_server(MockHealthServicer(), server) monkeypatch.setenv("PYFLUENT_LAUNCHED_FROM_FLUENT", "1") server.start() - session = BaseSession(ip=ip, port=port, cleanup_on_exit=False) + session = _BaseSession(_FluentConnection(ip=ip, port=port, cleanup_on_exit=False)) assert session.check_health() == HealthCheckService.Status.SERVING.name server.stop(None) session.exit() @@ -53,7 +54,7 @@ def test_create_session_by_setting_ip_and_port_env_var( server.start() monkeypatch.setenv("PYFLUENT_FLUENT_IP", ip) monkeypatch.setenv("PYFLUENT_FLUENT_PORT", str(port)) - session = BaseSession(cleanup_on_exit=False) + session = _BaseSession(_FluentConnection(cleanup_on_exit=False)) assert session.check_health() == HealthCheckService.Status.SERVING.name server.stop(None) session.exit() @@ -71,7 +72,7 @@ def test_create_session_by_passing_grpc_channel( monkeypatch.setenv("PYFLUENT_LAUNCHED_FROM_FLUENT", "1") server.start() channel = grpc.insecure_channel(f"{ip}:{port}") - session = BaseSession(channel=channel, cleanup_on_exit=False) + session = _BaseSession(_FluentConnection(channel=channel, cleanup_on_exit=False)) assert session.check_health() == HealthCheckService.Status.SERVING.name server.stop(None) session.exit() @@ -87,7 +88,7 @@ def test_create_session_from_server_info_file(tmp_path: Path) -> None: server.start() server_info_file = tmp_path / "server_info.txt" server_info_file.write_text(f"{ip}:{port}\n12345") - session = BaseSession.create_from_server_info_file( + session = _BaseSession.create_from_server_info_file( server_info_filepath=str(server_info_file), cleanup_on_exit=False ) assert session.check_health() == HealthCheckService.Status.SERVING.name @@ -107,7 +108,7 @@ def test_create_session_from_server_info_file_with_wrong_password( server.start() server_info_file = tmp_path / "server_info.txt" server_info_file.write_text(f"{ip}:{port}\n1234") - session = BaseSession.create_from_server_info_file( + session = _BaseSession.create_from_server_info_file( server_info_filepath=str(server_info_file), cleanup_on_exit=False ) assert session.check_health() == HealthCheckService.Status.NOT_SERVING.name From 15d6e36818b7326559030afe13b4d00b0dab4bb1 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 15 Aug 2022 16:41:48 +0100 Subject: [PATCH 41/49] reversion --- src/ansys/fluent/core/fluent_connection.py | 273 +++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 src/ansys/fluent/core/fluent_connection.py diff --git a/src/ansys/fluent/core/fluent_connection.py b/src/ansys/fluent/core/fluent_connection.py new file mode 100644 index 000000000000..f2ff1ba8a9e7 --- /dev/null +++ b/src/ansys/fluent/core/fluent_connection.py @@ -0,0 +1,273 @@ +from ctypes import c_int, sizeof +import itertools +import os +import threading +from typing import Callable, List, Optional, Tuple +import weakref + +import grpc + +from ansys.fluent.core.services.datamodel_se import ( + DatamodelService as DatamodelService_SE, +) +from ansys.fluent.core.services.datamodel_tui import ( + DatamodelService as DatamodelService_TUI, +) +from ansys.fluent.core.services.events import EventsService +from ansys.fluent.core.services.field_data import FieldData, FieldDataService, FieldInfo +from ansys.fluent.core.services.health_check import HealthCheckService +from ansys.fluent.core.services.monitor import MonitorsService +from ansys.fluent.core.services.scheme_eval import SchemeEval, SchemeEvalService +from ansys.fluent.core.services.settings import SettingsService +from ansys.fluent.core.services.transcript import TranscriptService +from ansys.fluent.core.solver.events_manager import EventsManager +from ansys.fluent.core.solver.monitors_manager import MonitorsManager + + +def _get_max_c_int_limit() -> int: + """Get the maximum limit of a C int. + + Returns + ------- + int + The maximum limit of a C int + """ + return 2 ** (sizeof(c_int) * 8 - 1) - 1 + + +class MonitorThread(threading.Thread): + """A class used for monitoring a Fluent session. + + Daemon thread which will ensure cleanup of session objects, shutdown of + non-deamon threads etc. + + Attributes + ---------- + cbs : List[Callable] + Cleanup/shutdown functions + """ + + def __init__(self): + super().__init__(daemon=True) + self.cbs: List[Callable] = [] + + def run(self) -> None: + main_thread = threading.main_thread() + main_thread.join() + for cb in self.cbs: + cb() + + +class _FluentConnection: + """Encapsulates a Fluent connection. + + Methods + ------- + start_transcript() + Start streaming of Fluent transcript + + stop_transcript() + Stop streaming of Fluent transcript + + check_health() + Check health of Fluent connection + + exit() + Close the Fluent connection and exit Fluent. + """ + + _on_exit_cbs: List[Callable] = [] + _id_iter = itertools.count() + _monitor_thread: Optional[MonitorThread] = None + + def __init__( + self, + ip: str = None, + port: int = None, + password: str = None, + channel: grpc.Channel = None, + cleanup_on_exit: bool = True, + start_transcript: bool = True, + remote_instance=None, + ): + """Instantiate a Session. + + Parameters + ---------- + ip : str, optional + IP address to connect to existing Fluent instance. Used only + when ``channel`` is ``None``. Defaults to ``"127.0.0.1"`` + and can also be set by the environment variable + ``PYFLUENT_FLUENT_IP=``. + port : int, optional + Port to connect to existing Fluent instance. Used only + when ``channel`` is ``None``. Defaults value can be set by + the environment variable ``PYFLUENT_FLUENT_PORT=``. + password : str, optional + Password to connect to existing Fluent instance. + channel : grpc.Channel, optional + Grpc channel to use to connect to existing Fluent instance. + ip and port arguments will be ignored when channel is + specified. + cleanup_on_exit : bool, optional + When True, the connected Fluent session will be shut down + when PyFluent is exited or exit() is called on the session + instance, by default True. + start_transcript : bool, optional + The Fluent transcript is started in the client only when + start_transcript is True. It can be started and stopped + subsequently via method calls on the Session object. + remote_instance : ansys.platform.instancemanagement.Instance + The corresponding remote instance when Fluent is launched through + PyPIM. This instance will be deleted when calling + ``Session.exit()``. + """ + self._channel_str = None + if channel is not None: + self._channel = channel + else: + if not ip: + ip = os.getenv("PYFLUENT_FLUENT_IP", "127.0.0.1") + if not port: + port = os.getenv("PYFLUENT_FLUENT_PORT") + self._channel_str = f"{ip}:{port}" + if not port: + raise ValueError( + "The port to connect to Fluent session is not provided." + ) + # Same maximum message length is used in the server + max_message_length = _get_max_c_int_limit() + self._channel = grpc.insecure_channel( + f"{ip}:{port}", + options=[ + ("grpc.max_send_message_length", max_message_length), + ("grpc.max_receive_message_length", max_message_length), + ], + ) + self._metadata: List[Tuple[str, str]] = ( + [("password", password)] if password else [] + ) + self._id = f"session-{next(_FluentConnection._id_iter)}" + + if not _FluentConnection._monitor_thread: + _FluentConnection._monitor_thread = MonitorThread() + _FluentConnection._monitor_thread.start() + + self._transcript_service = TranscriptService(self._channel, self._metadata) + self._transcript_thread: Optional[threading.Thread] = None + + self._events_service = EventsService(self._channel, self._metadata) + self.events_manager = EventsManager(self._id, self._events_service) + + self._monitors_service = MonitorsService(self._channel, self._metadata) + self.monitors_manager = MonitorsManager(self._id, self._monitors_service) + + self.events_manager.register_callback( + "InitializedEvent", self.monitors_manager.refresh + ) + self.events_manager.register_callback( + "DataReadEvent", self.monitors_manager.refresh + ) + self.events_manager.start() + self.datamodel_service_tui = DatamodelService_TUI(self._channel, self._metadata) + self.datamodel_service_se = DatamodelService_SE(self._channel, self._metadata) + self.settings_service = SettingsService(self._channel, self._metadata) + + self._field_data_service = FieldDataService(self._channel, self._metadata) + self.field_info = FieldInfo(self._field_data_service) + self.field_data = FieldData(self._field_data_service, self.field_info) + + self._health_check_service = HealthCheckService(self._channel, self._metadata) + + self._scheme_eval_service = SchemeEvalService(self._channel, self._metadata) + self.scheme_eval = SchemeEval(self._scheme_eval_service) + + self._cleanup_on_exit = cleanup_on_exit + self._start_transcript = start_transcript + + if start_transcript: + self.start_transcript() + + self._remote_instance = remote_instance + + self._finalizer = weakref.finalize( + self, + _FluentConnection._exit, + self._channel, + self._cleanup_on_exit, + self.scheme_eval, + self._transcript_service, + self.events_manager, + self._remote_instance, + ) + _FluentConnection._monitor_thread.cbs.append(self._finalizer) + + @property + def id(self) -> str: + """Return the session id.""" + return self._id + + @staticmethod + def _print_transcript(transcript: str): + print(transcript) + + @staticmethod + def _process_transcript(transcript_service): + responses = transcript_service.begin_streaming() + transcript = "" + while True: + try: + response = next(responses) + transcript += response.transcript + if transcript[-1] == "\n": + _FluentConnection._print_transcript(transcript[0:-1]) + transcript = "" + except StopIteration: + break + + def start_transcript(self) -> None: + """Start streaming of Fluent transcript.""" + self._transcript_thread = threading.Thread( + target=_FluentConnection._process_transcript, + args=(self._transcript_service,), + ) + + self._transcript_thread.start() + + def stop_transcript(self) -> None: + """Stop streaming of Fluent transcript.""" + self._transcript_service.end_streaming() + + def check_health(self) -> str: + """Check health of Fluent connection.""" + if self._channel: + try: + return self._health_check_service.check_health() + except Exception: + return HealthCheckService.Status.NOT_SERVING.name + else: + return HealthCheckService.Status.NOT_SERVING.name + + def exit(self) -> None: + """Close the Fluent connection and exit Fluent.""" + self._finalizer() + + @staticmethod + def _exit( + channel, + cleanup_on_exit, + scheme_eval, + transcript_service, + events_manager, + remote_instance, + ) -> None: + if channel: + if cleanup_on_exit: + scheme_eval.exec(("(exit-server)",)) + transcript_service.end_streaming() + events_manager.stop() + channel.close() + channel = None + + if remote_instance: + remote_instance.delete() From fda13802f056f560d1a143a275a3e20926d5c25b Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 15 Aug 2022 17:14:35 +0100 Subject: [PATCH 42/49] workflow --- src/ansys/fluent/core/meshing/workflow.py | 4 ++++ src/ansys/fluent/core/services/datamodel_se.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index ed9d4780fd8a..fa853082db50 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -44,6 +44,10 @@ def __init__(self, meshing, name): self._cmd = None self.Arguments = MeshingWorkflow.Task.Args(self) + @property + def CommandArguments(self): + return self._refreshed_command() + def get_command_argument_attribute_value(self, attribute_sub_path: str) -> Any: cmd = self._refreshed_command() return cmd.get_attrib_value(attribute_sub_path) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index c5282e69503c..e1df414900a9 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -616,6 +616,8 @@ def get_attrib_value(self, attrib: str) -> Any: attrib_path = f"{self.name}/{attrib}" return self.parent.get_attrib_value(attrib_path) + getAttribValue = get_attrib_value + def help(self) -> None: pass From 4efe2329e74d41584aad2567816a58ca2f404f15 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 15 Aug 2022 17:22:48 +0100 Subject: [PATCH 43/49] workflow --- .../fluent/core/services/datamodel_se.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index e1df414900a9..755d6da68b79 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -104,6 +104,8 @@ def execute_command( ) -> DataModelProtoModule.ExecuteCommandResponse: return self.__stub.executeCommand(request, metadata=self.__metadata) + # pending the proto changes + """ @catch_grpc_error def create_command_arguments( self, request: DataModelProtoModule.CreateCommandArgumentsRequest @@ -115,6 +117,7 @@ def delete_command_arguments( self, request: DataModelProtoModule.DeleteCommandArgumentsRequest ) -> DataModelProtoModule.DeleteCommandArgumentsResponse: return self.__stub.deleteCommandArguments(request, metadata=self.__metadata) + """ @catch_grpc_error def get_specs( @@ -368,12 +371,16 @@ def rename(self, new_name: str) -> None: ) def create_command_arguments(self, command): + pass + # pending the proto changes + """ request = DataModelProtoModule.CreateCommandArgumentsRequest() request.rules = self.rules request.path = _convert_path_to_se_path(self.path) request.command = command response = self.service.create_command_arguments(request) return response.commandid + """ class PyNamedObjectContainer: @@ -576,18 +583,26 @@ def help(self) -> None: print(help_string) def _create_command_arguments(self): + # pending the proto changes + pass + """ request = DataModelProtoModule.CreateCommandArgumentsRequest() request.rules = self.rules request.path = _convert_path_to_se_path(self.path) request.command = self.command response = self.service.create_command_arguments(request) return response.commandid + """ def new(self): + # pending the proto changes + pass + """ id = self._create_command_arguments() return PyCommandArguments( self.service, self.rules, self.command, self.path.copy(), id ) + """ class PyCommandArgumentsSubItem(PyCallableStateObject): @@ -630,6 +645,9 @@ def __init__( self.path.append((command, id)) def __del__(self): + # pending the proto changes + pass + """ request = DataModelProtoModule.DeleteCommandArgumentsRequest() request.rules = self.rules request.path = _convert_path_to_se_path(self.path[:-1]) @@ -640,6 +658,7 @@ def __del__(self): except ValueError: # "Cannot invoke RPC on closed channel!" pass + """ def __getattr__(self, attr): return PyCommandArgumentsSubItem(self, attr) From 20c90b88e1690f2f764064d2976c7ea73d2fe52b Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 15 Aug 2022 17:34:48 +0100 Subject: [PATCH 44/49] fix name --- codegen/datamodelgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen/datamodelgen.py b/codegen/datamodelgen.py index 6f791305216f..dd449e25b77e 100644 --- a/codegen/datamodelgen.py +++ b/codegen/datamodelgen.py @@ -5,7 +5,7 @@ from typing import Any, Dict from ansys.api.fluent.v0 import datamodel_se_pb2 as DataModelProtoModule -from ansys.fluent.core.session import BaseSession as Session +from ansys.fluent.core.session import _BaseSession as Session _THIS_DIR = Path(__file__).parent From 1c1c6ff512d42c5e9f534645ae24cd2b6ae8b168 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 15 Aug 2022 19:00:39 +0100 Subject: [PATCH 45/49] log --- src/ansys/fluent/core/session_base_meshing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/fluent/core/session_base_meshing.py b/src/ansys/fluent/core/session_base_meshing.py index f1dabbfa2874..7b9ae21fa333 100644 --- a/src/ansys/fluent/core/session_base_meshing.py +++ b/src/ansys/fluent/core/session_base_meshing.py @@ -3,6 +3,7 @@ from ansys.fluent.core.services.datamodel_se import PyMenuGeneric from ansys.fluent.core.services.datamodel_tui import TUIMenuGeneric from ansys.fluent.core.session_shared import _CODEGEN_MSG_DATAMODEL, _CODEGEN_MSG_TUI +from ansys.fluent.core.utils.logging import LOG class _BaseMeshing: From 2c00e3c499d2211259cf75843e1d00d4b9640e9e Mon Sep 17 00:00:00 2001 From: Sean Pearson <93727996+seanpearsonuk@users.noreply.github.com> Date: Tue, 16 Aug 2022 06:19:31 +0100 Subject: [PATCH 46/49] Update test_pure_mesh_vs_mesh_workflow.py revert --- tests/test_pure_mesh_vs_mesh_workflow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_pure_mesh_vs_mesh_workflow.py b/tests/test_pure_mesh_vs_mesh_workflow.py index 091d6ec951d0..af5bb0ef8254 100644 --- a/tests/test_pure_mesh_vs_mesh_workflow.py +++ b/tests/test_pure_mesh_vs_mesh_workflow.py @@ -38,5 +38,5 @@ def test_meshing_mode_post_switching_to_solver(load_mixing_elbow_meshing): meshing_session = load_mixing_elbow_meshing meshing_session.switch_to_solver() # Post switching to solver session, meshing session specific attributes are unavailable - # with pytest.raises(AttributeError): - # meshing_session.workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") + with pytest.raises(AttributeError): + meshing_session.workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") From acb38a7f8e441c9ff14b320b06d53eb156a704de Mon Sep 17 00:00:00 2001 From: Sean Pearson <93727996+seanpearsonuk@users.noreply.github.com> Date: Tue, 16 Aug 2022 06:23:32 +0100 Subject: [PATCH 47/49] Update workflow.py --- src/ansys/fluent/core/meshing/workflow.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index fa853082db50..9aa706e8c893 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -27,15 +27,6 @@ def __init__(self, task): def __getattr__(self, attr): return getattr(self._args, attr) - def get_command_argument_state(self) -> Any: - return self._task.get_command_argument_state() - - def get_command_argument_attribute_value( - self, attribute_sub_path: str - ) -> Any: - return self._task.get_command_argument_attribute_value( - attribute_sub_path - ) def __init__(self, meshing, name): self._workflow = meshing._workflow @@ -48,13 +39,6 @@ def __init__(self, meshing, name): def CommandArguments(self): return self._refreshed_command() - def get_command_argument_attribute_value(self, attribute_sub_path: str) -> Any: - cmd = self._refreshed_command() - return cmd.get_attrib_value(attribute_sub_path) - - def get_command_argument_state(self) -> Any: - return self._refreshed_command().get_state() - def _refreshed_command(self): task_arg_state = self.Arguments.get_state() cmd = self._command() From c21c21494f41b615a9937ce04b30e4469ab676bc Mon Sep 17 00:00:00 2001 From: Prithwish Mukherjee Date: Tue, 16 Aug 2022 11:13:04 +0530 Subject: [PATCH 48/49] minor style update --- src/ansys/fluent/core/meshing/workflow.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index 9aa706e8c893..65a0928b793d 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -1,5 +1,3 @@ -from typing import Any - from ansys.fluent.core.services.datamodel_se import PyCallableStateObject @@ -27,7 +25,6 @@ def __init__(self, task): def __getattr__(self, attr): return getattr(self._args, attr) - def __init__(self, meshing, name): self._workflow = meshing._workflow self._meshing = meshing._meshing From 1115c086567bb9520ec5f5c4b54fded9f5a298b7 Mon Sep 17 00:00:00 2001 From: Sean Pearson <93727996+seanpearsonuk@users.noreply.github.com> Date: Tue, 16 Aug 2022 12:51:43 +0100 Subject: [PATCH 49/49] update dir, remove some redundant code (#725) * update dir, remove some redundant code * extend testing * Update test_session.py * add call op in wf class --- src/ansys/fluent/core/meshing/workflow.py | 22 +++++++++++-------- .../fluent/core/services/datamodel_se.py | 2 +- src/ansys/fluent/core/session.py | 18 +++++++++++++++ tests/test_pure_mesh_vs_mesh_workflow.py | 22 ++++++++++++++++++- tests/test_session.py | 8 +++++++ 5 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/ansys/fluent/core/meshing/workflow.py b/src/ansys/fluent/core/meshing/workflow.py index 65a0928b793d..7094ed11996e 100644 --- a/src/ansys/fluent/core/meshing/workflow.py +++ b/src/ansys/fluent/core/meshing/workflow.py @@ -17,20 +17,11 @@ def __init__(self, task_name): class MeshingWorkflow: class Task(PyCallableStateObject): - class Args(PyCallableStateObject): - def __init__(self, task): - self._task = task - self._args = task.Arguments - - def __getattr__(self, attr): - return getattr(self._args, attr) - def __init__(self, meshing, name): self._workflow = meshing._workflow self._meshing = meshing._meshing self._task = self._workflow.TaskObject[name] self._cmd = None - self.Arguments = MeshingWorkflow.Task.Args(self) @property def CommandArguments(self): @@ -50,6 +41,11 @@ def _command(self): def __getattr__(self, attr): return getattr(self._task, attr) + def __dir__(self): + return sorted( + set(list(self.__dict__.keys()) + dir(type(self)) + dir(self._task)) + ) + def __init__(self, workflow, meshing): self._workflow = workflow self._meshing = meshing @@ -59,3 +55,11 @@ def task(self, name): def __getattr__(self, attr): return getattr(self._workflow, attr) + + def __dir__(self): + return sorted( + set(list(self.__dict__.keys()) + dir(type(self)) + dir(self._workflow)) + ) + + def __call__(self): + return self._workflow() diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 755d6da68b79..d2dd3daddd11 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -583,8 +583,8 @@ def help(self) -> None: print(help_string) def _create_command_arguments(self): - # pending the proto changes pass + # pending the proto changes """ request = DataModelProtoModule.CreateCommandArgumentsRequest() request.rules = self.rules diff --git a/src/ansys/fluent/core/session.py b/src/ansys/fluent/core/session.py index 0bd7f5694ce6..db4129324141 100644 --- a/src/ansys/fluent/core/session.py +++ b/src/ansys/fluent/core/session.py @@ -136,6 +136,15 @@ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any): def __getattr__(self, attr): return getattr(self.fluent_connection, attr) + def __dir__(self): + return sorted( + set( + list(self.__dict__.keys()) + + dir(type(self)) + + dir(self.fluent_connection) + ) + ) + class Session: """Instantiates a Fluent connection. This is a deprecated class. This has @@ -275,6 +284,15 @@ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any): def __getattr__(self, attr): return getattr(self.fluent_connection, attr) + def __dir__(self): + return sorted( + set( + list(self.__dict__.keys()) + + dir(type(self)) + + dir(self.fluent_connection) + ) + ) + class Solver: def __init__( self, tui_service: DatamodelService_TUI, settings_service: SettingsService diff --git a/tests/test_pure_mesh_vs_mesh_workflow.py b/tests/test_pure_mesh_vs_mesh_workflow.py index af5bb0ef8254..2504776ce196 100644 --- a/tests/test_pure_mesh_vs_mesh_workflow.py +++ b/tests/test_pure_mesh_vs_mesh_workflow.py @@ -6,7 +6,21 @@ @pytest.mark.setup def test_pure_meshing_mode(load_mixing_elbow_pure_meshing): pure_meshing_session = load_mixing_elbow_pure_meshing - assert pure_meshing_session.workflow.TaskObject["Import Geometry"].Execute() + # check a few dir elements + # n.b. 'field_data', 'field_info' need to + # be eliminated from meshing sessions + session_dir = dir(pure_meshing_session) + for attr in ("field_data", "field_info", "meshing", "workflow"): + assert attr in session_dir + workflow = pure_meshing_session.workflow + workflow_dir = dir(workflow) + for attr in ("TaskObject", "InsertNewTask", "Workflow", "setState"): + assert attr in workflow_dir + import_geometry = workflow.TaskObject["Import Geometry"] + import_geometry_dir = dir(import_geometry) + for attr in ("AddChildToTask", "Arguments", "Execute", "setState"): + assert attr in import_geometry_dir + assert import_geometry.Execute() with pytest.raises(AttributeError): pure_meshing_session.switch_to_solver() @@ -16,6 +30,12 @@ def test_pure_meshing_mode(load_mixing_elbow_pure_meshing): @pytest.mark.setup def test_meshing_mode(load_mixing_elbow_meshing): meshing_session = load_mixing_elbow_meshing + # check a few dir elements + # n.b. 'field_data', 'field_info' need to + # be eliminated from meshing sessions + session_dir = dir(meshing_session) + for attr in ("field_data", "field_info", "meshing", "workflow"): + assert attr in session_dir assert meshing_session.workflow.TaskObject["Import Geometry"].Execute() assert meshing_session.switch_to_solver() diff --git a/tests/test_session.py b/tests/test_session.py index f9f4e9d484ad..249a7669d22d 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -130,6 +130,10 @@ def test_create_session_from_launch_fluent_by_passing_ip_and_port( session = launch_fluent( start_instance=False, ip=ip, port=port, cleanup_on_exit=False, mode="solver" ) + # check a few dir elements + session_dir = dir(session) + for attr in ("field_data", "field_info", "setup", "solution"): + assert attr in session_dir assert session.check_health() == HealthCheckService.Status.SERVING.name server.stop(None) session.exit() @@ -149,6 +153,10 @@ def test_create_session_from_launch_fluent_by_setting_ip_and_port_env_var( monkeypatch.setenv("PYFLUENT_FLUENT_IP", ip) monkeypatch.setenv("PYFLUENT_FLUENT_PORT", str(port)) session = launch_fluent(start_instance=False, cleanup_on_exit=False, mode="solver") + # check a few dir elements + session_dir = dir(session) + for attr in ("field_data", "field_info"): + assert attr in session_dir assert session.check_health() == HealthCheckService.Status.SERVING.name server.stop(None) session.exit()