diff --git a/src/ansys/dpf/core/result_info.py b/src/ansys/dpf/core/result_info.py index b950ac32d21..e81d9a1a5db 100644 --- a/src/ansys/dpf/core/result_info.py +++ b/src/ansys/dpf/core/result_info.py @@ -5,6 +5,7 @@ import traceback import warnings +from typing import List, Union from enum import Enum, unique from types import SimpleNamespace from ansys.dpf.gate import ( @@ -24,6 +25,9 @@ from ansys.dpf.core.cyclic_support import CyclicSupport from ansys.dpf.core.label_space import LabelSpace from ansys.dpf.core.check_version import version_requires +from ansys.dpf.core.dimensionality import natures +from ansys.dpf.core.common import locations +from ansys.dpf.core.available_result import Homogeneity @unique @@ -61,14 +65,25 @@ class ResultInfo: This class describes the metadata of the analysis and the available results. + .. note:: + Creating a new ResultInfo from an analysis type and physics type is currently only available + InProcess. + Parameters ---------- - result_info : ctypes.c_void_p, ansys.grpc.dpf.result_info_pb2.ResultInfo message + result_info: ctypes.c_void_p, ansys.grpc.dpf.result_info_pb2.ResultInfo + Existing ResultInfo internal object + + server: ansys.dpf.core.server, optional + Server with the channel connected to the remote or local instance. + The default is ``None``, in which case an attempt is made to use the + global server. + + analysis_type: analysis_types + Type of the analysis for a new ResultInfo. - server : ansys.dpf.core.server, optional - Server with the channel connected to the remote or local instance. - The default is ``None``, in which case an attempt is made to use the - global server. + physics_type: physics_types + Type of physics for the new ResultInfo. Examples -------- @@ -87,7 +102,7 @@ class ResultInfo: """ - def __init__(self, result_info, server=None): + def __init__(self, result_info=None, server=None, analysis_type: analysis_types = None, physics_type: physics_types = None): """Initialize with a ResultInfo message""" # ############################ # step 1: get server @@ -109,7 +124,13 @@ def __init__(self, result_info, server=None): else: self._internal_obj = result_info elif result_info is None: - raise Exception("Result_info given is None") + if not self._server.has_client(): + if not (analysis_type or physics_type): + self._internal_obj = None + raise ValueError("Creating a new ResultInfo requires an analysis_type and a physics_type.") + self._internal_obj = self._api.result_info_new(analysis_type=analysis_type.value, physics_type=physics_type.value) + else: + raise NotImplementedError("Cannot create a new ResultInfo via gRPC.") def __str__(self): try: @@ -158,6 +179,56 @@ def _names(self): def __contains__(self, value): return value in self._names + def add_result( + self, + operator_name: str, + scripting_name: str, + homogeneity: Homogeneity, + location: locations, + nature: natures, + dimensions: Union[List[int], None] = None, + description: str = "", + ): + """Add an available result to the ResultInfo. + + .. note:: + Adding a new result to a ResultInfo is currently only available InProcess. + + Parameters + ---------- + operator_name: + Name of the DPF operator to use for result extraction. + scripting_name: + Name to use when requesting the result. + homogeneity: + Homogeneity of the result. + location: + Location of the result. + nature: + Mathematical nature of the result (scalar, vector...). + dimensions: + List of dimensions of the result when vector or matrix. + Enter ``[N]`` for an N-size vector result. + Enter ``[N, M]`` for a rank-2, NxM matrix result. + For example: + * ``[3]``: 3d vector + * ``[3, 3]``: ``3 x 3`` matrix + description: + Description of the result. + """ + if self._server.has_client(): + raise NotImplementedError("Cannot add a result to a ResultInfo via gRPC.") + if nature == natures.scalar: + dimensions = [1] + else: + if not dimensions: + raise ValueError(f"Argument 'dimensions' is required for a {nature.name} result.") + size_dim = len(dimensions) + self._api.result_info_add_result( + self, operator_name, scripting_name, dimensions, + size_dim, nature.value, location, homogeneity.name, description + ) + @property def analysis_type(self): """Retrieves the analysis type. diff --git a/tests/test_resultinfo.py b/tests/test_resultinfo.py index 12f932846f7..d1dd05b1005 100644 --- a/tests/test_resultinfo.py +++ b/tests/test_resultinfo.py @@ -4,6 +4,7 @@ from ansys.dpf.core import Model from conftest import ( SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_5_0, + SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_6_0, SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_7_0, SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_7_1, SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_8_0, @@ -165,3 +166,83 @@ def test_result_info_memory_leaks(model): # j = res.job_name # n = res.product_name # t = res.main_title + + +def test_create_result_info(server_type): + from ansys.dpf.core.available_result import Homogeneity + if not server_type.has_client(): + result_info = dpf.core.ResultInfo( + analysis_type=dpf.core.result_info.analysis_types.static, + physics_type=dpf.core.result_info.physics_types.mechanical, + server=server_type + ) + result_info.add_result( + operator_name="operator_name", + scripting_name="scripting_name", + homogeneity=Homogeneity.temperature, + location=dpf.core.locations.nodal, + nature=dpf.core.natures.scalar, + dimensions=None, + description="description", + ) + if SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_6_0: + ref = """Static analysis +Unit system: Undefined +Physics Type: Mechanical +Available results: + - scripting_name: Nodal Scripting Name +""" + elif SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_5_0: + ref = """Static analysis +Unit system: +Physics Type: Mechanical +Available results: + - scripting_name: Nodal Scripting Name +""" + else: + ref = """Static analysis +Unit system: +Physics Type: Mecanic +Available results: + - scripting_name: Nodal Scripting Name +""" + assert str(result_info) == ref + with pytest.raises(ValueError, match="requires"): + _ = dpf.core.ResultInfo() + else: + with pytest.raises(NotImplementedError, match="Cannot create a new ResultInfo via gRPC."): + _ = dpf.core.ResultInfo( + analysis_type=dpf.core.result_info.analysis_types.static, + physics_type=dpf.core.result_info.physics_types.mechanical, + server=server_type + ) + + +def test_result_info_add_result(model): + from ansys.dpf.core.available_result import Homogeneity + res = model.metadata.result_info + if not model._server.has_client(): + res.add_result( + operator_name="operator_name", + scripting_name="scripting_name", + homogeneity=Homogeneity.temperature, + location=dpf.core.locations.nodal, + nature=dpf.core.natures.scalar, + dimensions=None, + description="description", + ) + else: + with pytest.raises( + NotImplementedError, + match="Cannot add a result to a ResultInfo via gRPC." + ): + res.add_result( + operator_name="operator_name", + scripting_name="scripting_name", + homogeneity=Homogeneity.temperature, + location=dpf.core.locations.nodal, + nature=dpf.core.natures.scalar, + dimensions=None, + description="description", + ) +