From a2b21de0b0a83a6eabba0f14cccffa0a54d5d4fe Mon Sep 17 00:00:00 2001 From: Tiziana Date: Mon, 23 Jun 2025 17:50:29 +0200 Subject: [PATCH 01/16] New Maxwell2D-Lumerical Workflow for an Ion Trap Application. Requires the Lumerical *.lsf script files and img_001.jpg be downloaded to be run after the Maxwell2D results are computed. The Maxwell2D project is generated from scratch --- maxwell2d-lumerical/.gitignore | 1 + maxwell2d-lumerical/GC_Opt.lsf | 301 +++++++++++++++++++++ maxwell2d-lumerical/GC_farfield.lsf | 104 +++++++ maxwell2d-lumerical/IonTrapM2D_lum_2025.py | 246 +++++++++++++++++ maxwell2d-lumerical/README.rst | 4 + maxwell2d-lumerical/Readata.lsf | 6 + maxwell2d-lumerical/img_001.jpg | Bin 0 -> 181596 bytes maxwell2d-lumerical/requirements_25.1.txt | 2 + 8 files changed, 664 insertions(+) create mode 100644 maxwell2d-lumerical/.gitignore create mode 100644 maxwell2d-lumerical/GC_Opt.lsf create mode 100644 maxwell2d-lumerical/GC_farfield.lsf create mode 100644 maxwell2d-lumerical/IonTrapM2D_lum_2025.py create mode 100644 maxwell2d-lumerical/README.rst create mode 100644 maxwell2d-lumerical/Readata.lsf create mode 100644 maxwell2d-lumerical/img_001.jpg create mode 100644 maxwell2d-lumerical/requirements_25.1.txt diff --git a/maxwell2d-lumerical/.gitignore b/maxwell2d-lumerical/.gitignore new file mode 100644 index 000000000..e6d35e74c --- /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 000000000..f42a043c4 --- /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 000000000..aea9789bf --- /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 000000000..4b8aebb0b --- /dev/null +++ b/maxwell2d-lumerical/IonTrapM2D_lum_2025.py @@ -0,0 +1,246 @@ +# # 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 +# +# Keywords: **Ion Trap**, **Electrostatic** + +# ## Perform imports and define constants +# +# Perform required imports. + +import os,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" + +import ansys.aedt.core +import lumapi +from PIL import Image + +# 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') +Grating_Schema + +# 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 000000000..0dc866b5f --- /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 000000000..c24a79bf3 --- /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 0000000000000000000000000000000000000000..a243ad07840ee1e7115f8fdfebcdf1b55889a110 GIT binary patch literal 181596 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 Gnff2|auVYJ literal 0 HcmV?d00001 diff --git a/maxwell2d-lumerical/requirements_25.1.txt b/maxwell2d-lumerical/requirements_25.1.txt new file mode 100644 index 000000000..d4012b38d --- /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 From 3c71ca988a19d8f83617ec8e8fe29ae5557f8f2c Mon Sep 17 00:00:00 2001 From: Tiziana Date: Mon, 23 Jun 2025 17:50:52 +0200 Subject: [PATCH 02/16] New Maxwell2D-Lumerical Workflow for an Ion Trap Application. Requires the Lumerical *.lsf script files and img_001.jpg be downloaded to be run after the Maxwell2D results are computed. The Maxwell2D project is generated from scratch --- .idea/.gitignore | 3 +++ .idea/AnsysWorkflows.iml | 12 ++++++++++++ .idea/inspectionProfiles/profiles_settings.xml | 6 ++++++ .idea/misc.xml | 7 +++++++ .idea/modules.xml | 8 ++++++++ .idea/vcs.xml | 6 ++++++ 6 files changed, 42 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/AnsysWorkflows.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..26d33521a --- /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 000000000..039314de6 --- /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 000000000..105ce2da2 --- /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 000000000..c76d81abb --- /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 000000000..0395b48d2 --- /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 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 2e578a7052d6fe2e05ae718bc7245cc32eace747 Mon Sep 17 00:00:00 2001 From: Tiziana Date: Tue, 24 Jun 2025 09:21:50 +0200 Subject: [PATCH 03/16] New Maxwell2D-Lumerical Workflow for an Ion Trap Application. Requires the Lumerical *.lsf script files and img_001.jpg be downloaded to be run after the Maxwell2D results are computed. The Maxwell2D project is generated from scratch --- maxwell2d-lumerical/IonTrapM2D_lum_2025.py | 1 + 1 file changed, 1 insertion(+) diff --git a/maxwell2d-lumerical/IonTrapM2D_lum_2025.py b/maxwell2d-lumerical/IonTrapM2D_lum_2025.py index 4b8aebb0b..09c395768 100644 --- a/maxwell2d-lumerical/IonTrapM2D_lum_2025.py +++ b/maxwell2d-lumerical/IonTrapM2D_lum_2025.py @@ -6,6 +6,7 @@ # 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** From cb0dd295f8b08042943c065a47494da2a5933613 Mon Sep 17 00:00:00 2001 From: Tiziana Date: Tue, 24 Jun 2025 09:22:26 +0200 Subject: [PATCH 04/16] New Maxwell2D-Lumerical Workflow for an Ion Trap Application. Requires the Lumerical *.lsf script files and img_001.jpg be downloaded to be run after the Maxwell2D results are computed. The Maxwell2D project is generated from scratch --- maxwell2d-lumerical/IonTrapM2D_lum_2025.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maxwell2d-lumerical/IonTrapM2D_lum_2025.py b/maxwell2d-lumerical/IonTrapM2D_lum_2025.py index 09c395768..085253ead 100644 --- a/maxwell2d-lumerical/IonTrapM2D_lum_2025.py +++ b/maxwell2d-lumerical/IonTrapM2D_lum_2025.py @@ -6,7 +6,7 @@ # 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 +# 4. Launch the Lumerical Scripts # # Keywords: **Ion Trap**, **Electrostatic** From c392782d561772e5be01750072e2f0226ee9a752 Mon Sep 17 00:00:00 2001 From: Tiziana Date: Tue, 24 Jun 2025 09:35:42 +0200 Subject: [PATCH 05/16] New Maxwell2D-Lumerical Workflow for an Ion Trap Application. Requires the Lumerical *.lsf script files and img_001.jpg be downloaded to be run after the Maxwell2D results are computed. The Maxwell2D project is generated from scratch --- maxwell2d-lumerical/IonTrapM2D_lum_2025.py | 1 - 1 file changed, 1 deletion(-) diff --git a/maxwell2d-lumerical/IonTrapM2D_lum_2025.py b/maxwell2d-lumerical/IonTrapM2D_lum_2025.py index 085253ead..687bcc80d 100644 --- a/maxwell2d-lumerical/IonTrapM2D_lum_2025.py +++ b/maxwell2d-lumerical/IonTrapM2D_lum_2025.py @@ -236,7 +236,6 @@ print('Grating minimum duty cycle:',str(Gc2.getv('GC_DCmin'))) Grating_Schema = Image.open(my_path+'img_001.jpg') -Grating_Schema # Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory. time.sleep(3) From e6b6d5c803164f7040c3016a4f44c707d016b91e Mon Sep 17 00:00:00 2001 From: Roberto Pastor Muela <37798125+RobPasMue@users.noreply.github.com> Date: Tue, 24 Jun 2025 10:51:19 +0200 Subject: [PATCH 06/16] fix: code-style issues --- maxwell2d-lumerical/GC_Opt.lsf | 42 ++-- maxwell2d-lumerical/GC_farfield.lsf | 6 +- maxwell2d-lumerical/IonTrapM2D_lum_2025.py | 213 +++++++++++++-------- maxwell2d-lumerical/Readata.lsf | 4 +- 4 files changed, 164 insertions(+), 101 deletions(-) diff --git a/maxwell2d-lumerical/GC_Opt.lsf b/maxwell2d-lumerical/GC_Opt.lsf index f42a043c4..ed5df0a13 100644 --- a/maxwell2d-lumerical/GC_Opt.lsf +++ b/maxwell2d-lumerical/GC_Opt.lsf @@ -8,7 +8,7 @@ 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 +setprofile = 0; # not add the profile monitor for the first run; 1 to set this monitor um=1e-6; #################################### add simulation region/mesh/source ############################## @@ -81,7 +81,7 @@ L = n_periods*pitch_uniform + etch_width; sidewall_angle_rad = (90-sidewall_angle)*pi/180; -if(%etch depth% > %h total%) { +if(%etch depth% > %h total%) { %etch depth% = %h total%; } @@ -92,8 +92,8 @@ set("name","input waveguide"); set("vertices", vtx); set("x", 0); set("y", 0); -set("material",material); -if(get("material")=="") +set("material",material); +if(get("material")=="") { set("index",index); } set("override mesh order from material database", 1); set("mesh order", 3); @@ -106,14 +106,14 @@ if(%etch depth% < %h total%) { set("x max",%output length%); set("y min",0); set("y max",%h total%-%etch depth%); - set("material",material); - if(get("material")=="") + 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; @@ -121,11 +121,11 @@ for(i=1:(n_uniform_gratings+n_apodized_gratings)){ set("vertices", vtx); set("x", 0); set("y", 0); - set("material",material); - if(get("material")=="") + 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; @@ -133,11 +133,11 @@ for(i=1:(n_uniform_gratings+n_apodized_gratings)){ set("vertices", vtx); set("x", 0); set("y", 0); - set("material",material); - if(get("material")=="") + set("material",material); + if(get("material")=="") { set("index",index); } } - + } selectall; @@ -150,7 +150,7 @@ set("z span",1e-6); -addrect; # add +addrect; # add set("name","cladding"); set("x",19.5*um); # sets the x position set("x span",121*um); # sets the x position @@ -159,11 +159,11 @@ 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("override mesh order from material database", true); set("mesh order", 5); # material name has to be exact # add structures -addrect; # add a +addrect; # add a set("name","BOx"); set("x",19.5*um); # sets the x position set("x span",121*um); # sets the x position @@ -172,11 +172,11 @@ 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("override mesh order from material database", true); #set("mesh order", 5); # material name has to be exact # add structures -addrect; # add a +addrect; # add a set("name","Substrate"); set("x",19.5*um); # sets the x position set("x span",121*um); # sets the x position @@ -185,13 +185,13 @@ 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("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; +Mselect=M(5,1)*1e-6; ################Analysis Group####################### ## Figure of Merit --- Focus Beam ## @@ -222,7 +222,7 @@ 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); diff --git a/maxwell2d-lumerical/GC_farfield.lsf b/maxwell2d-lumerical/GC_farfield.lsf index aea9789bf..d0a21c8a1 100644 --- a/maxwell2d-lumerical/GC_farfield.lsf +++ b/maxwell2d-lumerical/GC_farfield.lsf @@ -19,7 +19,7 @@ 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); @@ -32,7 +32,7 @@ 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; + Mselect=M(5,1)*1e-6; # farfield along x axis E3_z = farfieldexact2d('near_field',x,Mselect); @@ -45,7 +45,7 @@ ind1 = find(E3_z,max(E3_z)); xmax = x(ind1); indR1 = find(E3_z,E3_z(ind1)/2); if ( ind1 Date: Thu, 16 Oct 2025 11:21:33 +0200 Subject: [PATCH 07/16] chore: remove unwanted files --- .idea/.gitignore | 3 --- .idea/AnsysWorkflows.iml | 12 ------------ .idea/inspectionProfiles/profiles_settings.xml | 6 ------ .idea/misc.xml | 7 ------- .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ 6 files changed, 42 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/AnsysWorkflows.iml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d33521a..000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/AnsysWorkflows.iml b/.idea/AnsysWorkflows.iml deleted file mode 100644 index 039314de6..000000000 --- a/.idea/AnsysWorkflows.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2da2..000000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index c76d81abb..000000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 0395b48d2..000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddfb..000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 2a2f6dedfdeb6003147f48baadc279859a3ed095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= Date: Thu, 16 Oct 2025 11:29:07 +0200 Subject: [PATCH 08/16] ci: prepare draft of workflow --- .github/workflows/maxwell2d-lumerical.yml | 116 ++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 .github/workflows/maxwell2d-lumerical.yml diff --git a/.github/workflows/maxwell2d-lumerical.yml b/.github/workflows/maxwell2d-lumerical.yml new file mode 100644 index 000000000..1b90cee80 --- /dev/null +++ b/.github/workflows/maxwell2d-lumerical.yml @@ -0,0 +1,116 @@ +name: Maxwell2D Lumerical Workflow + +on: + workflow_dispatch: + inputs: + doc-build: + required: false + default: false + type: boolean + description: 'Whether to build the documentation' + workflow_call: + inputs: + doc-build: + required: false + default: false + type: boolean + description: 'Whether to build the documentation' + push: + branches: + - main + pull_request: + paths: + - 'maxwell2d-lumerical/**' + +env: + ANSYSLMD_LICENSE_FILE: ${{ format('1055@{0}', secrets.LICENSE_SERVER )}} + ANSYS_RELEASE_FOR_DOCS: 25.2.0 + # AWP_ROOT252: 'C:\Program Files\ANSYS Inc\v252' + MAIN_PYTHON_VERSION: '3.12' + # ON_CI: true + RUN_DOC_BUILD: false + +jobs: + + maxwell2d-lumerical: + name: Maxwell2D Lumerical + runs-on: [self-hosted, Windows, pyansys-workflows] + strategy: + fail-fast: false + matrix: + ansys-release: [25.1, 25.2] + steps: + - name: Checkout code + uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2 + with: + sparse-checkout: | + maxwell2d-lumerical + doc + + - name: Set up Python ${{ env.MAIN_PYTHON_VERSION }} + uses: actions/setup-python@2e3e4b15a884dc73a63f962bff250a855150a234 # v5.6.0 + with: + python-version: ${{ env.MAIN_PYTHON_VERSION }} + + # - name: Set up environment variables + # shell: bash + # run: | + # VERSION="${{ matrix.ansys-release }}" + # ANSYS_RELEASE_SHORT="${VERSION%.*}" + # echo "ANSYS_RELEASE_SHORT=$ANSYS_RELEASE_SHORT" >> $GITHUB_ENV + # ANSYS_RELEASE_COMPACT="${ANSYS_RELEASE_SHORT//./}" + # echo "ANSYS_RELEASE_COMPACT=$ANSYS_RELEASE_COMPACT" >> $GITHUB_ENV + + - name: Install dependencies + shell: bash + run: | + python -m pip install --upgrade pip + python -m venv .venv + source .venv/Scripts/activate + pip install -r maxwell2d-lumerical/requirements_${{ matrix.ansys-release }}.txt + + - name: Run the workflow script + shell: bash + run: | + source .venv/Scripts/activate + python maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py + + - name: (DOCS) Check if docs should be built + if: (github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') && inputs.doc-build + shell: bash + run: | + echo "Requested to build docs..." + if [ "${{ matrix.ansys-release }}" = "$ANSYS_RELEASE_FOR_DOCS" ]; then + echo "Building docs" + echo "RUN_DOC_BUILD=true" >> $GITHUB_ENV + else + echo "Not building docs - since not primary release" + echo "RUN_DOC_BUILD=false" >> $GITHUB_ENV + fi + + - name: (DOCS) Build the documentation (only on ${{ env.ANSYS_RELEASE_FOR_DOCS}}) + if: ${{ env.RUN_DOC_BUILD == 'true' }} + env: + BUILD_DOCS_SCRIPT: 'maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py' + shell: bash + run: | + .venv/Scripts/activate + cd doc + pip install -r requirements.txt + ./make.bat html + + - name: (DOCS) Adapt the documentation paths + if: ${{ env.RUN_DOC_BUILD == 'true' }} + shell: bash + run: | + find . -type f -exec sed -i 's|C:\\Users\\ansys\\actions-runner\\_work\\pyansys-workflows\\pyansys-workflows\\doc\\source\\examples\\maxwell2d-lumerical\\images\\|./images/|g' {} + + + - name: (DOCS) Upload docs artifacts + if: ${{ env.RUN_DOC_BUILD == 'true' }} + uses: actions/upload-artifact@v4 + with: + name: maxwell2d-lumerical-docs + path: | + doc/_build/ + doc/source/examples/maxwell2d-lumerical/ + overwrite: true From 1f898956522ac55e179ca6d29a1737c353be0d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= Date: Thu, 16 Oct 2025 11:29:43 +0200 Subject: [PATCH 09/16] docs: add section to fill in README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 4a33c8bf8..2e1d77512 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ for every part of the simulation process. The available workflows are: - For geometry: Ansys SpaceClaim / Ansys Discovery / Ansys Geometry Service - For meshing: Ansys Fluent Meshing - For simulation: Ansys Fluent Solver + - [Geometry, mechanical and post-processing](https://github.com/ansys/pyansys-workflows/tree/main/geometry-mechanical-dpf): this workflow demonstrates how to create a printed circuit board (PCB) geometry, mesh, run steady state and transient thermal analysis, and post-process using DPF. The geometry generated is a simple PCB with multiple chips. @@ -35,10 +36,12 @@ for every part of the simulation process. The available workflows are: - For geometry: Ansys SpaceClaim / Ansys Discovery / Ansys Geometry Service - For simulation: Ansys Mechanical - For post-procesing: Ansys Data Processing Framework + - [Fluent and mechanical analysis](https://github.com/ansys/pyansys-workflows/tree/main/fluent-mechanical): this workflow demonstrates how to perform a Conjugate Heat Transfer (CHT) analysis for an exhaust manifold to simulate heat transfer between solid and fluid domains, calculate heat transfer coefficients (HTCs) and temperature distribution, and export results for thermo-mechanical analysis. The thermo-mechanical assessment is then performed to evaluate the exhaust manifold's performance under thermal cycling, aiding in design optimization for durability The involved Ansys products are: - For fluids analysis: Ansys Fluent - For thermal analysis: Ansys Mechanical + - [Speos and optiSLang robustness analysis](https://github.com/ansys/pyansys-workflows/tree/main/speos-optislang): this workflow performs a robustness study to evaluate how variations in LED source power and position influence lightguide performance using PySpeos and PyOptiSLang. The analysis quantifies performance through key metrics such as RMS contrast, average luminance, and the number of failed regulations. @@ -46,6 +49,8 @@ for every part of the simulation process. The available workflows are: - For optical analysis: Ansys Speos - For robustness analysis: Ansys optiSLang +- [Maxwell2D and Lumerical ion trap modelling](https://github.com/ansys/pyansys-workflows/tree/main/maxwell2d-lumerical): this workflow ... + ## How to run the workflows All workflows are structured in the same way, with a Python script for each part of the simulation process. From 8b2ec3928e22d6aa9b0553d7fee72d4d3de3b129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= Date: Thu, 16 Oct 2025 11:30:07 +0200 Subject: [PATCH 10/16] docs: add doc configuration --- doc/source/conf.py | 2 ++ doc/source/examples.rst | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/doc/source/conf.py b/doc/source/conf.py index b9a24a9f5..c681c3f42 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -139,6 +139,7 @@ def examples_gallery_dirs_and_filename_pattern(): "../../geometry-mesh", "../../geometry-mesh-fluent", "../../speos-optislang", + "../../maxwell2d-lumerical", ] gallery_dirs = [ "examples/fluent-mechanical", @@ -146,6 +147,7 @@ def examples_gallery_dirs_and_filename_pattern(): "examples/geometry-mesh", "examples/geometry-mesh-fluent", "examples/speos-optislang", + "examples/maxwell2d-lumerical", ] return examples_dirs, gallery_dirs, filename_pattern diff --git a/doc/source/examples.rst b/doc/source/examples.rst index daab7737b..5446adeb9 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -32,3 +32,7 @@ Workflow examples .. include:: examples/speos-optislang/index.rst :start-line: 1 :end-before: .. toctree + +.. include:: examples/maxwell2d-lumerical/index.rst + :start-line: 1 + :end-before: .. toctree From 7dca4a76bd16f8e221046ec47935d0b548ecf748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= Date: Thu, 16 Oct 2025 11:30:52 +0200 Subject: [PATCH 11/16] chore: update requirements and extend to 25.2 --- maxwell2d-lumerical/requirements_25.1.txt | 5 +++-- maxwell2d-lumerical/requirements_25.2.txt | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 maxwell2d-lumerical/requirements_25.2.txt diff --git a/maxwell2d-lumerical/requirements_25.1.txt b/maxwell2d-lumerical/requirements_25.1.txt index d4012b38d..7827613d4 100644 --- a/maxwell2d-lumerical/requirements_25.1.txt +++ b/maxwell2d-lumerical/requirements_25.1.txt @@ -1,2 +1,3 @@ -.pyaedt [all]==0.17.3 -.PIL \ No newline at end of file +pyaedt[all]==0.17.3 +Pillow==12.0.0 +ansys-api-lumerical==0.1.0 \ No newline at end of file diff --git a/maxwell2d-lumerical/requirements_25.2.txt b/maxwell2d-lumerical/requirements_25.2.txt new file mode 100644 index 000000000..7827613d4 --- /dev/null +++ b/maxwell2d-lumerical/requirements_25.2.txt @@ -0,0 +1,3 @@ +pyaedt[all]==0.17.3 +Pillow==12.0.0 +ansys-api-lumerical==0.1.0 \ No newline at end of file From b49beccc6747f86f10e0665d3ea8d9fdf8c78337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= Date: Thu, 16 Oct 2025 12:26:38 +0200 Subject: [PATCH 12/16] refactor: rename file and update content --- ...2025.py => wf_ml_01_ion_trap_modelling.py} | 93 +++++++++++-------- 1 file changed, 54 insertions(+), 39 deletions(-) rename maxwell2d-lumerical/{IonTrapM2D_lum_2025.py => wf_ml_01_ion_trap_modelling.py} (74%) diff --git a/maxwell2d-lumerical/IonTrapM2D_lum_2025.py b/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py similarity index 74% rename from maxwell2d-lumerical/IonTrapM2D_lum_2025.py rename to maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py index 913ffb100..30df112fb 100644 --- a/maxwell2d-lumerical/IonTrapM2D_lum_2025.py +++ b/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py @@ -37,36 +37,48 @@ # Perform required imports. import os -import sys +from pathlib import Path 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 +from ansys.aedt.core import Maxwell2d +from ansys.api.lumerical.lumapi import FDTD + +# sphinx_gallery_start_ignore +# Check if the __file__ variable is defined. If not, set it. +# This is a workaround to run the script in Sphinx-Gallery. +if "__file__" not in locals(): + __file__ = Path(os.getcwd(), "wf_so_01_light_guide_robustness_study.py") +# sphinx_gallery_end_ignore + +# 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" +AEDT_VERSION = os.getenv("AEDT_VERSION", "2025.1") # Set your AEDT version here NUM_CORES = 4 NG_MODE = False # Open AEDT UI when it is launched. +NODE_FILENAME = "NodePositionTable.tab" +LEGEND_FILENAME = "legend.txt" +PARENT_DIR_PATH = Path(__file__).parent.absolute() # ## Create temporary directory # temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +lumerical_script_folder = temp_folder / "lumerical_scripts" # ## Launch AEDT and application # project_name = os.path.join(temp_folder.name, "IonTrapMaxwell.aedt") -m2d = ansys.aedt.core.Maxwell2d( +m2d = Maxwell2d( project=project_name, design="01_IonTrap_3binary2D", solution_type="Electrostatic", @@ -135,7 +147,7 @@ material="vacuum", ) -# Create dummy objects for mesh, center_line for Post Processing and Region +# Create dummy objects for mesh and center_line for Post Processing and Region dummy = m2d.modeler.create_rectangle( origin=["0", "metal_thickness/2", "0"], @@ -159,7 +171,8 @@ 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 +# For good quality results, please uncomment the following mesh operations lines +# # m2d.mesh.assign_length_mesh( # assignment=center_line.id, # maximum_length=1e-7, @@ -211,7 +224,7 @@ # Create parametric sweep -# keeping w_rf constant, we recompute the w_dc values from the desired ratios w_rf/w_dc +# 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 @@ -224,15 +237,11 @@ name="w_dc_sweep", ) add_points = [1, 1.3] -[ +for p in add_points: 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 @@ -253,7 +262,8 @@ 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") +file_path = lumerical_script_folder / NODE_FILENAME +my_plots[1].export_table_to_file(my_plots[1].plot_name, str(file_path), "Legend") # ## Release AEDT @@ -261,44 +271,49 @@ 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: +with open(lumerical_script_folder / 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: +with open(lumerical_script_folder + LEGEND_FILENAME, "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") +gc_0 = FDTD( + str(PARENT_DIR_PATH / "GC_Opt.lsf") +) # Run the first script: Build geometry & Run optimization +gc_1 = FDTD(str(PARENT_DIR_PATH / "Readata.lsf")) print( "Optimize for the Nodal point located", - str(Gc1.getv("T5")), + str(gc_1.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)) +gc_2 = FDTD( + str(lumerical_script_folder / "Testsim_Intensity_best_solution") +) # Run the optimized design +gc_2.save(str(lumerical_script_folder / "GC_farfields_calc")) +gc_2.run() +gc_2.feval(str(PARENT_DIR_PATH / "GC_farfield.lsf")) # Run the second script for calculating plots +print("Target focal distance of output laser beam, (um) :", str(gc_2.getv("Mselect") * 1000000)) print( - "Actual focal distance for the optimised geometry, (um) :", str(Gc2.getv("Mactual") * 1000000) + "Actual focal distance for the optimised geometry, (um) :", str(gc_2.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("Relative error:", str(gc_2.getv("RelVal") * 100), "(%)") +print("FWHM of vertical direction at focus, (um) ", str(gc_2.getv("FWHM_X") * 1000000)) +print("FWHM of horizontal direction at focus, (um) ", str(gc_2.getv("FWHM_Y") * 1000000)) +print("Substrate material :", str(gc_2.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"))) +print("Waveguide etch depth, (nm) ", str(gc_2.getv("GC_etch") * 1000000000)) +print("Grating period (P), (nm) ", str(gc_2.getv("GC_period") * 1000000000)) +print("Grating minimum duty cycle:", str(gc_2.getv("GC_DCmin"))) -Grating_Schema = Image.open(my_path + "img_001.jpg") +# 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) From 1c990c2e1f65482e9e18a7260e528d16828003e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= Date: Wed, 22 Oct 2025 11:47:30 +0200 Subject: [PATCH 13/16] fix: wrong name of file --- maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py b/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py index 30df112fb..79eeb7ce3 100644 --- a/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py +++ b/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py @@ -49,7 +49,7 @@ # Check if the __file__ variable is defined. If not, set it. # This is a workaround to run the script in Sphinx-Gallery. if "__file__" not in locals(): - __file__ = Path(os.getcwd(), "wf_so_01_light_guide_robustness_study.py") + __file__ = Path(os.getcwd(), "wf_ml_01_ion_trap_modelling.py") # sphinx_gallery_end_ignore # sys.path.append("C:\\Program Files\\Lumerical\\v251\\api\\python\\") From 6897616c5a89c091aecadbf5cca206a8b8e3ee65 Mon Sep 17 00:00:00 2001 From: Tiziana Date: Thu, 20 Nov 2025 17:49:12 +0100 Subject: [PATCH 14/16] New M2D-Lumerical Workflow for an Ion Trap Application. Requires the downloads of the files as per lines 281-285. Updated with the new PyLumerical package. Also Readme has been updated --- maxwell2d-lumerical/README.rst | 9 ++- .../wf_ml_01_ion_trap_modelling.py | 73 ++++++++++--------- 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/maxwell2d-lumerical/README.rst b/maxwell2d-lumerical/README.rst index 0dc866b5f..43a347c4d 100644 --- a/maxwell2d-lumerical/README.rst +++ b/maxwell2d-lumerical/README.rst @@ -1,4 +1,11 @@ Maxwell2D and Lumerical ======================= -Below is an example of a geometry and meshing workflow PyAEDT and Lumerical APIS +Surface electrodes adjacent to grating couplers render an integrated ion trap. In this +workflow we model surface electrodes using ANSYS Maxwell and grating couplers using +ANSYS Lumerical.ANSYS Maxwell finite element method electrostatic solver allows to +evaluate the the ion trap height.Then the coordinates of the ion trap are passed to an optimization +algorithm to define the optimal two dimensional grating coupler design, which will focus the laser +beam at the ion trap height. + + diff --git a/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py b/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py index 79eeb7ce3..d9b323360 100644 --- a/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py +++ b/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py @@ -40,10 +40,12 @@ from pathlib import Path import tempfile import time +import shutil +import numpy as np +import matplotlib.pyplot as plt -# from PIL import Image from ansys.aedt.core import Maxwell2d -from ansys.api.lumerical.lumapi import FDTD +import ansys.lumerical.core as lumapi # sphinx_gallery_start_ignore # Check if the __file__ variable is defined. If not, set it. @@ -52,16 +54,9 @@ __file__ = Path(os.getcwd(), "wf_ml_01_ion_trap_modelling.py") # sphinx_gallery_end_ignore -# 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" - - # Define constants. -AEDT_VERSION = os.getenv("AEDT_VERSION", "2025.1") # Set your AEDT version here +AEDT_VERSION = os.getenv("AEDT_VERSION", "2025.2") # Set your AEDT version here NUM_CORES = 4 NG_MODE = False # Open AEDT UI when it is launched. NODE_FILENAME = "NodePositionTable.tab" @@ -72,7 +67,7 @@ # temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") -lumerical_script_folder = temp_folder / "lumerical_scripts" +lumerical_script_folder = Path(temp_folder.name)#/ "lumerical_scripts" # ## Launch AEDT and application # @@ -160,7 +155,7 @@ 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"]], + points=[["0", "metal_thickness/2", "0"], ["0", "metal_thickness/2+200um", "0"]], name="center_line", ) @@ -254,52 +249,56 @@ 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].edit_x_axis_scaling(min_scale="20um", max_scale="200um") 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"] + "XAtYVal", arguments=["0"], solution_range=["Full", "20", "200"] ) -file_path = lumerical_script_folder / NODE_FILENAME -my_plots[1].export_table_to_file(my_plots[1].plot_name, str(file_path), "Legend") - -# ## Release AEDT - -m2d.save_project() -m2d.release_desktop() +write_path = lumerical_script_folder / NODE_FILENAME +my_plots[1].export_table_to_file(my_plots[1].plot_name, write_path.__str__(),table_type="Legend") # ## Edit the outputted file to be read in by Lumerical new_line = [] -with open(lumerical_script_folder / NODE_FILENAME, "r", encoding="utf-8") as f: +with open((lumerical_script_folder / NODE_FILENAME).__str__(), "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(lumerical_script_folder + LEGEND_FILENAME, "w", encoding="utf-8") as f: +with open((lumerical_script_folder / LEGEND_FILENAME).__str__(), "w", encoding="utf-8") as f: for line in new_line: f.write(line) -# ## Start the Lumerical Process +# ## Copy Lumerical scripts to the local folder +#from ansys.aedt.core.examples.downloads import download_leaf +#file_name_xlsx = download_file( +# source="field_line_traces", name="my_copper.xlsx", local_path=temp_folder.name +#) +scripts_source_path = Path(r"C:\AnsysDev\AnsysWorkflows\maxwell2d-lumerical") +shutil.copy((scripts_source_path/Path("GC_farfield.lsf")).__str__(),lumerical_script_folder.__str__()) +shutil.copy((scripts_source_path/Path("GC_Opt.lsf")).__str__(),lumerical_script_folder.__str__()) +shutil.copy((scripts_source_path/Path("Readata.lsf")).__str__(),lumerical_script_folder.__str__()) +shutil.copy((scripts_source_path/Path("img_001.jpg")).__str__(),lumerical_script_folder.__str__()) -gc_0 = FDTD( - str(PARENT_DIR_PATH / "GC_Opt.lsf") -) # Run the first script: Build geometry & Run optimization -gc_1 = FDTD(str(PARENT_DIR_PATH / "Readata.lsf")) +# ## Start the Lumerical Process +fdtd = lumapi.FDTD() +gc_0 = lumapi.FDTD((lumerical_script_folder/Path("GC_Opt.lsf")).__str__()) # Run the first script: Build geometry & Run optimization +gc_1 = lumapi.FDTD((lumerical_script_folder/Path("Readata.lsf")).__str__()) print( "Optimize for the Nodal point located", str(gc_1.getv("T5")), "um, above the linearly apodized grating coupler", ) -gc_2 = FDTD( - str(lumerical_script_folder / "Testsim_Intensity_best_solution") -) # Run the optimized design -gc_2.save(str(lumerical_script_folder / "GC_farfields_calc")) +# Run the optimized design +gc_2 = lumapi.FDTD((lumerical_script_folder/Path("Testsim_Intensity_best_solution")).__str__()) +gc_2.save((lumerical_script_folder/Path("GC_farfields_calc")).__str__()) gc_2.run() -gc_2.feval(str(PARENT_DIR_PATH / "GC_farfield.lsf")) # Run the second script for calculating plots +# Run the second script for calculating plots +gc_2.feval((lumerical_script_folder/Path("GC_farfield.lsf")).__str__()) print("Target focal distance of output laser beam, (um) :", str(gc_2.getv("Mselect") * 1000000)) print( "Actual focal distance for the optimised geometry, (um) :", str(gc_2.getv("Mactual") * 1000000) @@ -313,7 +312,13 @@ print("Grating period (P), (nm) ", str(gc_2.getv("GC_period") * 1000000000)) print("Grating minimum duty cycle:", str(gc_2.getv("GC_DCmin"))) -# Grating_Schema = Image.open(my_path + "img_001.jpg") +from PIL import Image +Grating_Schema = Image.open("img_001.jpg") +Grating_Schema + +# ## Release AEDT + +m2d.save_project() # Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory. time.sleep(3) From c42a75cc86ed1fb61718e7dde0331570e2a548de Mon Sep 17 00:00:00 2001 From: Tiziana Date: Tue, 25 Nov 2025 15:25:00 +0100 Subject: [PATCH 15/16] New M2D-Lumerical Workflow for an Ion Trap Application. Requires the downloads of the files as per lines 281-285. Updated with the new PyLumerical package. Also Readme has been updated --- maxwell2d-lumerical/README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/maxwell2d-lumerical/README.rst b/maxwell2d-lumerical/README.rst index 43a347c4d..476efa157 100644 --- a/maxwell2d-lumerical/README.rst +++ b/maxwell2d-lumerical/README.rst @@ -7,5 +7,7 @@ ANSYS Lumerical.ANSYS Maxwell finite element method electrostatic solver allows evaluate the the ion trap height.Then the coordinates of the ion trap are passed to an optimization algorithm to define the optimal two dimensional grating coupler design, which will focus the laser beam at the ion trap height. +This workflow is explained in detail in this article: +https://optics.ansys.com/hc/en-us/articles/20715978394131-Integrated-Ion-Traps-using-Surface-Electrodes-and-Grating-Couplers From f9327c508d7ba635e0a0baebb2251f8b34afd8a0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 08:57:54 +0000 Subject: [PATCH 16/16] chore: auto fixes from pre-commit hooks --- .../wf_ml_01_ion_trap_modelling.py | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py b/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py index d9b323360..fa3dffd27 100644 --- a/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py +++ b/maxwell2d-lumerical/wf_ml_01_ion_trap_modelling.py @@ -38,14 +38,14 @@ import os from pathlib import Path +import shutil import tempfile import time -import shutil -import numpy as np -import matplotlib.pyplot as plt from ansys.aedt.core import Maxwell2d import ansys.lumerical.core as lumapi +import matplotlib.pyplot as plt +import numpy as np # sphinx_gallery_start_ignore # Check if the __file__ variable is defined. If not, set it. @@ -67,7 +67,7 @@ # temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") -lumerical_script_folder = Path(temp_folder.name)#/ "lumerical_scripts" +lumerical_script_folder = Path(temp_folder.name) # / "lumerical_scripts" # ## Launch AEDT and application # @@ -258,7 +258,7 @@ "XAtYVal", arguments=["0"], solution_range=["Full", "20", "200"] ) write_path = lumerical_script_folder / NODE_FILENAME -my_plots[1].export_table_to_file(my_plots[1].plot_name, write_path.__str__(),table_type="Legend") +my_plots[1].export_table_to_file(my_plots[1].plot_name, write_path.__str__(), table_type="Legend") # ## Edit the outputted file to be read in by Lumerical @@ -274,31 +274,39 @@ f.write(line) # ## Copy Lumerical scripts to the local folder -#from ansys.aedt.core.examples.downloads import download_leaf -#file_name_xlsx = download_file( +# from ansys.aedt.core.examples.downloads import download_leaf +# file_name_xlsx = download_file( # source="field_line_traces", name="my_copper.xlsx", local_path=temp_folder.name -#) +# ) scripts_source_path = Path(r"C:\AnsysDev\AnsysWorkflows\maxwell2d-lumerical") -shutil.copy((scripts_source_path/Path("GC_farfield.lsf")).__str__(),lumerical_script_folder.__str__()) -shutil.copy((scripts_source_path/Path("GC_Opt.lsf")).__str__(),lumerical_script_folder.__str__()) -shutil.copy((scripts_source_path/Path("Readata.lsf")).__str__(),lumerical_script_folder.__str__()) -shutil.copy((scripts_source_path/Path("img_001.jpg")).__str__(),lumerical_script_folder.__str__()) +shutil.copy( + (scripts_source_path / Path("GC_farfield.lsf")).__str__(), lumerical_script_folder.__str__() +) +shutil.copy((scripts_source_path / Path("GC_Opt.lsf")).__str__(), lumerical_script_folder.__str__()) +shutil.copy( + (scripts_source_path / Path("Readata.lsf")).__str__(), lumerical_script_folder.__str__() +) +shutil.copy( + (scripts_source_path / Path("img_001.jpg")).__str__(), lumerical_script_folder.__str__() +) # ## Start the Lumerical Process fdtd = lumapi.FDTD() -gc_0 = lumapi.FDTD((lumerical_script_folder/Path("GC_Opt.lsf")).__str__()) # Run the first script: Build geometry & Run optimization -gc_1 = lumapi.FDTD((lumerical_script_folder/Path("Readata.lsf")).__str__()) +gc_0 = lumapi.FDTD( + (lumerical_script_folder / Path("GC_Opt.lsf")).__str__() +) # Run the first script: Build geometry & Run optimization +gc_1 = lumapi.FDTD((lumerical_script_folder / Path("Readata.lsf")).__str__()) print( "Optimize for the Nodal point located", str(gc_1.getv("T5")), "um, above the linearly apodized grating coupler", ) # Run the optimized design -gc_2 = lumapi.FDTD((lumerical_script_folder/Path("Testsim_Intensity_best_solution")).__str__()) -gc_2.save((lumerical_script_folder/Path("GC_farfields_calc")).__str__()) +gc_2 = lumapi.FDTD((lumerical_script_folder / Path("Testsim_Intensity_best_solution")).__str__()) +gc_2.save((lumerical_script_folder / Path("GC_farfields_calc")).__str__()) gc_2.run() # Run the second script for calculating plots -gc_2.feval((lumerical_script_folder/Path("GC_farfield.lsf")).__str__()) +gc_2.feval((lumerical_script_folder / Path("GC_farfield.lsf")).__str__()) print("Target focal distance of output laser beam, (um) :", str(gc_2.getv("Mselect") * 1000000)) print( "Actual focal distance for the optimised geometry, (um) :", str(gc_2.getv("Mactual") * 1000000) @@ -313,6 +321,7 @@ print("Grating minimum duty cycle:", str(gc_2.getv("GC_DCmin"))) from PIL import Image + Grating_Schema = Image.open("img_001.jpg") Grating_Schema