diff --git a/doc/source/_static/03_ProxySolver.png b/doc/source/_static/03_ProxySolver.png new file mode 100644 index 000000000..1fd67c284 Binary files /dev/null and b/doc/source/_static/03_ProxySolver.png differ diff --git a/doc/source/api/derived_node_classes.rst b/doc/source/api/derived_node_classes.rst index e8d71197d..7d9fa3189 100644 --- a/doc/source/api/derived_node_classes.rst +++ b/doc/source/api/derived_node_classes.rst @@ -6,3 +6,4 @@ Derived node classes :toctree: _autosummary IntegrationNode + ProxySolverNode diff --git a/examples/workflow_creation/03_proxy_solver.py b/examples/workflow_creation/03_proxy_solver.py new file mode 100644 index 000000000..4c4b51ff6 --- /dev/null +++ b/examples/workflow_creation/03_proxy_solver.py @@ -0,0 +1,213 @@ +# Copyright (C) 2022 - 2024 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +""" +.. _ref_proxy_solver: + +Proxy solver +------------ + +This example demonstrates how to obtain designs from parametric system and process them externally. + +It creates a proxy solver node inside parametric system and solves it's designs externally. +""" + +######################################################### +# Perform required imports +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Perform the required imports. +import time + +from ansys.optislang.core import Optislang +import ansys.optislang.core.node_types as node_types +from ansys.optislang.core.nodes import DesignFlow, ParametricSystem, ProxySolverNode +from ansys.optislang.core.project_parametric import ( + ComparisonType, + ObjectiveCriterion, + OptimizationParameter, +) +from ansys.optislang.core.utils import find_all_osl_exec + +######################################################### +# Create solver +# ~~~~~~~~~~~~~ +# Define a simple calculator function to solve the variations + + +def calculator(hid, X1, X2, X3, X4, X5): + from math import sin + + Y = 0.5 * X1 + X2 + 0.5 * X1 * X2 + 5 * sin(X3) + 0.2 * X4 + 0.1 * X5 + return Y + + +def calculate(designs): + result_design_list = [] + print(f"Calculate {len(designs)} designs") + for design in designs: + hid = design["hid"] + parameters = design["parameters"] + X1 = 0.0 + X2 = 0.0 + X3 = 0.0 + X4 = 0.0 + X5 = 0.0 + for parameter in parameters: + if parameter["name"] == "X1": + X1 = parameter["value"] + elif parameter["name"] == "X2": + X2 = parameter["value"] + elif parameter["name"] == "X3": + X3 = parameter["value"] + elif parameter["name"] == "X4": + X4 = parameter["value"] + elif parameter["name"] == "X5": + X5 = parameter["value"] + Y = calculator(hid, X1, X2, X3, X4, X5) + + result_design = {} + result_design["hid"] = hid + responses = [{"name": "Y", "value": Y}] + result_design["responses"] = responses + result_design_list.append(result_design) + + print(f"Return {len(result_design_list)} designs") + return result_design_list + + +######################################################### +# Create optiSLang instance +# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# Find the optiSLang >= 25.1 executable. Initialize the Optislang class instance with the executable. + +available_optislang_executables = find_all_osl_exec() +version, executables = available_optislang_executables.popitem(last=False) +if not version >= 251: + raise KeyError("OptiSLang installation >= 25R1 wasn't found, please specify path manually.") + +osl = Optislang(executable=executables[0]) + +print(f"Using optiSLang version {osl.osl_version_string}") + + +######################################################### +# Create workflow +# ~~~~~~~~~~~~~~~ + +root_system = osl.application.project.root_system + +# Create the algorithm system of your choice. + +algorithm_system: ParametricSystem = root_system.create_node( + type_=node_types.Sensitivity, name="Sensitivity" +) + +num_discretization = 2000 + +algorithm_settings = algorithm_system.get_property("AlgorithmSettings") +algorithm_settings["num_discretization"] = num_discretization +algorithm_system.set_property("AlgorithmSettings", algorithm_settings) + +# Fast running solver settings + +algorithm_system.set_property("AutoSaveMode", "no_auto_save") +algorithm_system.set_property("SolveTwice", True) +algorithm_system.set_property("UpdateResultFile", "never") +algorithm_system.set_property("WriteDesignStartSetFlag", False) + +# Add the Proxy Solver node and set the desired maximum number of designs you handle in one go. + +proxy_solver: ProxySolverNode = algorithm_system.create_node( + type_=node_types.ProxySolver, name="Calculator", design_flow=DesignFlow.RECEIVE_SEND +) + +multi_design_launch_num = 99 # set -1 to solve all designs simultaneously +proxy_solver.set_property("MultiDesignLaunchNum", multi_design_launch_num) +proxy_solver.set_property("ForwardHPCLicenseContextEnvironment", True) + +# Add parameters to the algorithm system and register them in the proxy solver. + +for i in range(1, 6): + parameter = OptimizationParameter(name=f"X{i}", reference_value=1.0, range=(-3.14, 3.14)) + algorithm_system.parameter_manager.add_parameter(parameter) + proxy_solver.register_location_as_parameter( + {"dir": {"value": "input"}, "name": parameter.name, "value": parameter.reference_value} + ) + +# Register response in the proxy solver and create criterion in algorithm + +proxy_solver.register_location_as_response({"dir": {"value": "output"}, "name": "Y", "value": 3.0}) +criterion = ObjectiveCriterion( + name="obj", expression="Y", expression_value=3.0, criterion=ComparisonType.MIN +) +algorithm_system.criteria_manager.add_criterion(criterion) + + +######################################################### +# Optionally save project +# ~~~~~~~~~~~~~~~~~~~~~~~ +# If you want to save the project to some desired location, +# uncomment and edit these lines: +# +# .. code:: python +# +# dir_path = Path(r"") +# project_name = "proxy_solver_workflow.opf" +# osl.application.save_as(dir_path / project_name) + + +######################################################### +# Run workflow +# ~~~~~~~~~~~~ +# Run the workflow created by the preceding scripts. + +# Start the optiSLang project execution. +osl.application.project.start(wait_for_finished=False) + + +# Now loop until get_status() returns "Processing done" for the root system. Use the GET_DESIGNS query and the SET_DESIGNS command for the Proxy Solver node to get designs and set responses until the system is done. + +while not osl.project.root_system.get_status() == "Processing done": + design_list = proxy_solver.get_designs() + if len(design_list): + responses_dict = calculate(design_list) + proxy_solver.set_designs(responses_dict) + time.sleep(0.1) + +print("Solved Successfully!") + + +######################################################### +# Stop and cancel project +# ~~~~~~~~~~~~~~~~~~~~~~~ +# Stop and cancel the project. +osl.dispose() + +######################################################### +# View generated workflow +# ~~~~~~~~~~~~~~~~~~~~~~~ +# This image shows the generated workflow. +# +# .. image:: ../../_static/03_ProxySolver.png +# :width: 400 +# :alt: Result of script. +# diff --git a/src/ansys/optislang/core/node_types.py b/src/ansys/optislang/core/node_types.py index e6dc86366..30e101d05 100644 --- a/src/ansys/optislang/core/node_types.py +++ b/src/ansys/optislang/core/node_types.py @@ -291,6 +291,9 @@ def subtype(self) -> AddinType: ProEProcess = NodeType( id="ProEProcess", subtype=AddinType.BUILT_IN, osl_class_type=NodeClassType.INTEGRATION_NODE ) +ProxySolver = NodeType( + id="ProxySolver", subtype=AddinType.BUILT_IN, osl_class_type=NodeClassType.PROXY_SOLVER +) Python2 = NodeType( id="Python2", subtype=AddinType.BUILT_IN, osl_class_type=NodeClassType.INTEGRATION_NODE ) diff --git a/src/ansys/optislang/core/nodes.py b/src/ansys/optislang/core/nodes.py index f31c85a88..c44758b59 100644 --- a/src/ansys/optislang/core/nodes.py +++ b/src/ansys/optislang/core/nodes.py @@ -95,6 +95,7 @@ class NodeClassType(Enum): PARAMETRIC_SYSTEM = 2 ROOT_SYSTEM = 3 INTEGRATION_NODE = 4 + PROXY_SOLVER = 5 @classmethod def from_str(cls, string: str) -> NodeClassType: @@ -796,12 +797,17 @@ def get_registered_responses( pass @abstractmethod - def load(self) -> None: # pragma: no cover + def load(self, args: Optional[dict] = None) -> None: # pragma: no cover """Explicitly load the node. Some optiSLang nodes support/need an explicit load prior to being able to register or to make registering more convenient. + Parameters + ---------- + args: Optional[dict], optional + Additional arguments, by default ``None``. + Raises ------ OslCommunicationError @@ -1044,6 +1050,55 @@ def re_register_locations_as_response(self) -> None: # pragma: no cover pass +class ProxySolverNode(IntegrationNode): + """Base class for classes which provide for creating and operating on an proxy solver node.""" + + @abstractmethod + def __init__(self): # pragma: no cover + """``ProxySolverNode`` class is an abstract base class and cannot be instantiated.""" + pass + + @abstractmethod + def get_designs(self) -> Any: # pragma: no cover + """Get pending designs from parent node. + + Returns + ------- + Any + Pending designs. + + Raises + ------ + OslCommunicationError + Raised when an error occurs while communicating with the server. + OslCommandError + Raised when a command or query fails. + TimeoutError + Raised when the timeout float value expires. + """ + pass + + @abstractmethod + def set_designs(self, designs: Any) -> None: # pragma: no cover + """Set calculated designs. + + Parameters + ---------- + Any + Calculated designs. + + Raises + ------ + OslCommunicationError + Raised when an error occurs while communicating with the server. + OslCommandError + Raised when a command or query fails. + TimeoutError + Raised when the timeout float value expires. + """ + pass + + class System(Node): """Base class for classes which provide for creating and operating on a system.""" @@ -1077,6 +1132,12 @@ def create_node( Raises ------ + OslCommunicationError + Raised when an error occurs while communicating with the server. + OslCommandError + Raised when a command or query fails. + TimeoutError + Raised when the timeout float value expires. TypeError Raised when unsupported type of ``type_`` is given. ValueError diff --git a/src/ansys/optislang/core/tcp/nodes.py b/src/ansys/optislang/core/tcp/nodes.py index 2c4587ec7..6eb0d8a27 100644 --- a/src/ansys/optislang/core/tcp/nodes.py +++ b/src/ansys/optislang/core/tcp/nodes.py @@ -50,6 +50,7 @@ NodeClassType, OutputSlot, ParametricSystem, + ProxySolverNode, RootSystem, Slot, SlotType, @@ -1095,7 +1096,7 @@ def __init__( type_: NodeType, logger=None, ) -> None: - """Create an ``TcpSystemProxy`` instance. + """Create an ``TcpIntegrationNodeProxy`` instance. Parameters ---------- @@ -1295,12 +1296,17 @@ def get_registered_responses(self, include_reference_values: bool = True) -> Tup ) ) - def load(self) -> None: + def load(self, args: Optional[Dict[str, Any]] = None) -> None: """Explicitly load the node. Some optiSLang nodes support/need an explicit LOAD prior to being able to register or to make registering more convenient. + Parameters + ---------- + args: Optional[Dict[str, any]], optional + Additional arguments, by default ``None``. + Raises ------ OslCommunicationError @@ -1311,7 +1317,7 @@ def load(self) -> None: Raised when the timeout float value expires. """ # TODO: test - self._osl_server.load(self.uid) + self._osl_server.load(uid=self.uid, args=args) def register_location_as_input_slot( self, @@ -1549,6 +1555,80 @@ def re_register_locations_as_response(self) -> None: self._osl_server.re_register_locations_as_response(uid=self.uid) +class TcpProxySolverNodeProxy(TcpIntegrationNodeProxy, ProxySolverNode): + """Provides for creating and operating on integration nodes.""" + + def __init__( + self, + uid: str, + osl_server: TcpOslServer, + type_: NodeType, + logger=None, + ) -> None: + """Create an ``TcpProxySolverProxy`` instance. + + Parameters + ---------- + uid: str + Unique ID. + osl_server: TcpOslServer + Object providing access to the optiSLang server. + type_: NodeType + Instance of the ``NodeType`` class. + logger: Any, optional + Object for logging. If ``None``, standard logging object is used. Defaults to ``None``. + """ + super().__init__( + uid=uid, + osl_server=osl_server, + type_=type_, + logger=logger, + ) + + def get_designs(self) -> List[dict]: + """Get pending designs from parent node. + + Returns + ------- + List[dict] + List of pending designs. + + Raises + ------ + OslCommunicationError + Raised when an error occurs while communicating with the server. + OslCommandError + Raised when a command or query fails. + TimeoutError + Raised when the timeout float value expires. + """ + return self._osl_server.get_designs(self.uid) + + def set_designs(self, designs: Iterable[dict]) -> None: + """Set calculated designs. + + Parameters + ---------- + Iterable[dict] + Iterable of calculated designs. + Design format: + { + "hid": "0.1", + "responses": [{"name": "res1", "value": 1.0}, {...}, ...], + } + + Raises + ------ + OslCommunicationError + Raised when an error occurs while communicating with the server. + OslCommandError + Raised when a command or query fails. + TimeoutError + Raised when the timeout float value expires. + """ + self._osl_server.set_designs(actor_uid=self.uid, designs=designs) + + # endregion @@ -3228,6 +3308,7 @@ def connect_to(self, to_slot: TcpSlotProxy) -> Edge: NodeClassType.INTEGRATION_NODE.name: TcpIntegrationNodeProxy, NodeClassType.SYSTEM.name: TcpSystemProxy, NodeClassType.PARAMETRIC_SYSTEM.name: TcpParametricSystemProxy, + NodeClassType.PROXY_SOLVER.name: TcpProxySolverNodeProxy, NodeClassType.ROOT_SYSTEM.name: TcpRootSystemProxy, } diff --git a/src/ansys/optislang/core/tcp/osl_server.py b/src/ansys/optislang/core/tcp/osl_server.py index c7306c59e..71dd3ed96 100644 --- a/src/ansys/optislang/core/tcp/osl_server.py +++ b/src/ansys/optislang/core/tcp/osl_server.py @@ -2188,6 +2188,38 @@ def get_criterion(self, uid: str, name: str) -> Dict: max_request_attempts=self.max_request_attempts_register.get_value(current_func_name), )["criteria"] + def get_designs(self, uid: str) -> List[dict]: + """Get pending designs from parent node. + + Parameters + ---------- + uid : str + Actor uid. + + Returns + ------- + List[dict] + List of pending designs. + + Raises + ------ + OslCommunicationError + Raised when an error occurs while communicating with server. + OslCommandError + Raised when the command or query fails. + TimeoutError + Raised when the timeout float value expires. + """ + current_func_name = self.get_designs.__name__ + return self.send_command( + command=queries.get_designs( + uid=uid, + password=self.__password, + ), + timeout=self.timeouts_register.get_value(current_func_name), + max_request_attempts=self.max_request_attempts_register.get_value(current_func_name), + )["designs"] + def get_doe_size(self, uid: str, sampling_type: str, num_discrete_levels: int) -> int: """Get the DOE size for given sampling type and number of levels for a specific actor. @@ -2212,7 +2244,7 @@ def get_doe_size(self, uid: str, sampling_type: str, num_discrete_levels: int) - TimeoutError Raised when the timeout float value expires. """ - current_func_name = self.add_criterion.__name__ + current_func_name = self.get_doe_size.__name__ return self.send_command( command=queries.doe_size( uid=uid, @@ -2945,13 +2977,15 @@ def get_working_dir(self) -> Path: return None return Path(project_info.get("projects", [{}])[0].get("working_dir", None)) - def load(self, uid: str) -> None: + def load(self, uid: str, args: Optional[Dict[str, Any]] = None) -> None: """Explicit load of node. Parameters ---------- uid: str Actor uid. + args: Optional[Dict[str, any]], optional + Additional arguments, by default ``None``. Raises ------ @@ -2967,6 +3001,7 @@ def load(self, uid: str) -> None: self.send_command( command=commands.load( actor_uid=uid, + args=args, password=self.__password, ), timeout=self.timeouts_register.get_value(current_func_name), @@ -3851,6 +3886,34 @@ def set_criterion_property( max_request_attempts=self.max_request_attempts_register.get_value(current_func_name), ) + def set_designs(self, actor_uid: str, designs: Iterable[dict]) -> None: + """Set an actor property. + + Parameters + ---------- + actor_uid : str + Actor uid. + designs : Iterable[dict] + Iterable of calculated designs. + + Raises + ------ + OslCommunicationError + Raised when an error occurs while communicating with server. + OslCommandError + Raised when the command or query fails. + TimeoutError + Raised when the timeout float value expires. + """ + current_func_name = self.set_designs.__name__ + self.send_command( + command=commands.set_designs( + actor_uid=actor_uid, designs=designs, password=self.__password + ), + timeout=self.timeouts_register.get_value(current_func_name), + max_request_attempts=self.max_request_attempts_register.get_value(current_func_name), + ) + @deprecated( version="0.5.0", reason="Use :py:attr:`TcpOslServer.timeouts_register.default_value` instead.", diff --git a/src/ansys/optislang/core/tcp/server_commands.py b/src/ansys/optislang/core/tcp/server_commands.py index 96d3b3c50..e76175e48 100644 --- a/src/ansys/optislang/core/tcp/server_commands.py +++ b/src/ansys/optislang/core/tcp/server_commands.py @@ -71,6 +71,7 @@ _SET_ACTOR_SETTING = "SET_ACTOR_SETTING" _SET_ACTOR_STATE_PROPERTY = "SET_ACTOR_STATE_PROPERTY" _SET_CRITERION_PROPERTY = "SET_CRITERION_PROPERTY" +_SET_DESIGNS = "SET_DESIGNS" _SET_PLACEHOLDER_VALUE = "SET_PLACEHOLDER_VALUE" _SET_PROJECT_SETTING = "SET_PROJECT_SETTING" _SET_REGISTERED_FILE_VALUE = "SET_REGISTERED_FILE_VALUE" @@ -547,13 +548,15 @@ def link_registered_file(actor_uid: str, uid: str, password: Optional[str] = Non ) -def load(actor_uid: str, password: Optional[str] = None) -> str: +def load(actor_uid: str, args: Optional[CommandArgs] = None, password: Optional[str] = None) -> str: """Generate JSON string of ``load`` command. Parameters ---------- actor_uid: str Actor uid entry. + args: Optional[CommandArgs], optional + Dictionary with additional arguments, by default ``None``. password : Optional[str], optional Password, by default ``None``. @@ -562,7 +565,9 @@ def load(actor_uid: str, password: Optional[str] = None) -> str: str JSON string of ``load`` command. """ - return _to_json(_gen_server_command(command=_LOAD, actor_uid=actor_uid, password=password)) + return _to_json( + _gen_server_command(command=_LOAD, args=args, actor_uid=actor_uid, password=password) + ) def new(password: Optional[str] = None) -> str: @@ -1490,6 +1495,31 @@ def set_criterion_property( ) +def set_designs(actor_uid: str, designs: Iterable[dict], password: Optional[str] = None) -> str: + """Generate JSON string of ``set_designs`` command. + + Parameters + ---------- + actor_uid: str + Actor uid entry. + designs: Iterable[dict] + Iterable of calculated designs. + password : Optional[str], optional + Password. Defaults to ``None``. + + Returns + ------- + str + JSON string of ``set_designs`` command. + """ + args: CommandArgs = {} + args["designs"] = designs + + return _to_json( + _gen_server_command(command=_SET_DESIGNS, actor_uid=actor_uid, args=args, password=password) + ) + + def set_placeholder_value(name: str, value: str, password: Optional[str] = None) -> str: """Generate JSON string of ``set placeholder value`` command. diff --git a/src/ansys/optislang/core/tcp/server_queries.py b/src/ansys/optislang/core/tcp/server_queries.py index 40303ca3c..d2eaff1b5 100644 --- a/src/ansys/optislang/core/tcp/server_queries.py +++ b/src/ansys/optislang/core/tcp/server_queries.py @@ -46,6 +46,7 @@ _FULL_PROJECT_TREE_WITH_PROPERTIES = "FULL_PROJECT_TREE_WITH_PROPERTIES" _GET_CRITERIA = "GET_CRITERIA" _GET_CRITERION = "GET_CRITERION" +_GET_DESIGNS = "GET_DESIGNS" _HPC_LICENSING_FORWARDED_ENVIRONMENT = "HPC_LICENSING_FORWARDED_ENVIRONMENT" _INPUT_SLOT_VALUE = "INPUT_SLOT_VALUE" _OUTPUT_SLOT_VALUE = "OUTPUT_SLOT_VALUE" @@ -619,6 +620,24 @@ def get_criterion(uid: str, name: str, password: Optional[str] = None) -> str: ) +def get_designs(uid: str, password: Optional[str] = None) -> str: + """Generate JSON string of get_designs query. + + Parameters + ---------- + uid: str + Uid entry. + password : Optional[str], optional + Password. Defaults to ``None``. + + Returns + ------- + str + JSON string of get_designs query. + """ + return _to_json(_gen_query(what=_GET_DESIGNS, uid=uid, password=password)) + + def hpc_licensing_forwarded_environment(uid: str, password: Optional[str] = None) -> str: """Generate JSON string of hpc_licensing_forwarded_environment query. diff --git a/tests/tcp/test_tcp_server_commands.py b/tests/tcp/test_tcp_server_commands.py index 1640e6e59..9bf1e403a 100644 --- a/tests/tcp/test_tcp_server_commands.py +++ b/tests/tcp/test_tcp_server_commands.py @@ -1154,32 +1154,6 @@ def test_set_actor_property(): sc.set_actor_property(name="MaxParallel", value="32") -def test_set_criterion_property(): - "Test set_criterion_property." - # basic - json_string = sc.set_criterion_property( - actor_uid=actor_uid, criterion_name="obj2", name="type", value="min" - ) - dictionary = json.loads(json_string) - requiered_string = json.loads( - '{"projects": [{"commands": [{"actor_uid": "5cdfb20b-bef6-4412-9985-89f5ded5ee95", \ - "args": {"criterion_name": "obj2", "name": "type", "value": "min"}, \ - "command": "SET_CRITERION_PROPERTY", "type": "builtin"}]}]}' - ) - assert type(json_string) == str - assert sorted(dictionary.items()) == sorted(requiered_string.items()) - # with password - json_string = sc.set_criterion_property( - actor_uid=actor_uid, - criterion_name="obj2", - name="type", - value="min", - password=example_password, - ) - dictionary = json.loads(json_string) - dictionary["Password"] == example_password - - def test_set_actor_setting(): "Test set_actor_setting." # basic @@ -1243,6 +1217,65 @@ def test_set_actor_state_property(): sc.set_actor_state_property(name="stop_after_execution", value="true") +def test_set_criterion_property(): + "Test set_criterion_property." + # basic + json_string = sc.set_criterion_property( + actor_uid=actor_uid, criterion_name="obj2", name="type", value="min" + ) + dictionary = json.loads(json_string) + requiered_string = json.loads( + '{"projects": [{"commands": [{"actor_uid": "5cdfb20b-bef6-4412-9985-89f5ded5ee95", \ + "args": {"criterion_name": "obj2", "name": "type", "value": "min"}, \ + "command": "SET_CRITERION_PROPERTY", "type": "builtin"}]}]}' + ) + assert type(json_string) == str + assert sorted(dictionary.items()) == sorted(requiered_string.items()) + # with password + json_string = sc.set_criterion_property( + actor_uid=actor_uid, + criterion_name="obj2", + name="type", + value="min", + password=example_password, + ) + dictionary = json.loads(json_string) + dictionary["Password"] == example_password + + +def test_set_designs(): + "Test set_designs." + # basic + designs = [ + { + "hid": "0.1", + "responses": [{"name": "res1", "value": 1.0}], + }, + { + "hid": "0.2", + "responses": [{"name": "res1", "value": 2.0}], + }, + ] + json_string = sc.set_designs(actor_uid=actor_uid, designs=designs) + dictionary = json.loads(json_string) + requiered_string = json.loads( + '{"projects": [{"commands": [{"actor_uid": "5cdfb20b-bef6-4412-9985-89f5ded5ee95", \ + "args": {"designs": [{"hid": "0.1", "responses": [{"name": "res1", "value": 1.0}]}, \ + {"hid": "0.2","responses": [{"name": "res1", "value": 2.0}]}]}, \ + "command": "SET_DESIGNS","type": "builtin"}]}]}' + ) + assert type(json_string) == str + assert sorted(dictionary.items()) == sorted(requiered_string.items()) + # with password + json_string = sc.set_designs( + actor_uid=actor_uid, + designs=designs, + password=example_password, + ) + dictionary = json.loads(json_string) + dictionary["Password"] == example_password + + def test_set_placeholder_value(): "Test set_placeholder_value." # basic diff --git a/tests/tcp/test_tcp_server_queries.py b/tests/tcp/test_tcp_server_queries.py index 8b16e3c33..f335b6ed9 100644 --- a/tests/tcp/test_tcp_server_queries.py +++ b/tests/tcp/test_tcp_server_queries.py @@ -387,6 +387,24 @@ def test_get_criterion(): assert dictionary["Password"] == example_password +def test_get_designs(): + "Test get_designs." + json_string = sq.get_designs(uid=example_uid) + dictionary = json.loads(json_string) + requiered_string = json.loads( + '{"What": "GET_DESIGNS", "uid": "5cdfb20b-bef6-4412-9985-89f5ded5ee95"}' + ) + assert type(json_string) == str + assert sorted(dictionary.items()) == sorted(requiered_string.items()) + # with password + json_string = sq.get_designs( + uid=example_uid, + password=example_password, + ) + dictionary = json.loads(json_string) + assert dictionary["Password"] == example_password + + def test_hpc_licensing_forwarded_environment(): "Test hpc_licensing_forwarded_environment." json_string = sq.hpc_licensing_forwarded_environment(uid=example_uid) diff --git a/tests/test_nodes.py b/tests/test_nodes.py index fc87f0a62..4368a079f 100644 --- a/tests/test_nodes.py +++ b/tests/test_nodes.py @@ -84,6 +84,7 @@ def test_design_flow(name: str): "PARAMETRIC_SYSTEM", "ROOT_SYSTEM", "INTEGRATION_NODE", + "PROXY_SOLVER", ], ) def test_node_class_type(name: str):