-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1. The user can choose which parameters to run. 2. Progress bars show the progress of the simulation. 3. Simulation summary is parsed from markdown.
- Loading branch information
Showing
5 changed files
with
300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
from flask import Flask, render_template, request, Response | ||
from .parameter import ParameterManager | ||
|
||
import queue | ||
import json | ||
import os | ||
|
||
# TODO: These should be options on the web interface | ||
parameter_manager = ParameterManager(max_runs=None, run_path=None, jobs=None) | ||
parameter_manager.find_datasheet(os.getcwd()) | ||
|
||
any_queue = queue.Queue() | ||
|
||
app = Flask(__name__, template_folder='web', static_folder='web/static') | ||
|
||
|
||
@app.route('/') | ||
def homepage(): | ||
pnames = parameter_manager.get_all_pnames() | ||
data = [{'name': pname} for pname in pnames] | ||
|
||
return render_template(template_name_or_list='index.html', data=data) | ||
|
||
|
||
@app.route('/runsim', methods=['POST']) | ||
def runsim(): | ||
parameter_manager.results = {} | ||
parameter_manager.result_types = {} | ||
|
||
params = request.form.getlist('selected_params') | ||
|
||
for param in params: | ||
parameter_manager.queue_parameter( | ||
param, | ||
start_cb=lambda param, steps: ( | ||
any_queue.put( | ||
{'task': 'start', 'param': param, 'steps': steps} | ||
) | ||
), | ||
step_cb=lambda param: ( | ||
any_queue.put({'task': 'step', 'param': param}) | ||
), | ||
cancel_cb=lambda param: ( | ||
any_queue.put({'task': 'cancel', 'param': param}) | ||
), | ||
end_cb=lambda param: any_queue.put( | ||
{'task': 'end', 'param': param} | ||
), | ||
) | ||
|
||
# TODO: These should be options on the web interface | ||
parameter_manager.set_runtime_options('force', False) | ||
parameter_manager.set_runtime_options('noplot', False) | ||
parameter_manager.set_runtime_options('nosim', False) | ||
parameter_manager.set_runtime_options('sequential', False) | ||
parameter_manager.set_runtime_options('netlist_source', 'best') | ||
parameter_manager.set_runtime_options('parallel_parameters', 4) | ||
|
||
parameter_manager.run_parameters_async() | ||
return render_template(template_name_or_list='runsim.html', params=params) | ||
|
||
|
||
def generate_sse(): | ||
num_params = parameter_manager.num_parameters() | ||
datasheet = parameter_manager.datasheet['parameters'] | ||
|
||
params_completed = 0 | ||
while num_params != params_completed: | ||
aqg = any_queue.get() | ||
|
||
if aqg['task'] == 'end': | ||
params_completed += 1 | ||
elif aqg['task'] == 'end_stream': | ||
return | ||
|
||
aqg['param'] = list(datasheet.keys())[ | ||
list(datasheet.values()).index(aqg['param']) | ||
] | ||
yield f'data: {json.dumps(aqg)}\n\n' | ||
|
||
data = {'task': 'close'} | ||
yield f'data: {json.dumps(data)}\n\n' | ||
|
||
|
||
@app.route('/stream') | ||
def stream(): | ||
return Response(generate_sse(), content_type='text/event-stream') | ||
|
||
|
||
@app.route('/end_stream', methods=['POST']) | ||
def end_stream(): | ||
any_queue.put({'task': 'end_stream'}) | ||
return '', 200 | ||
|
||
|
||
@app.route('/simresults') | ||
def simresults(): | ||
parameter_manager.join_parameters() | ||
result = [] | ||
|
||
summary_lines = parameter_manager.summarize_datasheet().split('\n')[7:-2] | ||
lengths = { | ||
param: len( | ||
list( | ||
parameter_manager.datasheet['parameters'][param]['spec'].keys() | ||
) | ||
) | ||
for param in parameter_manager.get_all_pnames() | ||
} | ||
for param in parameter_manager.get_result_types().keys(): | ||
total = 0 | ||
for i in parameter_manager.get_all_pnames(): | ||
if i == param: | ||
for j in range(lengths[param]): | ||
row = summary_lines[total + j].split('|') | ||
result.append( | ||
{ | ||
'parameter_str': row[1], | ||
'tool_str': row[2], | ||
'result_str': row[3], | ||
'min_limit_str': row[4], | ||
'min_value_str': row[5], | ||
'max_limit_str': row[6], | ||
'max_value_str': row[7], | ||
'typ_limit_str': row[8], | ||
'typ_value_str': row[9], | ||
'status_str': row[10], | ||
} | ||
) | ||
|
||
total += lengths[i] | ||
|
||
return render_template( | ||
template_name_or_list='simresults.html', data=result | ||
) | ||
|
||
|
||
def web(): | ||
app.run(debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<link rel="stylesheet" href="static/style.css" /> | ||
</head> | ||
<body> | ||
<form method="POST" action="/runsim"> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th>Select</th> | ||
<th>Name</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{% for row in data %} | ||
<tr> | ||
<td class="checkbox-column"> | ||
<input | ||
type="checkbox" | ||
name="selected_params" | ||
value="{{ row.name }}" | ||
/> | ||
</td> | ||
<td>{{ row.name }}</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
<button type="submit">Submit</button> | ||
</form> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<link rel="stylesheet" href="static/style.css" /> | ||
</head> | ||
<body> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th>Select</th> | ||
<th>Name</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{% for param in params %} | ||
<tr> | ||
<td>{{ param }}</td> | ||
<td> | ||
<progress id="{{param}}" value="0" max="100"></progress> | ||
</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
|
||
<button onclick="window.open('http://localhost:5000/simresults','_blank')">Simulation Results</button> | ||
<p>Click the button above after all simulations have finished</p> | ||
|
||
<script> | ||
// Connect to the SSE stream | ||
const eventSource = new EventSource("/stream"); | ||
|
||
// Listen for messages from the server | ||
eventSource.onmessage = function (event) { | ||
let data = JSON.parse(event.data); | ||
let task = data.task; | ||
if (task == "close") { | ||
eventSource.close(); | ||
} else if (task == "start") { | ||
console.log("start"); | ||
let outputDiv = document.getElementById(data.param); | ||
outputDiv.max = data.steps; | ||
} else if (task == "step") { | ||
console.log("step"); | ||
let outputDiv = document.getElementById(data.param); | ||
outputDiv.value++; | ||
} else if (task == "cancel") { | ||
} else if (task == "end") { | ||
} | ||
}; | ||
|
||
window.onbeforeunload = function () { | ||
// Send a POST request to the /ping endpoint and ignore the response | ||
fetch(`${window.location.origin}/end_stream`, { | ||
method: "POST", | ||
}); | ||
eventSource.close(); | ||
}; | ||
|
||
eventSource.onerror = function () { | ||
console.error("Error occurred while receiving SSE."); | ||
}; | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<link rel="stylesheet" href="static/style.css" /> | ||
</head> | ||
<body> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th>Parameter</th> | ||
<th>Tool</th> | ||
<th>Result</th> | ||
<th>Minimum Limit</th> | ||
<th>Minimum Value</th> | ||
<th>Typical Limit</th> | ||
<th>Typical Value</th> | ||
<th>Maximum Limit</th> | ||
<th>Maximum Value</th> | ||
<th>Status</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{% for row in data %} | ||
<tr> | ||
<td>{{ row.parameter_str }}</td> | ||
<td>{{ row.tool_str }}</td> | ||
<td>{{ row.result_str }}</td> | ||
<td>{{ row.min_limit_str }}</td> | ||
<td>{{ row.min_value_str }}</td> | ||
<td>{{ row.max_limit_str }}</td> | ||
<td>{{ row.max_value_str }}</td> | ||
<td>{{ row.typ_limit_str }}</td> | ||
<td>{{ row.typ_value_str }}</td> | ||
<td>{{ row.status_str }}</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
table { | ||
border-collapse: collapse; | ||
margin: 25px 0; | ||
font-size: 18px; | ||
text-align: left; | ||
} | ||
table th, | ||
table td { | ||
padding: 8px; | ||
border: 1px solid #ddd; | ||
} | ||
table th { | ||
background-color: #f2f2f2; | ||
} | ||
progress { | ||
width: 300px; | ||
} |