.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/workflow_creation/03_2_proxy_solver_amop.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_workflow_creation_03_2_proxy_solver_amop.py: .. _ref_proxy_solver_amop: Proxy solver with AMOP ---------------------- This example demonstrates how to obtain designs from a parametric system and process them externally. It creates a proxy solver node inside an AMOP parametric system, modifies the maximum number of designs in the AMOP settings, and solves its designs externally. This is a unified approach for "optiSLang inside" solutions. **Workflow overview (mapped to code sections below):** 1. **"Perform required imports"** -- Import pyOptislang classes for workflow creation. 2. **"Create solver"** -- Define a Python calculator function that serves as the external solver. This function receives design dicts with parameter values and returns response values. 3. **"Create optiSLang instance"** -- Discover an optiSLang >= 25.1 installation and start a headless optiSLang server. 4. **"Create workflow"** -- Build the parametric workflow: a. Create an ``AMOP`` system (``node_types.AMOP``) -- Adaptive Metamodel-based Optimization Process that iteratively builds surrogate models and refines the design space. b. Read and modify algorithm settings via ``get_property("AMopSettings")``: set ``num_designs_max`` to 150 (maximum number of designs to evaluate). c. Set fast-running solver properties (``AutoSaveMode``, ``SolveTwice``, etc.). d. Add a ``ProxySolver`` node (``DesignFlow.RECEIVE_SEND``) inside the AMOP system and configure batch size via ``MultiDesignLaunchNum``. e. Load 5 input parameters (X1..X5) and 1 response (Y) into the proxy solver via ``load()``. f. Register them as system-level parameters/responses and set bounds [-3.14, 3.14]. g. Add a minimization criterion on Y. 5. **"Run workflow"** -- Start the project in non-blocking mode and loop externally: poll ``proxy_solver.get_designs()``, compute responses via the calculator, and return results via ``proxy_solver.set_designs()`` until the system finishes. 6. **"Stop and cancel project"** -- Dispose of the optiSLang instance. **Key APIs used:** - ``node_types.AMOP`` -- Adaptive Metamodel-based Optimization Process algorithm - ``get_property("AMopSettings")`` / ``set_property("AMopSettings", ...)`` -- read/write AMOP-specific settings (e.g. ``num_designs_max``, ``num_discretization_initial``) - ``node_types.ProxySolver`` with ``DesignFlow.RECEIVE_SEND`` -- external solver integration - ``proxy_solver.get_designs()`` / ``proxy_solver.set_designs()`` -- design exchange loop - ``register_locations_as_parameter()`` / ``register_locations_as_response()`` -- register solver slots as system-level parameters and responses .. GENERATED FROM PYTHON SOURCE LINES 72-78 Perform required imports ~~~~~~~~~~~~~~~~~~~~~~~~ Import the pyOptislang core classes: ``Optislang`` for server management, ``node_types`` for algorithm and solver type constants, ``DesignFlow``/``ParametricSystem``/``ProxySolverNode`` for workflow construction, and parametric classes for defining parameters, criteria, and bounds. .. GENERATED FROM PYTHON SOURCE LINES 78-90 .. code-block:: Python 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 .. GENERATED FROM PYTHON SOURCE LINES 91-98 Create solver ~~~~~~~~~~~~~ Define the external solver functions that will evaluate designs outside optiSLang. ``calculator()`` computes response Y from 5 input parameters using a nonlinear formula. ``calculate()`` processes a batch of design dicts received from the proxy solver: each design contains ``hid`` (design ID) and ``parameters`` (list of name/value pairs). It returns a list of result dicts with ``hid`` and ``responses`` (list of name/value pairs). .. GENERATED FROM PYTHON SOURCE LINES 98-141 .. code-block:: Python 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 .. GENERATED FROM PYTHON SOURCE LINES 142-148 Create optiSLang instance ~~~~~~~~~~~~~~~~~~~~~~~~~ Discover available optiSLang installations using ``find_all_osl_exec()``. The ProxySolver node requires optiSLang >= 25R1 (version code 251). ``Optislang(executable=...)`` starts a headless optiSLang server process and establishes a TCP connection for remote control. .. GENERATED FROM PYTHON SOURCE LINES 148-161 .. code-block:: Python available_optislang_executables = find_all_osl_exec() if not available_optislang_executables: raise KeyError("No optiSLang executables were found, please specify path manually.") 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}") .. GENERATED FROM PYTHON SOURCE LINES 162-166 Create workflow ~~~~~~~~~~~~~~~ Build the complete parametric workflow. The root system is the top-level container for all nodes in an optiSLang project. .. GENERATED FROM PYTHON SOURCE LINES 166-254 .. code-block:: Python root_system = osl.application.project.root_system # **Step 4a: Create the AMOP algorithm system.** # ``node_types.AMOP`` (Adaptive Metamodel-based Optimization Process) iteratively builds # and refines surrogate models (MOP) while exploring the design space, then runs optimization # on the surrogate to find promising regions and validates them with the real solver. algorithm_system: ParametricSystem = root_system.create_node(type_=node_types.AMOP, name="AMOP") # **Step 4b: Read and modify algorithm settings.** # ``get_property("AMopSettings")`` returns the AMOP-specific settings dict. # ``num_designs_max`` controls the maximum total number of designs AMOP will evaluate # across all iterations (default is 300; set to 150 here). # The modified dict is written back with ``set_property()``. max_num_designs = 150 amop_settings = algorithm_system.get_property("AMopSettings") amop_settings["num_designs_max"] = max_num_designs algorithm_system.set_property("AMopSettings", amop_settings) # **Step 4c: Set fast-running solver properties.** # These reduce I/O overhead for fast external solvers: # - ``AutoSaveMode``: disable auto-saving to avoid filesystem delays. # - ``SolveTwice``: re-evaluate the reference design for verification. # - ``UpdateResultFile``: skip writing intermediate result files. algorithm_system.set_property("AutoSaveMode", "no_auto_save") algorithm_system.set_property("SolveTwice", True) algorithm_system.set_property("UpdateResultFile", "never") # **Step 4d: Add the Proxy Solver node.** # The ``ProxySolver`` with ``DesignFlow.RECEIVE_SEND`` acts as a bridge: optiSLang sends # designs to it, and the external Python code retrieves them via ``get_designs()``, # evaluates them, and returns results via ``set_designs()``. # ``MultiDesignLaunchNum`` controls the batch size (99 = up to 99 designs per batch; # set to -1 to receive all pending designs at once). 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) # **Step 4e: Load parameters and responses into the proxy solver.** # Define 5 input parameters (X1..X5) with reference value 1.0 and 1 output response (Y) # with reference value 3.0. The ``load()`` call configures the proxy solver's interface # so optiSLang knows which values to send and expect back. load_json = {} load_json["parameters"] = [] load_json["responses"] = [] for i in range(1, 6): parameter = {"dir": {"value": "input"}, "name": f"X{i}", "value": 1.0} load_json["parameters"].append(parameter) response = {"dir": {"value": "output"}, "name": "Y", "value": 3.0} load_json["responses"].append(response) proxy_solver.load(args=load_json) # **Step 4f: Register parameters/responses and set bounds.** # ``register_locations_as_parameter()`` promotes the proxy solver's input slots to # system-level parameters visible to the AMOP algorithm. # ``register_locations_as_response()`` does the same for outputs. # Then modify each parameter to an ``OptimizationParameter`` with bounds [-3.14, 3.14]. proxy_solver.register_locations_as_parameter() proxy_solver.register_locations_as_response() for i in range(1, 6): algorithm_system.parameter_manager.modify_parameter( OptimizationParameter(name=f"X{i}", reference_value=1.0, range=(-3.14, 3.14)) ) # **Step 4g: Add optimization criterion.** # Add a minimization objective on the response Y. AMOP will build surrogate models for Y # and optimize on them to find the minimum. algorithm_system.criteria_manager.add_criterion( ObjectiveCriterion(name="obj", expression="Y", criterion=ComparisonType.MIN) ) .. GENERATED FROM PYTHON SOURCE LINES 255-265 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_amop_workflow.opf" osl.application.save_as(dir_path / project_name) .. GENERATED FROM PYTHON SOURCE LINES 268-276 Run workflow ~~~~~~~~~~~~ **Step 5: Execute the workflow with the external proxy solver loop.** ``start(wait_for_finished=False)`` launches the optiSLang project execution in the background. The while-loop then acts as the external solver: it polls ``get_designs()`` to receive pending design batches from optiSLang, evaluates them with the ``calculate()`` function, and returns the computed responses via ``set_designs()``. The loop continues until ``get_status()`` reports ``"Processing done"``. .. GENERATED FROM PYTHON SOURCE LINES 276-289 .. code-block:: Python osl.application.project.start(wait_for_finished=False) 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!") .. GENERATED FROM PYTHON SOURCE LINES 290-294 Stop and cancel project ~~~~~~~~~~~~~~~~~~~~~~~ **Step 6: Dispose of the optiSLang instance.** ``dispose()`` stops the optiSLang server process and cleans up resources. .. GENERATED FROM PYTHON SOURCE LINES 294-296 .. code-block:: Python osl.dispose() .. GENERATED FROM PYTHON SOURCE LINES 297-306 View generated workflow ~~~~~~~~~~~~~~~~~~~~~~~ This image shows the generated workflow. However, it is important to note, that this workflow is only usable through pyoptislang and cannot be used interactively! .. image:: ../../_static/03_2_ProxySolverAMOP.png :width: 400 :alt: Result of script. .. _sphx_glr_download_examples_workflow_creation_03_2_proxy_solver_amop.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 03_2_proxy_solver_amop.ipynb <03_2_proxy_solver_amop.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 03_2_proxy_solver_amop.py <03_2_proxy_solver_amop.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 03_2_proxy_solver_amop.zip <03_2_proxy_solver_amop.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_