From 225db4374e66a55d727e6bdd8af24c3f1ec78936 Mon Sep 17 00:00:00 2001 From: Camille Bellot <80476446+cbellot000@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:17:58 +0200 Subject: [PATCH] fixes for performance (#1669) --- src/ansys/dpf/core/any.py | 158 +++++++++---------- src/ansys/dpf/core/common.py | 139 ++++++++-------- src/ansys/dpf/core/generic_data_container.py | 45 +++--- src/ansys/dpf/core/property_field.py | 10 +- 4 files changed, 185 insertions(+), 167 deletions(-) diff --git a/src/ansys/dpf/core/any.py b/src/ansys/dpf/core/any.py index 6a4681dc3f..209708e789 100644 --- a/src/ansys/dpf/core/any.py +++ b/src/ansys/dpf/core/any.py @@ -89,7 +89,7 @@ def _new_from_string_as_bytes_on_client(self, client, str): else: return self._api.any_new_from_string_on_client(client, str) - def _type_to_new_from_get_as_method(self): + def _type_to_new_from_get_as_method(self, obj): from ansys.dpf.core import ( field, property_field, @@ -100,74 +100,72 @@ def _type_to_new_from_get_as_method(self): custom_type_field, collection, ) - - return [ - ( - int, + if issubclass(obj, int): + return ( self._api.any_new_from_int, self._api.any_get_as_int, self._api.any_new_from_int_on_client, - ), - ( - str, + ) + elif issubclass(obj, str): + return ( self._new_from_string, self._get_as_string, self._new_from_string_on_client, - ), - ( - float, + ) + elif issubclass(obj, float): + return ( self._api.any_new_from_double, self._api.any_get_as_double, self._api.any_new_from_double_on_client, - ), - ( - bytes, + ) + elif issubclass(obj, bytes): + return ( self._new_from_string_as_bytes, self._get_as_string_as_bytes, self._new_from_string_as_bytes_on_client, - ), - (field.Field, self._api.any_new_from_field, self._api.any_get_as_field), - ( - property_field.PropertyField, + ) + elif issubclass(obj, field.Field): + return self._api.any_new_from_field, self._api.any_get_as_field + elif issubclass(obj, property_field.PropertyField): + return ( self._api.any_new_from_property_field, self._api.any_get_as_property_field, - ), - ( - string_field.StringField, + ) + elif issubclass(obj, string_field.StringField): + return ( self._api.any_new_from_string_field, self._api.any_get_as_string_field, - ), - ( - generic_data_container.GenericDataContainer, + ) + elif issubclass(obj, generic_data_container.GenericDataContainer): + return ( self._api.any_new_from_generic_data_container, self._api.any_get_as_generic_data_container, - ), - ( - scoping.Scoping, + ) + elif issubclass(obj, scoping.Scoping): + return ( self._api.any_new_from_scoping, self._api.any_get_as_scoping, - ), - ( - data_tree.DataTree, + ) + elif issubclass(obj, data_tree.DataTree): + return ( self._api.any_new_from_data_tree, self._api.any_get_as_data_tree, - ), - ( - custom_type_field.CustomTypeField, + ) + elif issubclass(obj, custom_type_field.CustomTypeField): + return ( self._api.any_new_from_custom_type_field, self._api.any_get_as_custom_type_field, - ), - ( - collection.Collection, + ) + elif issubclass(obj, collection.Collection): + return ( self._api.any_new_from_any_collection, self._api.any_get_as_any_collection, - ), - ( - dpf_vector.DPFVectorInt, + ) + elif issubclass(obj, dpf_vector.DPFVectorInt): + return ( self._api.any_new_from_int_collection, self._api.any_get_as_int_collection, - ), - ] + ) @staticmethod def new_from(obj, server=None): @@ -190,30 +188,31 @@ def new_from(obj, server=None): any_dpf = Any(server=inner_server) - for type_tuple in any_dpf._type_to_new_from_get_as_method(): - if isinstance(obj, type_tuple[0]): - # call respective new_from function - if isinstance(server, ansys.dpf.core.server_types.InProcessServer) or not ( - isinstance(obj, (int, str, float, bytes)) - ): - any_dpf._internal_obj = type_tuple[1](obj) - else: - any_dpf._internal_obj = type_tuple[3](inner_server.client, obj) - # store get_as & type for casting back to original type - any_dpf._internal_type = type_tuple[0] - any_dpf._get_as_method = type_tuple[2] - + type_tuple = any_dpf._type_to_new_from_get_as_method(type(obj)) + if type_tuple is not None: + # call respective new_from function + if isinstance(server, ansys.dpf.core.server_types.InProcessServer) or not ( + isinstance(obj, (int, str, float, bytes)) + ): + any_dpf._internal_obj = type_tuple[0](obj) + else: + any_dpf._internal_obj = type_tuple[2](inner_server.client, obj) + # store get_as & type for casting back to original type + any_dpf._internal_type = type(obj) + any_dpf._get_as_method = type_tuple[1] + + return any_dpf + elif isinstance(obj, (list, np.ndarray)): + type_tuple = any_dpf._type_to_new_from_get_as_method(dpf_vector.DPFVectorInt) + from ansys.dpf.core import collection + if server_meet_version_and_raise("9.0", inner_server, "Creating an Any from a list is only supported " + "with" + "server versions starting at 9.0"): + inpt = collection.CollectionBase.integral_collection(obj, inner_server) + any_dpf._internal_obj = type_tuple[0](inpt) + any_dpf._internal_type = dpf_vector.DPFVectorInt + any_dpf._get_as_method = type_tuple[1] return any_dpf - if isinstance(obj, (list, np.ndarray)) and type_tuple[0]==dpf_vector.DPFVectorInt: - from ansys.dpf.core import collection - if server_meet_version_and_raise("9.0", inner_server, "Creating an Any from a list is only supported " - "with" - "server versions starting at 9.0"): - inpt = collection.CollectionBase.integral_collection(obj, inner_server) - any_dpf._internal_obj = type_tuple[1](inpt) - any_dpf._internal_type = type_tuple[0] - any_dpf._get_as_method = type_tuple[2] - return any_dpf raise TypeError(f"{obj.__class__} is not currently supported by the Any class.") @@ -258,22 +257,21 @@ def cast(self, output_type=None): self._internal_type = output_type if output_type is not None else self._internal_type - for type_tuple in Any._type_to_new_from_get_as_method(self): - if issubclass(self._internal_type, type_tuple[0]): - # call the get_as function for the appropriate type - internal_obj = type_tuple[2](self) - if ( - self._internal_type is int - or self._internal_type is str - or self._internal_type is float - or self._internal_type is bytes - - ): - obj = internal_obj - else: - return create_dpf_instance(self._internal_type, internal_obj, self._server) - - return obj + type_tuple = self._type_to_new_from_get_as_method(self._internal_type) + if type_tuple is not None: + internal_obj = type_tuple[1](self) + if ( + self._internal_type is int + or self._internal_type is str + or self._internal_type is float + or self._internal_type is bytes + + ): + obj = internal_obj + else: + return create_dpf_instance(self._internal_type, internal_obj, self._server) + + return obj raise TypeError(f"{output_type} is not currently supported by the Any class.") diff --git a/src/ansys/dpf/core/common.py b/src/ansys/dpf/core/common.py index 08f0420769..0500887c85 100644 --- a/src/ansys/dpf/core/common.py +++ b/src/ansys/dpf/core/common.py @@ -319,74 +319,87 @@ def _common_percentage_progress_bar(text): return TqdmProgressBar(text, "%", 100) +class SubClassSmartDict(dict): + def __getitem__(self, item): + """If found returns the item of key == ìtem`, else returns item with key matching `issubclass(item, + key)`.""" + if item in self: + return super().__getitem__(item) + else: + for key, value in self.items(): + if issubclass(item, key): + return value + raise KeyError + + +_type_to_internal_object_keyword = None + + def type_to_internal_object_keyword(): - from ansys.dpf.core import ( - cyclic_support, - data_sources, - field, - fields_container, - meshed_region, - meshes_container, - property_field, - string_field, - custom_type_field, - result_info, - scoping, - scopings_container, - time_freq_support, - dpf_operator, - data_tree, - workflow, - streams_container, - generic_data_container, - any, - collection, - ) + global _type_to_internal_object_keyword + if _type_to_internal_object_keyword is None: + from ansys.dpf.core import ( + cyclic_support, + data_sources, + field, + fields_container, + meshed_region, + meshes_container, + property_field, + string_field, + custom_type_field, + result_info, + scoping, + scopings_container, + time_freq_support, + dpf_operator, + data_tree, + workflow, + streams_container, + generic_data_container, + any, + collection, + ) - class _smart_dict_types(dict): - def __getitem__(self, item): - """If found returns the item of key == ìtem`, else returns item with key matching `issubclass(item, - key)`.""" - if item in self: - return super().__getitem__(item) - else: - for key, value in self.items(): - if issubclass(item, key): - return value - raise KeyError - - return _smart_dict_types({ - field.Field: "field", - property_field.PropertyField: "property_field", - string_field.StringField: "string_field", - custom_type_field.CustomTypeField: "field", - scoping.Scoping: "scoping", - fields_container.FieldsContainer: "fields_container", - scopings_container.ScopingsContainer: "scopings_container", - meshes_container.MeshesContainer: "meshes_container", - streams_container.StreamsContainer: "streams_container", - data_sources.DataSources: "data_sources", - cyclic_support.CyclicSupport: "cyclic_support", - meshed_region.MeshedRegion: "mesh", - result_info.ResultInfo: "result_info", - time_freq_support.TimeFreqSupport: "time_freq_support", - workflow.Workflow: "workflow", - data_tree.DataTree: "data_tree", - dpf_operator.Operator: "operator", - generic_data_container.GenericDataContainer: "generic_data_container", - any.Any: "any_dpf", - collection.Collection: "collection", - }) + _type_to_internal_object_keyword = SubClassSmartDict({ + field.Field: "field", + property_field.PropertyField: "property_field", + string_field.StringField: "string_field", + custom_type_field.CustomTypeField: "field", + scoping.Scoping: "scoping", + fields_container.FieldsContainer: "fields_container", + scopings_container.ScopingsContainer: "scopings_container", + meshes_container.MeshesContainer: "meshes_container", + streams_container.StreamsContainer: "streams_container", + data_sources.DataSources: "data_sources", + cyclic_support.CyclicSupport: "cyclic_support", + meshed_region.MeshedRegion: "mesh", + result_info.ResultInfo: "result_info", + time_freq_support.TimeFreqSupport: "time_freq_support", + workflow.Workflow: "workflow", + data_tree.DataTree: "data_tree", + dpf_operator.Operator: "operator", + generic_data_container.GenericDataContainer: "generic_data_container", + any.Any: "any_dpf", + collection.Collection: "collection", + }) + return _type_to_internal_object_keyword + + +_type_to_special_dpf_constructors = None def type_to_special_dpf_constructors(): - from ansys.dpf.gate.dpf_vector import DPFVectorInt - from ansys.dpf.core import collection_base - return {DPFVectorInt: - lambda obj, server: collection_base.IntCollection( - server=server, collection=obj - ).get_integral_entries() - } + global _type_to_special_dpf_constructors + if _type_to_special_dpf_constructors is None: + from ansys.dpf.gate.dpf_vector import DPFVectorInt + from ansys.dpf.core import collection_base + _type_to_special_dpf_constructors = {DPFVectorInt: + lambda obj, server: collection_base.IntCollection( + server=server, collection=obj + ).get_integral_entries() + } + return _type_to_special_dpf_constructors def create_dpf_instance(type, internal_obj, server): diff --git a/src/ansys/dpf/core/generic_data_container.py b/src/ansys/dpf/core/generic_data_container.py index 867498fd52..843eb65e7b 100644 --- a/src/ansys/dpf/core/generic_data_container.py +++ b/src/ansys/dpf/core/generic_data_container.py @@ -70,6 +70,7 @@ def __init__(self, generic_data_container=None, server=None): ) else: self._internal_obj = self._api.generic_data_container_new() + self._prop_description_instance = None @property def _api(self): @@ -114,6 +115,7 @@ def set_property( Property object. """ + self._prop_description_instance = None if not isinstance(prop, (int, float, str, bytes, list, np.ndarray)) and server_meet_version("8.1", self._server): self._api.generic_data_container_set_property_dpf_type(self, property_name, prop) else: @@ -164,28 +166,29 @@ def get_property_description(self): description: dict Description of the GenericDataContainer's contents """ + if self._prop_description_instance is None: + coll_obj = collection_base.StringCollection( + collection=self._api.generic_data_container_get_property_names(self), + server=self._server, + ) + property_names = coll_obj.get_integral_entries() - coll_obj = collection_base.StringCollection( - collection=self._api.generic_data_container_get_property_names(self), - server=self._server, - ) - property_names = coll_obj.get_integral_entries() - - coll_obj = collection_base.StringCollection( - collection=self._api.generic_data_container_get_property_types(self), - server=self._server, - ) - property_types = coll_obj.get_integral_entries() - - python_property_types = [] - for _, property_type in enumerate(property_types): - if property_type == "vector": - python_type = dpf_vector.DPFVectorInt.__name__ - else: - python_type = map_types_to_python[property_type] - python_property_types.append(python_type) - - return dict(zip(property_names, python_property_types)) + coll_obj = collection_base.StringCollection( + collection=self._api.generic_data_container_get_property_types(self), + server=self._server, + ) + property_types = coll_obj.get_integral_entries() + + python_property_types = [] + for _, property_type in enumerate(property_types): + if property_type == "vector": + python_type = dpf_vector.DPFVectorInt.__name__ + else: + python_type = map_types_to_python[property_type] + python_property_types.append(python_type) + + self._prop_description_instance = dict(zip(property_names, python_property_types)) + return self._prop_description_instance def __del__(self): if self._internal_obj is not None: diff --git a/src/ansys/dpf/core/property_field.py b/src/ansys/dpf/core/property_field.py index 3059f43316..b5af040a2b 100644 --- a/src/ansys/dpf/core/property_field.py +++ b/src/ansys/dpf/core/property_field.py @@ -72,9 +72,7 @@ def __init__( field=property_field, server=server, ) - self._field_definition = None - if meets_version(self._server.version, "8.1"): - self._field_definition = self._load_field_definition() + self._field_definition_instance = None @property def _api(self) -> property_field_abstract_api.PropertyFieldAbstractAPI: @@ -85,6 +83,12 @@ def _api(self) -> property_field_abstract_api.PropertyFieldAbstractAPI: ) return self._api_instance + @property + def _field_definition(self): + if self._field_definition_instance is None and meets_version(self._server.version, "8.1"): + self._field_definition_instance = self._load_field_definition() + return self._field_definition_instance + def _init_api_env(self): self._api.init_property_field_environment(self)