Skip to content

Commit

Permalink
Cleanup integration
Browse files Browse the repository at this point in the history
  • Loading branch information
francescov1 committed May 3, 2020
1 parent 9e2326a commit 5c5fc99
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 74 deletions.
127 changes: 79 additions & 48 deletions API/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import os
from pprint import pprint
from Lumerical import interface
#import Lumerical

class API:

Expand All @@ -8,8 +10,8 @@ def __init__(self):

def load_cache(self):
wgT = []
activeBentWg = []
passiveBentWg = []
activebentwg = []
passivebentwg = []
neff = []

for root, subdirs, files in os.walk("./Lumerical/cache"):
Expand All @@ -36,7 +38,7 @@ def load_cache(self):

elif filename.startswith("activebentwg_") and filename.endswith(".ldf"):
_, start_wavelength, end_wavelength, min_v, max_v, interval_v, _ = filename.split("_")
activeBentWg.append({
activebentwg.append({
"start_wavelength": float(start_wavelength),
"end_wavelength": float(end_wavelength),
"min_v": float(min_v),
Expand All @@ -48,21 +50,21 @@ def load_cache(self):

elif filename.startswith("passivebentwg_") and filename.endswith(".ldf"):
_, start_wavelength, end_wavelength, _ = filename.split("_")
passiveBentWg.append({
passivebentwg.append({
"start_wavelength": float(start_wavelength),
"end_wavelength": float(end_wavelength),
"filename": filename,
})
passiveBentWg.append(filename)
passivebentwg.append(filename)
break

self.wgT = wgT
self.activeBentWg = activeBentWg
self.passiveBentWg = passiveBentWg
self.activebentwg = activebentwg
self.passivebentwg = passivebentwg
self.neff = neff

def get_param_suggestions(self):

print("Getting param suggestions")
# fallbacks if no files in cache
laser_wavelength = 1545e-9
min_v = 4.5
Expand All @@ -89,64 +91,93 @@ def get_param_suggestions(self):
'constant_v': str(constant_v)
}

def run(self, params):
print("API run func called. Params:")
pprint(params)
# TODO: split each component into own function
# TODO: look into if wavelength precision changes affect cached sims

# TODO
# heat
def get_heat_sim(self):
cached_to_use = None
for cached in self.wgT:
if (params['max_v'] <= cached['max_v'] and
params['min_v'] >= cached['min_v'] and
params['interval_v'] >= cached['interval_v']):
if (self.inputs['max_v'] <= cached['max_v'] and
self.inputs['min_v'] >= cached['min_v'] and
self.inputs['interval_v'] >= cached['interval_v']):
cached_to_use = cached
break

if not cached_to_use:
print("Run heat sim")
# run sim
if cached_to_use:
print("Using cached heat simulation: " + cached_to_use['filename'])
return "cache/" + cached_to_use['filename']
else:
return interface.heat(self.inputs)


# active bend
def get_passivebentwg_sim(self):
cached_to_use = None
for cached in self.activeBentWg:
if (params['min_v'] >= cached['min_v'] and
params['max_v'] <= cached['max_v'] and
params['interval_v'] >= cached['interval_v'] and
params['start_wavelength'] >= cached['start_wavelength'] and
params['end_wavelength'] <= cached['end_wavelength']):
for cached in self.passivebentwg:
if (self.inputs['start_wavelength'] >= cached['start_wavelength'] and
self.inputs['end_wavelength'] <= cached['end_wavelength']):
cached_to_use = cached
break

if not cached_to_use:
# run sim
print("run active sim")
if cached_to_use:
print("Using cached passivebentwg simulation: " + cached_to_use['filename'])
return "cache/" + cached_to_use['filename']
else:
return interface.passivebentwg(self.inputs)


# passive bend
def get_activebentwg_sim(self):
cached_to_use = None
for cached in self.passiveBentWg:
if (params['start_wavelength'] >= cached['start_wavelength'] and
params['end_wavelength'] <= cached['end_wavelength']):
for cached in self.activebentwg:
if (self.inputs['min_v'] >= cached['min_v'] and
self.inputs['max_v'] <= cached['max_v'] and
self.inputs['interval_v'] >= cached['interval_v'] and
self.inputs['start_wavelength'] >= cached['start_wavelength'] and
self.inputs['end_wavelength'] <= cached['end_wavelength']):
cached_to_use = cached
break

if not cached_to_use:
# run sim
print("run passive sim")
if cached_to_use:
print("Using cached activebentwg simulation: " + cached_to_use['filename'])
return "cache/" + cached_to_use['filename']
else:
filename, mode = interface.activebentwg(self.inputs)

# neff
# this can then be used for neff calc, rather than reconfiguring a sim
self.lum_mode = mode
return filename


def get_effective_index_sim(self):
cached_to_use = None
for cached in self.neff:
if (params['min_v'] >= cached['min_v'] and
params['max_v'] <= cached['max_v'] and
params['interval_v'] >= cached['interval_v'] and
params['source_wavelength'] <= cached['laser_wavelength']):
if (self.inputs['min_v'] >= cached['min_v'] and
self.inputs['max_v'] <= cached['max_v'] and
self.inputs['interval_v'] >= cached['interval_v'] and
self.inputs['source_wavelength'] <= cached['laser_wavelength']):
cached_to_use = cached
break

if not cached_to_use:
# run sim
print("run neff sim")
lum_mode = self.lum_mode if hasattr(self, 'lum_mode') else None
if cached_to_use:
print("Using cached effective_index simulation: " + cached_to_use['filename'])
# if lum_mode is defined we should close it to minimize resources
# (since this sim is cached, so we dont need it)
if lum_mode is not None:
lum_mode.close()
return "cache/" + cached_to_use['filename']
else:
return interface.effective_index(self.inputs, lum_mode)

def get_interconnect_sim(self):
return "Lumerical/weight_bank.icp"

def run(self, inputs):
print("API inputs:")
pprint(inputs)
self.inputs = inputs

files = {
'heat': self.get_heat_sim(),
'passivebentwg': self.get_passivebentwg_sim(),
'activebentwg': self.get_activebentwg_sim(),
'effective_index': self.get_effective_index_sim(),
'interconnect': self.get_interconnect_sim()
}

interface.interconnect(inputs, files)
13 changes: 10 additions & 3 deletions CLI/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ def run(self):
]

params = prompt(questions)
params['min_v'] = float(params['min_v'])
params['max_v'] = float(params['max_v'])
params['interval_v'] = float(params['interval_v'])
params['source_wavelength'] = float(params['source_wavelength'])

# this is to standardize parameter names
Expand All @@ -85,5 +82,15 @@ def run(self):
params['start_wavelength'] = params['source_wavelength'] - half_window
params['end_wavelength'] = params['source_wavelength'] + half_window

if params['heater_sim_type'] == "constant voltage":
params['constant_v'] = float(params['constant_v'])
params['min_v'] = params['constant_v']
params['max_v'] = params['constant_v']
params['interval_v'] = 1
else:
params['min_v'] = float(params['min_v'])
params['max_v'] = float(params['max_v'])
params['interval_v'] = float(params['interval_v'])

self.params = params
return params
Binary file added Lumerical/cache/wgT_4.5_4.6_0.1_.mat
Binary file not shown.
88 changes: 65 additions & 23 deletions Lumerical/full_integration.py → Lumerical/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ def activebentwg_name(start_wavelength, end_wavelength, min_v, max_v, interval_v
def neff_name(laser_wavelength, min_v, max_v, interval_v):
return "cache/neff_" + str(laser_wavelength) + "_" + str(min_v) + "_" + str(max_v) + "_" + str(interval_v) + "_.txt"

def heat(min_v, max_v, interval_v):
device = lumapi.DEVICE("ndoped_heater.ldev")
def heat(inputs):
print("Running heat simulation")
min_v, max_v, interval_v = [inputs[k] for k in ('min_v','max_v', 'interval_v')]
filename = wgT_name(min_v, max_v, interval_v)

device = lumapi.DEVICE("Lumerical/ndoped_heater.ldev")
device.switchtolayout()
device.setnamed("HEAT::temp", "filename", wgT_name(min_v, max_v, interval_v))
device.setnamed("HEAT::temp", "filename", filename)

v_bc_name = "HEAT::boundary conditions::wire1"
device.setnamed(v_bc_name, "range start", min_v)
Expand All @@ -33,6 +37,7 @@ def heat(min_v, max_v, interval_v):

device.run()

'''
boundaries = device.getresult('HEAT','boundaries');
current = [x[0] for x in boundaries['I_wire1'][0][0]]
Expand All @@ -42,21 +47,26 @@ def heat(min_v, max_v, interval_v):
resistance = reg[0]
print("Resistance = " + str(resistance) + " Ohms")
'''
plt.plot(current, voltage)
plt.xlabel("current")
plt.ylabel("voltage")
plt.show()
'''

device.close()
return current, voltage
#return current, voltage

return filename


# NOTE: straight waveguides arent included here
# NOTE: this does not usually need to be re-simulated
def passiveBentWg(start_wavelength, end_wavelength):
mode = lumapi.MODE("rib_waveguide.lms")
def passivebentwg(inputs):
print("Running passive bent waveguide simulation")
start_wavelength, end_wavelength = [inputs[k] for k in ('start_wavelength', 'end_wavelength')]
filename = passivebentwg_name(start_wavelength, end_wavelength)

mode = lumapi.MODE("Lumerical/rib_waveguide.lms")

mode.switchtolayout()
mode.select("temperature")
Expand All @@ -76,14 +86,17 @@ def passiveBentWg(start_wavelength, end_wavelength):
mode.frequencysweep()

dataname = mode.copydcard("frequencysweep");
mode.savedcard(passivebentwg_name(start_wavelength, end_wavelength), dataname);
mode.savedcard(filename, dataname);
mode.close()
return

return filename

#def neffModeSolver(laser_wavelength, min_v, max_v, interval_v):
def activeBentWg(start_wavelength, end_wavelength, min_v, max_v, interval_v):
mode = lumapi.MODE("rib_waveguide.lms")
def activebentwg(inputs):
print("Running active bent waveguide simulation")
start_wavelength, end_wavelength, min_v, max_v, interval_v = [inputs[k] for k in ('start_wavelength', 'end_wavelength', 'min_v', 'max_v', 'interval_v')]
filename = activebentwg_name(start_wavelength, end_wavelength, min_v, max_v, interval_v)

mode = lumapi.MODE("Lumerical/rib_waveguide.lms")

mode.switchtolayout()
mode.select("temperature")
Expand All @@ -102,12 +115,24 @@ def activeBentWg(start_wavelength, end_wavelength, min_v, max_v, interval_v):

mode.frequencysweep()
dataname = mode.copydcard("frequencysweep")
mode.savedcard(activebentwg_name(start_wavelength, end_wavelength, min_v, max_v, interval_v), dataname)
mode.savedcard(filename, dataname)

# same sim will be used for neff.txt so dont close yet
return mode
# same sim can be used for neff.txt so dont close yet
return filename, mode

def effective_index(inputs, mode = None):
print("Running effective index simulation")
source_wavelength, min_v, max_v, interval_v = [inputs[k] for k in ('source_wavelength', 'min_v', 'max_v', 'interval_v')]
filename = neff_name(source_wavelength, min_v, max_v, interval_v)

if mode is None:
# TODO: test this for active notbeing run but neff still being run (will need to call this itself rather than get mode from activebent sim)
print("Setting up mode")
mode = lumapi.MODE("Lumerical/rib_waveguide.lms")
mode.setanalysis("number of trial modes", 2)
mode.setanalysis("wavelength", source_wavelength)
mode.setanalysis("use max index", 1)

def effective_index(mode, laser_wavelength, min_v, max_v, interval_v):
voltage = np.arange(min_v, max_v, step=interval_v) # volts
neffT = []

Expand All @@ -125,37 +150,54 @@ def effective_index(mode, laser_wavelength, min_v, max_v, interval_v):

result_str += str(v) + " " + str(np.real(neff)) + " " + str(np.imag(neff)) + "\n"

f = open(neff_name(laser_wavelength, min_v, max_v, interval_v),"w+")
f = open(filename,"w+")
f.write(result_str)
f.close()
mode.close()

return neffT
return filename

# TODO: figure out what to do with current defaults, maybe just rename them and
# put in cache although we dont want absolute paths if someone justwants to run sim
def interconnect(inputs, files):
print("Running interconnect simulation")
source_wavelength, sim_type = [inputs[k] for k in ('source_wavelength', 'sim_type')]

def interconnect(laser_wavelength, sim_type):
ic = lumapi.INTERCONNECT("weight_bank.icp")
ic = lumapi.INTERCONNECT(files['interconnect'])

ic.switchtodesign()
ic.setnamed("::Root Element","time window", time_window)
# number of samples defines the INTERCONNECT time step dt
# by dt = time_window/(Nsamples+1).
ic.setnamed("::Root Element","number of samples", n_samples)

# set simulated/cached resources
ic.setnamed("::Root Element::COMPOUND_1::WGD_6","ldf filename", files['activebentwg'])
ic.setnamed("::Root Element::COMPOUND_1::WGD_5","ldf filename", files['passivebentwg'])
ic.setnamed("::Root Element::COMPOUND_1::OM_1","measurement filename", files['effective_index'])

if sim_type == "single laser":
ic.addelement("CW Laser")
ic.setnamed("CWL_1", "frequency", c/laser_wavelength)
ic.setnamed("CWL_1", "frequency", c/source_wavelength)
ic.setnamed("CWL_1", "power", 0.001)
ic.select("ONA_1")
ic.delete()
ic.connect("CWL_1", "output", "COMPOUND_1", "input")

# TODO: if user is doing voltage sweep, run laser_sweep
else:
print("scatter")

# TODO: if user is doing voltage sweep, run ona_sweep

ic.run()
input("Simulation complete. Please export any data you would like to keep from Lumerical and press ENTER once finished.")
return ic

#heat(0,20,0.2)

#neffModeSolver(1545e-9, 0, 20, 0.2)
#mode = activeBentWg(1500e-9, 1600e-9, 0, 20, 0.2)
#mode = activebentwg(1500e-9, 1600e-9, 0, 20, 0.2)
#effective_index(mode, 1500e-9, 0, 20, 0.2)

passiveBentWg(1500e-9, 1698e-9)
#passivebentwg(1500e-9, 1698e-9)
Binary file modified Lumerical/ndoped_heater.ldev
Binary file not shown.

0 comments on commit 5c5fc99

Please sign in to comment.