.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/workflow_creation/03_1_proxy_solver_sensitivity.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_1_proxy_solver_sensitivity.py: .. _ref_proxy_solver_sensitivity: Proxy solver with Sensitivity ----------------------------- This example demonstrates how to obtain designs from a parametric system and process them externally. It creates a proxy solver node inside a Sensitivity parametric system 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 a ``Sensitivity`` system (``node_types.Sensitivity``) -- Latin Hypercube sampling. b. Read and modify algorithm settings via ``get_property("AlgorithmSettings")``: set ``num_discretization`` to 2000 sampling points. c. Set fast-running solver properties (``AutoSaveMode``, ``SolveTwice``, etc.). d. Add a ``ProxySolver`` node (``DesignFlow.RECEIVE_SEND``) inside the Sensitivity 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.Sensitivity`` -- Sensitivity analysis algorithm (Latin Hypercube sampling) - ``get_property("AlgorithmSettings")`` / ``set_property("AlgorithmSettings", ...)`` -- read/write algorithm-specific settings (e.g. ``num_discretization``) - ``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 70-76 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 76-88 .. 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 89-96 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 96-139 .. 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 140-146 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 146-157 .. code-block:: Python 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}") .. GENERATED FROM PYTHON SOURCE LINES 158-162 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 162-252 .. code-block:: Python root_system = osl.application.project.root_system # **Step 4a: Create the Sensitivity algorithm system.** # ``node_types.Sensitivity`` performs a design of experiments using Latin Hypercube sampling # to explore the parameter space and compute sensitivity indices (e.g. CoP values). algorithm_system: ParametricSystem = root_system.create_node( type_=node_types.Sensitivity, name="Sensitivity" ) # **Step 4b: Read and modify algorithm settings.** # ``get_property("AlgorithmSettings")`` returns the Sensitivity-specific settings dict. # ``num_discretization`` controls the number of sampling points (default is lower; set to 2000 # for a more thorough exploration). The modified dict is written back with ``set_property()``. num_discretization = 2000 algorithm_settings = algorithm_system.get_property("AlgorithmSettings") algorithm_settings["num_discretization"] = num_discretization algorithm_system.set_property("AlgorithmSettings", algorithm_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. # - ``WriteDesignStartSetFlag``: skip writing start-set markers. 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) # **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 Sensitivity 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. The Sensitivity algorithm will compute # sensitivity metrics for this criterion across the sampled design space. algorithm_system.criteria_manager.add_criterion( ObjectiveCriterion(name="obj", expression="Y", criterion=ComparisonType.MIN) ) .. GENERATED FROM PYTHON SOURCE LINES 253-263 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) .. GENERATED FROM PYTHON SOURCE LINES 266-274 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 274-287 .. 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 288-292 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 292-294 .. code-block:: Python osl.dispose() .. GENERATED FROM PYTHON SOURCE LINES 295-304 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_1_ProxySolverSensitivity.png :width: 400 :alt: Result of script. .. _sphx_glr_download_examples_workflow_creation_03_1_proxy_solver_sensitivity.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 03_1_proxy_solver_sensitivity.ipynb <03_1_proxy_solver_sensitivity.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 03_1_proxy_solver_sensitivity.py <03_1_proxy_solver_sensitivity.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 03_1_proxy_solver_sensitivity.zip <03_1_proxy_solver_sensitivity.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_