Skip to content

Commit

Permalink
modify defaults and add double pad elmer sim
Browse files Browse the repository at this point in the history
  • Loading branch information
rmoretti9 committed Oct 22, 2024
1 parent 83c8d09 commit bc6ad8d
Show file tree
Hide file tree
Showing 20 changed files with 2,959 additions and 1 deletion.
2 changes: 1 addition & 1 deletion klayout_package/python/kqcircuits/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

TMP_PATH.mkdir(parents=True, exist_ok=True) # TODO move elsewhere?

ANSYS_EXECUTABLE = find_ansys_executable(r"%PROGRAMFILES%\AnsysEM\v241\Win64\ansysedt.exe")
ANSYS_EXECUTABLE = find_ansys_executable(r"%PROGRAMFILES%\AnsysEM\AnsysEM21.2\Win64\ansysedt.exe")
ANSYS_SCRIPT_PATHS = [
SCRIPTS_PATH.joinpath("simulations").joinpath("ansys"),
SCRIPTS_PATH.joinpath("simulations").joinpath("post_process"),
Expand Down
1 change: 1 addition & 0 deletions klayout_package/python/kqcircuits/junctions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"No Squid",
"Manhattan",
"Manhattan Single Junction",
'Manhattan Single Junction Centered',
#'QCD1',
"Sim",
]
53 changes: 53 additions & 0 deletions klayout_package/python/scripts/calculate_q_from_s.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# This code is part of KQCircuits
# Copyright (C) 2024 IQM Finland Oy
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# https://www.gnu.org/licenses/gpl-3.0.html.
#
# The software distribution should follow IQM trademark policy for open-source software
# (meetiqm.com/developers/osstmpolicy). IQM welcomes contributions to the code. Please see our contribution agreements
# for individuals (meetiqm.com/developers/clas/individual) and organizations (meetiqm.com/developers/clas/organization).
"""
Calculates Q-factors from S-parameter results.
For each port creates network where all other ports are terminated by resistor.
The Q-factor of the port is the calculated from y-parameters by imag(y) / real(y),
"""
import json
import os
import sys
import skrf

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "util"))
from post_process_helpers import read_snp_network # pylint: disable=wrong-import-position, no-name-in-module

# Find data files
path = os.path.curdir
result_files = [f for f in os.listdir(path) if f[:-2].endswith("_project_SMatrix.s")]
for result_file in result_files:
snp_network, z0s = read_snp_network(result_file)
freq = skrf.Frequency.from_f(snp_network.f)

output_data = {"frequencies": list(freq.f)}
for i, z0 in enumerate(z0s):
port = skrf.Circuit.Port(freq, "port", z0=z0)
connections = [[(snp_network, i), (port, 0)]]
for j, z0j in enumerate(z0s):
if j != i:
resistor = skrf.Circuit.SeriesImpedance(freq, z0j, f"res{j}]")
gnd = skrf.Circuit.Ground(freq, f"gnd{j}")
connections += [[(snp_network, j), (resistor, 0)], [(resistor, 1), (gnd, 0)]]
circ = skrf.Circuit(connections)
q = [y[0][0].imag / y[0][0].real for y in circ.network.y]
if any(v > 0 for v in q): # ignore ports that gets invalid q values
output_data[f"Q_port{i + 1}"] = q

output_file = result_file[:-2].replace("_project_SMatrix.s", "_q.json")
with open(output_file, "w") as f:
json.dump(output_data, f, indent=4)
97 changes: 97 additions & 0 deletions klayout_package/python/scripts/create_capacitive_pi_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# This code is part of KQCircuits
# Copyright (C) 2021 IQM Finland Oy
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# https://www.gnu.org/licenses/gpl-3.0.html.
#
# The software distribution should follow IQM trademark policy for open-source software
# (meetiqm.com/developers/osstmpolicy). IQM welcomes contributions to the code. Please see our contribution agreements
# for individuals (meetiqm.com/developers/clas/individual) and organizations (meetiqm.com/developers/clas/organization).


# This is a Python 2.7 script that should be run in Ansys Electronics Desktop in order to create capacitance matrix
# output variables.
import os
import sys
import time

import ScriptEnv

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "util"))
from util import get_enabled_setup, get_enabled_sweep # pylint: disable=wrong-import-position,no-name-in-module

# Set up environment
ScriptEnv.Initialize("Ansoft.ElectronicsDesktop")

oDesktop.RestoreWindow()
oProject = oDesktop.GetActiveProject()
oDesign = oProject.GetActiveDesign()
oBoundarySetup = oDesign.GetModule("BoundarySetup")
oOutputVariable = oDesign.GetModule("OutputVariable")


oDesktop.AddMessage("", "", 0, "Creating capacitive PI model for all ports (%s)" % time.asctime(time.localtime()))

design_type = oDesign.GetDesignType()
if design_type == "HFSS":
setup = get_enabled_setup(oDesign)
if oDesign.GetSolutionType() == "HFSS Terminal Network":
sweep = get_enabled_sweep(oDesign, setup)
solution = setup + (" : LastAdaptive" if sweep is None else " : " + sweep)
context = [] if sweep is None else ["Domain:=", "Sweep"]

ports = oBoundarySetup.GetExcitations()[::2]

for i, port_i in enumerate(ports):
for j, port_j in enumerate(ports):
# PI model admittance element
if i == j:
# admittance yii between port i and ground
expression = " + ".join(["Yt(%s,%s)" % (port_i, port_k) for port_k in ports])
else:
# admittance yij between port i and j
expression = "-Yt(%s,%s)" % (port_i, port_j)

oOutputVariable.CreateOutputVariable(
"yy_%s_%s" % (port_i, port_j), expression, solution, "Terminal Solution Data", []
)

# Estimate capacitance vs frequency assuming capacitive elements
oOutputVariable.CreateOutputVariable(
"C_%s_%s" % (port_i, port_j),
"im(yy_%s_%s)/(2*pi*Freq)" % (port_i, port_j),
solution,
"Terminal Solution Data",
[],
)

elif design_type == "Q3D Extractor":
setup = get_enabled_setup(oDesign, tab="General")
nets = oBoundarySetup.GetExcitations()[::2]
net_types = oBoundarySetup.GetExcitations()[1::2]
signal_nets = [net for net, net_type in zip(nets, net_types) if net_type == "SignalNet"]

for i, net_i in enumerate(signal_nets):
for j, net_j in enumerate(signal_nets):
if i == j:
expression = " + ".join(["C({},{})".format(net_i, net_k) for net_k in signal_nets])
else:
expression = "-C({},{})".format(net_i, net_j)

oOutputVariable.CreateOutputVariable(
"C_{}_{}".format(net_i, net_j),
expression,
setup + " : LastAdaptive",
"Matrix",
["Context:=", "Original"],
)

# Notify the end of script
oDesktop.AddMessage("", "", 0, "The capacitive PI model created (%s)" % time.asctime(time.localtime()))
179 changes: 179 additions & 0 deletions klayout_package/python/scripts/create_reports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# This code is part of KQCircuits
# Copyright (C) 2023 IQM Finland Oy
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# https://www.gnu.org/licenses/gpl-3.0.html.
#
# The software distribution should follow IQM trademark policy for open-source software
# (meetiqm.com/developers/osstmpolicy). IQM welcomes contributions to the code. Please see our contribution agreements
# for individuals (meetiqm.com/developers/clas/individual) and organizations (meetiqm.com/developers/clas/organization).


# This is a Python 2.7 script that should be run in Ansys Electronics Desktop in order to create reports.
import os
import sys
import time

import ScriptEnv

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "util"))
# fmt: off
from util import get_enabled_setup, get_enabled_sweep, create_x_vs_y_plot, get_quantities \
# pylint: disable=wrong-import-position,no-name-in-module
# fmt: on

# Set up environment
ScriptEnv.Initialize("Ansoft.ElectronicsDesktop")

oDesktop.RestoreWindow()
oProject = oDesktop.GetActiveProject()
oDesign = oProject.GetActiveDesign()
oBoundarySetup = oDesign.GetModule("BoundarySetup")
oOutputVariable = oDesign.GetModule("OutputVariable")
oReportSetup = oDesign.GetModule("ReportSetup")

# Create model separately for HFSS and Q3D
oDesktop.AddMessage("", "", 0, "Creating reports (%s)" % time.asctime(time.localtime()))

design_type = oDesign.GetDesignType()
if design_type == "HFSS":
setup = get_enabled_setup(oDesign)
if oDesign.GetSolutionType() == "HFSS Terminal Network":
sweep = get_enabled_sweep(oDesign, setup)
solution = setup + (" : LastAdaptive" if sweep is None else " : " + sweep)
context = [] if sweep is None else ["Domain:=", "Sweep"]
ports = oBoundarySetup.GetExcitations()[::2]

# Create capacitance vs frequency report
unique_elements_c = [
"C_%s_%s" % (port_i, ports[j]) for i, port_i in enumerate(ports) for j in range(i, len(ports))
] # The unique elements (half matrix), used for plotting C-matrix
unique_output_c = [e for e in unique_elements_c if e in oOutputVariable.GetOutputVariables()]
if unique_output_c:
create_x_vs_y_plot(
oReportSetup,
"Capacitance vs Frequency",
"Terminal Solution Data",
solution,
context,
["Freq:=", ["All"]],
"Freq",
"C [fF]",
unique_output_c,
)

# Create S vs frequency and S convergence reports
unique_elements_s = [
"St(%s,%s)" % (port_i, ports[j]) for i, port_i in enumerate(ports) for j in range(i, len(ports))
] # The unique elements (half matrix), used for plotting S-matrix
unique_output_s = [
"dB(%s)" % e
for e in unique_elements_s
if e in get_quantities(oReportSetup, "Terminal Solution Data", solution, context, "Terminal S Parameter")
]
if unique_output_s:
create_x_vs_y_plot(
oReportSetup,
"S vs Frequency",
"Terminal Solution Data",
solution,
context,
["Freq:=", ["All"]],
"Freq",
"S [dB]",
unique_output_s,
)
create_x_vs_y_plot(
oReportSetup,
"Solution Convergence",
"Terminal Solution Data",
setup + " : Adaptivepass",
[],
["Pass:=", ["All"], "Freq:=", ["All"]],
"Pass",
"S [dB]",
unique_output_s,
)

elif oDesign.GetSolutionType() == "Eigenmode":
# Create eigenmode convergence report
solution = setup + " : AdaptivePass"
modes = get_quantities(oReportSetup, "Eigenmode Parameters", solution, [], "Eigen Modes")
create_x_vs_y_plot(
oReportSetup,
"Solution Convergence",
"Eigenmode Parameters",
solution,
[],
["Pass:=", ["All"]],
"Pass",
"Frequency [Hz]",
["re({})".format(m) for m in modes],
)

# Create integral reports
solution = setup + " : LastAdaptive"
integrals = get_quantities(oReportSetup, "Fields", solution, [], "Calculator Expressions")
energies = [e for e in integrals if e.startswith("E_") or e.startswith("Ez_") or e.startswith("Exy_")]
if energies:
create_x_vs_y_plot(
oReportSetup, "Energy Integrals", "Fields", solution, [], ["Phase:=", ["0deg"]], "Phase", "E [J]", energies
)
fluxes = [e for e in integrals if e.startswith("flux_")]
if fluxes:
create_x_vs_y_plot(
oReportSetup,
"Magnetic Fluxes",
"Fields",
solution,
[],
["Phase:=", ["0deg"]],
"Phase",
"Magnetic flux quanta",
fluxes,
)

elif design_type == "Q3D Extractor":
setup = get_enabled_setup(oDesign, tab="General")
nets = oBoundarySetup.GetExcitations()[::2]
net_types = oBoundarySetup.GetExcitations()[1::2]
signal_nets = [net for net, net_type in zip(nets, net_types) if net_type == "SignalNet"]

# Create capacitance vs frequency and capacitance convergence reports
unique_elements_c = [
"C_%s_%s" % (net_i, signal_nets[j]) for i, net_i in enumerate(signal_nets) for j in range(i, len(signal_nets))
] # The unique elements (half matrix), used for plotting
unique_output_c = [e for e in unique_elements_c if e in oOutputVariable.GetOutputVariables()]
if unique_output_c:
create_x_vs_y_plot(
oReportSetup,
"Capacitance vs Frequency",
"Matrix",
setup + " : LastAdaptive",
["Context:=", "Original"],
["Freq:=", ["All"]],
"Freq",
"C",
unique_output_c,
)
create_x_vs_y_plot(
oReportSetup,
"Solution Convergence",
"Matrix",
setup + " : AdaptivePass",
["Context:=", "Original"],
["Pass:=", ["All"], "Freq:=", ["All"]],
"Pass",
"C",
unique_output_c,
)

# Notify the end of script
oDesktop.AddMessage("", "", 0, "Reports created (%s)" % time.asctime(time.localtime()))
35 changes: 35 additions & 0 deletions klayout_package/python/scripts/delete_all_output_variables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This code is part of KQCircuits
# Copyright (C) 2021 IQM Finland Oy
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# https://www.gnu.org/licenses/gpl-3.0.html.
#
# The software distribution should follow IQM trademark policy for open-source software
# (meetiqm.com/developers/osstmpolicy). IQM welcomes contributions to the code. Please see our contribution agreements
# for individuals (meetiqm.com/developers/clas/individual) and organizations (meetiqm.com/developers/clas/organization).


# This is a Python 2.7 script that should be run in HFSS in order to import and run the simulation
import time
import ScriptEnv

## SET UP ENVIRONMENT
ScriptEnv.Initialize("Ansoft.ElectronicsDesktop")

oDesktop.RestoreWindow()
oProject = oDesktop.GetActiveProject()
oDesign = oProject.GetActiveDesign()
oOutputVariable = oDesign.GetModule("OutputVariable")

outputvars = oOutputVariable.GetOutputVariables()
for x in outputvars:
oOutputVariable.DeleteOutputVariable(x)

oDesktop.AddMessage("", "", 0, "Deleted %d output variables (%s)" % (len(outputvars), time.asctime(time.localtime())))
Loading

0 comments on commit bc6ad8d

Please sign in to comment.