{ "cells": [ { "cell_type": "markdown", "id": "019bb8b5", "metadata": {}, "source": [ "# LTI ROM creation and simulation" ] }, { "cell_type": "markdown", "id": "20ef7acb", "metadata": {}, "source": [ "This example shows how you can use PyAEDT to create a Linear Time Invariant (LTI) ROM in Twin Builder\n", "and run a Twin Builder time-domain simulation. Inputs data are defined using Datapairs blocks with CSV files.\n", "\n", "Keywords: **Twin Builder**, **LTI**, **ROM**." ] }, { "cell_type": "markdown", "id": "d430eebd", "metadata": {}, "source": [ "## Perform imports and define constants\n", "\n", "Perform required imports." ] }, { "cell_type": "code", "execution_count": null, "id": "a6c9ed2c", "metadata": {}, "outputs": [], "source": [ "import datetime\n", "import os\n", "import subprocess\n", "import tempfile\n", "import time" ] }, { "cell_type": "code", "execution_count": null, "id": "831f51c0", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "from ansys.aedt.core import TwinBuilder, downloads\n", "from ansys.aedt.core.application.variables import CSVDataset" ] }, { "cell_type": "markdown", "id": "e9a00a20", "metadata": {}, "source": [ "Define constants" ] }, { "cell_type": "code", "execution_count": null, "id": "e1ef1a0c", "metadata": {}, "outputs": [], "source": [ "AEDT_VERSION = \"2024.2\"\n", "NUM_CORES = 4\n", "NG_MODE = False # Open AEDT UI when it is launched." ] }, { "cell_type": "markdown", "id": "bb6f1a1a", "metadata": {}, "source": [ "## Set paths and define input files and variables\n", "\n", "Set paths." ] }, { "cell_type": "code", "execution_count": null, "id": "f0b8bfb9", "metadata": {}, "outputs": [], "source": [ "training_data_folder = \"LTI_training_data.zip\"\n", "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", "input_dir = downloads.download_twin_builder_data(\n", " training_data_folder, True, temp_folder.name\n", ")" ] }, { "cell_type": "markdown", "id": "e8f4cd1b", "metadata": {}, "source": [ "Download data from example_data repository" ] }, { "cell_type": "code", "execution_count": null, "id": "416bece5", "metadata": {}, "outputs": [], "source": [ "data_folder = os.path.join(input_dir, \"LTI_training\")" ] }, { "cell_type": "markdown", "id": "7c1ef067", "metadata": {}, "source": [ "Unzip training data and parse ports names" ] }, { "cell_type": "code", "execution_count": null, "id": "6581dd1f", "metadata": { "lines_to_next_cell": 2 }, "outputs": [], "source": [ "downloads.unzip(os.path.join(input_dir, training_data_folder), data_folder)\n", "ports_names_file = \"Input_PortNames.txt\"" ] }, { "cell_type": "markdown", "id": "ba6950f7", "metadata": { "lines_to_next_cell": 2 }, "source": [ "## Get ports information from file" ] }, { "cell_type": "code", "execution_count": null, "id": "2ffefe72", "metadata": {}, "outputs": [], "source": [ "def get_ports_info(ports_file):\n", " with open(ports_file, \"r\") as PortNameFile:\n", " res = []\n", " line = PortNameFile.readline()\n", " line_list = list(line.split())\n", " for i in range(len(line_list)):\n", " res.append(\"Input\" + str(i + 1) + \"_\" + line_list[i])\n", "\n", " line = PortNameFile.readline()\n", " line_list = list(line.split())\n", " for i in range(len(line_list)):\n", " res.append(\"Output\" + str(i + 1) + \"_\" + line_list[i])\n", " return res" ] }, { "cell_type": "code", "execution_count": null, "id": "44c3854f", "metadata": {}, "outputs": [], "source": [ "pin_names = get_ports_info(os.path.join(data_folder, ports_names_file))" ] }, { "cell_type": "markdown", "id": "053c4e99", "metadata": {}, "source": [ "## Launch Twin Builder\n", "\n", "Launch Twin Builder using an implicit declaration and add a new design with\n", "the default setup." ] }, { "cell_type": "code", "execution_count": null, "id": "d62fb763", "metadata": {}, "outputs": [], "source": [ "project_name = os.path.join(temp_folder.name, \"LTI_ROM.aedt\")\n", "tb = TwinBuilder(\n", " project=project_name, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True\n", ")" ] }, { "cell_type": "markdown", "id": "dd587793", "metadata": {}, "source": [ "## Build the LTI ROM with specified configuration file" ] }, { "cell_type": "code", "execution_count": null, "id": "125098a0", "metadata": {}, "outputs": [], "source": [ "install_dir = tb.odesktop.GetRegistryString(\"Desktop/InstallationDirectory\")\n", "fitting_exe = os.path.join(install_dir, \"FittingTool.exe\")\n", "path = '\"' + fitting_exe + '\"' + \" \" + '\"t\"' + \" \" + '\"' + data_folder + '\"'\n", "process = subprocess.Popen(\n", " path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE\n", ")\n", "tb.logger.info(\"Fitting the LTI ROM training data\")\n", "exec = True\n", "startTime = datetime.datetime.now()\n", "execTime = 0.0\n", "while (\n", " exec and execTime < 60.0\n", "): # limiting the fitting process execution time to 1 minute\n", " out, err = process.communicate()\n", " execTime = (datetime.datetime.now() - startTime).total_seconds()\n", " if \"An LTI ROM has been generated\" in str(out):\n", " process.terminate()\n", " exec = False" ] }, { "cell_type": "code", "execution_count": null, "id": "d6d847f2", "metadata": {}, "outputs": [], "source": [ "rom_file = \"\"\n", "model_name_sml = \"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "23429fa3", "metadata": {}, "outputs": [], "source": [ "for i in os.listdir(data_folder):\n", " if i.endswith(\".sml\"):\n", " model_name_sml = i.split(\".\")[0]\n", " rom_file = os.path.join(data_folder, i)" ] }, { "cell_type": "code", "execution_count": null, "id": "679efb02", "metadata": { "lines_to_next_cell": 2 }, "outputs": [], "source": [ "if os.path.exists(rom_file):\n", " tb.logger.info(\"Built intermediate ROM file successfully at: %s\", rom_file)\n", "else:\n", " tb.logger.info(\"ROM file does not exist at the expected location : %s\", rom_file)" ] }, { "cell_type": "markdown", "id": "223be5da", "metadata": {}, "source": [ "## Import the ROM component model" ] }, { "cell_type": "code", "execution_count": null, "id": "cc8363fb", "metadata": {}, "outputs": [], "source": [ "is_created = tb.modeler.schematic.create_component_from_sml(\n", " input_file=rom_file, model=model_name_sml, pins_names=pin_names\n", ")\n", "os.remove(rom_file)\n", "tb.logger.info(\"LTI ROM model successfully imported.\")" ] }, { "cell_type": "markdown", "id": "b9a08734", "metadata": {}, "source": [ "## Import the ROM component model in Twin Builder\n", "\n", "Place components to create a schematic." ] }, { "cell_type": "markdown", "id": "34a73254", "metadata": {}, "source": [ "Define the grid distance for ease in calculations" ] }, { "cell_type": "code", "execution_count": null, "id": "78c8008f", "metadata": {}, "outputs": [], "source": [ "grid_distance = 0.00254" ] }, { "cell_type": "markdown", "id": "3f2158e4", "metadata": {}, "source": [ "Place the ROM component" ] }, { "cell_type": "code", "execution_count": null, "id": "80a780d3", "metadata": {}, "outputs": [], "source": [ "rom1 = tb.modeler.schematic.create_component(\n", " \"ROM1\", \"\", model_name_sml, [36 * grid_distance, 28 * grid_distance]\n", ")" ] }, { "cell_type": "markdown", "id": "584b4f6a", "metadata": {}, "source": [ "Place datapairs blocks for inputs definition" ] }, { "cell_type": "code", "execution_count": null, "id": "0944fd1e", "metadata": {}, "outputs": [], "source": [ "source1 = tb.modeler.schematic.create_component(\n", " \"source1\",\n", " \"\",\n", " \"Simplorer Elements\\\\Basic Elements\\\\Tools\\\\Time Functions:DATAPAIRS\",\n", " [20 * grid_distance, 29 * grid_distance],\n", ")\n", "source2 = tb.modeler.schematic.create_component(\n", " \"source2\",\n", " \"\",\n", " \"Simplorer Elements\\\\Basic Elements\\\\Tools\\\\Time Functions:DATAPAIRS\",\n", " [20 * grid_distance, 25 * grid_distance],\n", ")" ] }, { "cell_type": "markdown", "id": "25332785", "metadata": {}, "source": [ "Import Datasets" ] }, { "cell_type": "code", "execution_count": null, "id": "c397aab8", "metadata": {}, "outputs": [], "source": [ "data1 = CSVDataset(os.path.join(data_folder, \"data1.csv\"))\n", "data2 = CSVDataset(os.path.join(data_folder, \"data2.csv\"))\n", "dataset1 = tb.create_dataset(\"data1\", data1.data[\"time\"], data1.data[\"input1\"])\n", "dataset2 = tb.create_dataset(\"data2\", data2.data[\"time\"], data2.data[\"input2\"])" ] }, { "cell_type": "code", "execution_count": null, "id": "1553a016", "metadata": {}, "outputs": [], "source": [ "source1.parameters[\"CH_DATA\"] = dataset1.name\n", "source2.parameters[\"CH_DATA\"] = dataset2.name" ] }, { "cell_type": "code", "execution_count": null, "id": "991d7f70", "metadata": {}, "outputs": [], "source": [ "tb.modeler.schematic.update_quantity_value(source1.composed_name, \"PERIO\", \"0\")" ] }, { "cell_type": "code", "execution_count": null, "id": "dd068803", "metadata": {}, "outputs": [], "source": [ "tb.modeler.schematic.update_quantity_value(\n", " source1.composed_name, \"TPERIO\", \"Tend+1\", \"s\"\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "e3a34153", "metadata": {}, "outputs": [], "source": [ "tb.modeler.schematic.update_quantity_value(source2.composed_name, \"PERIO\", \"0\")" ] }, { "cell_type": "code", "execution_count": null, "id": "b272e390", "metadata": {}, "outputs": [], "source": [ "tb.modeler.schematic.update_quantity_value(\n", " source2.composed_name, \"TPERIO\", \"Tend+1\", \"s\"\n", ")" ] }, { "cell_type": "markdown", "id": "090575b3", "metadata": {}, "source": [ "Connect components with wires" ] }, { "cell_type": "code", "execution_count": null, "id": "1bc24002", "metadata": {}, "outputs": [], "source": [ "tb.modeler.schematic.create_wire(\n", " points=[source1.pins[0].location, rom1.pins[0].location]\n", ")\n", "tb.modeler.schematic.create_wire(\n", " points=[source2.pins[0].location, rom1.pins[1].location]\n", ")" ] }, { "cell_type": "markdown", "id": "43f94ee5", "metadata": {}, "source": [ "Zoom to fit the schematic" ] }, { "cell_type": "code", "execution_count": null, "id": "2a3dc3ee", "metadata": {}, "outputs": [], "source": [ "tb.modeler.zoom_to_fit()" ] }, { "cell_type": "markdown", "id": "2beac154", "metadata": {}, "source": [ "## Parametrize transient setup\n", "\n", "Parametrize the default transient setup by setting the end time and minimum/maximum time steps." ] }, { "cell_type": "code", "execution_count": null, "id": "c1cd8c90", "metadata": {}, "outputs": [], "source": [ "tb.set_end_time(\"700s\")\n", "tb.set_hmin(\"0.001s\")\n", "tb.set_hmax(\"1s\")" ] }, { "cell_type": "markdown", "id": "d1b01f6a", "metadata": {}, "source": [ "## Solve transient setup\n", "\n", "Solve the transient setup." ] }, { "cell_type": "code", "execution_count": null, "id": "0d56e4a1", "metadata": {}, "outputs": [], "source": [ "tb.analyze_setup(\"TR\")" ] }, { "cell_type": "markdown", "id": "09010d93", "metadata": {}, "source": [ "## Get report data and plot using Matplotlib\n", "\n", "Get report data and plot it using Matplotlib. The following code gets and plots\n", "the values for the inputs and outputs of the LTI ROM." ] }, { "cell_type": "markdown", "id": "00197998", "metadata": {}, "source": [ "Units used are based on AEDT default units." ] }, { "cell_type": "code", "execution_count": null, "id": "8a551713", "metadata": {}, "outputs": [], "source": [ "variables_postprocessing = []\n", "pin_names_str = \",\".join(pin_names)\n", "rom_pins = pin_names_str.lower().split(\",\")\n", "fig, ax = plt.subplots(ncols=1, nrows=2, figsize=(18, 7))\n", "fig.subplots_adjust(hspace=0.5)" ] }, { "cell_type": "code", "execution_count": null, "id": "f4376660", "metadata": {}, "outputs": [], "source": [ "for i in range(0, 2):\n", " variable = \"ROM1.\" + rom_pins[i]\n", " x = tb.post.get_solution_data(variable, \"TR\", \"Time\")\n", " ax[0].plot(\n", " [el for el in x.intrinsics[\"Time\"]], x.data_real(variable), label=variable\n", " )" ] }, { "cell_type": "code", "execution_count": null, "id": "29d3c9af", "metadata": {}, "outputs": [], "source": [ "ax[0].set_title(\"ROM inputs\")\n", "ax[0].legend(loc=\"upper left\")" ] }, { "cell_type": "code", "execution_count": null, "id": "f9a52240", "metadata": {}, "outputs": [], "source": [ "for i in range(2, 4):\n", " variable = \"ROM1.\" + rom_pins[i]\n", " x = tb.post.get_solution_data(variable, \"TR\", \"Time\")\n", " ax[1].plot(\n", " [el for el in x.intrinsics[\"Time\"]], x.data_real(variable), label=variable\n", " )" ] }, { "cell_type": "code", "execution_count": null, "id": "b00e3051", "metadata": {}, "outputs": [], "source": [ "ax[1].set_title(\"ROM outputs\")\n", "ax[1].legend(loc=\"upper left\")" ] }, { "cell_type": "markdown", "id": "0b381ac1", "metadata": {}, "source": [ "Show plot" ] }, { "cell_type": "code", "execution_count": null, "id": "6f8dea71", "metadata": {}, "outputs": [], "source": [ "plt.show()" ] }, { "cell_type": "markdown", "id": "c299fe6b", "metadata": {}, "source": [ "## Release AEDT\n", "\n", "Release AEDT and close the example." ] }, { "cell_type": "code", "execution_count": null, "id": "af79a5fd", "metadata": {}, "outputs": [], "source": [ "tb.save_project()\n", "tb.release_desktop()" ] }, { "cell_type": "markdown", "id": "216cefa5", "metadata": {}, "source": [ "Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory." ] }, { "cell_type": "code", "execution_count": null, "id": "e8c9d9f0", "metadata": {}, "outputs": [], "source": [ "time.sleep(3)" ] }, { "cell_type": "markdown", "id": "658accca", "metadata": {}, "source": [ "## Clean up\n", "\n", "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", "can retrieve those project files. The following cell removes all temporary files, including the project folder." ] }, { "cell_type": "code", "execution_count": null, "id": "a6f093c4", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }