diff --git a/src/ansys/pyaedt/examples/__init__.py b/src/ansys/pyaedt/examples/__init__.py new file mode 100644 index 000000000..160ef9601 --- /dev/null +++ b/src/ansys/pyaedt/examples/__init__.py @@ -0,0 +1,27 @@ +# Copyright (C) 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. + +""" +Project dedicated to PyAEDT examples +""" + +__version__ = "0.1.dev0" diff --git a/src/ansys/pyaedt/examples/constants.py b/src/ansys/pyaedt/examples/constants.py new file mode 100644 index 000000000..dcd9a9bc9 --- /dev/null +++ b/src/ansys/pyaedt/examples/constants.py @@ -0,0 +1,111 @@ +# Copyright (C) 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. +"""Constants used in PyAEDT examples. +""" + +AEDT_VERSION = "2023.2" +EDB_VERSION = "2023.2" + +HEADER = """# Copyright (C) 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.""" + +EDB_PREAMBLE = """# This example shows how you can use EDB to create a layout. +# ## Final expected project +# +# """ + +EDB_IMPORTS = """ +# + +import os +import tempfile + +from src.ansys.pyaedt.examples.constants import EDB_VERSION +from pyaedt import Edb +# -""" + +EDB_TMP_DIR = r"""# Create and return a temporary directory +temp_dir = tempfile.TemporaryDirectory(suffix=".ansys") +print(f"Temporary directory created at {temp_dir.name}")""" + +EDB_APP_SETUP = r"""# + +aedb_path = os.path.join(temp_dir.name, "create_via.aedb") +print(f"Path used to save the AEDB file: {aedb_path}") + +edb = Edb(edbpath=aedb_path, edbversion=edb_version) +# -""" + +EDB_PROCESSING = """# ## Add stackup layers +# A stackup can be created layer by layer or imported from a CSV file or XML file. + +edb.stackup.add_layer("GND") +edb.stackup.add_layer( + "Diel", "GND", layer_type="dielectric", thickness="0.1mm", material="FR4_epoxy" +) +edb.stackup.add_layer("TOP", "Diel", thickness="0.05mm") + +# ## Create signal net and ground planes + +points = [[0.0, 0], [100e-3, 0.0]] +edb.modeler.create_trace(points, "TOP", width=1e-3) +points = [[0.0, 1e-3], [0.0, 10e-3], [100e-3, 10e-3], [100e-3, 1e-3], [0.0, 1e-3]] +edb.modeler.create_polygon(points, "TOP") +points = [[0.0, -1e-3], [0.0, -10e-3], [100e-3, -10e-3], [100e-3, -1e-3], [0.0, -1e-3]] +edb.modeler.create_polygon(points, "TOP") + +# ## Create vias with parametric positions + +edb.padstacks.create("MyVia") +edb.padstacks.place([5e-3, 5e-3], "MyVia") +edb.padstacks.place([15e-3, 5e-3], "MyVia") +edb.padstacks.place([35e-3, 5e-3], "MyVia") +edb.padstacks.place([45e-3, 5e-3], "MyVia") +edb.padstacks.place([5e-3, -5e-3], "MyVia") +edb.padstacks.place([15e-3, -5e-3], "MyVia") +edb.padstacks.place([35e-3, -5e-3], "MyVia") +edb.padstacks.place([45e-3, -5e-3], "MyVia") + +# ## Generate geometry plot + +edb.nets.plot(None, color_by_net=True) + +# ## Generate stackup plot + +edb.stackup.plot(plot_definitions="MyVia")""" diff --git a/src/ansys/pyaedt/examples/edb_writer.py b/src/ansys/pyaedt/examples/edb_writer.py new file mode 100644 index 000000000..85f2e1043 --- /dev/null +++ b/src/ansys/pyaedt/examples/edb_writer.py @@ -0,0 +1,75 @@ +# Copyright (C) 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. +"""Utils to write an EDB example. + +If used as a python script, this file will generate a simple example. +""" + +import os + +from ansys.pyaedt.examples.constants import ( + EDB_APP_SETUP, + EDB_IMPORTS, + EDB_PREAMBLE, + EDB_PROCESSING, + EDB_TMP_DIR, + EDB_VERSION, + HEADER, +) +from ansys.pyaedt.examples.models import CodeCell, EDBModel, TextCell +from jinja2 import Environment, FileSystemLoader + +PARENT_DIR = os.path.dirname(os.path.abspath(__file__)) + + +def write_example(example_path, data: EDBModel): + """Write a new example using a template and user information.""" + + file_loader = FileSystemLoader(os.path.join(PARENT_DIR, "templates")) + env = Environment(loader=file_loader) + template = env.get_template("template_edb.j2") + + output = template.render(data.model_dump()) + with open(example_path, "w") as f: + f.write(output) + + +if __name__ == "__main__": + + # Data of a simple edb example + data = { + "header_required": False, + "header": HEADER, + "example_title": "Simple workflow using EDB", + "example_preamble": TextCell(EDB_PREAMBLE), + "step_imports": CodeCell(EDB_IMPORTS), + "step_temp_dir": CodeCell(EDB_TMP_DIR), + "download_required": False, + "step_download": CodeCell(""), + "edb_version": EDB_VERSION, + "step_app_setup": CodeCell(EDB_APP_SETUP), + "step_processing": EDB_PROCESSING, + } + model_data = EDBModel(**data) + + example_path = os.path.join(PARENT_DIR, "simple_example.py") + write_example(example_path, data=model_data) diff --git a/src/ansys/pyaedt/examples/models.py b/src/ansys/pyaedt/examples/models.py new file mode 100644 index 000000000..0423b5818 --- /dev/null +++ b/src/ansys/pyaedt/examples/models.py @@ -0,0 +1,83 @@ +# Copyright (C) 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. +"""Models used to store data related to writing PyAEDT examples. +""" +from typing import Union + +from ansys.pyaedt.examples.constants import EDB_APP_SETUP, EDB_IMPORTS, EDB_TMP_DIR, EDB_VERSION +from pydantic import BaseModel, field_validator + + +class CodeCell(BaseModel): + """Notebook code cell""" + + code: str + + def __init__(self, code: str = None, **data): + code_value = code if code is not None else data.get("code") + super().__init__(code=code_value) + + @field_validator("code") + def multiple_blocs(cls, v): + if v.startswith("# +") and not v.endswith("# -"): + raise ValueError("multiple blocks must begin with '# +' and end with '# -'") + return v + + +class TextCell(BaseModel): + """Notebook text cell""" + + text: str + + def __init__(self, text: str = None, **data): + text_value = text if text is not None else data.get("text") + super().__init__(text=text_value) + + @field_validator("text") + def must_start_with_hash(cls, v): + lines = v.split("\n") + for line in lines: + if line == "#": + continue + if not line.startswith("# "): + raise ValueError("each line of a text cell must be '#' or start with '# '") + return v + + +class EDBModel(BaseModel): + """Store AEDT properties.""" + + header_required: bool = False + header: Union[TextCell, str] = "" + example_title: str = "Simple workflow using EDB" + example_preamble: Union[TextCell, str] = "" + step_imports: CodeCell = CodeCell(EDB_IMPORTS) + step_temp_dir: CodeCell = CodeCell(EDB_TMP_DIR) + download_required: bool = False + step_download: CodeCell = CodeCell("") + edb_version: str = EDB_VERSION + step_app_setup: CodeCell = CodeCell(EDB_APP_SETUP) + step_processing: str = "" + + +if __name__ == "__main__": + model = EDBModel() diff --git a/src/ansys/pyaedt/examples/templates/template_edb.j2 b/src/ansys/pyaedt/examples/templates/template_edb.j2 new file mode 100644 index 000000000..92b4653b6 --- /dev/null +++ b/src/ansys/pyaedt/examples/templates/template_edb.j2 @@ -0,0 +1,45 @@ +{%- if header_required -%} +{{ header }} +{%- endif -%} +# ## {{ example_title }} +# +{{ example_preamble.text }} + +# ## Perform required imports and create a temporary folder. +# +# Perform imports required to run the example and create a temporary folder in which to save files. +{{ step_imports.code }} + +{{ step_temp_dir.code }} + +{%- if download_required -%} +# ## Download the EDB file. +{{ step_download.code }} +{% endif %} + +# ## Create an instance of the Electronics Database using the `pyaedt.Edb` class. +# +# > Note that units are SI. + +# Select EDB version (change it manually if needed, e.g. "2023.2") +edb_version = {{ edb_version }} +print(f"EDB version: {edb_version}") + +{{ step_app_setup.code }} + +{{ step_processing }} + +# ## Save and clean up +# +# The following commands save and close the EDB. After that, the temporary +# directory containing the project is deleted. To keep this project, save it to +# another folder of your choice prior to running the following cell. + +# + +edb.save_edb() +edb.close_edb() +print("EDB saved correctly to {}. You can import in AEDT.".format(aedb_path)) + +# Removing the temporary directory +temp_dir.cleanup() +# - diff --git a/src/ansys/pyaedt/examples/utils.py b/src/ansys/pyaedt/examples/utils.py new file mode 100644 index 000000000..442d303b8 --- /dev/null +++ b/src/ansys/pyaedt/examples/utils.py @@ -0,0 +1,75 @@ +# Copyright (C) 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. +"""Utilities module. +""" + +import requests + + +def download_file(url, local_filename): + """Download a file from an URL into a local file.""" + with requests.get(url, stream=True) as r: + r.raise_for_status() + with open(local_filename, "wb") as f: + for chunk in r.iter_content(chunk_size=4096): + f.write(chunk) + return local_filename + + +import os + +from jinja2 import Environment, FileSystemLoader + +# Charger le template Jinja +file_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__))) +env = Environment(loader=file_loader) +template = env.get_template("template.j2") + +# Données pour le template +data = { + "imports": "import os\nimport sys", + "functions": [ + {"name": "my_function", "description": "Cette function fait quelque chose."}, + ], + "environment_setup": "Création d'un répertoire temporaire...", + "app_setup": "Configuration de l'application...", + "processing": "Traitement des données...", + "cleanup": "Nettoyage et suppression du répertoire temporaire...", +} + +# Générer le fichier Markdown +output = template.render(**data) +with open("example.md", "w") as f: + f.write(output) +# Données pour le template +data = { + "imports": "import os\nimport sys", + "functions": [ + {"name": "my_function", "description": "Cette function fait quelque chose."}, + ], + "environment_setup": "Création d'un répertoire temporaire...", + "download_required": True, # ou False, en function de vos besoins + "download_step": "Téléchargement des fichiers nécessaires...", + "app_setup": "Configuration de l'application...", + "processing": "Traitement des données...", + "cleanup": "Nettoyage et suppression du répertoire temporaire...", +}