From a7e7b27104166da07fe6b2bcb2fc33ac3c36890b Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Fri, 5 Sep 2025 17:31:49 -0600 Subject: [PATCH 01/18] Crude prototype with an existing example, the example had to copied to the directory -- need to implement method to copy and uncopy the files from output. --- doc/source/basic_session_management.py | 65 +++++++++++++++++++ doc/source/conf.py | 8 +++ doc/source/examples.rst | 7 +- .../basic_session_management.py | 39 +++++------ 4 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 doc/source/basic_session_management.py diff --git a/doc/source/basic_session_management.py b/doc/source/basic_session_management.py new file mode 100644 index 0000000..1b449d9 --- /dev/null +++ b/doc/source/basic_session_management.py @@ -0,0 +1,65 @@ +# # Basic Session Management +# +# This example demonstrates how to initialize a local Lumerical session. +# PyLumerical interacts with Lumerical products through sessions. +# +# ## Prerequisites: +# +# Valid FDTD and MODE licenses are required. + + + + +# ### Perform required imports + +import ansys.lumerical.core as lumapi + +# +# ### Open an interactive session + +fdtd = lumapi.FDTD() +# Wait for a second, then add FDTD region +fdtd.pause(1) +fdtd.addfdtd() +fdtd.print("Example complete. Press space bar to close.") +fdtd.pause(30) # Will close in 30 seconds if left idle +fdtd.close() + +mode = lumapi.MODE() +mode.print("Example complete. Press space bar to close.") +mode.pause(30) +mode.close() + +# Load a session but hide the application window +fdtd = lumapi.FDTD(hide=True) +fdtd.close() + + +# ### Use the "with" context manager + +with lumapi.FDTD() as fdtd: + fdtd.addfdtd() + fdtd.print("Example complete. Press space bar to close.") + fdtd.pause(30) +# FDTD closes automatically + + + +# ### Session wrapped in a function +# Get the number of grid cells in FDTD region for set span + + +def get_x_cells(fdtd_span): + """Return the number of grid cells in FDTD region for a set span.""" + with lumapi.FDTD() as fdtd: + # Adds FDTD region with span set by fdtd_span + fdtd.addfdtd(dimension="3D", x_span=fdtd_span, y_span=fdtd_span, z_span=fdtd_span) + # Get the x-coordinates of created FDTD region + x = fdtd.getresult("FDTD", "x") + x_cells = len(x) + return x_cells + + +# ### Test the function and print out the result +test = get_x_cells(1e-6) +print(test) diff --git a/doc/source/conf.py b/doc/source/conf.py index 3abfbf2..7681be5 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -46,6 +46,7 @@ "sphinx_copybutton", "sphinx_design", # Needed for cards "sphinx.ext.extlinks", + "nbsphinx", ] # Intersphinx mapping @@ -93,6 +94,13 @@ def autodoc_skip_member_custom(app, what, name, obj, skip, options): """Skip members that are not documented.""" return True if obj.__doc__ is None else None # need to return none if exclude is false otherwise it will interfere with other skip functions +# nbpsphinx configurations + +nbsphinx_execute = "never" + +nbsphinx_custom_formats = { + ".py": ["jupytext.reads", {"fmt": ""}] +} # RST prolog for substitution of custom variables diff --git a/doc/source/examples.rst b/doc/source/examples.rst index ecc711f..be9271a 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -28,4 +28,9 @@ For in-depth discussion of PyLumerical concepts, see the :doc:`User guide `. -.. Provide links to the files in doc/source/examples below: \ No newline at end of file +.. toctree:: + + basic_session_management + + + \ No newline at end of file diff --git a/examples/Sessions and Objects/basic_session_management.py b/examples/Sessions and Objects/basic_session_management.py index 8384e9f..1b449d9 100644 --- a/examples/Sessions and Objects/basic_session_management.py +++ b/examples/Sessions and Objects/basic_session_management.py @@ -1,25 +1,21 @@ -""" +# # Basic Session Management +# +# This example demonstrates how to initialize a local Lumerical session. +# PyLumerical interacts with Lumerical products through sessions. +# +# ## Prerequisites: +# +# Valid FDTD and MODE licenses are required. -Basic session management. ------------------------- -This example demonstrates how to initialize a local Lumerical session. -PyLumerical interacts with Lumerical products through sessions. -Prerequisites: Valid FDTD and MODE licenses are required. -""" -############################################################################### -# -# Perform required imports -# ~~~~~~~~~~~~~~~~~~~~~~~~ +# ### Perform required imports import ansys.lumerical.core as lumapi -############################################################################### # -# Open an interactive session -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ### Open an interactive session fdtd = lumapi.FDTD() # Wait for a second, then add FDTD region @@ -38,10 +34,8 @@ fdtd = lumapi.FDTD(hide=True) fdtd.close() -############################################################################### -# -# Use the "with" context manager -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# ### Use the "with" context manager with lumapi.FDTD() as fdtd: fdtd.addfdtd() @@ -49,11 +43,10 @@ fdtd.pause(30) # FDTD closes automatically -############################################################################### -# -# Session wrapped in a function + + +# ### Session wrapped in a function # Get the number of grid cells in FDTD region for set span -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def get_x_cells(fdtd_span): @@ -67,6 +60,6 @@ def get_x_cells(fdtd_span): return x_cells -# Test the function and print out the result +# ### Test the function and print out the result test = get_x_cells(1e-6) print(test) From a0bb5b24f16dd0c9bc0a18ef7e70aaa22d5bedcd Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Mon, 8 Sep 2025 11:37:34 -0600 Subject: [PATCH 02/18] Added functions to copy example to source folder and remove it after build. Added a link from examples page to the rendered example. Modified one example file in the example folder to have markdown. --- doc/source/basic_session_management.py | 65 ------------------- doc/source/conf.py | 21 ++++++ doc/source/examples.rst | 9 +-- .../basic_session_management.py | 12 ++-- 4 files changed, 28 insertions(+), 79 deletions(-) delete mode 100644 doc/source/basic_session_management.py diff --git a/doc/source/basic_session_management.py b/doc/source/basic_session_management.py deleted file mode 100644 index 1b449d9..0000000 --- a/doc/source/basic_session_management.py +++ /dev/null @@ -1,65 +0,0 @@ -# # Basic Session Management -# -# This example demonstrates how to initialize a local Lumerical session. -# PyLumerical interacts with Lumerical products through sessions. -# -# ## Prerequisites: -# -# Valid FDTD and MODE licenses are required. - - - - -# ### Perform required imports - -import ansys.lumerical.core as lumapi - -# -# ### Open an interactive session - -fdtd = lumapi.FDTD() -# Wait for a second, then add FDTD region -fdtd.pause(1) -fdtd.addfdtd() -fdtd.print("Example complete. Press space bar to close.") -fdtd.pause(30) # Will close in 30 seconds if left idle -fdtd.close() - -mode = lumapi.MODE() -mode.print("Example complete. Press space bar to close.") -mode.pause(30) -mode.close() - -# Load a session but hide the application window -fdtd = lumapi.FDTD(hide=True) -fdtd.close() - - -# ### Use the "with" context manager - -with lumapi.FDTD() as fdtd: - fdtd.addfdtd() - fdtd.print("Example complete. Press space bar to close.") - fdtd.pause(30) -# FDTD closes automatically - - - -# ### Session wrapped in a function -# Get the number of grid cells in FDTD region for set span - - -def get_x_cells(fdtd_span): - """Return the number of grid cells in FDTD region for a set span.""" - with lumapi.FDTD() as fdtd: - # Adds FDTD region with span set by fdtd_span - fdtd.addfdtd(dimension="3D", x_span=fdtd_span, y_span=fdtd_span, z_span=fdtd_span) - # Get the x-coordinates of created FDTD region - x = fdtd.getresult("FDTD", "x") - x_cells = len(x) - return x_cells - - -# ### Test the function and print out the result -test = get_x_cells(1e-6) -print(test) diff --git a/doc/source/conf.py b/doc/source/conf.py index 7681be5..c4effe1 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -2,6 +2,8 @@ from datetime import datetime import os +import shutil +import pathlib from ansys_sphinx_theme import get_version_match @@ -102,6 +104,20 @@ def autodoc_skip_member_custom(app, what, name, obj, skip, options): ".py": ["jupytext.reads", {"fmt": ""}] } +# Define auxiliary functions needed for examples + +def copy_examples_to_source_dir(app): + """Copy examples to source directory for nbsphinx.""" + + source_dir = pathlib.Path(app.srcdir) + + shutil.copytree(source_dir.parent.parent / "examples", source_dir / "examples", dirs_exist_ok=True) + +def remove_examples_from_source_dir(app, exception): + """Remove examples from source directory after build.""" + source_dir = pathlib.Path(app.srcdir) + shutil.rmtree(source_dir / "examples") + # RST prolog for substitution of custom variables rst_prolog = "" @@ -137,6 +153,11 @@ def autodoc_skip_member_custom(app, what, name, obj, skip, options): extlinks = {"examples_url": (f"{html_theme_options['github_url']}/blob/main/examples/%s", "%s")} + +# Define setup function + def setup(app): """Sphinx setup function.""" + app.connect("builder-inited", copy_examples_to_source_dir) app.connect("autodoc-skip-member", autodoc_skip_member_custom) + app.connect("build-finished", remove_examples_from_source_dir) diff --git a/doc/source/examples.rst b/doc/source/examples.rst index be9271a..ca8220d 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -8,11 +8,11 @@ For in-depth discussion of PyLumerical concepts, see the :doc:`User guide `. - .. grid-item-card:: Basic FDTD simulation - Lumerical style commands This example demonstrates how to set up a basic FDTD simulation with a Gaussian source and frequency-domain monitor. @@ -28,9 +28,4 @@ For in-depth discussion of PyLumerical concepts, see the :doc:`User guide `. -.. toctree:: - - basic_session_management - - \ No newline at end of file diff --git a/examples/Sessions and Objects/basic_session_management.py b/examples/Sessions and Objects/basic_session_management.py index 1b449d9..f0fd762 100644 --- a/examples/Sessions and Objects/basic_session_management.py +++ b/examples/Sessions and Objects/basic_session_management.py @@ -6,10 +6,7 @@ # ## Prerequisites: # # Valid FDTD and MODE licenses are required. - - - - +# # ### Perform required imports import ansys.lumerical.core as lumapi @@ -17,6 +14,8 @@ # # ### Open an interactive session +# + + fdtd = lumapi.FDTD() # Wait for a second, then add FDTD region fdtd.pause(1) @@ -34,6 +33,7 @@ fdtd = lumapi.FDTD(hide=True) fdtd.close() +# - # ### Use the "with" context manager @@ -43,12 +43,9 @@ fdtd.pause(30) # FDTD closes automatically - - # ### Session wrapped in a function # Get the number of grid cells in FDTD region for set span - def get_x_cells(fdtd_span): """Return the number of grid cells in FDTD region for a set span.""" with lumapi.FDTD() as fdtd: @@ -61,5 +58,6 @@ def get_x_cells(fdtd_span): # ### Test the function and print out the result + test = get_x_cells(1e-6) print(test) From 948e30c33e4487a57d550509f3c70360cf81e846 Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Mon, 8 Sep 2025 11:39:07 -0600 Subject: [PATCH 03/18] pre-commit suggestions. --- doc/source/conf.py | 13 +++++++------ doc/source/examples.rst | 1 - .../basic_session_management.py | 5 +++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index c4effe1..a9df6e9 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -2,8 +2,8 @@ from datetime import datetime import os -import shutil import pathlib +import shutil from ansys_sphinx_theme import get_version_match @@ -96,28 +96,29 @@ def autodoc_skip_member_custom(app, what, name, obj, skip, options): """Skip members that are not documented.""" return True if obj.__doc__ is None else None # need to return none if exclude is false otherwise it will interfere with other skip functions + # nbpsphinx configurations nbsphinx_execute = "never" -nbsphinx_custom_formats = { - ".py": ["jupytext.reads", {"fmt": ""}] -} +nbsphinx_custom_formats = {".py": ["jupytext.reads", {"fmt": ""}]} # Define auxiliary functions needed for examples + def copy_examples_to_source_dir(app): """Copy examples to source directory for nbsphinx.""" - source_dir = pathlib.Path(app.srcdir) shutil.copytree(source_dir.parent.parent / "examples", source_dir / "examples", dirs_exist_ok=True) + def remove_examples_from_source_dir(app, exception): """Remove examples from source directory after build.""" source_dir = pathlib.Path(app.srcdir) shutil.rmtree(source_dir / "examples") + # RST prolog for substitution of custom variables rst_prolog = "" @@ -153,9 +154,9 @@ def remove_examples_from_source_dir(app, exception): extlinks = {"examples_url": (f"{html_theme_options['github_url']}/blob/main/examples/%s", "%s")} - # Define setup function + def setup(app): """Sphinx setup function.""" app.connect("builder-inited", copy_examples_to_source_dir) diff --git a/doc/source/examples.rst b/doc/source/examples.rst index ca8220d..432ab93 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -28,4 +28,3 @@ For in-depth discussion of PyLumerical concepts, see the :doc:`User guide `. - \ No newline at end of file diff --git a/examples/Sessions and Objects/basic_session_management.py b/examples/Sessions and Objects/basic_session_management.py index f0fd762..8ff1153 100644 --- a/examples/Sessions and Objects/basic_session_management.py +++ b/examples/Sessions and Objects/basic_session_management.py @@ -3,8 +3,8 @@ # This example demonstrates how to initialize a local Lumerical session. # PyLumerical interacts with Lumerical products through sessions. # -# ## Prerequisites: -# +# ## Prerequisites: +# # Valid FDTD and MODE licenses are required. # # ### Perform required imports @@ -46,6 +46,7 @@ # ### Session wrapped in a function # Get the number of grid cells in FDTD region for set span + def get_x_cells(fdtd_span): """Return the number of grid cells in FDTD region for a set span.""" with lumapi.FDTD() as fdtd: From dd6234294cc22e6641805123eb117da454a7d511 Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Thu, 11 Sep 2025 16:20:50 -0600 Subject: [PATCH 04/18] Changed example section with links to built html files. --- doc/source/examples.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/source/examples.rst b/doc/source/examples.rst index 432ab93..ec0073c 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -14,17 +14,18 @@ For in-depth discussion of PyLumerical concepts, see the :doc:`User guide `. .. grid-item-card:: Basic FDTD simulation - Python style commands + :link: examples/Sessions_and_Objects/fdtd_example1_pythonic + :link-type: doc This example demonstrates how to set up a basic FDTD simulation with a Gaussian source and frequency-domain monitor. This example uses PyLumerical with workflows and syntax that is more native to Python. - Download the example :examples_url:`here `. - From 9a5c0efdefd0f8a1d4b8db552f02dd596ec55bce Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Mon, 15 Sep 2025 15:45:35 -0600 Subject: [PATCH 05/18] Added functions to move python files to output directory. Also added prolog to rst outputs from nbsphinx. Redirection of example download needs further testing. --- doc/source/conf.py | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index a9df6e9..8b15349 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -103,6 +103,37 @@ def autodoc_skip_member_custom(app, what, name, obj, skip, options): nbsphinx_custom_formats = {".py": ["jupytext.reads", {"fmt": ""}]} +nbsphinx_prolog = """ + + +.. grid:: 1 2 2 2 + + .. grid-item:: + + .. button-link:: {base_path}/{ipynb_file_path} + :color: secondary + :shadow: + :align: center + + :octicon:`download` Download Jupyter Notebook (.ipynb) + + + .. grid-item:: + + .. button-link:: {base_path}/{py_file_path} + :color: secondary + :shadow: + :align: center + + :octicon:`download` Download Python script (.py) + + ---- +""".format( + base_path = f"https://{cname}/version/{get_version_match(version)}", + py_file_path ="{{ env.docname }}.py", + ipynb_file_path ="{{ env.docname }}.ipynb" +) + # Define auxiliary functions needed for examples @@ -118,8 +149,13 @@ def remove_examples_from_source_dir(app, exception): source_dir = pathlib.Path(app.srcdir) shutil.rmtree(source_dir / "examples") +def copy_examples_to_output_dir(app, exception): + """Copy examples to output directory.""" + + source_dir = pathlib.Path(app.srcdir) + build_dir = pathlib.Path(app.outdir) -# RST prolog for substitution of custom variables + shutil.copytree(source_dir.parent.parent / "examples", build_dir / "examples", dirs_exist_ok=True) rst_prolog = "" @@ -162,3 +198,6 @@ def setup(app): app.connect("builder-inited", copy_examples_to_source_dir) app.connect("autodoc-skip-member", autodoc_skip_member_custom) app.connect("build-finished", remove_examples_from_source_dir) + app.connect("build-finished", copy_examples_to_output_dir) + + From 7de430032e3303fce57b24e318e7e65076ed8dc7 Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Mon, 15 Sep 2025 16:16:57 -0600 Subject: [PATCH 06/18] Fixed some issues in configuration by adding excluded patterns for build. Light formatting on examples files to give them Markdown style headings and such. --- doc/source/conf.py | 5 ++- .../Sessions_and_Objects/fdtd_example1_lsf.py | 43 +++++++++++-------- .../fdtd_example1_pythonic.py | 29 +++++++------ 3 files changed, 46 insertions(+), 31 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 8b15349..8fa8b5f 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -90,6 +90,9 @@ copybutton_prompt_text = r">>> ?|\.\.\. ?" copybutton_prompt_is_regexp = True +#Ignore files for build + +exclude_patterns =["conf.py"] # Skipping members def autodoc_skip_member_custom(app, what, name, obj, skip, options): @@ -127,7 +130,7 @@ def autodoc_skip_member_custom(app, what, name, obj, skip, options): :octicon:`download` Download Python script (.py) - ---- +---- """.format( base_path = f"https://{cname}/version/{get_version_match(version)}", py_file_path ="{{ env.docname }}.py", diff --git a/examples/Sessions_and_Objects/fdtd_example1_lsf.py b/examples/Sessions_and_Objects/fdtd_example1_lsf.py index bbda79e..219e431 100644 --- a/examples/Sessions_and_Objects/fdtd_example1_lsf.py +++ b/examples/Sessions_and_Objects/fdtd_example1_lsf.py @@ -1,25 +1,29 @@ -""" +# # Basic FDTD Simulation - Lumerical style commands -A simple example to demonstrate using PyLumerical using Lumerical Script File (lsf) style commands. +# A simple example to demonstrate using PyLumerical using Lumerical Script File (lsf) style commands. +# Sets up and runs a basic FDTD simulation. E field results are plotted in Lumerical. -------------------------------------------------- -Sets up and runs a basic FDTD simulation. E field results are plotted in Lumerical. - -Prerequisites: Valid FDTD license is required. -""" - -############################################################################### +# ## Prerequisites: +# +# Valid FDTD license is required. # -# Perform required imports -# ~~~~~~~~~~~~~~~~~~~~~~~~ +# ### Perform required imports import ansys.lumerical.core as lumapi +# ### Open an interactive session + +# + + # Set hide = True to hide the Lumerical GUI. fdtd = lumapi.FDTD(hide=False) -# Set up simulation region +# - + +# +# ### Set up simulation region + fdtd.addfdtd() fdtd.set("x", 0) fdtd.set("x span", 8e-6) @@ -28,7 +32,8 @@ fdtd.set("z", 0.25e-6) fdtd.set("z span", 0.5e-6) -# Set up source +# ### Set up source + fdtd.addgaussian() fdtd.set("injection axis", "z") fdtd.set("direction", "forward") @@ -43,7 +48,8 @@ fdtd.setglobalsource("wavelength start", 1e-6) fdtd.setglobalsource("wavelength stop", 1e-6) -# Set up monitor +# ### Set up monitor + fdtd.adddftmonitor() fdtd.set("monitor type", "2D Z-normal") fdtd.set("x", 0) @@ -52,14 +58,17 @@ fdtd.set("y span", 16e-6) fdtd.set("z", 0.3e-6) -# Run and save simulation +# ### Run and save simulation + fdtd.save("fdtd_tutorial.fsp") fdtd.run() -# Retrieve and plot results +# ### Retrieve and plot results + E = fdtd.getresult("monitor", "E") fdtd.visualize(E) -# Keep session open until user clicks space bar +# ### Keep session open until user clicks space bar + fdtd.print("Example complete. Hit space bar to close.") fdtd.pause(60) diff --git a/examples/Sessions_and_Objects/fdtd_example1_pythonic.py b/examples/Sessions_and_Objects/fdtd_example1_pythonic.py index 720b0a1..1dddb4b 100644 --- a/examples/Sessions_and_Objects/fdtd_example1_pythonic.py +++ b/examples/Sessions_and_Objects/fdtd_example1_pythonic.py @@ -1,19 +1,18 @@ -""" - -A simple example to demonstrate using PyLumerical. - -------------------------------------------------- -Sets up and runs a basic FDTD simulation. E field results are plotted using Matplotlib -Demonstrates initializing objects using keyword arguments and OrderedDict. - +# # Basic FDTD Simulation - Python style commands +# +# A simple example to demonstrate using PyLumerical. +# +# Sets up and runs a basic FDTD simulation. E field results are plotted using Matplotlib +# Demonstrates initializing objects using keyword arguments and OrderedDict. -Prerequisites: Valid FDTD license is required. -""" -############################################################################### +# ## Prerequisites: +# +# Valid FDTD license is required. # -# Perform required imports -# ~~~~~~~~~~~~~~~~~~~~~~~~ +# ### Perform required imports + +# + from collections import OrderedDict @@ -21,6 +20,10 @@ import ansys.lumerical.core as lumapi +# - + +# ### Open interactive session with the "with" context manager, run session, retrieve and plots results, and close session + # Set hide = True to hide the Lumerical GUI. with lumapi.FDTD() as fdtd: # Set up simulation region using keyword arguments From 027ddb4cd1858faa3f6d41ba3827e2d6dcb295d2 Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Wed, 17 Sep 2025 14:57:25 -0600 Subject: [PATCH 07/18] Modified pyproject.toml to include python libraries necessary for doc build with nbsphinx/jupytext. --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2aa83c0..8483a8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,9 +43,12 @@ tests = [ doc = [ "ansys-sphinx-theme==1.4.2", "numpydoc==1.8.0", - "sphinx==8.2.3", + "sphinx==8.1.3", "sphinx-copybutton==0.5.2", "sphinx_design==0.6.1", + "nbsphinx==0.9.7", + "jupytext==1.17.3", + "ipykernel==6.30.1" ] [tool.flit.module] From 10ccc28fdd02aa9fdabe528180930d844d334b3d Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Wed, 22 Oct 2025 17:40:35 -0600 Subject: [PATCH 08/18] Added basic instructions on how to write example files that can be used by PyLumerical to be converted into formatted pages. --- doc/styles/config/vocabularies/ANSYS/accept.txt | 3 ++- examples/README.md | 1 - examples/README.rst | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) delete mode 100644 examples/README.md create mode 100644 examples/README.rst diff --git a/doc/styles/config/vocabularies/ANSYS/accept.txt b/doc/styles/config/vocabularies/ANSYS/accept.txt index e18451b..1380d3d 100644 --- a/doc/styles/config/vocabularies/ANSYS/accept.txt +++ b/doc/styles/config/vocabularies/ANSYS/accept.txt @@ -29,4 +29,5 @@ photonic photonics lumopt lumslurm -[Aa]utodiscovery \ No newline at end of file +[Aa]utodiscovery +[Jj]upytext \ No newline at end of file diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index df635b4..0000000 --- a/examples/README.md +++ /dev/null @@ -1 +0,0 @@ -# Examples diff --git a/examples/README.rst b/examples/README.rst new file mode 100644 index 0000000..03f88ad --- /dev/null +++ b/examples/README.rst @@ -0,0 +1,17 @@ +Examples +======== + +Examples source files for PyLumerical are .py files. The PyLumerical documentation infrastructure converts these .py source files into .rst files for display on the documentation site, by first converting them into Jupyter Notebooks using `Jupytext `_, and then converting the notebooks into .rst files using `nbsphinx `_. + +Formatting +---------- + +Example files must be compliant with `PEP8 `_ guidelines, as listed on the PyAnsys Developer's `guide `_. + +Currently, PyLumerical examples uses the "Light" format for jupytext conversion. To write comment cells into your source file, follow the formatting guidelines listed in the `Jupytext documentation `_. + +Always ensure that your example files run without errors, and are properly formatted prior to submitting a pull request. + +The documentation build process currently not automatically execute the examples, as such, no outputs are displayed in the resulting documentation pages. + +You can test your examples locally by running them as scripts, and you can test that the documentation formatting is correct by locally building the documentation. See the `contributing section <../doc/source/contributing.rst>`_ for more information. From d931d778ed8a6978de36f34410422051c0f42e6c Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Wed, 22 Oct 2025 17:43:24 -0600 Subject: [PATCH 09/18] Broken link fix --- examples/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.rst b/examples/README.rst index 03f88ad..a2de589 100644 --- a/examples/README.rst +++ b/examples/README.rst @@ -1,7 +1,7 @@ Examples ======== -Examples source files for PyLumerical are .py files. The PyLumerical documentation infrastructure converts these .py source files into .rst files for display on the documentation site, by first converting them into Jupyter Notebooks using `Jupytext `_, and then converting the notebooks into .rst files using `nbsphinx `_. +Examples source files for PyLumerical are .py files. The PyLumerical documentation infrastructure converts these .py source files into .rst files for display on the documentation site, by first converting them into Jupyter Notebooks using `Jupytext `_, and then converting the notebooks into .rst files using `nbsphinx `_. Formatting ---------- From 203f005961576f019eca610facc0a761231a4094 Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Wed, 22 Oct 2025 17:44:12 -0600 Subject: [PATCH 10/18] Wording fix --- examples/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.rst b/examples/README.rst index a2de589..b7ecf88 100644 --- a/examples/README.rst +++ b/examples/README.rst @@ -8,7 +8,7 @@ Formatting Example files must be compliant with `PEP8 `_ guidelines, as listed on the PyAnsys Developer's `guide `_. -Currently, PyLumerical examples uses the "Light" format for jupytext conversion. To write comment cells into your source file, follow the formatting guidelines listed in the `Jupytext documentation `_. +PyLumerical examples uses the "Light" format for jupytext conversion. To write comment cells into your source file, follow the formatting guidelines listed in the `Jupytext documentation `_. Always ensure that your example files run without errors, and are properly formatted prior to submitting a pull request. From 4cf225c882f711f078c219d30eff5fae3772c100 Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Fri, 7 Nov 2025 09:19:51 -0700 Subject: [PATCH 11/18] dependencies:ci Adding pandoc dependency for doc example build --- .github/workflows/ci_cd_pr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci_cd_pr.yml b/.github/workflows/ci_cd_pr.yml index 4477a90..59e0fae 100644 --- a/.github/workflows/ci_cd_pr.yml +++ b/.github/workflows/ci_cd_pr.yml @@ -133,6 +133,7 @@ jobs: skip-install: true python-version: ${{ env.MAIN_PYTHON_VERSION }} use-python-cache: false + dependencies: "pandoc" needs-quarto: true doc-deploy-pr: From 7a32436b6f1aaf6acb1c1371cd735982a9d914b0 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:27:05 +0000 Subject: [PATCH 12/18] chore: adding changelog file 19.maintenance.md [dependabot-skip] --- doc/source/changelog/19.maintenance.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/source/changelog/19.maintenance.md diff --git a/doc/source/changelog/19.maintenance.md b/doc/source/changelog/19.maintenance.md new file mode 100644 index 0000000..261e849 --- /dev/null +++ b/doc/source/changelog/19.maintenance.md @@ -0,0 +1 @@ +Add pandoc to dependencies for doc build From 20bed21f6c8321e437aacaaf5f927b31ec29f77f Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Fri, 7 Nov 2025 09:31:29 -0700 Subject: [PATCH 13/18] fix pre-commit errors --- doc/source/examples.rst | 2 +- examples/Sessions_and_Objects/fdtd_example1_lsf.py | 4 ++-- examples/Sessions_and_Objects/fdtd_example1_pythonic.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/source/examples.rst b/doc/source/examples.rst index ec0073c..6719fe4 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -16,7 +16,7 @@ For in-depth discussion of PyLumerical concepts, see the :doc:`User guide Date: Fri, 7 Nov 2025 09:44:48 -0700 Subject: [PATCH 14/18] docs: added autodiscovery to allow list for vale vocabularies --- doc/styles/config/vocabularies/ANSYS/accept.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/styles/config/vocabularies/ANSYS/accept.txt b/doc/styles/config/vocabularies/ANSYS/accept.txt index bb58542..9e947a2 100644 --- a/doc/styles/config/vocabularies/ANSYS/accept.txt +++ b/doc/styles/config/vocabularies/ANSYS/accept.txt @@ -29,4 +29,5 @@ photonic photonics lumopt lumslurm -[Jj]upytext \ No newline at end of file +[Jj]upytext +[Aa]utodiscovery \ No newline at end of file From 32b3ec5db2b5a6ce2b01d4eef594780d9389bbe6 Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Fri, 7 Nov 2025 11:00:18 -0700 Subject: [PATCH 15/18] docs: Added examples to toctree, and ignore the readme.rst file in examples as that file is not meant to be included in documentation site for now. --- doc/source/conf.py | 2 +- doc/source/examples.rst | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index e7591e8..c76a9c8 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -95,7 +95,7 @@ # Ignore files for build -exclude_patterns = ["conf.py"] +exclude_patterns = ["conf.py", "examples/README.rst"] # Skipping members diff --git a/doc/source/examples.rst b/doc/source/examples.rst index 6719fe4..125fdea 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -29,3 +29,9 @@ For in-depth discussion of PyLumerical concepts, see the :doc:`User guide Date: Mon, 3 Nov 2025 12:02:06 -0800 Subject: [PATCH 16/18] Add files via upload --- .../Sessions_and_Objects/waveguide_FDE.py | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 examples/Sessions_and_Objects/waveguide_FDE.py diff --git a/examples/Sessions_and_Objects/waveguide_FDE.py b/examples/Sessions_and_Objects/waveguide_FDE.py new file mode 100644 index 0000000..677ec43 --- /dev/null +++ b/examples/Sessions_and_Objects/waveguide_FDE.py @@ -0,0 +1,131 @@ +# --- +# jupyter: +# jupytext: +# formats: ipynb,py:light +# text_representation: +# extension: .py +# format_name: light +# format_version: '1.5' +# jupytext_version: 1.18.1 +# kernelspec: +# display_name: .venv +# language: python +# name: .venv +# --- + +# A simple example using MODE. +# Waveguide (FDE): https://optics.ansys.com/hc/en-us/articles/360042800453-Waveguide-FDE +# +# The Finite Difference Eigenmode (FDE) solver in MODE is used to characterize a straight waveguide. +# +# In Part 1, we build the structure and set the FDE simulation region. +# In Part 2, we calculate the supported mode profiles of the waveguide. +# In Part 3, we perform a frequency sweep and obtain the effective index, group index, and dispersion. +# +# Prerequisites: +# Valid MODE license is required. + +# Perform required imports + +import ansys.lumerical.core as lumapi +import matplotlib.pyplot as plt +import numpy as np +from collections import OrderedDict + +# Part 1: Set up structures and simulation objects + +# + +# Set hide = True to hide the Lumerical GUI. +mode = lumapi.MODE(hide=False) + +# Set key paramters +wavelength = 1.55e-6 # Center wavelength +# Set the waveguide cross-section and material +wg_width = 0.5e-6 +wg_height = 0.22e-6 +wg_material = "Si (Silicon) - Palik" +# Set substrate and cladding cross-section and material +sub_width = 10e-6 +sub_height = 5e-6 +sub_material = "SiO2 (Glass) - Palik" +clad_width = 10e-6 +clad_height = 5e-6 +clad_material = "SiO2 (Glass) - Palik" +# Set FDE region +fde_x_span = 3e-6 +fde_y_span = 3e-6 +fde_y_center = wg_height/2 +fde_z = 0e-6 + +z_span = 1.0e-6 # Sets z span for all structures, but note FDE solver utilizes a cross section + +# Build substrate and cladding +mode.addrect(name="substrate", x=0, x_span=sub_width, y_min=-sub_height, y_max=0, z=0, z_span=z_span, + material=sub_material) +mode.addrect(name="clad", x=0, x_span=clad_width, y_min=0, y_max=clad_height, z=0, z_span=z_span, + material=clad_material) +# Build waveguide +# Use mesh order override to ensure waveguide object is prioritized over substrate and cladding +wg_props = OrderedDict([("name","waveguide"),("x",0),("x span",wg_width),("y min",0),("y max",wg_height), + ("z",0),("z span",z_span),("material",wg_material), + ("override mesh order from material database",True),("mesh order",1)]) +mode.addrect(properties=wg_props) + +# Add FDE solver region +fde_props = OrderedDict([("x",0),("x span",fde_x_span),("y",fde_y_center),("y span",fde_y_span), + ("z",fde_z)]) +mode.addfde(properties=fde_props) + +# Add mesh override region +mesh_props = OrderedDict([("set maximum mesh step",True),("override x mesh",True),("override y mesh",True), + ("dx",0.01e-6),("dy",0.01e-6),("based on a structure",True),("structure","waveguide")]) +mode.addmesh(properties=mesh_props) +# - + +# Part 2: Calculate the supported modes of the waveguide. The analysis_props are equivalent to the settings in the Eigensolver Analysis window in the GUI. + +# + +mode.setanalysis("wavelength",wavelength) +mode.setanalysis("number of trial modes", 10) +mode.setanalysis("search","near n") +mode.setanalysis("use max index",True) +mode.findmodes() + +# Select and plot the fundamental mode +selected_mode_number = 1 +selected_mode = "mode"+str(selected_mode_number) +Efield = mode.getresult("FDE::data::"+selected_mode,"E") + +# Plot in Python - requries matplotlib +# Note that passing field data from Lumerical to Python may require additional effort. +# Lumerical uses an unstructured mesh, so the spacing between points may be non-constant. +#Ex = mode.getdata("FDE::data::"+selected_mode,"Ex")[:,:,0,0] +#Ey = mode.getdata("FDE::data::"+selected_mode,"Ey")[:,:,0,0] +#Ez = mode.getdata("FDE::data::"+selected_mode,"Ez")[:,:,0,0] +#absE = np.abs(Ex)**2+np.abs(Ey)**2+np.abs(Ez)**2 +#plt.figure() +#plt.imshow(np.transpose(absE)) +#plt.show() + +# Plot in Lumerical GUI +mode.visualize((Efield)) +# - +# Part 3: Perform a frequency sweep for the selected mode of the waveguide. + + +# + +mode.selectmode(selected_mode_number) +mode.setanalysis('track selected mode',1) +mode.setanalysis('detailed dispersion calculation',1) +mode.setanalysis('stop wavelength',1.6e-6) +mode.setanalysis('number of points',10) +mode.frequencysweep() + +# Save completed simulation file +mode.save("fde_wg_tutorial.lms") + +mode.print("Example complete. Hit space bar to continue.") +mode.pause(60) +# - + + From 42156d8253e417a5a6e9f8aa613f91f1de6ab673 Mon Sep 17 00:00:00 2001 From: Adan Wang Date: Fri, 7 Nov 2025 11:45:25 -0700 Subject: [PATCH 17/18] docs:examples FDE example test --- doc/source/examples.rst | 12 +- .../Sessions_and_Objects/waveguide_FDE.py | 105 ++++++++++-------- 2 files changed, 70 insertions(+), 47 deletions(-) diff --git a/doc/source/examples.rst b/doc/source/examples.rst index 125fdea..5fc282e 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -5,7 +5,7 @@ You can use the examples below to get started with PyLumerical and learn its bas For in-depth discussion of PyLumerical concepts, see the :doc:`User guide `. -.. grid:: 2 2 3 3 +.. grid:: 2 2 4 4 .. grid-item-card:: Session management :link: examples/Sessions_and_Objects/basic_session_management @@ -28,10 +28,18 @@ For in-depth discussion of PyLumerical concepts, see the :doc:`User guide Date: Wed, 19 Nov 2025 10:38:29 -0800 Subject: [PATCH 18/18] Refactored example 1 and added 2 solver eg --- .../basic_session_management.py | 64 ------- ...onic.py => example1_session_management.py} | 94 +++++++-- .../Sessions_and_Objects/fdtd_example1_lsf.py | 74 -------- .../EME_edge_coupler.py | 61 ++++++ .../Single_Solver_Workflows/FDTD_nanowire.py | 178 ++++++++++++++++++ .../assets/nanowire_build_script.lsf | 100 ++++++++++ .../assets/nanowire_plotcs.lsf | 40 ++++ .../assets/nanowire_theory.csv | 100 ++++++++++ 8 files changed, 560 insertions(+), 151 deletions(-) delete mode 100644 examples/Sessions_and_Objects/basic_session_management.py rename examples/Sessions_and_Objects/{fdtd_example1_pythonic.py => example1_session_management.py} (53%) delete mode 100644 examples/Sessions_and_Objects/fdtd_example1_lsf.py create mode 100644 examples/Single_Solver_Workflows/EME_edge_coupler.py create mode 100644 examples/Single_Solver_Workflows/FDTD_nanowire.py create mode 100644 examples/Single_Solver_Workflows/assets/nanowire_build_script.lsf create mode 100644 examples/Single_Solver_Workflows/assets/nanowire_plotcs.lsf create mode 100644 examples/Single_Solver_Workflows/assets/nanowire_theory.csv diff --git a/examples/Sessions_and_Objects/basic_session_management.py b/examples/Sessions_and_Objects/basic_session_management.py deleted file mode 100644 index 8ff1153..0000000 --- a/examples/Sessions_and_Objects/basic_session_management.py +++ /dev/null @@ -1,64 +0,0 @@ -# # Basic Session Management -# -# This example demonstrates how to initialize a local Lumerical session. -# PyLumerical interacts with Lumerical products through sessions. -# -# ## Prerequisites: -# -# Valid FDTD and MODE licenses are required. -# -# ### Perform required imports - -import ansys.lumerical.core as lumapi - -# -# ### Open an interactive session - -# + - -fdtd = lumapi.FDTD() -# Wait for a second, then add FDTD region -fdtd.pause(1) -fdtd.addfdtd() -fdtd.print("Example complete. Press space bar to close.") -fdtd.pause(30) # Will close in 30 seconds if left idle -fdtd.close() - -mode = lumapi.MODE() -mode.print("Example complete. Press space bar to close.") -mode.pause(30) -mode.close() - -# Load a session but hide the application window -fdtd = lumapi.FDTD(hide=True) -fdtd.close() - -# - - -# ### Use the "with" context manager - -with lumapi.FDTD() as fdtd: - fdtd.addfdtd() - fdtd.print("Example complete. Press space bar to close.") - fdtd.pause(30) -# FDTD closes automatically - -# ### Session wrapped in a function -# Get the number of grid cells in FDTD region for set span - - -def get_x_cells(fdtd_span): - """Return the number of grid cells in FDTD region for a set span.""" - with lumapi.FDTD() as fdtd: - # Adds FDTD region with span set by fdtd_span - fdtd.addfdtd(dimension="3D", x_span=fdtd_span, y_span=fdtd_span, z_span=fdtd_span) - # Get the x-coordinates of created FDTD region - x = fdtd.getresult("FDTD", "x") - x_cells = len(x) - return x_cells - - -# ### Test the function and print out the result - -test = get_x_cells(1e-6) -print(test) diff --git a/examples/Sessions_and_Objects/fdtd_example1_pythonic.py b/examples/Sessions_and_Objects/example1_session_management.py similarity index 53% rename from examples/Sessions_and_Objects/fdtd_example1_pythonic.py rename to examples/Sessions_and_Objects/example1_session_management.py index e97cfa2..ce2dcad 100644 --- a/examples/Sessions_and_Objects/fdtd_example1_pythonic.py +++ b/examples/Sessions_and_Objects/example1_session_management.py @@ -1,25 +1,90 @@ -# # Basic FDTD Simulation - Python style commands -# -# A simple example to demonstrate using PyLumerical. -# -# Sets up and runs a basic FDTD simulation. E field results are plotted using Matplotlib -# Demonstrates initializing objects using keyword arguments and OrderedDict. +# %% [markdown] +# ## Basic FDTD Simulation - Lumerical style commands +# +# This simple example demonstrates using PyLumerical to start a session using Lumerical Script File (lsf) style commands. +# Sets up and runs a basic FDTD simulation. E field results are plotted in Lumerical. +# [Lumerical API](https://optics.ansys.com/hc/en-us/articles/360037824513-Python-API-overview) +# +# +# ## Prerequisites: +# +# Valid FDTD license is required. +# +# %% +import ansys.lumerical.core as lumapi + + +# Set hide = True to hide the Lumerical GUI. +fdtd = lumapi.FDTD(hide=False) + +# - -# ## Prerequisites: -# -# Valid FDTD license is required. # -# ### Perform required imports +# ### Set up simulation region + +fdtd.addfdtd() +fdtd.set("x", 0) +fdtd.set("x span", 8e-6) +fdtd.set("y", 0) +fdtd.set("y span", 8e-6) +fdtd.set("z", 0.25e-6) +fdtd.set("z span", 0.5e-6) + +# ### Set up source + +fdtd.addgaussian() +fdtd.set("injection axis", "z") +fdtd.set("direction", "forward") +fdtd.set("x", 0) +fdtd.set("x span", 16e-6) +fdtd.set("y", 0) +fdtd.set("y span", 16e-6) +fdtd.set("z", 0.2e-6) +fdtd.set("use scalar approximation", 1) +fdtd.set("waist radius w0", 2e-6) +fdtd.set("distance from waist", 0) +fdtd.setglobalsource("wavelength start", 1e-6) +fdtd.setglobalsource("wavelength stop", 1e-6) -# + +# ### Set up monitor +fdtd.adddftmonitor() +fdtd.set("monitor type", "2D Z-normal") +fdtd.set("x", 0) +fdtd.set("x span", 16e-6) +fdtd.set("y", 0) +fdtd.set("y span", 16e-6) +fdtd.set("z", 0.3e-6) + +# ### Run and save simulation + +fdtd.save("fdtd_tutorial.fsp") +fdtd.run() + +# ### Retrieve and plot results + +E = fdtd.getresult("monitor", "E") +fdtd.visualize(E) + +# ### Keep session open until user clicks space bar + +fdtd.print("Example complete. Hit space bar to close.") +fdtd.pause(60) + +# %% [markdown] +# ## Python style commands +# +# A simple example to demonstrate using PyLumerical. +# +# Sets up and runs a basic FDTD simulation. E field results are plotted using Matplotlib +# Demonstrates initializing objects using keyword arguments and OrderedDict. + +# %% from collections import OrderedDict import matplotlib.pyplot as plt -import ansys.lumerical.core as lumapi - # - # ### Open interactive session with the "with" context manager, run session, retrieve and plots results, and close session @@ -67,3 +132,6 @@ print("Example complete. Press Enter to close.") input() + + + diff --git a/examples/Sessions_and_Objects/fdtd_example1_lsf.py b/examples/Sessions_and_Objects/fdtd_example1_lsf.py deleted file mode 100644 index 6805ec7..0000000 --- a/examples/Sessions_and_Objects/fdtd_example1_lsf.py +++ /dev/null @@ -1,74 +0,0 @@ -# # Basic FDTD Simulation - Lumerical style commands - -# A simple example to demonstrate using PyLumerical using Lumerical Script File (lsf) style commands. -# Sets up and runs a basic FDTD simulation. E field results are plotted in Lumerical. - - -# ## Prerequisites: -# -# Valid FDTD license is required. -# -# ### Perform required imports - -import ansys.lumerical.core as lumapi - -# ### Open an interactive session - -# + - -# Set hide = True to hide the Lumerical GUI. -fdtd = lumapi.FDTD(hide=False) - -# - - -# -# ### Set up simulation region - -fdtd.addfdtd() -fdtd.set("x", 0) -fdtd.set("x span", 8e-6) -fdtd.set("y", 0) -fdtd.set("y span", 8e-6) -fdtd.set("z", 0.25e-6) -fdtd.set("z span", 0.5e-6) - -# ### Set up source - -fdtd.addgaussian() -fdtd.set("injection axis", "z") -fdtd.set("direction", "forward") -fdtd.set("x", 0) -fdtd.set("x span", 16e-6) -fdtd.set("y", 0) -fdtd.set("y span", 16e-6) -fdtd.set("z", 0.2e-6) -fdtd.set("use scalar approximation", 1) -fdtd.set("waist radius w0", 2e-6) -fdtd.set("distance from waist", 0) -fdtd.setglobalsource("wavelength start", 1e-6) -fdtd.setglobalsource("wavelength stop", 1e-6) - -# ### Set up monitor - -fdtd.adddftmonitor() -fdtd.set("monitor type", "2D Z-normal") -fdtd.set("x", 0) -fdtd.set("x span", 16e-6) -fdtd.set("y", 0) -fdtd.set("y span", 16e-6) -fdtd.set("z", 0.3e-6) - -# ### Run and save simulation - -fdtd.save("fdtd_tutorial.fsp") -fdtd.run() - -# ### Retrieve and plot results - -E = fdtd.getresult("monitor", "E") -fdtd.visualize(E) - -# ### Keep session open until user clicks space bar - -fdtd.print("Example complete. Hit space bar to close.") -fdtd.pause(60) diff --git a/examples/Single_Solver_Workflows/EME_edge_coupler.py b/examples/Single_Solver_Workflows/EME_edge_coupler.py new file mode 100644 index 0000000..7b79489 --- /dev/null +++ b/examples/Single_Solver_Workflows/EME_edge_coupler.py @@ -0,0 +1,61 @@ +# %% [markdown] +# ### Edge Coupler +# +# This example demonstrates how to use EME and run propogation length sweep + +# %% +import ansys.lumerical.core as lumapi +import matplotlib.pyplot as plt +import os + +fname = os.path.join(os.path.realpath(os.path.dirname(__file__)),'assets/spot_size_converter.lms') +print(fname) +##Open the session without GUI +with lumapi.MODE(filename=fname,hide=False) as mode: + ## Switch to layour before updating EME properties + mode.switchtolayout() + + ####################################### + ## Query geometry and can update + mode.select("taper") + taper_prop = mode.queryuserprop("taper") + print(taper_prop['name']) + + ## This shows how to update the values + mode.setnamed("taper","index",1.5) + + ###################################### + ## Update EME solver parameters + sc = mode.getnamed("EME","subcell method"); + + print(sc) + ## sub_cell is an array the length of the group span with 0 = none, and 1 = CVCS + sc[1] = 1 #Ensure you have CVCS enabled in cell group 2 + mode.setnamed("EME","subcell method",sc); #update EME solver + + ###################################### + ##Run EME solver + mode.run() + + ###################################### + ## Set propagation sweep settings + mode.setemeanalysis("propagation sweep",1) + mode.setemeanalysis("parameter","group span 2") + mode.setemeanalysis("start",20e-6) + mode.setemeanalysis("stop",200e-6) + mode.setemeanalysis("number of points",201) + + # run propagation sweep tool + mode.emesweep() + + # get propagation sweep result + S = mode.getemesweep('S') + + plt.plot(S['group_span_2']*1e6,abs(S['s21'])**2) + plt.title("Output Power") + plt.xlabel("Length [um]") + plt.ylabel("|S_21|^2") + plt.show() + input("Enter") + + diff --git a/examples/Single_Solver_Workflows/FDTD_nanowire.py b/examples/Single_Solver_Workflows/FDTD_nanowire.py new file mode 100644 index 0000000..f6437f2 --- /dev/null +++ b/examples/Single_Solver_Workflows/FDTD_nanowire.py @@ -0,0 +1,178 @@ +# %% [markdown] +# ### FDTD Nanowire Example +# +# This example demonstrates how to define an FDTD workflow as a python function. It will then load theory data from a csv file and it will then plot the results using matplot. +# [Nanowire Example](https://optics.ansys.com/hc/en-us/articles/360034416574-Using-the-Python-API-in-the-nanowire-application-example) + +# %% +#Import the required modules +import ansys.lumerical.core as lumapi +import numpy as np +import matplotlib.pyplot as plt + +#Define an FDTD function +def runNanowireSimulation(profile_monitor_wavelength=1e-6): + """ This function makes is convenient to reconstruct the simulation, + while changing a few key properties, a brand new FDTD will start + and close within this function + """ + fdtd = lumapi.FDTD() + fdtd.addcircle() + fdtd.addfdtd() + fdtd.addmesh() + fdtd.addtfsf() + + fdtd.addobject("cross_section") + fdtd.set("name", "scat") + fdtd.addobject("cross_section") + fdtd.set("name", "total") + + fdtd.addtime() + fdtd.set("name", "time") + + fdtd.adddftmonitor() + fdtd.set("name", "profile") + + configuration = ( + ("source", (("polarization angle", 0.), + ("injection axis", "y"), + ("x", 0.), + ("y", 0.), + ("x span", 100.0e-9), + ("y span", 100.0e-9), + ("wavelength start", 300.0e-9), + ("wavelength stop", 400.0e-9))), + + ("mesh", (("dx", 0.5e-9), + ("dy", 0.5e-9), + ("x", 0.), + ("y", 0.), + ("x span", 110.0e-9), + ("y span", 110.0e-9))), + + ("FDTD", (("simulation time", 200e-15), # in seconds + ("dimension", "2D"), + ("x",0.0e-9), + ("y",0.), + ("z",0.), + ("x span", 800.0e-9), + ("y span", 800.0e-9), + ("mesh refinement", "conformal variant 1"))), + + ("circle", (("x", 0.0e-9), + ("y", 0.0e-9), + ("z", 0.0e-9), + ("radius", 25.0e-9), # in meters + ("material", "Ag (Silver) - Palik (0-2um)"))), + + ("scat", (("x", 0.), + ("y", 0.), + ("z", 0.), + ("x span", 110.0e-9), + ("y span", 110.0e-9))), + + ("total", (("x", 0.), + ("y", 0.), + ("z", 0.), + ("x span", 90.0e-9), + ("y span", 90.0e-9))), + + ("time", (("x", 28.0e-9), + ("y", 26.0e-9))), + + ("profile", (("x", 0.), + ("y", 0.), + ("x span", 90e-9), + ("y span", 90e-9), + ("override global monitor settings", True), + ("use source limits", False), + ("frequency points", 1), + ("wavelength center", float(profile_monitor_wavelength)), + ("wavelength span", 0.))), + ) + + for obj, parameters in configuration: + for k, v in parameters: + fdtd.setnamed(obj, k, v) + + fdtd.setnamed("profile", "wavelength center", float(profile_monitor_wavelength)) + + fdtd.setglobalmonitor("frequency points", 100) # setting the global frequency resolution + + fdtd.save("nanowire_test") + fdtd.run("FDTD","CPU") + + return fdtd.getresult("scat", "sigma"), fdtd.getresult("total", "sigma"), fdtd.getresult("profile", "E") + + + +# %% [markdown] +# ## Plot results + +# %% +import os + +# run the simulation once, to determine resonance wavelength +## and get cross-sections from analysis objects +sigmascat, sigmaabs, _ = runNanowireSimulation() + +lam_sim = sigmascat['lambda'][:,0] +f_sim = sigmascat['f'][:,0] +sigmascat = sigmascat['sigma'] +sigmaabs = sigmaabs['sigma'] +sigmaext = -sigmaabs + sigmascat + +#load cross section theory from text file +nw_theory = np.genfromtxt(os.path.join(os.path.realpath(os.path.dirname(__file__)),"assets/nanowire_theory.csv"), delimiter=",") +nw_theory.shape + +lam_theory = nw_theory[:,0]*1.e-9 + +r23 = nw_theory[:,1:4]*2*23*1e-9 #flipping data +r24 = nw_theory[:,4:7]*2*24*1e-9 +r25 = nw_theory[:,7:10]*2*25*1e-9 +r26 = nw_theory[:,10:13]*2*26*1e-9 +r27 = nw_theory[:,13:16]*2*27*1e-9 + +for i in range(0, 3): + r23[:,i] = np.interp(lam_sim, lam_theory, r23[:,i]) + r24[:,i] = np.interp(lam_sim, lam_theory, r24[:,i]) + r25[:,i] = np.interp(lam_sim, lam_theory, r25[:,i]) + r26[:,i] = np.interp(lam_sim, lam_theory, r26[:,i]) + r27[:,i] = np.interp(lam_sim, lam_theory, r27[:,i]) + +# compare FDTD to theory +plt.plot(lam_sim, sigmaext*1e9, label='sigmaext') +plt.plot(lam_sim, -sigmaabs*1e9) +plt.plot(lam_sim, sigmascat*1e9) +plt.plot(lam_sim, r25*1e9) +plt.xlabel('wavelength (nm)') +plt.ylabel('cross section (nm)') + +plt.show() + +plt.plot(lam_sim, sigmaext*1e9, label='sigmaext') +plt.plot(lam_sim, -sigmaabs*1e9) +plt.plot(lam_sim, sigmascat*1e9) +plt.plot(lam_sim, r24*1e9) +plt.plot(lam_sim, r26*1e9) +plt.xlabel('wavelength (nm)') +plt.ylabel('cross section (nm)') + +plt.show() + +## run the simulation again using the resonance wavelength +_, _, E = runNanowireSimulation(profile_monitor_wavelength=lam_sim[np.argmax(sigmascat)]) + +## show the field intensity profile +Ey = E["E"][:,:,0,0,1] +plt.pcolor(np.transpose(abs(Ey)**2), vmax=5, vmin=0) +plt.xlabel("x (nm)") +plt.ylabel("y (nm)") +plt.xticks(range(Ey.shape[0])[::25], [int(v) for v in E["x"][:,0][::25]*1e9]) +plt.yticks(range(Ey.shape[1])[::25], [int(v) for v in E["y"][:,0][::25]*1e9]) +plt.colorbar() +plt.show() + + + diff --git a/examples/Single_Solver_Workflows/assets/nanowire_build_script.lsf b/examples/Single_Solver_Workflows/assets/nanowire_build_script.lsf new file mode 100644 index 0000000..beccb9c --- /dev/null +++ b/examples/Single_Solver_Workflows/assets/nanowire_build_script.lsf @@ -0,0 +1,100 @@ +# This script file builds the simulation for the nanowire example +# entirely using script commands. Objects are added to the simulation file +# using the specific add commands. The set commands sets the +# parameter you defined, any other parameters that are not set will remain as is (Default). + +switchtolayout; + +selectall; deleteall; # select and delete all objects to make sure we start with a clean project file +setprofile = 0; # not add the profile monitor for the first run; 1 to set this monitor + +############################################ +# add structures +addcircle; # add a circle object +set("x",0); # sets the x position +set("y",0); +set("z",0); +set("radius", 25e-9); # sets the radius of the circle, in meter +set("material", "Ag (Silver) - Palik (0-2um)"); # material name has to be exact + + +############################################# +# add simulation region and mesh override +addfdtd; +set("simulation time", 200e-15); # the unit is second +set("dimension", "2D"); +set("x",0); +set("y",0); +set("z",0); +set("x span", 800e-9); +set("y span", 800e-9); +# add finer mesh +addmesh; +set("dx", 1e-9); +set("dy", 1e-9); +set("x", 0); +set("y", 0); +set("x span", 110e-9); +set("y span", 110e-9); +# Mesh Reinement and Boundary conditions use the deault settings. + +############################################# +# add light source +addtfsf; +set("polarization angle", 0); +set("x", 0); +set("y", 0); +set("x span", 100e-9); +set("y span", 100e-9); +set("wavelength start", 300e-9); +set("wavelength stop", 400e-9); + + +############################################# +# add analysis group +addobject("cross_section"); +set("name", "scat"); +set("x", 0); +set("y", 0); +set("z", 0); +set("x span", 110e-9); +set("y span", 110e-9); + +addobject("cross_section"); +set("name", "total"); +set("x", 0); +set("y", 0); +set("z", 0); +set("x span", 90e-9); +set("y span", 90e-9); + +############################################# +# add monitos + + +addtime; +set("name", "time"); +set("x", 28e-9); +set("y", 26e-9); + +setglobalmonitor("frequency points", 100); # setting the global frequency resolution + +# +if(setprofile == 1){# once you know the wavelength to be monitored +addprofile; +set("name", "profile"); +set("x", 0); +set("y", 0); +set("x span", 90e-9); +set("y span", 90e-9); +set("override global monitor settings",1); +set("use source limits",0); +set("frequency points",1);# only record one frequnecy point +set("wavelength center",345e-9); +set("wavelength span",0); + +setnamed("mesh","dx",0.5e-9); +setnamed("mesh","dy",0.5e-9); + +setnamed("FDTD","mesh refinement","conformal variant 1"); +} \ No newline at end of file diff --git a/examples/Single_Solver_Workflows/assets/nanowire_plotcs.lsf b/examples/Single_Solver_Workflows/assets/nanowire_plotcs.lsf new file mode 100644 index 0000000..596cab7 --- /dev/null +++ b/examples/Single_Solver_Workflows/assets/nanowire_plotcs.lsf @@ -0,0 +1,40 @@ +# scriptfile: plotcs.lsf +# This script calculates the scattering, absorption +# and extinction cross-sections in 2D. + +# get cross-sections from analysis objects +sigmascat = getresult("scat","sigma"); +sigmaabs = getresult("total","sigma"); +sigmaext = -(sigmaabs.sigma) + (sigmascat.sigma); +lam = c/(sigmascat.f)*1e9;#in nanometer + +#load cross section theory from text file +tmp=readdata("nanowire_theory.csv"); +lam_theory=tmp(1:100,1)/1e9; +f_theory = c/lam_theory; +r23=tmp(1:100,2:4)*2*23*1e-9; +r24=tmp(1:100,5:7)*2*24*1e-9; +r25=tmp(1:100,8:10)*2*25*1e-9; +r26=tmp(1:100,11:13)*2*26*1e-9; +r27=tmp(1:100,14:16)*2*27*1e-9; + +for (i=1:3) { #interpolate onto FDTD's frequency points + r23(1:100,i)=interp(r23(1:100,i),f_theory,sigmascat.f); + r24(1:100,i)=interp(r24(1:100,i),f_theory,sigmascat.f); + r25(1:100,i)=interp(r25(1:100,i),f_theory,sigmascat.f); + r26(1:100,i)=interp(r26(1:100,i),f_theory,sigmascat.f); + r27(1:100,i)=interp(r27(1:100,i),f_theory,sigmascat.f); +} + +# Compare FDTD to theory +plot(lam, sigmaext*1e9, -(sigmaabs.sigma)*1e9, sigmascat.sigma*1e9, + r25(1:100,1)*1e9, r25(1:100,2)*1e9, r25(1:100,3)*1e9, + "wavelength (nm)","cross section (nm)","Cross sections"); +legend("Extinction", "Absorption", "Scattering", "r25 theory", "r25 theory", "r25 theory"); +# compare FDTD to theory of 24 and 26nm particle +plot(lam, sigmaext*1e9, -(sigmaabs.sigma)*1e9, sigmascat.sigma*1e9, + r24(1:100,1)*1e9, r24(1:100,2)*1e9, r24(1:100,3)*1e9, + r26(1:100,1)*1e9, r26(1:100,2)*1e9, r26(1:100,3)*1e9, + "wavelength (nm)", "cross section (nm)", "Cross sections"); +legend("Extinction", "Absorption", "Scattering", "r24 theory", "r24 theory", + "r24 theory", "r26 theory", "r26 theory", "r26 theory"); diff --git a/examples/Single_Solver_Workflows/assets/nanowire_theory.csv b/examples/Single_Solver_Workflows/assets/nanowire_theory.csv new file mode 100644 index 0000000..d5201c0 --- /dev/null +++ b/examples/Single_Solver_Workflows/assets/nanowire_theory.csv @@ -0,0 +1,100 @@ +3.00E+02,7.47E-01,5.81E-01,1.66E-01,7.94E-01,6.08E-01,1.86E-01,8.43E-01,6.36E-01,2.07E-01,8.92E-01,6.63E-01,2.28E-01,9.41E-01,6.90E-01,2.51E-01 +3.01E+02,7.29E-01,5.76E-01,1.53E-01,7.74E-01,6.03E-01,1.71E-01,8.20E-01,6.30E-01,1.90E-01,8.67E-01,6.57E-01,2.10E-01,9.13E-01,6.83E-01,2.30E-01 +3.02E+02,7.14E-01,5.74E-01,1.40E-01,7.57E-01,6.00E-01,1.57E-01,8.00E-01,6.26E-01,1.74E-01,8.44E-01,6.52E-01,1.92E-01,8.88E-01,6.77E-01,2.11E-01 +3.03E+02,7.01E-01,5.73E-01,1.28E-01,7.42E-01,5.98E-01,1.44E-01,7.83E-01,6.23E-01,1.60E-01,8.25E-01,6.48E-01,1.76E-01,8.66E-01,6.73E-01,1.93E-01 +3.04E+02,6.91E-01,5.74E-01,1.18E-01,7.30E-01,5.98E-01,1.31E-01,7.69E-01,6.23E-01,1.46E-01,8.08E-01,6.47E-01,1.61E-01,8.48E-01,6.71E-01,1.77E-01 +3.05E+02,6.84E-01,5.76E-01,1.08E-01,7.21E-01,6.00E-01,1.20E-01,7.58E-01,6.24E-01,1.34E-01,7.95E-01,6.48E-01,1.47E-01,8.33E-01,6.71E-01,1.62E-01 +3.06E+02,6.79E-01,5.80E-01,9.85E-02,7.14E-01,6.04E-01,1.10E-01,7.50E-01,6.27E-01,1.22E-01,7.85E-01,6.50E-01,1.35E-01,8.21E-01,6.73E-01,1.48E-01 +3.07E+02,6.77E-01,5.87E-01,9.03E-02,7.11E-01,6.10E-01,1.01E-01,7.45E-01,6.33E-01,1.12E-01,7.79E-01,6.55E-01,1.24E-01,8.13E-01,6.77E-01,1.36E-01 +3.08E+02,6.78E-01,5.95E-01,8.31E-02,7.10E-01,6.18E-01,9.28E-02,7.43E-01,6.40E-01,1.03E-01,7.76E-01,6.62E-01,1.14E-01,8.08E-01,6.83E-01,1.25E-01 +3.09E+02,6.81E-01,6.04E-01,7.69E-02,7.13E-01,6.27E-01,8.58E-02,7.44E-01,6.49E-01,9.51E-02,7.76E-01,6.71E-01,1.05E-01,8.07E-01,6.92E-01,1.15E-01 +3.10E+02,6.88E-01,6.16E-01,7.17E-02,7.19E-01,6.39E-01,7.99E-02,7.49E-01,6.61E-01,8.86E-02,7.80E-01,6.82E-01,9.77E-02,8.10E-01,7.03E-01,1.07E-01 +3.11E+02,6.98E-01,6.30E-01,6.76E-02,7.28E-01,6.52E-01,7.53E-02,7.57E-01,6.74E-01,8.35E-02,7.87E-01,6.95E-01,9.19E-02,8.16E-01,7.16E-01,1.01E-01 +3.12E+02,7.10E-01,6.46E-01,6.47E-02,7.40E-01,6.68E-01,7.20E-02,7.69E-01,6.90E-01,7.98E-02,7.98E-01,7.10E-01,8.78E-02,8.27E-01,7.31E-01,9.62E-02 +3.13E+02,7.27E-01,6.64E-01,6.30E-02,7.56E-01,6.86E-01,7.02E-02,7.85E-01,7.07E-01,7.76E-02,8.13E-01,7.28E-01,8.54E-02,8.42E-01,7.48E-01,9.35E-02 +3.14E+02,7.47E-01,6.84E-01,6.28E-02,7.76E-01,7.06E-01,6.98E-02,8.05E-01,7.27E-01,7.72E-02,8.33E-01,7.48E-01,8.49E-02,8.61E-01,7.68E-01,9.29E-02 +3.15E+02,7.71E-01,7.07E-01,6.40E-02,8.00E-01,7.29E-01,7.12E-02,8.29E-01,7.50E-01,7.86E-02,8.57E-01,7.70E-01,8.64E-02,8.85E-01,7.90E-01,9.44E-02 +3.16E+02,7.99E-01,7.32E-01,6.69E-02,8.28E-01,7.54E-01,7.43E-02,8.57E-01,7.75E-01,8.20E-02,8.86E-01,7.96E-01,9.01E-02,9.13E-01,8.15E-01,9.84E-02 +3.17E+02,8.32E-01,7.60E-01,7.16E-02,8.62E-01,7.82E-01,7.95E-02,8.91E-01,8.03E-01,8.77E-02,9.19E-01,8.23E-01,9.62E-02,9.47E-01,8.42E-01,1.05E-01 +3.18E+02,8.70E-01,7.91E-01,7.84E-02,9.00E-01,8.13E-01,8.69E-02,9.30E-01,8.34E-01,9.57E-02,9.59E-01,8.54E-01,1.05E-01,9.87E-01,8.73E-01,1.14E-01 +3.19E+02,9.13E-01,8.26E-01,8.74E-02,9.44E-01,8.48E-01,9.67E-02,9.75E-01,8.68E-01,1.06E-01,1.00E+00,8.88E-01,1.17E-01,1.03E+00,9.06E-01,1.27E-01 +3.20E+02,9.63E-01,8.64E-01,9.89E-02,9.95E-01,8.85E-01,1.09E-01,1.03E+00,9.06E-01,1.20E-01,1.06E+00,9.25E-01,1.31E-01,1.09E+00,9.43E-01,1.43E-01 +3.21E+02,1.02E+00,9.06E-01,1.13E-01,1.05E+00,9.27E-01,1.25E-01,1.08E+00,9.47E-01,1.37E-01,1.12E+00,9.65E-01,1.50E-01,1.15E+00,9.83E-01,1.63E-01 +3.22E+02,1.08E+00,9.51E-01,1.31E-01,1.12E+00,9.72E-01,1.44E-01,1.15E+00,9.92E-01,1.58E-01,1.18E+00,1.01E+00,1.72E-01,1.21E+00,1.03E+00,1.87E-01 +3.23E+02,1.15E+00,1.00E+00,1.51E-01,1.19E+00,1.02E+00,1.67E-01,1.22E+00,1.04E+00,1.82E-01,1.26E+00,1.06E+00,1.98E-01,1.29E+00,1.07E+00,2.15E-01 +3.24E+02,1.23E+00,1.06E+00,1.76E-01,1.27E+00,1.08E+00,1.93E-01,1.30E+00,1.09E+00,2.11E-01,1.34E+00,1.11E+00,2.30E-01,1.37E+00,1.12E+00,2.48E-01 +3.25E+02,1.32E+00,1.12E+00,2.05E-01,1.36E+00,1.13E+00,2.25E-01,1.40E+00,1.15E+00,2.45E-01,1.43E+00,1.17E+00,2.66E-01,1.47E+00,1.18E+00,2.87E-01 +3.26E+02,1.42E+00,1.18E+00,2.39E-01,1.46E+00,1.20E+00,2.61E-01,1.50E+00,1.21E+00,2.84E-01,1.53E+00,1.23E+00,3.08E-01,1.57E+00,1.24E+00,3.31E-01 +3.27E+02,1.53E+00,1.25E+00,2.78E-01,1.57E+00,1.27E+00,3.03E-01,1.61E+00,1.28E+00,3.29E-01,1.65E+00,1.29E+00,3.55E-01,1.68E+00,1.30E+00,3.82E-01 +3.28E+02,1.65E+00,1.33E+00,3.22E-01,1.69E+00,1.34E+00,3.51E-01,1.73E+00,1.35E+00,3.80E-01,1.77E+00,1.36E+00,4.10E-01,1.81E+00,1.37E+00,4.39E-01 +3.29E+02,1.78E+00,1.41E+00,3.72E-01,1.82E+00,1.42E+00,4.05E-01,1.86E+00,1.43E+00,4.37E-01,1.90E+00,1.43E+00,4.70E-01,1.94E+00,1.44E+00,5.03E-01 +3.30E+02,1.92E+00,1.49E+00,4.29E-01,1.97E+00,1.50E+00,4.65E-01,2.01E+00,1.51E+00,5.02E-01,2.05E+00,1.51E+00,5.38E-01,2.09E+00,1.51E+00,5.74E-01 +3.31E+02,2.07E+00,1.58E+00,4.93E-01,2.12E+00,1.59E+00,5.33E-01,2.16E+00,1.59E+00,5.73E-01,2.20E+00,1.59E+00,6.13E-01,2.24E+00,1.59E+00,6.52E-01 +3.32E+02,2.24E+00,1.68E+00,5.63E-01,2.28E+00,1.68E+00,6.07E-01,2.33E+00,1.68E+00,6.51E-01,2.37E+00,1.67E+00,6.94E-01,2.40E+00,1.67E+00,7.37E-01 +3.33E+02,2.41E+00,1.77E+00,6.39E-01,2.46E+00,1.77E+00,6.87E-01,2.50E+00,1.76E+00,7.35E-01,2.54E+00,1.76E+00,7.82E-01,2.57E+00,1.75E+00,8.28E-01 +3.34E+02,2.59E+00,1.87E+00,7.22E-01,2.63E+00,1.86E+00,7.74E-01,2.68E+00,1.85E+00,8.26E-01,2.71E+00,1.84E+00,8.76E-01,2.75E+00,1.82E+00,9.25E-01 +3.35E+02,2.77E+00,1.96E+00,8.09E-01,2.82E+00,1.95E+00,8.66E-01,2.86E+00,1.93E+00,9.21E-01,2.89E+00,1.92E+00,9.75E-01,2.93E+00,1.90E+00,1.03E+00 +3.36E+02,2.95E+00,2.05E+00,9.01E-01,3.00E+00,2.03E+00,9.61E-01,3.04E+00,2.02E+00,1.02E+00,3.07E+00,1.99E+00,1.08E+00,3.10E+00,1.97E+00,1.13E+00 +3.37E+02,3.13E+00,2.13E+00,9.94E-01,3.17E+00,2.11E+00,1.06E+00,3.21E+00,2.09E+00,1.12E+00,3.24E+00,2.06E+00,1.18E+00,3.28E+00,2.04E+00,1.24E+00 +3.38E+02,3.29E+00,2.21E+00,1.09E+00,3.34E+00,2.18E+00,1.16E+00,3.37E+00,2.15E+00,1.22E+00,3.41E+00,2.12E+00,1.29E+00,3.44E+00,2.09E+00,1.35E+00 +3.39E+02,3.44E+00,2.26E+00,1.18E+00,3.49E+00,2.23E+00,1.25E+00,3.52E+00,2.20E+00,1.32E+00,3.56E+00,2.17E+00,1.39E+00,3.59E+00,2.14E+00,1.45E+00 +3.40E+02,3.57E+00,2.31E+00,1.27E+00,3.62E+00,2.27E+00,1.34E+00,3.65E+00,2.24E+00,1.42E+00,3.69E+00,2.20E+00,1.48E+00,3.72E+00,2.17E+00,1.55E+00 +3.41E+02,3.67E+00,2.33E+00,1.34E+00,3.72E+00,2.29E+00,1.43E+00,3.76E+00,2.26E+00,1.50E+00,3.79E+00,2.22E+00,1.57E+00,3.82E+00,2.18E+00,1.64E+00 +3.42E+02,3.74E+00,2.33E+00,1.41E+00,3.80E+00,2.30E+00,1.50E+00,3.84E+00,2.26E+00,1.58E+00,3.88E+00,2.22E+00,1.66E+00,3.91E+00,2.18E+00,1.73E+00 +3.43E+02,3.79E+00,2.32E+00,1.47E+00,3.84E+00,2.28E+00,1.56E+00,3.89E+00,2.25E+00,1.65E+00,3.93E+00,2.21E+00,1.73E+00,3.97E+00,2.17E+00,1.80E+00 +3.44E+02,3.80E+00,2.28E+00,1.52E+00,3.86E+00,2.25E+00,1.61E+00,3.92E+00,2.22E+00,1.70E+00,3.96E+00,2.18E+00,1.78E+00,4.00E+00,2.14E+00,1.86E+00 +3.45E+02,3.78E+00,2.23E+00,1.55E+00,3.85E+00,2.21E+00,1.65E+00,3.91E+00,2.17E+00,1.74E+00,3.97E+00,2.14E+00,1.83E+00,4.01E+00,2.10E+00,1.91E+00 +3.46E+02,3.73E+00,2.17E+00,1.57E+00,3.82E+00,2.15E+00,1.67E+00,3.89E+00,2.12E+00,1.77E+00,3.95E+00,2.09E+00,1.86E+00,4.00E+00,2.05E+00,1.94E+00 +3.47E+02,3.66E+00,2.09E+00,1.57E+00,3.76E+00,2.08E+00,1.68E+00,3.84E+00,2.05E+00,1.78E+00,3.90E+00,2.03E+00,1.88E+00,3.96E+00,1.99E+00,1.97E+00 +3.48E+02,3.58E+00,2.01E+00,1.57E+00,3.68E+00,2.00E+00,1.68E+00,3.77E+00,1.98E+00,1.79E+00,3.84E+00,1.96E+00,1.89E+00,3.91E+00,1.93E+00,1.98E+00 +3.49E+02,3.47E+00,1.92E+00,1.55E+00,3.59E+00,1.92E+00,1.67E+00,3.68E+00,1.90E+00,1.78E+00,3.77E+00,1.88E+00,1.88E+00,3.84E+00,1.86E+00,1.98E+00 +3.51E+02,3.36E+00,1.83E+00,1.53E+00,3.48E+00,1.83E+00,1.65E+00,3.59E+00,1.82E+00,1.76E+00,3.68E+00,1.81E+00,1.87E+00,3.76E+00,1.79E+00,1.97E+00 +3.52E+02,3.24E+00,1.74E+00,1.50E+00,3.37E+00,1.75E+00,1.62E+00,3.48E+00,1.74E+00,1.74E+00,3.58E+00,1.73E+00,1.85E+00,3.67E+00,1.72E+00,1.95E+00 +3.53E+02,3.11E+00,1.65E+00,1.46E+00,3.25E+00,1.66E+00,1.59E+00,3.37E+00,1.66E+00,1.71E+00,3.47E+00,1.65E+00,1.82E+00,3.57E+00,1.64E+00,1.93E+00 +3.54E+02,2.99E+00,1.56E+00,1.42E+00,3.12E+00,1.58E+00,1.55E+00,3.25E+00,1.58E+00,1.67E+00,3.36E+00,1.58E+00,1.79E+00,3.47E+00,1.57E+00,1.90E+00 +3.55E+02,2.86E+00,1.48E+00,1.38E+00,3.00E+00,1.49E+00,1.51E+00,3.13E+00,1.50E+00,1.63E+00,3.25E+00,1.50E+00,1.75E+00,3.36E+00,1.50E+00,1.86E+00 +3.56E+02,2.73E+00,1.40E+00,1.34E+00,2.88E+00,1.41E+00,1.46E+00,3.01E+00,1.42E+00,1.59E+00,3.14E+00,1.43E+00,1.71E+00,3.25E+00,1.43E+00,1.82E+00 +3.57E+02,2.61E+00,1.32E+00,1.29E+00,2.76E+00,1.34E+00,1.42E+00,2.90E+00,1.35E+00,1.54E+00,3.02E+00,1.36E+00,1.66E+00,3.14E+00,1.36E+00,1.78E+00 +3.58E+02,2.50E+00,1.24E+00,1.25E+00,2.64E+00,1.27E+00,1.38E+00,2.78E+00,1.28E+00,1.50E+00,2.91E+00,1.29E+00,1.62E+00,3.03E+00,1.30E+00,1.74E+00 +3.59E+02,2.38E+00,1.18E+00,1.21E+00,2.53E+00,1.20E+00,1.33E+00,2.67E+00,1.22E+00,1.45E+00,2.80E+00,1.23E+00,1.57E+00,2.93E+00,1.23E+00,1.69E+00 +3.60E+02,2.28E+00,1.11E+00,1.16E+00,2.42E+00,1.14E+00,1.29E+00,2.56E+00,1.15E+00,1.41E+00,2.70E+00,1.17E+00,1.53E+00,2.82E+00,1.18E+00,1.65E+00 +3.61E+02,2.17E+00,1.05E+00,1.12E+00,2.32E+00,1.08E+00,1.24E+00,2.46E+00,1.10E+00,1.36E+00,2.59E+00,1.11E+00,1.48E+00,2.72E+00,1.12E+00,1.60E+00 +3.62E+02,2.08E+00,9.95E-01,1.08E+00,2.22E+00,1.02E+00,1.20E+00,2.36E+00,1.04E+00,1.32E+00,2.50E+00,1.06E+00,1.44E+00,2.62E+00,1.07E+00,1.56E+00 +3.63E+02,1.99E+00,9.43E-01,1.05E+00,2.13E+00,9.68E-01,1.16E+00,2.27E+00,9.89E-01,1.28E+00,2.40E+00,1.01E+00,1.40E+00,2.53E+00,1.02E+00,1.51E+00 +3.64E+02,1.90E+00,8.94E-01,1.01E+00,2.04E+00,9.20E-01,1.12E+00,2.18E+00,9.41E-01,1.24E+00,2.31E+00,9.59E-01,1.35E+00,2.44E+00,9.72E-01,1.47E+00 +3.65E+02,1.82E+00,8.49E-01,9.73E-01,1.96E+00,8.74E-01,1.08E+00,2.09E+00,8.96E-01,1.20E+00,2.23E+00,9.14E-01,1.31E+00,2.35E+00,9.28E-01,1.42E+00 +3.66E+02,1.75E+00,8.07E-01,9.39E-01,1.88E+00,8.32E-01,1.05E+00,2.01E+00,8.54E-01,1.16E+00,2.14E+00,8.72E-01,1.27E+00,2.27E+00,8.87E-01,1.38E+00 +3.67E+02,1.67E+00,7.67E-01,9.07E-01,1.81E+00,7.92E-01,1.01E+00,1.94E+00,8.14E-01,1.12E+00,2.07E+00,8.33E-01,1.23E+00,2.19E+00,8.48E-01,1.34E+00 +3.68E+02,1.61E+00,7.31E-01,8.76E-01,1.74E+00,7.56E-01,9.80E-01,1.86E+00,7.77E-01,1.09E+00,1.99E+00,7.96E-01,1.19E+00,2.12E+00,8.12E-01,1.30E+00 +3.69E+02,1.54E+00,6.97E-01,8.47E-01,1.67E+00,7.21E-01,9.48E-01,1.80E+00,7.43E-01,1.05E+00,1.92E+00,7.62E-01,1.16E+00,2.04E+00,7.78E-01,1.27E+00 +3.70E+02,1.48E+00,6.65E-01,8.19E-01,1.61E+00,6.89E-01,9.18E-01,1.73E+00,7.11E-01,1.02E+00,1.85E+00,7.29E-01,1.12E+00,1.98E+00,7.46E-01,1.23E+00 +3.71E+02,1.43E+00,6.36E-01,7.92E-01,1.55E+00,6.59E-01,8.89E-01,1.67E+00,6.80E-01,9.88E-01,1.79E+00,6.99E-01,1.09E+00,1.91E+00,7.15E-01,1.19E+00 +3.72E+02,1.38E+00,6.08E-01,7.67E-01,1.49E+00,6.31E-01,8.61E-01,1.61E+00,6.52E-01,9.59E-01,1.73E+00,6.71E-01,1.06E+00,1.85E+00,6.87E-01,1.16E+00 +3.73E+02,1.33E+00,5.83E-01,7.43E-01,1.44E+00,6.05E-01,8.34E-01,1.56E+00,6.25E-01,9.30E-01,1.67E+00,6.44E-01,1.03E+00,1.79E+00,6.60E-01,1.13E+00 +3.74E+02,1.28E+00,5.59E-01,7.20E-01,1.39E+00,5.80E-01,8.09E-01,1.50E+00,6.01E-01,9.03E-01,1.62E+00,6.19E-01,9.99E-01,1.73E+00,6.35E-01,1.10E+00 +3.75E+02,1.23E+00,5.36E-01,6.98E-01,1.34E+00,5.57E-01,7.85E-01,1.45E+00,5.77E-01,8.76E-01,1.57E+00,5.95E-01,9.71E-01,1.68E+00,6.11E-01,1.07E+00 +3.76E+02,1.19E+00,5.15E-01,6.77E-01,1.30E+00,5.36E-01,7.62E-01,1.41E+00,5.55E-01,8.51E-01,1.52E+00,5.73E-01,9.44E-01,1.63E+00,5.89E-01,1.04E+00 +3.77E+02,1.15E+00,4.95E-01,6.57E-01,1.26E+00,5.16E-01,7.40E-01,1.36E+00,5.35E-01,8.28E-01,1.47E+00,5.52E-01,9.18E-01,1.58E+00,5.68E-01,1.01E+00 +3.78E+02,1.11E+00,4.77E-01,6.38E-01,1.22E+00,4.96E-01,7.19E-01,1.32E+00,5.15E-01,8.05E-01,1.43E+00,5.32E-01,8.93E-01,1.53E+00,5.48E-01,9.84E-01 +3.79E+02,1.08E+00,4.59E-01,6.20E-01,1.18E+00,4.78E-01,6.99E-01,1.28E+00,4.97E-01,7.83E-01,1.38E+00,5.14E-01,8.69E-01,1.49E+00,5.29E-01,9.59E-01 +3.80E+02,1.05E+00,4.43E-01,6.03E-01,1.14E+00,4.62E-01,6.80E-01,1.24E+00,4.79E-01,7.62E-01,1.34E+00,4.96E-01,8.47E-01,1.45E+00,5.11E-01,9.34E-01 +3.81E+02,1.01E+00,4.27E-01,5.86E-01,1.11E+00,4.46E-01,6.62E-01,1.20E+00,4.63E-01,7.42E-01,1.30E+00,4.79E-01,8.25E-01,1.41E+00,4.95E-01,9.11E-01 +3.82E+02,9.83E-01,4.12E-01,5.70E-01,1.07E+00,4.31E-01,6.44E-01,1.17E+00,4.48E-01,7.22E-01,1.27E+00,4.64E-01,8.04E-01,1.37E+00,4.79E-01,8.88E-01 +3.83E+02,9.54E-01,3.99E-01,5.55E-01,1.04E+00,4.16E-01,6.27E-01,1.14E+00,4.33E-01,7.04E-01,1.23E+00,4.49E-01,7.84E-01,1.33E+00,4.64E-01,8.66E-01 +3.84E+02,9.26E-01,3.86E-01,5.41E-01,1.01E+00,4.03E-01,6.11E-01,1.11E+00,4.19E-01,6.86E-01,1.20E+00,4.35E-01,7.64E-01,1.29E+00,4.49E-01,8.45E-01 +3.85E+02,9.00E-01,3.73E-01,5.27E-01,9.86E-01,3.90E-01,5.96E-01,1.08E+00,4.06E-01,6.69E-01,1.17E+00,4.21E-01,7.46E-01,1.26E+00,4.36E-01,8.25E-01 +3.86E+02,8.75E-01,3.62E-01,5.14E-01,9.59E-01,3.78E-01,5.81E-01,1.05E+00,3.94E-01,6.53E-01,1.14E+00,4.09E-01,7.28E-01,1.23E+00,4.23E-01,8.06E-01 +3.87E+02,8.51E-01,3.50E-01,5.01E-01,9.33E-01,3.67E-01,5.67E-01,1.02E+00,3.82E-01,6.37E-01,1.11E+00,3.97E-01,7.10E-01,1.20E+00,4.10E-01,7.87E-01 +3.88E+02,8.29E-01,3.40E-01,4.89E-01,9.09E-01,3.56E-01,5.53E-01,9.92E-01,3.71E-01,6.22E-01,1.08E+00,3.85E-01,6.94E-01,1.17E+00,3.99E-01,7.69E-01 +3.89E+02,8.07E-01,3.30E-01,4.77E-01,8.85E-01,3.45E-01,5.40E-01,9.67E-01,3.60E-01,6.07E-01,1.05E+00,3.74E-01,6.78E-01,1.14E+00,3.87E-01,7.52E-01 +3.90E+02,7.86E-01,3.20E-01,4.66E-01,8.63E-01,3.35E-01,5.27E-01,9.43E-01,3.50E-01,5.93E-01,1.03E+00,3.64E-01,6.62E-01,1.11E+00,3.77E-01,7.35E-01 +3.91E+02,7.66E-01,3.11E-01,4.55E-01,8.41E-01,3.26E-01,5.15E-01,9.20E-01,3.40E-01,5.80E-01,1.00E+00,3.54E-01,6.48E-01,1.09E+00,3.67E-01,7.19E-01 +3.92E+02,7.47E-01,3.03E-01,4.44E-01,8.21E-01,3.17E-01,5.04E-01,8.98E-01,3.31E-01,5.67E-01,9.78E-01,3.44E-01,6.33E-01,1.06E+00,3.57E-01,7.03E-01 +3.93E+02,7.29E-01,2.95E-01,4.34E-01,8.01E-01,3.09E-01,4.92E-01,8.76E-01,3.22E-01,5.54E-01,9.55E-01,3.35E-01,6.20E-01,1.04E+00,3.48E-01,6.88E-01 +3.94E+02,7.11E-01,2.87E-01,4.25E-01,7.82E-01,3.01E-01,4.82E-01,8.56E-01,3.14E-01,5.42E-01,9.33E-01,3.27E-01,6.06E-01,1.01E+00,3.39E-01,6.74E-01 +3.95E+02,6.95E-01,2.79E-01,4.15E-01,7.64E-01,2.93E-01,4.71E-01,8.36E-01,3.06E-01,5.31E-01,9.12E-01,3.18E-01,5.93E-01,9.90E-01,3.30E-01,6.60E-01 +3.96E+02,6.79E-01,2.72E-01,4.06E-01,7.46E-01,2.85E-01,4.61E-01,8.17E-01,2.98E-01,5.19E-01,8.92E-01,3.11E-01,5.81E-01,9.68E-01,3.22E-01,6.46E-01 +3.97E+02,6.63E-01,2.65E-01,3.98E-01,7.30E-01,2.78E-01,4.51E-01,7.99E-01,2.91E-01,5.08E-01,8.72E-01,3.03E-01,5.69E-01,9.48E-01,3.15E-01,6.33E-01 +3.98E+02,6.48E-01,2.59E-01,3.89E-01,7.13E-01,2.71E-01,4.42E-01,7.82E-01,2.84E-01,4.98E-01,8.53E-01,2.96E-01,5.58E-01,9.27E-01,3.07E-01,6.20E-01 +3.99E+02,6.34E-01,2.53E-01,3.81E-01,6.98E-01,2.65E-01,4.33E-01,7.65E-01,2.77E-01,4.88E-01,8.35E-01,2.89E-01,5.46E-01,9.08E-01,3.00E-01,6.08E-01 +4.00E+02,6.20E-01,2.47E-01,3.74E-01,6.83E-01,2.59E-01,4.24E-01,7.49E-01,2.71E-01,4.78E-01,8.18E-01,2.82E-01,5.35E-01,8.89E-01,2.93E-01,5.96E-01