diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..26d33521
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/AnsysWorkflows.iml b/.idea/AnsysWorkflows.iml
new file mode 100644
index 00000000..039314de
--- /dev/null
+++ b/.idea/AnsysWorkflows.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 00000000..105ce2da
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..c76d81ab
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..0395b48d
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/maxwell2d-lumerical/.gitignore b/maxwell2d-lumerical/.gitignore
new file mode 100644
index 00000000..e6d35e74
--- /dev/null
+++ b/maxwell2d-lumerical/.gitignore
@@ -0,0 +1 @@
+outputs
\ No newline at end of file
diff --git a/maxwell2d-lumerical/GC_Opt.lsf b/maxwell2d-lumerical/GC_Opt.lsf
new file mode 100644
index 00000000..ed5df0a1
--- /dev/null
+++ b/maxwell2d-lumerical/GC_Opt.lsf
@@ -0,0 +1,301 @@
+# This script file builds the simulation file for the apodized grating coupler, GC
+# entirely using script commands, with the goal to focus the output laser beam at a specific distance. Objects are added to the simulation file
+# using the specific add commands. Then the script reads the coordinates of the nodal points calculated from Maxwell
+# and sets the 5th solution as the target distance of the foccused beam. An optimization is created based on the define FoM in the analysis group & uses as
+# as optimization parameters, the pitch, the etch depth and the minimum duty cycle of the GC.
+
+clear;
+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
+um=1e-6;
+
+#################################### add simulation region/mesh/source ##############################
+addfdtd;
+set("simulation time", 3000e-15); # the unit is second
+set("dimension", "2D");
+set("x",16*um);
+set("y",-0.75*um);
+set("z",0*um);
+set("x span", 48*um);
+set("y span", 3.5*um);
+set("mesh accuracy", 2);
+
+addmode; #addsource
+set("injection axis","x");
+set("x",-3*um);
+set("y",-1*um);
+set("y span",1*um);
+set("z",0);
+set("z span",1.14*um);
+set("wavelength start", 1550e-9);
+set("wavelength stop", 1550e-9);
+
+adddftmonitor; #addmonitor
+set("name","near_field");
+set("monitor type",6);
+set("x",24e-6); set("x span",60e-6);
+set("y",0.7e-6);
+set("z",0e-6); set("z span",15.85e-6);
+
+############################################ Define geometry ##############################################
+# add structures
+
+
+########### Scripted part of the Structure Group ###########
+addstructuregroup; # add an apodised grating
+set("name","GC_2D");
+set("x",0); # sets the x position
+
+set("y",-1.1*um);
+
+set("z",0*um);
+adduserprop("index",0,2);
+adduserprop("sidewall_angle",0,90);
+adduserprop("duty cycle",0,0.8);
+adduserprop("n_uniform_gratings",0,1);
+adduserprop("dc_min",0,0.476);
+adduserprop("dc_uniform",0,0.85);
+adduserprop("n_apodized_gratings",0,30);
+adduserprop("target length",0,50);
+adduserprop("h total",2,0.3*um);
+adduserprop("etch depth",2,0.3*um);
+adduserprop("input length",2,10*um);
+adduserprop("output length",2,80*um);
+adduserprop("pitch_uniform",2,0.761*um);
+adduserprop("material",5,"");
+set('script','
+
+deleteall;
+fill_width_uniform = pitch_uniform*dc_uniform;
+etch_width_uniform = pitch_uniform*(1-dc_uniform);
+
+
+etch_width_apod = linspace(dc_uniform, dc_min, n_apodized_gratings);
+
+n_periods = ceil(%target length%/pitch_uniform);
+fill_width = pitch_uniform*dc_uniform;
+etch_width = pitch_uniform*(1-dc_uniform);
+L = n_periods*pitch_uniform + etch_width;
+sidewall_angle_rad = (90-sidewall_angle)*pi/180;
+
+
+if(%etch depth% > %h total%) {
+ %etch depth% = %h total%;
+}
+
+# input waveguide
+vtx = [-%input length%,%h total%;0,%h total%;%h total%*tan(sidewall_angle_rad),0;-%input length%-%h total%*tan(sidewall_angle_rad),0]; # microns
+addpoly;
+set("name","input waveguide");
+set("vertices", vtx);
+set("x", 0);
+set("y", 0);
+set("material",material);
+if(get("material")=="")
+{ set("index",index); }
+set("override mesh order from material database", 1);
+set("mesh order", 3);
+
+# lower layer below grating
+if(%etch depth% < %h total%) {
+ addrect;
+ set("name","lower layer");
+ set("x min",-%input length%);
+ set("x max",%output length%);
+ set("y min",0);
+ set("y max",%h total%-%etch depth%);
+ set("material",material);
+ if(get("material")=="")
+ { set("index",index); }
+}
+
+#add grating
+for(i=1:(n_uniform_gratings+n_apodized_gratings)){
+
+ if (i<=n_uniform_gratings){
+ vtx = [pitch_uniform*(i-1)+etch_width_uniform,%h total%;pitch_uniform*i,%h total%;pitch_uniform*i+%etch depth%*tan(sidewall_angle_rad),%h total%-%etch depth%;pitch_uniform*(i-1)+etch_width_uniform-%etch depth%*tan(sidewall_angle_rad),%h total%-%etch depth%]; # microns
+ addpoly;
+ set("name","grating");
+ set("vertices", vtx);
+ set("x", 0);
+ set("y", 0);
+ set("material",material);
+ if(get("material")=="")
+ { set("index",index); }
+ }else{
+
+ ew = pitch_uniform*(1-etch_width_apod(i-n_uniform_gratings));
+ vtx = [pitch_uniform*(i-1)+ew,%h total%;pitch_uniform*i,%h total%;pitch_uniform*i+%etch depth%*tan(sidewall_angle_rad),%h total%-%etch depth%;pitch_uniform*(i-1)+ew-%etch depth%*tan(sidewall_angle_rad),%h total%-%etch depth%]; # microns
+ addpoly;
+ set("name","grating");
+ set("vertices", vtx);
+ set("x", 0);
+ set("y", 0);
+ set("material",material);
+ if(get("material")=="")
+ { set("index",index); }
+ }
+
+}
+
+selectall;
+
+set("z",0);
+set("z span",1e-6);
+
+');
+
+
+
+
+addrect; # add
+set("name","cladding");
+set("x",19.5*um); # sets the x position
+set("x span",121*um); # sets the x position
+set("y",-0.3*um);
+set("y span",1.6*um);
+set("z",0*um);
+set("z span",1*um);
+set("material", "SiO2 (Glass) - Palik"); # material name has to be exact
+set("override mesh order from material database", true);
+set("mesh order", 5); # material name has to be exact
+
+# add structures
+addrect; # add a
+set("name","BOx");
+set("x",19.5*um); # sets the x position
+set("x span",121*um); # sets the x position
+set("y",-1.55*um);
+set("y span",0.9*um);
+set("z",0*um);
+set("z span",1*um);
+set("material", "SiO2 (Glass) - Palik"); # material name has to be exact
+#set("override mesh order from material database", true);
+#set("mesh order", 5); # material name has to be exact
+
+# add structures
+addrect; # add a
+set("name","Substrate");
+set("x",19.5*um); # sets the x position
+set("x span",121*um); # sets the x position
+set("y",-6*um);
+set("y span",8*um);
+set("z",0*um);
+set("z span",1*um);
+set("material", "SiO2 (Glass) - Palik"); # material name has to be exact
+set("override mesh order from material database", true);
+set("mesh order", 1); # material name has to be exact
+
+## Read Data from ASCII file ##
+cd(filedirectory(currentscriptname));
+M=readdata("legend.txt");
+Mselect=M(5,1)*1e-6;
+
+################Analysis Group#######################
+ ## Figure of Merit --- Focus Beam ##
+##############################################
+addanalysisgroup;
+set("name","FoM_beam");
+set("x", 0);
+set("y", 0);
+set("z", 0);
+
+addanalysisresult("FoM");
+addanalysisprop("Mselect",2,M(5,1)*um);
+########### Scripted part of the Analysis Group ###########
+
+set('analysis script','
+
+# Define far field position vector
+
+x=linspace(-40-06,-5e-06,800);
+y=linspace(Mselect-5e-06,Mselect+5e-06,800);
+
+# Do far field projection
+E_H_far=farfieldexact2d("nearfield_profile",x,y,{"field":"E and H"});
+E_far = E_H_far.E;
+H_far = E_H_far.H;
+
+
+Ex=E_far(:,:,:,:,1);
+Ey=E_far(:,:,:,:,2);
+Ez=E_far(:,:,:,:,3);
+
+Hx=H_far(:,:,:,:,1);
+Hy=H_far(:,:,:,:,2);
+Hz=H_far(:,:,:,:,3);
+
+E2_far=(pinch(abs(Ex)))^2+(pinch(abs(Ey)))^2+(pinch(abs(Ez)))^2;
+H2_far=(pinch(abs(Hx)))^2+(pinch(abs(Hy)))^2+(pinch(abs(Hz)))^2;
+
+#FoM=integrate(E2_far,1:2,x,y);
+
+ind2 = find(y,Mselect);
+A=pinch(E2_far,2,ind2);
+FoM=max(A);
+
+');
+
+adddftmonitor;
+set("name","nearfield_profile");
+set("monitor type",6); # 2D y-normal
+set("x",26*um);
+set("x span",65*um);
+set("y",0.7*um);
+set("z",0);
+addtogroup("FoM_beam");
+
+########################## Save model ########################
+
+save("Testsim");
+
+########################## add Optimization sweep ########################
+
+addsweep(1);
+setsweep("optimization", "name", "Intensity");
+setsweep("Intensity", "Type", "Maximize");
+setsweep("Intensity", "algorithm", "Particle Swarm");
+setsweep("Intensity", "maximum generations", 5);
+setsweep("Intensity", "generation size", 8);
+setsweep("Intensity", "tolerance", 0);
+
+# define the grating pitch size
+para1 = struct;
+para1.Parameter = "::model::GC_2D::pitch_uniform";
+para1.Type = "Length";
+para1.Min = 0.7e-6;
+para1.Max = 0.9e-6;
+para1.Units = "microns";
+addsweepparameter("Intensity", para1);
+
+# define the grating etch depth
+para2 = struct;
+para2.Parameter = "::model::GC_2D::etch depth";
+para2.Type = "Length";
+para2.Min = 0.1e-6;
+para2.Max = 0.3e-6;
+para2.Units = "microns";
+addsweepparameter("Intensity", para2);
+
+para3 = struct;
+para3.Parameter = "::model::GC_2D::dc_min";
+para3.Type = "Number";
+para3.Min = 0.1;
+para3.Max = 0.6;
+para3.Units = "microns";
+addsweepparameter("Intensity", para3);
+
+# define figure of merit
+result_1 = struct;
+result_1.Name = "new_result";
+result_1.Result = "::model::FoM_beam::FoM";
+result_1.Optimize = true;
+
+# add the figure of merits R & T to the optimization
+addsweepresult("Intensity", result_1);
+save("Testsim");
+## run optimization
+runsweep("Intensity");
+
diff --git a/maxwell2d-lumerical/GC_farfield.lsf b/maxwell2d-lumerical/GC_farfield.lsf
new file mode 100644
index 00000000..d0a21c8a
--- /dev/null
+++ b/maxwell2d-lumerical/GC_farfield.lsf
@@ -0,0 +1,104 @@
+## This script calculates the E and H component of the grating coupler
+## and calculates the properties of the focused beam.
+
+clear;
+# Define far field position vector
+
+num=500; # number of points
+x = linspace(-80e-6,50e-6,num);
+y = linspace(1e-6,400e-6,2*num);
+
+# Do far field projection
+
+E_H_far=farfieldexact2d("near_field",x,y,{"field":"E and H"});
+E_far = E_H_far.E;
+H_far = E_H_far.H;
+
+# Extract electric & magnetic components from the E_H_far dataset
+
+Ex=E_far(:,:,:,:,1);
+Ey=E_far(:,:,:,:,2);
+Ez=E_far(:,:,:,:,3);
+
+Hx=H_far(:,:,:,:,1);
+Hy=H_far(:,:,:,:,2);
+Hz=H_far(:,:,:,:,3);
+
+E2_far=(pinch(abs(Ex)))^2+(pinch(abs(Ey)))^2+(pinch(abs(Ez)))^2;
+H2_far=(pinch(abs(Hx)))^2+(pinch(abs(Hy)))^2+(pinch(abs(Hz)))^2;
+image(x*1e6,y*1e6, E2_far,"x-coordinate (um)","y-coordinate (um)","|E|^2");
+
+
+cd(filedirectory(currentscriptname));
+## Read Data from ASCII file ##
+ M=readdata("legend.txt");
+ Mselect=M(5,1)*1e-6;
+
+# farfield along x axis
+E3_z = farfieldexact2d('near_field',x,Mselect);
+E3_z = pinch(sum(abs(E3_z)^2,3));
+plot(x*1e6,E3_z,'x (um)','|E|^2 (V^2/m^2)','Line projection at y='+num2str(floor(Mselect*1e6),"%2d")+'um','linewidth=2');
+legend("");
+
+# find FWHM along x axis
+ind1 = find(E3_z,max(E3_z));
+xmax = x(ind1);
+indR1 = find(E3_z,E3_z(ind1)/2);
+if ( ind1indR2 ) {
+ indR2= ind2 + (ind2-indR2);
+ }
+indL2 = abs(ind2-(abs(indR2-ind2)));
+FWHM_Y=abs(y(indR2)-y(indL2));
+
+##Calculate deviation between actual and target coordinates of the trap ##
+#Get the length of the properties
+nx = length(x);
+ny = length(y);
+#Get the intensity values
+e2 = E2_far;
+#Get the maximum intensity value
+indexE2_far = find(e2, max(e2));
+#Create the grids that will be used to extract the actual position values
+X = meshgridx(x,y);
+Y = meshgridy(x,y);
+?Mselect;
+Mactual=Y(indexE2_far);
+RelVal=(abs(Mselect-Mactual)/Mactual);
+
+# Print geometric properties in the code editor
+select("Substrate");
+Material = get("material");
+select("BOx");
+BOX = get("material");
+select("GC_2D");
+GC_period = get("pitch_uniform");
+GC_etch = get("etch depth");
+GC_DCmin = get("dc_min");
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maxwell2d-lumerical/IonTrapM2D_lum_2025.py b/maxwell2d-lumerical/IonTrapM2D_lum_2025.py
new file mode 100644
index 00000000..913ffb10
--- /dev/null
+++ b/maxwell2d-lumerical/IonTrapM2D_lum_2025.py
@@ -0,0 +1,309 @@
+# Copyright (C) 2024 - 2025 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.
+
+# # Maxwell2D - Simplified IonTrap Modelling
+#
+# Description:
+#
+# First step of a multi-tool workflow: Maxwell 2D model to identify electric field node in Ion Trap
+# 1. Set up the Maxwell 2D Parametric Model
+# 2. Identify the Electric Field Node Point for Each Design Point
+# 3. Export the Node Coordinates for the subsequent Lumerical Step
+# 4. Launch the Lumerical Scripts
+#
+# Keywords: **Ion Trap**, **Electrostatic**
+
+# ## Perform imports and define constants
+#
+# Perform required imports.
+
+import os
+import sys
+import tempfile
+import time
+
+sys.path.append("C:\\Program Files\\Lumerical\\v251\\api\\python\\")
+sys.path.append(os.path.dirname(__file__)) # Current directory
+my_path = r"D:/2025/17_IonTrap/PyAnsys_GC_test/" # Directory where Lumerical Scripts are stored
+my_node_filename = "NodePositionTable.tab"
+my_node_filename_lum = "legend.txt"
+
+from PIL import Image
+import ansys.aedt.core
+import lumapi
+
+# Define constants.
+
+AEDT_VERSION = "2025.1"
+NUM_CORES = 4
+NG_MODE = False # Open AEDT UI when it is launched.
+
+# ## Create temporary directory
+#
+
+temp_folder = tempfile.TemporaryDirectory(suffix=".ansys")
+
+# ## Launch AEDT and application
+#
+
+project_name = os.path.join(temp_folder.name, "IonTrapMaxwell.aedt")
+m2d = ansys.aedt.core.Maxwell2d(
+ project=project_name,
+ design="01_IonTrap_3binary2D",
+ solution_type="Electrostatic",
+ version=AEDT_VERSION,
+ non_graphical=NG_MODE,
+ new_desktop=True,
+)
+m2d.modeler.model_units = "um"
+
+# ## Preprocess
+#
+# Initialize dictionaries for design variables
+
+geom_params = {
+ "div": str(73 / 41),
+ "w_rf": "41um",
+ "w_dc": "41um*div",
+ "w_cut": "4um",
+ "metal_thickness": "1um",
+ "offset_glass": "50um",
+ "glass_thickness": "10um",
+ "x_dummy": "2um",
+ "y_dummy": "300um",
+}
+
+# Define variables from dictionaries
+
+for k, v in geom_params.items():
+ m2d[k] = v
+
+# Create Design Geometry
+
+dc = m2d.modeler.create_rectangle(
+ origin=["-w_dc/2", "-metal_thickness/2", "0"],
+ sizes=["w_dc", "metal_thickness", 0],
+ name="DC",
+ material="aluminum",
+)
+# dc.color = (0, 0, 255) # rgb
+
+gnd = m2d.modeler.create_rectangle(
+ origin=["-(w_dc/2+w_cut+w_rf+offset_glass)", "-(metal_thickness/2+glass_thickness)", "0"],
+ sizes=["2*(w_dc/2+w_cut+w_rf+offset_glass)", "-metal_thickness", 0],
+ name="gnd",
+ material="aluminum",
+)
+
+rf = m2d.modeler.create_rectangle(
+ origin=["-(w_dc/2+w_cut+w_rf)", "-metal_thickness/2", "0"],
+ sizes=["w_rf", "metal_thickness", 0],
+ name="RF",
+ material="aluminum",
+)
+
+sub_glass = m2d.modeler.create_rectangle(
+ origin=["-(w_dc/2+w_cut+w_rf+offset_glass)", "-metal_thickness/2", "0"],
+ sizes=["2*(w_dc/2+w_cut+w_rf+offset_glass)", "-glass_thickness", 0],
+ name="RF",
+ material="glass",
+)
+
+ins = m2d.modeler.create_rectangle(
+ origin=["-(w_dc/2+w_cut)", "-metal_thickness/2", "0"],
+ sizes=["w_cut", "metal_thickness", 0],
+ name="ins",
+ material="vacuum",
+)
+
+# Create dummy objects for mesh, center_line for Post Processing and Region
+
+dummy = m2d.modeler.create_rectangle(
+ origin=["0", "metal_thickness/2", "0"],
+ sizes=["-x_dummy", "y_dummy", 0],
+ name="dummy",
+ material="vacuum",
+)
+
+region = m2d.modeler.create_region(
+ pad_value=[100, 0, 100, 0], pad_type="Absolute Offset", name="Region"
+)
+center_line = m2d.modeler.create_polyline(
+ points=[["0", "metal_thickness/2", "0"], ["0", "metal_thickness/2+300um", "0"]],
+ name="center_line",
+)
+
+# Define Excitations
+
+m2d.assign_voltage(assignment=gnd.id, amplitude=0, name="ground")
+m2d.assign_voltage(assignment=dc.id, amplitude=0, name="V_dc")
+m2d.assign_voltage(assignment=rf.id, amplitude=1, name="V_rf")
+
+# Define Mesh Settings
+# for good quality results, please uncomment the following mesh operations lines
+# m2d.mesh.assign_length_mesh(
+# assignment=center_line.id,
+# maximum_length=1e-7,
+# maximum_elements=None,
+# name="center_line_0.1um",
+# )
+# m2d.mesh.assign_length_mesh(
+# assignment=dummy.name, maximum_length=2e-6, maximum_elements=1e6, name="dummy_2um"
+# )
+# m2d.mesh.assign_length_mesh(
+# assignment=ins.id,
+# maximum_length=8e-7,
+# inside_selection=False,
+# maximum_elements=1e6,
+# name="ins_0.8um",
+# )
+# m2d.mesh.assign_length_mesh(
+# assignment=[dc.id, rf.id],
+# maximum_length=5e-6,
+# inside_selection=False,
+# maximum_elements=1e6,
+# name="dc_5um",
+# )
+# m2d.mesh.assign_length_mesh(
+# assignment=gnd.id,
+# maximum_length=1e-5,
+# inside_selection=False,
+# maximum_elements=1e6,
+# name="gnd_10um",
+# )
+
+# Duplicate structures and assignments to complete the model
+
+m2d.modeler.duplicate_and_mirror(
+ assignment=[rf.id, dummy.id, ins.id],
+ origin=["0", "0", "0"],
+ vector=["-1", "0", "0"],
+ duplicate_assignment=True,
+)
+
+# Create, validate, and analyze setup
+
+setup_name = "MySetupAuto"
+setup = m2d.create_setup(name=setup_name)
+setup.props["PercentError"] = 0.1
+setup.update()
+m2d.validate_simple()
+m2d.analyze_setup(name=setup_name, use_auto_settings=False, cores=NUM_CORES)
+
+# Create parametric sweep
+
+# keeping w_rf constant, we recompute the w_dc values from the desired ratios w_rf/w_dc
+
+div_sweep_start = 1.4
+div_sweep_stop = 2
+sweep = m2d.parametrics.add(
+ variable="div",
+ start_point=div_sweep_start,
+ end_point=div_sweep_stop,
+ step=0.2,
+ variation_type="LinearStep",
+ name="w_dc_sweep",
+)
+add_points = [1, 1.3]
+[
+ sweep.add_variation(sweep_variable="div", start_point=p, variation_type="SingleValue")
+ for p in add_points
+]
+sweep["SaveFields"] = True
+sweep.analyze(cores=NUM_CORES)
+
+#
+
+# ## Postprocess
+#
+# Create the Ey expression in the PyAEDT Advanced Field Calculator
+# Due to the symmetric nature of this specific geometry, the electric field
+# node will be located along the center line. The electric field node is the
+# point where the Ey will be zero and can be found directly by Maxwell post
+# processing features
+
+e_line = m2d.post.fields_calculator.add_expression(calculation="e_line", assignment=None)
+my_plots = m2d.post.fields_calculator.expression_plot(
+ calculation="e_line", assignment="center_line", names=[e_line]
+)
+my_plots[1].edit_x_axis_scaling(min_scale="20um", max_scale="280um")
+my_plots[1].update_trace_in_report(
+ my_plots[1].get_solution_data().expressions, variations={"div": ["All"]}, context="center_line"
+)
+my_plots[1].add_cartesian_y_marker("0")
+my_plots[1].add_trace_characteristics(
+ "XAtYVal", arguments=["0"], solution_range=["Full", "20", "280"]
+)
+my_plots[1].export_table_to_file(my_plots[1].plot_name, my_path + "//" + my_node_filename, "Legend")
+
+# ## Release AEDT
+
+m2d.save_project()
+m2d.release_desktop()
+
+# ## Edit the outputted file to be read in by Lumerical
+new_line = []
+with open(my_path + my_node_filename, "r", encoding="utf-8") as f:
+ lines = f.readlines()
+new_line.append(lines[0])
+for line in lines[1:]:
+ new_line.append(line.split("\t")[0])
+ new_line.append("\n" + line.split("\t")[1].lstrip())
+with open(my_path + my_node_filename_lum, "w", encoding="utf-8") as f:
+ for line in new_line:
+ f.write(line)
+
+# ## Start the Lumerical Process
+
+GC0 = lumapi.FDTD(my_path + "GC_Opt.lsf") # run the first script: Build geometry & Run optimization
+Gc1 = lumapi.FDTD(my_path + "Readata.lsf")
+print(
+ "Optimize for the Nodal point located",
+ str(Gc1.getv("T5")),
+ "um, above the linearly apodized grating coupler",
+)
+Gc2 = lumapi.FDTD(my_path + "Testsim_Intensity_best_solution") # Run the optimized design
+Gc2.save(my_path + "GC_farfields_calc")
+Gc2.run()
+Gc2.feval(my_path + "GC_farfield.lsf") # run the second script for calculating plots
+print("Target focal distance of output laser beam, (um) :", str(Gc2.getv("Mselect") * 1000000))
+print(
+ "Actual focal distance for the optimised geometry, (um) :", str(Gc2.getv("Mactual") * 1000000)
+)
+print("Relative error:", str(Gc2.getv("RelVal") * 100), "(%)")
+print("FWHM of vertical direction at focus, (um) ", str(Gc2.getv("FWHM_X") * 1000000))
+print("FWHM of horizontal direction at focus, (um) ", str(Gc2.getv("FWHM_Y") * 1000000))
+print("Substrate material :", str(Gc2.getv("Material")))
+
+print("Waveguide etch depth, (nm) ", str(Gc2.getv("GC_etch") * 1000000000))
+print("Grating period (P), (nm) ", str(Gc2.getv("GC_period") * 1000000000))
+print("Grating minimum duty cycle:", str(Gc2.getv("GC_DCmin")))
+
+Grating_Schema = Image.open(my_path + "img_001.jpg")
+
+# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.
+time.sleep(3)
+
+# ## Clean up
+#
+
+temp_folder.cleanup()
diff --git a/maxwell2d-lumerical/README.rst b/maxwell2d-lumerical/README.rst
new file mode 100644
index 00000000..0dc866b5
--- /dev/null
+++ b/maxwell2d-lumerical/README.rst
@@ -0,0 +1,4 @@
+Maxwell2D and Lumerical
+=======================
+
+Below is an example of a geometry and meshing workflow PyAEDT and Lumerical APIS
diff --git a/maxwell2d-lumerical/Readata.lsf b/maxwell2d-lumerical/Readata.lsf
new file mode 100644
index 00000000..ecc62f52
--- /dev/null
+++ b/maxwell2d-lumerical/Readata.lsf
@@ -0,0 +1,6 @@
+cd(filedirectory(currentscriptname));
+## Read Data from ASCII file ##
+ M=readdata("legend.txt");
+
+
+ T1=M(1,1); T2=M(2,1); T3=M(3,1); T4=M(4,1); T5=M(5,1); T6=M(6,1); T7=M(7,1);
\ No newline at end of file
diff --git a/maxwell2d-lumerical/img_001.jpg b/maxwell2d-lumerical/img_001.jpg
new file mode 100644
index 00000000..a243ad07
Binary files /dev/null and b/maxwell2d-lumerical/img_001.jpg differ
diff --git a/maxwell2d-lumerical/requirements_25.1.txt b/maxwell2d-lumerical/requirements_25.1.txt
new file mode 100644
index 00000000..d4012b38
--- /dev/null
+++ b/maxwell2d-lumerical/requirements_25.1.txt
@@ -0,0 +1,2 @@
+.pyaedt [all]==0.17.3
+.PIL
\ No newline at end of file