gdsfactoryplus 1.3.13__cp313-cp313-win_amd64.whl → 1.3.14rc1__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of gdsfactoryplus might be problematic. Click here for more details.
- PYREADME.md +1 -1
- gdsfactoryplus/__init__.py +5 -2
- gdsfactoryplus/__init__.pyi +12 -6
- gdsfactoryplus/assets/templates/sax/base.html +376 -0
- gdsfactoryplus/assets/templates/sax/chart.html +299 -0
- gdsfactoryplus/assets/templates/sax/model-selector.html +488 -0
- gdsfactoryplus/assets/templates/sax/options.html +145 -0
- gdsfactoryplus/assets/templates/sax/parameter-editor.html +446 -0
- gdsfactoryplus/assets/templates/sax/port-selector.html +167 -0
- gdsfactoryplus/assets/templates/sax/probes.html +708 -0
- gdsfactoryplus/assets/templates/sax/styles.css +343 -0
- gdsfactoryplus/assets/templates/sax/wavelength-slider.html +388 -0
- gdsfactoryplus/assets/templates/viewer3d/base.html +650 -0
- gdsfactoryplus/assets/three-cad-viewer/three-cad-viewer.css +958 -0
- gdsfactoryplus/assets/three-cad-viewer/three-cad-viewer.esm.js +87784 -0
- gdsfactoryplus/cli/configure.py +1 -1
- gdsfactoryplus/core/__init__.py +1 -0
- gdsfactoryplus/core/__init__.pyi +2 -0
- gdsfactoryplus/core/bbox.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/build.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/callgraph.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/check.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/communication.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/database.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/export_spice.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/freeze.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/get_netlist.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/gfp_vlsir.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/imports.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/initialize.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/kcl.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/lazy.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/lvs.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/models.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/parse_spice.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/pdk.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/schema.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/shared.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/show3d.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/show_cell.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/core/simulation_storage.cp313-win_amd64.pyd +0 -0
- gdsfactoryplus/gdsfactoryplus.cp312-win_amd64.pyd +0 -0
- gdsfactoryplus/models.py +38 -0
- gdsfactoryplus/serve/__init__.py +42 -4
- gdsfactoryplus/serve/api.py +1 -48
- gdsfactoryplus/serve/sax.py +812 -0
- gdsfactoryplus/serve/viewer3d.py +150 -0
- gdsfactoryplus/settings.py +14 -2
- gdsfactoryplus/sim.py +117 -34
- gdsfactoryplus/version.py +1 -1
- {gdsfactoryplus-1.3.13.dist-info → gdsfactoryplus-1.3.14rc1.dist-info}/METADATA +2 -2
- gdsfactoryplus-1.3.14rc1.dist-info/RECORD +90 -0
- gdsfactoryplus/simulate.py +0 -173
- gdsfactoryplus-1.3.13.dist-info/RECORD +0 -76
- {gdsfactoryplus-1.3.13.dist-info → gdsfactoryplus-1.3.14rc1.dist-info}/WHEEL +0 -0
- {gdsfactoryplus-1.3.13.dist-info → gdsfactoryplus-1.3.14rc1.dist-info}/entry_points.txt +0 -0
PYREADME.md
CHANGED
gdsfactoryplus/__init__.py
CHANGED
|
@@ -11,6 +11,8 @@ __all__ = [
|
|
|
11
11
|
"F",
|
|
12
12
|
"FrozenPdk",
|
|
13
13
|
"Logger",
|
|
14
|
+
"ServerInfo",
|
|
15
|
+
"ServerRegistry",
|
|
14
16
|
"__version__",
|
|
15
17
|
"activate_pdk_by_name",
|
|
16
18
|
"add_components",
|
|
@@ -58,10 +60,11 @@ __all__ = [
|
|
|
58
60
|
"get_ports",
|
|
59
61
|
"get_project_dir",
|
|
60
62
|
"get_project_name",
|
|
63
|
+
"get_registry_path",
|
|
61
64
|
"get_runtime_factories_dependency_graph",
|
|
62
65
|
"get_runtime_factory_dependencies",
|
|
63
|
-
"get_schematic_recnet",
|
|
64
66
|
"get_settings",
|
|
67
|
+
"get_sim_x",
|
|
65
68
|
"get_static_records",
|
|
66
69
|
"get_svg",
|
|
67
70
|
"get_wls",
|
|
@@ -78,6 +81,7 @@ __all__ = [
|
|
|
78
81
|
"merge_rdb_strings",
|
|
79
82
|
"none",
|
|
80
83
|
"parse_oc_spice",
|
|
84
|
+
"ping_server",
|
|
81
85
|
"plot_callgraph",
|
|
82
86
|
"print_to_file",
|
|
83
87
|
"register_cells",
|
|
@@ -97,7 +101,6 @@ __all__ = [
|
|
|
97
101
|
"show",
|
|
98
102
|
"show3d",
|
|
99
103
|
"show_cell",
|
|
100
|
-
"simulate",
|
|
101
104
|
"sync_from_kcl",
|
|
102
105
|
"try_func",
|
|
103
106
|
"unlazy",
|
gdsfactoryplus/__init__.pyi
CHANGED
|
@@ -49,6 +49,7 @@ from .core import (
|
|
|
49
49
|
merge_rdb_strings,
|
|
50
50
|
none,
|
|
51
51
|
parse_oc_spice,
|
|
52
|
+
ping_server,
|
|
52
53
|
plot_callgraph,
|
|
53
54
|
print_to_file,
|
|
54
55
|
register_cells,
|
|
@@ -85,6 +86,11 @@ from .project import (
|
|
|
85
86
|
find_project_dir,
|
|
86
87
|
maybe_find_project_dir,
|
|
87
88
|
)
|
|
89
|
+
from .registry import (
|
|
90
|
+
ServerInfo,
|
|
91
|
+
ServerRegistry,
|
|
92
|
+
get_registry_path,
|
|
93
|
+
)
|
|
88
94
|
from .settings import (
|
|
89
95
|
get_build_dir,
|
|
90
96
|
get_db_path,
|
|
@@ -95,6 +101,7 @@ from .settings import (
|
|
|
95
101
|
get_project_dir,
|
|
96
102
|
get_project_name,
|
|
97
103
|
get_settings,
|
|
104
|
+
get_sim_x,
|
|
98
105
|
get_wls,
|
|
99
106
|
ignored_paths,
|
|
100
107
|
is_a_pdk,
|
|
@@ -102,10 +109,6 @@ from .settings import (
|
|
|
102
109
|
from .show import (
|
|
103
110
|
show,
|
|
104
111
|
)
|
|
105
|
-
from .simulate import (
|
|
106
|
-
get_schematic_recnet,
|
|
107
|
-
simulate,
|
|
108
|
-
)
|
|
109
112
|
from .version import (
|
|
110
113
|
__version__,
|
|
111
114
|
)
|
|
@@ -115,6 +118,8 @@ __all__ = [
|
|
|
115
118
|
"F",
|
|
116
119
|
"FrozenPdk",
|
|
117
120
|
"Logger",
|
|
121
|
+
"ServerInfo",
|
|
122
|
+
"ServerRegistry",
|
|
118
123
|
"__version__",
|
|
119
124
|
"activate_pdk_by_name",
|
|
120
125
|
"add_components",
|
|
@@ -162,10 +167,11 @@ __all__ = [
|
|
|
162
167
|
"get_ports",
|
|
163
168
|
"get_project_dir",
|
|
164
169
|
"get_project_name",
|
|
170
|
+
"get_registry_path",
|
|
165
171
|
"get_runtime_factories_dependency_graph",
|
|
166
172
|
"get_runtime_factory_dependencies",
|
|
167
|
-
"get_schematic_recnet",
|
|
168
173
|
"get_settings",
|
|
174
|
+
"get_sim_x",
|
|
169
175
|
"get_static_records",
|
|
170
176
|
"get_svg",
|
|
171
177
|
"get_wls",
|
|
@@ -182,6 +188,7 @@ __all__ = [
|
|
|
182
188
|
"merge_rdb_strings",
|
|
183
189
|
"none",
|
|
184
190
|
"parse_oc_spice",
|
|
191
|
+
"ping_server",
|
|
185
192
|
"plot_callgraph",
|
|
186
193
|
"print_to_file",
|
|
187
194
|
"register_cells",
|
|
@@ -201,7 +208,6 @@ __all__ = [
|
|
|
201
208
|
"show",
|
|
202
209
|
"show3d",
|
|
203
210
|
"show_cell",
|
|
204
|
-
"simulate",
|
|
205
211
|
"sync_from_kcl",
|
|
206
212
|
"try_func",
|
|
207
213
|
"unlazy",
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>SAX - {{ name }}</title>
|
|
7
|
+
<link
|
|
8
|
+
rel="stylesheet"
|
|
9
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
|
|
10
|
+
/>
|
|
11
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
12
|
+
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom"></script>
|
|
13
|
+
<style>
|
|
14
|
+
{% include 'styles.css' %}
|
|
15
|
+
</style>
|
|
16
|
+
</head>
|
|
17
|
+
|
|
18
|
+
<body>
|
|
19
|
+
<div class="container">
|
|
20
|
+
<div class="header">
|
|
21
|
+
<div class="title">
|
|
22
|
+
<i class="fas fa-wave-square"></i>
|
|
23
|
+
SAX Simulation
|
|
24
|
+
</div>
|
|
25
|
+
<div class="subtitle">{{ name }}</div>
|
|
26
|
+
{% if has_netlist_source %}
|
|
27
|
+
<div class="source-toggle" id="source-toggle">
|
|
28
|
+
<span class="source-toggle-label">Source:</span>
|
|
29
|
+
<div class="source-toggle-buttons">
|
|
30
|
+
<button
|
|
31
|
+
class="source-toggle-btn active"
|
|
32
|
+
data-mode="layout"
|
|
33
|
+
>
|
|
34
|
+
<i class="fas fa-shapes"></i> Layout
|
|
35
|
+
</button>
|
|
36
|
+
<button class="source-toggle-btn" data-mode="netlist">
|
|
37
|
+
<i class="fas fa-project-diagram"></i> Netlist
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
{% endif %}
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
{# Global Error Banner #}
|
|
45
|
+
<div class="error-banner" id="error-banner" style="display: none">
|
|
46
|
+
<div class="error-banner-icon">
|
|
47
|
+
<i class="fas fa-exclamation-triangle"></i>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="error-banner-content">
|
|
50
|
+
<div class="error-banner-title">
|
|
51
|
+
Error while building the layout for
|
|
52
|
+
<strong>{{ name }}</strong>
|
|
53
|
+
</div>
|
|
54
|
+
<div
|
|
55
|
+
class="error-banner-message"
|
|
56
|
+
id="error-banner-message"
|
|
57
|
+
></div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
{# Results Section - Plot on top #}
|
|
62
|
+
<div class="section results-section" id="results-section">
|
|
63
|
+
<div class="section-title">
|
|
64
|
+
<i class="fas fa-chart-line"></i>
|
|
65
|
+
Results
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
{# Port Selector Component #} {% include 'port-selector.html' %}
|
|
69
|
+
{# Chart Component #} {% include 'chart.html' %}
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
{# Wavelength Slider Component #} {% include
|
|
73
|
+
'wavelength-slider.html' %} {# Options Component #} {% include
|
|
74
|
+
'options.html' %} {# Probes Component #} {% include 'probes.html' %}
|
|
75
|
+
{# Model Selector Component #} {% include 'model-selector.html' %}
|
|
76
|
+
{# Parameter Editor Component #} {% include 'parameter-editor.html'
|
|
77
|
+
%} {# Simulate Button #}
|
|
78
|
+
<button class="btn btn-primary simulate-btn" id="simulate-btn">
|
|
79
|
+
<i class="fas fa-play"></i>
|
|
80
|
+
Simulate
|
|
81
|
+
</button>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<script>
|
|
85
|
+
const FACTORY_NAME = "{{ name }}";
|
|
86
|
+
|
|
87
|
+
// Configuration auto-sync module
|
|
88
|
+
const ConfigSync = (function() {
|
|
89
|
+
let saveTimeout = null;
|
|
90
|
+
let initialConfig = null;
|
|
91
|
+
|
|
92
|
+
async function load() {
|
|
93
|
+
try {
|
|
94
|
+
const response = await fetch(`/api/sax/${FACTORY_NAME}/config`);
|
|
95
|
+
const data = await response.json();
|
|
96
|
+
if (data.config) {
|
|
97
|
+
initialConfig = data.config;
|
|
98
|
+
return data.config;
|
|
99
|
+
}
|
|
100
|
+
} catch (err) {
|
|
101
|
+
console.warn("Failed to load config:", err);
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function save() {
|
|
107
|
+
// Debounce saves
|
|
108
|
+
if (saveTimeout) clearTimeout(saveTimeout);
|
|
109
|
+
saveTimeout = setTimeout(doSave, 500);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function doSave() {
|
|
113
|
+
try {
|
|
114
|
+
const wl = WavelengthSlider.getWavelengths();
|
|
115
|
+
const config = {
|
|
116
|
+
x: {
|
|
117
|
+
name: WavelengthSlider.isFrequency() ? "f" : "wl",
|
|
118
|
+
min: wl.min,
|
|
119
|
+
max: wl.max,
|
|
120
|
+
num: wl.num
|
|
121
|
+
},
|
|
122
|
+
options: Options.getOptions(),
|
|
123
|
+
probes: Probes.getConfig().probes,
|
|
124
|
+
models: ModelSelector.getSelectedModels(),
|
|
125
|
+
parameters: ParameterEditor.getParams(),
|
|
126
|
+
source: SourceMode.getMode()
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
await fetch(`/api/sax/${FACTORY_NAME}/config`, {
|
|
130
|
+
method: "POST",
|
|
131
|
+
headers: { "Content-Type": "application/json" },
|
|
132
|
+
body: JSON.stringify(config)
|
|
133
|
+
});
|
|
134
|
+
} catch (err) {
|
|
135
|
+
console.warn("Failed to save config:", err);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function getInitialConfig() {
|
|
140
|
+
return initialConfig;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return { load, save, getInitialConfig };
|
|
144
|
+
})();
|
|
145
|
+
|
|
146
|
+
// Source Mode Toggle module
|
|
147
|
+
const SourceMode = (function() {
|
|
148
|
+
let currentMode = "layout"; // "layout" or "netlist"
|
|
149
|
+
let changeCallbacks = [];
|
|
150
|
+
|
|
151
|
+
function init(savedMode = null) {
|
|
152
|
+
const toggle = document.getElementById("source-toggle");
|
|
153
|
+
if (!toggle) return; // Toggle not present (no netlist source)
|
|
154
|
+
|
|
155
|
+
// Restore saved mode if valid
|
|
156
|
+
if (savedMode === "layout" || savedMode === "netlist") {
|
|
157
|
+
currentMode = savedMode;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const buttons = toggle.querySelectorAll(".source-toggle-btn");
|
|
161
|
+
|
|
162
|
+
// Set initial button states
|
|
163
|
+
buttons.forEach(b => b.classList.toggle("active", b.dataset.mode === currentMode));
|
|
164
|
+
|
|
165
|
+
buttons.forEach(btn => {
|
|
166
|
+
btn.addEventListener("click", () => {
|
|
167
|
+
const mode = btn.dataset.mode;
|
|
168
|
+
if (mode === currentMode) return;
|
|
169
|
+
|
|
170
|
+
currentMode = mode;
|
|
171
|
+
buttons.forEach(b => b.classList.toggle("active", b.dataset.mode === mode));
|
|
172
|
+
|
|
173
|
+
// Fire change callbacks
|
|
174
|
+
changeCallbacks.forEach(cb => cb(mode));
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function isFromNetlist() {
|
|
180
|
+
return currentMode === "netlist";
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function getMode() {
|
|
184
|
+
return currentMode;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function onChange(callback) {
|
|
188
|
+
changeCallbacks.push(callback);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return { init, isFromNetlist, getMode, onChange };
|
|
192
|
+
})();
|
|
193
|
+
|
|
194
|
+
// Global Error Banner module
|
|
195
|
+
const ErrorBanner = (function() {
|
|
196
|
+
function show(errorMessage) {
|
|
197
|
+
const banner = document.getElementById("error-banner");
|
|
198
|
+
const messageEl = document.getElementById("error-banner-message");
|
|
199
|
+
const container = document.querySelector(".container");
|
|
200
|
+
|
|
201
|
+
// Parse error type and message
|
|
202
|
+
let displayMessage = errorMessage;
|
|
203
|
+
const colonIndex = errorMessage.indexOf(":");
|
|
204
|
+
if (colonIndex > 0 && colonIndex < 50) {
|
|
205
|
+
const errorType = errorMessage.substring(0, colonIndex).trim();
|
|
206
|
+
const errorMsg = errorMessage.substring(colonIndex + 1).trim();
|
|
207
|
+
displayMessage = `${errorType}: ${errorMsg}`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
messageEl.textContent = displayMessage;
|
|
211
|
+
banner.style.display = "flex";
|
|
212
|
+
container.classList.add("has-error");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function hide() {
|
|
216
|
+
const banner = document.getElementById("error-banner");
|
|
217
|
+
const container = document.querySelector(".container");
|
|
218
|
+
|
|
219
|
+
banner.style.display = "none";
|
|
220
|
+
container.classList.remove("has-error");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function isVisible() {
|
|
224
|
+
const banner = document.getElementById("error-banner");
|
|
225
|
+
return banner.style.display !== "none";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return { show, hide, isVisible };
|
|
229
|
+
})();
|
|
230
|
+
|
|
231
|
+
// Initialize components
|
|
232
|
+
document.addEventListener("DOMContentLoaded", async () => {
|
|
233
|
+
// Load saved configuration first
|
|
234
|
+
const savedConfig = await ConfigSync.load();
|
|
235
|
+
|
|
236
|
+
// Initialize source mode toggle (if present) with saved mode
|
|
237
|
+
SourceMode.init(savedConfig?.source);
|
|
238
|
+
|
|
239
|
+
// Initialize with saved config or defaults
|
|
240
|
+
if (savedConfig?.x) {
|
|
241
|
+
const isFreq = savedConfig.x.name === "f";
|
|
242
|
+
WavelengthSlider.init(savedConfig.x.min, savedConfig.x.max, savedConfig.x.num, isFreq);
|
|
243
|
+
} else {
|
|
244
|
+
WavelengthSlider.init({{ wl_min }}, {{ wl_max }});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
PortSelector.init();
|
|
248
|
+
Options.init(savedConfig);
|
|
249
|
+
ModelSelector.init(savedConfig);
|
|
250
|
+
Probes.init(savedConfig);
|
|
251
|
+
ParameterEditor.init(savedConfig);
|
|
252
|
+
|
|
253
|
+
// When source mode changes, reload everything
|
|
254
|
+
SourceMode.onChange(() => {
|
|
255
|
+
ErrorBanner.hide();
|
|
256
|
+
Probes.loadInstances();
|
|
257
|
+
ModelSelector.loadModels(Probes.getConfig());
|
|
258
|
+
ParameterEditor.loadAvailableParams();
|
|
259
|
+
ConfigSync.save();
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Connect wavelength slider mode changes to chart
|
|
263
|
+
WavelengthSlider.onModeChange(() => {
|
|
264
|
+
SaxChart.setFrequencyMode(WavelengthSlider.isFrequency());
|
|
265
|
+
SaxChart.update();
|
|
266
|
+
ConfigSync.save();
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Auto-save when wavelength changes
|
|
270
|
+
WavelengthSlider.onChange(() => {
|
|
271
|
+
ConfigSync.save();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Reload models when probes change (affects required models)
|
|
275
|
+
Probes.onChange(() => {
|
|
276
|
+
const config = Probes.getConfig();
|
|
277
|
+
ModelSelector.loadModels(config);
|
|
278
|
+
ParameterEditor.loadAvailableParams();
|
|
279
|
+
ConfigSync.save();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Auto-save when models change
|
|
283
|
+
ModelSelector.onChange(() => {
|
|
284
|
+
ConfigSync.save();
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Auto-save when parameters change
|
|
288
|
+
ParameterEditor.onChange(() => {
|
|
289
|
+
ConfigSync.save();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Reload models and parameters when options change (recursive affects required models)
|
|
293
|
+
Options.onChange(() => {
|
|
294
|
+
ModelSelector.loadModels(Probes.getConfig());
|
|
295
|
+
ParameterEditor.loadAvailableParams();
|
|
296
|
+
ConfigSync.save();
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Simulate button handler
|
|
301
|
+
document.getElementById("simulate-btn").addEventListener("click", runSimulation);
|
|
302
|
+
|
|
303
|
+
async function runSimulation() {
|
|
304
|
+
const btn = document.getElementById("simulate-btn");
|
|
305
|
+
const resultsSection = document.getElementById("results-section");
|
|
306
|
+
|
|
307
|
+
// Get wavelength parameters
|
|
308
|
+
const wl = WavelengthSlider.getWavelengths();
|
|
309
|
+
|
|
310
|
+
// Validate wavelength
|
|
311
|
+
if (isNaN(wl.min) || isNaN(wl.max) || isNaN(wl.num)) {
|
|
312
|
+
SaxChart.showError("Invalid wavelength parameters");
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Validate models are configured
|
|
317
|
+
if (!ModelSelector.isReady()) {
|
|
318
|
+
ModelSelector.expand();
|
|
319
|
+
ModelSelector.shake();
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Show loading state
|
|
324
|
+
btn.disabled = true;
|
|
325
|
+
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Simulating...';
|
|
326
|
+
SaxChart.hideError();
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
const probesConfig = Probes.getConfig();
|
|
330
|
+
const options = Options.getOptions();
|
|
331
|
+
const response = await fetch(`/api/sax/${FACTORY_NAME}/simulate`, {
|
|
332
|
+
method: "POST",
|
|
333
|
+
headers: { "Content-Type": "application/json" },
|
|
334
|
+
body: JSON.stringify({
|
|
335
|
+
wl_min: wl.min,
|
|
336
|
+
wl_max: wl.max,
|
|
337
|
+
wl_num: wl.num,
|
|
338
|
+
layout: {},
|
|
339
|
+
model: ParameterEditor.getParams(),
|
|
340
|
+
models: ModelSelector.getSelectedModels(),
|
|
341
|
+
probes: probesConfig.probes,
|
|
342
|
+
from_netlist: SourceMode.isFromNetlist(),
|
|
343
|
+
recursive: options.recursive,
|
|
344
|
+
ignore_impossible_connections: options.ignore_impossible_connections
|
|
345
|
+
})
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const data = await response.json();
|
|
349
|
+
|
|
350
|
+
if (data.detail) {
|
|
351
|
+
SaxChart.showError(data.detail);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Update chart with data
|
|
356
|
+
SaxChart.setData(data);
|
|
357
|
+
SaxChart.setFrequencyMode(WavelengthSlider.isFrequency());
|
|
358
|
+
resultsSection.classList.add("visible");
|
|
359
|
+
|
|
360
|
+
// Setup port selectors
|
|
361
|
+
const ports = Object.keys(data.sdict || {});
|
|
362
|
+
PortSelector.setupPorts(ports);
|
|
363
|
+
|
|
364
|
+
// Update chart
|
|
365
|
+
SaxChart.update();
|
|
366
|
+
|
|
367
|
+
} catch (err) {
|
|
368
|
+
SaxChart.showError(err.message || "Simulation failed");
|
|
369
|
+
} finally {
|
|
370
|
+
btn.disabled = false;
|
|
371
|
+
btn.innerHTML = '<i class="fas fa-play"></i> Simulate';
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
</script>
|
|
375
|
+
</body>
|
|
376
|
+
</html>
|