diff --git a/src/ansys/fluent/core/solver/flobject.py b/src/ansys/fluent/core/solver/flobject.py index 4fb4948ecc9..13e0990b384 100644 --- a/src/ansys/fluent/core/solver/flobject.py +++ b/src/ansys/fluent/core/solver/flobject.py @@ -1803,8 +1803,13 @@ class Query(Action): def __call__(self, **kwds): """Call a query with the specified keyword arguments.""" - newkwds = _get_new_keywords(self, **kwds) - return self.flproxy.execute_query(self._parent.path, self.obj_name, **newkwds) + kwds = _get_new_keywords(self, **kwds) + scmKwds = {} + for arg, value in kwds.items(): + argument = getattr(self, arg) + # Convert key-value to Scheme key-value + scmKwds[argument.fluent_name] = argument.to_scheme_keys(value) + return self.flproxy.execute_query(self._parent.path, self.obj_name, **scmKwds) _baseTypes = { diff --git a/src/ansys/fluent/core/systemcoupling.py b/src/ansys/fluent/core/systemcoupling.py index 945cfdc2c8b..182acea06a7 100644 --- a/src/ansys/fluent/core/systemcoupling.py +++ b/src/ansys/fluent/core/systemcoupling.py @@ -53,6 +53,11 @@ def __init__(self, solver): raise RuntimeError( f"Using {str(self._solver.get_fluent_version())}. PySystemCoupling integration requires {str(FluentVersion.v241)} or later." ) + if self._solver.get_fluent_version() >= FluentVersion.v251: + # enable feature to be able to make System Coupling settings APIs calls + self._solver.scheme_eval.scheme_eval( + "(enable-feature 'sc/participant-info)" + ) @property def participant_type(self) -> str: @@ -61,32 +66,153 @@ def participant_type(self) -> str: def get_variables(self) -> List[Variable]: """Get variables.""" - return self.__get_syc_setup()["variables"] + + if self._solver.get_fluent_version() >= FluentVersion.v251: + variables = list() + region_names = ( + self._solver.settings.setup.models.system_coupling.get_all_regions() + ) + variable_names = set() + for region_name in region_names: + in_var_names = self._get_list( + self._solver.settings.setup.models.system_coupling.get_input_vars( + region_name=region_name + ) + ) + out_var_names = self._get_list( + self._solver.settings.setup.models.system_coupling.get_output_vars( + region_name=region_name + ) + ) + variable_names.update(in_var_names) + variable_names.update(out_var_names) + variable_names = sorted(list(variable_names)) + for variable_name in variable_names: + variables.append( + Variable( + name=variable_name, + display_name=self._get_display_name(variable_name), + tensor_type=self._solver.settings.setup.models.system_coupling.get_tensor_type( + variable_name=variable_name + ), + is_extensive=self._solver.settings.setup.models.system_coupling.is_extensive_var( + variable_name=variable_name + ), + location=self._solver.settings.setup.models.system_coupling.get_data_location( + variable_name=variable_name + ), + quantity_type=self._get_quantity_type(variable_name), + ) + ) + return variables + else: + # maintains back-compatibility for 24.1 and 24.2 + return self.__get_syc_setup()["variables"] def get_regions(self) -> List[Region]: """Get regions.""" - return self.__get_syc_setup()["regions"] + + if self._solver.get_fluent_version() >= FluentVersion.v251: + region_names = ( + self._solver.settings.setup.models.system_coupling.get_all_regions() + ) + regions = list() + for region_name in region_names: + regions.append( + Region( + name=region_name, + display_name=self._get_display_name(region_name), + topology=self._solver.settings.setup.models.system_coupling.get_topology( + region_name=region_name + ), + input_variables=self._get_list( + self._solver.settings.setup.models.system_coupling.get_input_vars( + region_name=region_name + ) + ), + output_variables=self._get_list( + self._solver.settings.setup.models.system_coupling.get_output_vars( + region_name=region_name + ) + ), + ) + ) + return regions + else: + # maintains back-compatibility for 24.1 and 24.2 + return self.__get_syc_setup()["regions"] def get_analysis_type(self) -> str: """Get analysis type.""" - return self.__get_syc_setup()["analysis-type"] + if self._solver.get_fluent_version() >= FluentVersion.v251: + return ( + self._solver.settings.setup.models.system_coupling.get_analysis_type() + ) + else: + # maintains back-compatibility for 24.1 and 24.2 + return self.__get_syc_setup()["analysis-type"] def connect(self, host: str, port: int, name: str) -> None: - """Connect parallelly.""" - self._solver.setup.models.system_coupling.connect_parallel( + """Connect to System Coupling.""" + self._solver.settings.setup.models.system_coupling.connect_parallel( schost=host, scport=port, scname=name ) def solve(self) -> None: """Initialize and solve.""" - self._solver.setup.models.system_coupling.init_and_solve() + self._solver.settings.setup.models.system_coupling.init_and_solve() + + @staticmethod + def _get_quantity_type(variable_name: str) -> str: + """ + For some variables, System Coupling should know the quantity type. + """ + if variable_name in {"force", "lorentz-force"}: + return "Force" + elif variable_name in {"heatflow", "heatrate"}: + return "Heat Rate" + elif variable_name == "displacement": + return "Incremental Displacement" + elif variable_name == "temperature": + return "Temperature" + elif variable_name == "heat-transfer-coefficient": + return "Heat Transfer Coefficient" + elif variable_name == "near-wall-temperature": + return "Convection Reference Temperature" + elif variable_name == "electrical-conductivity": + return "Electrical Conductivity" + else: + return "Unspecified" + + @staticmethod + def _get_display_name(internal_name: str) -> str: + """ + Display names should not contain dashes. + """ + return internal_name.replace("-", " ") + + @staticmethod + def _get_list(value: list | None) -> list: + if isinstance(value, list): + return value + elif value is None: + return list() + raise TypeError(f"_get_list unexpected type of {value}") def __get_syc_setup(self) -> dict: + """ + This function is for backward-compatibility reasons for 24.1 and 24.2 versions. + It tells Fluent to write the SCP file and then parses it to get the setup + information. The SCP file is then deleted. + With newer versions, settings APIs can be used directly, without having + to write the SCP file at all. + """ + def get_scp_string() -> str: """Get the SCP file contents in the form of an XML string.""" scp_file_name = "fluent.scp" - self._solver.setup.models.system_coupling.write_scp_file( + self._solver.settings.setup.models.system_coupling.write_scp_file( file_name=scp_file_name ) diff --git a/tests/test_systemcoupling.py b/tests/test_systemcoupling.py index cc969a056e2..639e20a380c 100644 --- a/tests/test_systemcoupling.py +++ b/tests/test_systemcoupling.py @@ -1,9 +1,25 @@ import pytest -@pytest.mark.fluent_version(">=24.1") -def test_systemcoupling_mixing_elbow_settings(mixing_elbow_case_data_session): - """Very superficial test of System Coupling related settings.""" +@pytest.mark.fluent_version(">=25.1") +def test_systemcoupling_mixing_elbow_settings_apis(mixing_elbow_case_data_session): + """Test System Coupling related settings APIs""" + solver = mixing_elbow_case_data_session + # enable the feature flag to be able to make the queries + solver.scheme_eval.scheme_eval("(enable-feature 'sc/participant-info)") + elbow_fluid = "elbow-fluid" + region_names = solver.settings.setup.models.system_coupling.get_all_regions() + assert elbow_fluid in region_names + # elbow fluid must be a volume + assert ( + solver.settings.setup.models.system_coupling.get_topology( + region_name=elbow_fluid + ) + == "Volume" + ) + + +def _test_systemcoupling_mixing_elbow_settings_common(mixing_elbow_case_data_session): solver = mixing_elbow_case_data_session # check participant type, analysis type, regions, and variables assert solver.system_coupling.participant_type == "FLUENT" @@ -12,5 +28,17 @@ def test_systemcoupling_mixing_elbow_settings(mixing_elbow_case_data_session): variables = solver.system_coupling.get_variables() # [wall-inlet, wall-elbow, elbow-fluid, hot-inlet, cold-inlet, outlet] assert len(regions) >= 6 - # [force, dsip, temp, htc, hflow, nwt, hrate, cond, lorentz-force] - assert len(variables) >= 9 + # [force, temp, htc, hflow, nwt, hrate, e-cond, lorentz-force] + assert len(variables) >= 8 + + +@pytest.mark.fluent_version(">=25.1") +def test_systemcoupling_mixing_elbow_settings(mixing_elbow_case_data_session): + """Very superficial test of System Coupling related settings.""" + _test_systemcoupling_mixing_elbow_settings_common(mixing_elbow_case_data_session) + + +@pytest.mark.fluent_version(">=24.1,<25.1") +def test_systemcoupling_mixing_elbow_settings_legacy(mixing_elbow_case_data_session): + """Test legacy implementation of getting System Coupling related settings.""" + _test_systemcoupling_mixing_elbow_settings_common(mixing_elbow_case_data_session)