mirror of
https://github.com/gsi-upm/soil
synced 2024-11-22 19:22:29 +00:00
Model progress info
This commit is contained in:
parent
722a82c21c
commit
459b9a771b
2
run.py
2
run.py
@ -11,5 +11,5 @@ def run(model, params=None):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
soil = Model(dump=False)
|
||||
soil = Model(dump=True)
|
||||
run(soil)
|
||||
|
52
server.py
52
server.py
@ -9,6 +9,12 @@ import webbrowser
|
||||
import yaml
|
||||
import logging
|
||||
|
||||
import logging
|
||||
import threading
|
||||
import io
|
||||
from datetime import timedelta
|
||||
from contextlib import contextmanager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
@ -54,6 +60,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
def open(self):
|
||||
if self.application.verbose:
|
||||
logger.info('Socket opened!')
|
||||
|
||||
|
||||
def check_origin(self, origin):
|
||||
return True
|
||||
@ -79,9 +86,12 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
return
|
||||
else:
|
||||
config = config[0]
|
||||
self.send_log('INFO.soil', 'Using config: {name}'.format(name=config['name']))
|
||||
|
||||
self.name = config['name']
|
||||
self.application.model.run(config)
|
||||
|
||||
with self.logging(self.application.model.name):
|
||||
self.application.model.run(config)
|
||||
|
||||
trials = []
|
||||
for i in range(config['num_trials']):
|
||||
@ -92,6 +102,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
elif msg['type'] == 'get_trial':
|
||||
if self.application.verbose:
|
||||
logger.info('Trial {} requested!'.format(msg['data']))
|
||||
self.send_log('INFO.user', 'Trial {} requested!'.format(msg['data']))
|
||||
self.write_message({'type': 'get_trial',
|
||||
'data': self.application.model.get_trial(self.name, msg['data']) })
|
||||
|
||||
@ -99,6 +110,41 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
if self.application.verbose:
|
||||
logger.info('Unexpected message!')
|
||||
|
||||
def update_logging(self):
|
||||
try:
|
||||
if (not self.log_capture_string.closed and self.log_capture_string.getvalue()):
|
||||
self.send_log('INFO.soil', self.log_capture_string.getvalue())
|
||||
self.log_capture_string.truncate(0)
|
||||
self.log_capture_string.seek(0)
|
||||
finally:
|
||||
if self.capture_logging:
|
||||
thread = threading.Timer(0.01, self.update_logging)
|
||||
thread.start()
|
||||
|
||||
def on_close(self):
|
||||
logger.info('Socket closed!')
|
||||
|
||||
def send_log(self, logger, logging):
|
||||
self.write_message({'type': 'log',
|
||||
'logger': logger,
|
||||
'logging': logging })
|
||||
|
||||
@contextmanager
|
||||
def logging(self, logger):
|
||||
self.capture_logging = True
|
||||
self.logger_application = logging.getLogger(logger)
|
||||
self.log_capture_string = io.StringIO()
|
||||
ch = logging.StreamHandler(self.log_capture_string)
|
||||
self.logger_application.addHandler(ch)
|
||||
self.update_logging()
|
||||
yield self.capture_logging
|
||||
|
||||
self.capture_logging = False
|
||||
self.log_capture_string.close()
|
||||
self.logger_application.removeHandler(ch)
|
||||
return self.capture_logging
|
||||
|
||||
|
||||
|
||||
class ModularServer(tornado.web.Application):
|
||||
""" Main visualization application. """
|
||||
@ -110,7 +156,6 @@ class ModularServer(tornado.web.Application):
|
||||
page_handler = (r'/', PageHandler)
|
||||
socket_handler = (r'/ws', SocketHandler)
|
||||
static_handler = (r'/(.*)', tornado.web.StaticFileHandler,
|
||||
# {'path': os.path.dirname(__file__)})
|
||||
{'path': 'templates'})
|
||||
local_handler = (r'/local/(.*)', tornado.web.StaticFileHandler,
|
||||
{'path': ''})
|
||||
@ -133,7 +178,6 @@ class ModularServer(tornado.web.Application):
|
||||
self.model = model
|
||||
self.model_args = args
|
||||
self.model_kwargs = kwargs
|
||||
|
||||
#self.reset_model()
|
||||
|
||||
# Initializing the application itself:
|
||||
@ -155,5 +199,5 @@ class ModularServer(tornado.web.Application):
|
||||
url = 'http://127.0.0.1:{PORT}'.format(PORT=self.port)
|
||||
print('Interface starting at {url}'.format(url=url))
|
||||
self.listen(self.port)
|
||||
webbrowser.open(url)
|
||||
# webbrowser.open(url)
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
|
@ -1,4 +1,20 @@
|
||||
|
||||
html, body, .carousel-inner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.carousel {
|
||||
height: calc(100% - 150px);
|
||||
}
|
||||
|
||||
.carousel-indicators li {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.carousel-indicators li.active {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.node {
|
||||
stroke: #fff;
|
||||
stroke-width: 1.5px;
|
||||
@ -236,3 +252,42 @@ table#link-distance .min,
|
||||
table#link-distance .max {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
||||
/* Console */
|
||||
|
||||
#update, .console {
|
||||
padding: 10px 15px;
|
||||
height: 135px;
|
||||
border: 1px solid #585858;
|
||||
}
|
||||
|
||||
#update {
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
|
||||
.container-fluid.fixed {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.console {
|
||||
background-color: rgb(88,88,88);
|
||||
font-family: "Ubuntu Mono";
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
line-height: 14px;
|
||||
overflow: auto;
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
.console::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
.console::-webkit-scrollbar-thumb {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
|
||||
background-color: #555;
|
||||
}
|
||||
|
@ -28,13 +28,14 @@
|
||||
<!-- STYLESHEETS -->
|
||||
<link rel="stylesheet" type="text/css" href="css/main.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/timeline.css">
|
||||
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Ubuntu+Mono" />
|
||||
|
||||
<title>{{ model_name }}</title>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
|
||||
var width = window.innerWidth * 0.75,
|
||||
height = window.innerHeight * 4 / 5,
|
||||
height = window.innerHeight * 3 / 5,
|
||||
speed = 1000,
|
||||
play,
|
||||
slider;
|
||||
@ -43,7 +44,7 @@
|
||||
"use strict";
|
||||
|
||||
// Create svg, timeline and settings
|
||||
self.GraphVisualization.create('graph');
|
||||
self.GraphVisualization.create('graph', height, width);
|
||||
$('<div>').attr('id', 'load').appendTo('#graph_container').css('left', width / 2 - 25).css('top', height / 2);
|
||||
$('#configuration').css("height", height);
|
||||
d3.select('#slider3').attr("width", width).call(
|
||||
@ -51,7 +52,7 @@
|
||||
);
|
||||
|
||||
// Load a file
|
||||
$('#configuration #file').change(function() {
|
||||
$('#update #file').change(function() {
|
||||
|
||||
var file = $('#file')[0].files[0];
|
||||
self.GraphVisualization.reset();
|
||||
@ -93,6 +94,8 @@
|
||||
})
|
||||
});
|
||||
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
|
||||
}
|
||||
|
||||
///]]
|
||||
@ -103,13 +106,17 @@
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="container-fluid fixed">
|
||||
|
||||
<div id="graph_container">
|
||||
<svg id="graph" class="col-sm-9"></svg>
|
||||
<!-- CONSOLE -->
|
||||
<div class="col-sm-9 console">
|
||||
Please, update YAML file that define all the parameters of a simulation. <br/>
|
||||
If you don't know how to write the file, please visit this link:<br/>
|
||||
http://soilsim.readthedocs.io/en/latest/quickstart.html<br/><br/>
|
||||
</div>
|
||||
<!-- //CONSOLE -->
|
||||
|
||||
<div id="configuration" class="col-sm-3">
|
||||
<div id="update" class="col-sm-3">
|
||||
<!-- Load File -->
|
||||
<form enctype="multipart/form-data">
|
||||
<label class="custom-file">
|
||||
@ -117,7 +124,6 @@
|
||||
<span class="custom-file-control" data-content="Choose file..."></span>
|
||||
</label>
|
||||
</form>
|
||||
<hr />
|
||||
<!-- //Load File -->
|
||||
|
||||
<!-- TRIALS -->
|
||||
@ -126,101 +132,142 @@
|
||||
<select id="trials" class="form-control form-control-sm">
|
||||
</select>
|
||||
</div>
|
||||
<hr />
|
||||
<!-- //TRIALS -->
|
||||
|
||||
<!-- Graph Info -->
|
||||
<div class="config-item">
|
||||
<table id="info-graph">
|
||||
<tbody>
|
||||
<tr id="nodes"><th>Nodes:</th></tr>
|
||||
<tr id="links"><th>Links:</th></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="logo pull-right">
|
||||
<img src="img/logo_gsi.svg" style="height: 40px;">
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<!-- //Graph Info -->
|
||||
|
||||
<!-- PROPIEDADES -->
|
||||
<div class="config-item">
|
||||
Propiedades:
|
||||
<select id="properties" class="form-control form-control-sm">
|
||||
<optgroup id="properties-dynamic" label="Dynamics"></optgroup>
|
||||
<optgroup id="properties-static" label="Statics"></optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="config-item">
|
||||
<table id="percentTable">
|
||||
<tbody><tr><th></th></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr />
|
||||
<!-- //PROPIEDADES -->
|
||||
|
||||
<!-- SPEED -->
|
||||
<div class="config-item">
|
||||
<table id="speed"><tbody><tr>
|
||||
<th class="text-left min">min</th>
|
||||
<th class="text-center">Speed</th>
|
||||
<th class="text-right max">max</th>
|
||||
</tr></tbody></table>
|
||||
<div class="speed-slider">
|
||||
<input id="speed-slider" type="text" data-slider-min="1" data-slider-max="1000" data-slider-step="0.01" data-slider-value="1000" data-slider-tooltip="hide" data-slider-reversed="true" data-slider-enabled="false" data-slider-scale="logarithmic"/>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<script type="text/javascript">
|
||||
$('#speed-slider').slider();
|
||||
</script>
|
||||
<!-- //SPEED -->
|
||||
|
||||
<!-- LINK DISTANCE -->
|
||||
<div class="config-item">
|
||||
<table id="link-distance"><tbody><tr>
|
||||
<th class="text-left min">min</th>
|
||||
<th class="text-center">Link Distance</th>
|
||||
<th class="text-right max">max</th>
|
||||
</tr></tbody></table>
|
||||
<div class="link-distance-slider">
|
||||
<input id="link-distance-slider" type="text" data-slider-min="30" data-slider-max="1000" data-slider-step="0.01" data-slider-value="30" data-slider-tooltip="hide" data-slider-reversed="false" data-slider-enabled="false" data-slider-scale="logarithmic"/>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$('#link-distance-slider').slider();
|
||||
</script>
|
||||
<!-- //LINK DISTANCE -->
|
||||
</div>
|
||||
|
||||
<!-- TIMELINE -->
|
||||
<div id="timeline" class="col-sm-12">
|
||||
<div id="slider3" class="pull-left col-sm-9"></div>
|
||||
|
||||
<div class="btn-toolbar controls">
|
||||
<button type="button" id="button_play" class="btn btn-lg">
|
||||
<span class="glyphicon glyphicon-play" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button type="button" id="button_pause" class="btn btn-lg">
|
||||
<span class="glyphicon glyphicon-pause" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button type="button" id="button_zoomFit" class="btn btn-lg">
|
||||
<span class="glyphicon glyphicon-fullscreen" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- //TIMELINE -->
|
||||
|
||||
<!-- ERROR ALERT -->
|
||||
<div class="alert alert-danger alert-dismissable fade in" style="display: none;">
|
||||
<a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>
|
||||
<strong>Error! </strong><span id="error-message"></span>
|
||||
</div>
|
||||
<!-- //ERROR ALERT -->
|
||||
|
||||
</div>
|
||||
|
||||
<div id="myCarousel" class="carousel slide">
|
||||
|
||||
<!-- Indicators -->
|
||||
<ol class="carousel-indicators">
|
||||
<li data-target="#myCarousel" data-slide-to="0" class="active" data-toggle="tooltip" title="Graph" data-placement="top"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="1" data-toggle="tooltip" title="Settings" data-placement="top"></li>
|
||||
</ol>
|
||||
|
||||
<!-- Wrapper for slides -->
|
||||
<div class="carousel-inner">
|
||||
|
||||
<!-- Wrapper Graph Container -->
|
||||
<div class="item active">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div id="graph_container">
|
||||
<svg id="graph" class="col-sm-9"></svg>
|
||||
</div>
|
||||
|
||||
<div id="configuration" class="col-sm-3">
|
||||
<!-- Graph Info -->
|
||||
<div class="config-item" style="margin-top: 0 !important;">
|
||||
<table id="info-graph">
|
||||
<tbody>
|
||||
<tr id="nodes"><th>Nodes:</th></tr>
|
||||
<tr id="links"><th>Links:</th></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="logo pull-right">
|
||||
<img src="img/logo_gsi.svg" style="height: 40px;">
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<!-- //Graph Info -->
|
||||
|
||||
<!-- PROPIEDADES -->
|
||||
<div class="config-item">
|
||||
Propiedades:
|
||||
<select id="properties" class="form-control form-control-sm">
|
||||
<optgroup id="properties-dynamic" label="Dynamics"></optgroup>
|
||||
<optgroup id="properties-static" label="Statics"></optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="config-item">
|
||||
<table id="percentTable">
|
||||
<tbody><tr><th></th></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr />
|
||||
<!-- //PROPIEDADES -->
|
||||
|
||||
<!-- SPEED -->
|
||||
<div class="config-item">
|
||||
<table id="speed"><tbody><tr>
|
||||
<th class="text-left min">min</th>
|
||||
<th class="text-center">Speed</th>
|
||||
<th class="text-right max">max</th>
|
||||
</tr></tbody></table>
|
||||
<div class="speed-slider">
|
||||
<input id="speed-slider" type="text" data-slider-min="1" data-slider-max="1000" data-slider-step="0.01" data-slider-value="1000" data-slider-tooltip="hide" data-slider-reversed="true" data-slider-enabled="false" data-slider-scale="logarithmic"/>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<script type="text/javascript">
|
||||
$('#speed-slider').slider();
|
||||
</script>
|
||||
<!-- //SPEED -->
|
||||
|
||||
<!-- LINK DISTANCE -->
|
||||
<div class="config-item">
|
||||
<table id="link-distance"><tbody><tr>
|
||||
<th class="text-left min">min</th>
|
||||
<th class="text-center">Link Distance</th>
|
||||
<th class="text-right max">max</th>
|
||||
</tr></tbody></table>
|
||||
<div class="link-distance-slider">
|
||||
<input id="link-distance-slider" type="text" data-slider-min="30" data-slider-max="1000" data-slider-step="0.01" data-slider-value="30" data-slider-tooltip="hide" data-slider-reversed="false" data-slider-enabled="false" data-slider-scale="logarithmic"/>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$('#link-distance-slider').slider();
|
||||
</script>
|
||||
<!-- //LINK DISTANCE -->
|
||||
</div>
|
||||
|
||||
<!-- TIMELINE -->
|
||||
<div id="timeline" class="col-sm-12">
|
||||
<div id="slider3" class="pull-left col-sm-9"></div>
|
||||
|
||||
<div class="btn-toolbar controls">
|
||||
<button type="button" id="button_play" class="btn btn-lg">
|
||||
<span class="glyphicon glyphicon-play" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button type="button" id="button_pause" class="btn btn-lg">
|
||||
<span class="glyphicon glyphicon-pause" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button type="button" id="button_zoomFit" class="btn btn-lg">
|
||||
<span class="glyphicon glyphicon-fullscreen" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- //TIMELINE -->
|
||||
|
||||
<!-- ERROR ALERT -->
|
||||
<div class="alert alert-danger alert-dismissable fade in" style="display: none;">
|
||||
<a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>
|
||||
<strong>Error! </strong><span id="error-message"></span>
|
||||
</div>
|
||||
<!-- //ERROR ALERT -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- //Wrapper Graph Container -->
|
||||
|
||||
<!-- Wrapper Settings -->
|
||||
<div class="item">
|
||||
<div class="container-fluid">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- //Wrapper for slides -->
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
@ -34,6 +34,12 @@ ws.onmessage = function(message) {
|
||||
console.log(msg['error']);
|
||||
_socket.error(msg['error']);
|
||||
$('#load').removeClass('loader');
|
||||
break;
|
||||
|
||||
case 'log':
|
||||
console.log(msg['logging'])
|
||||
$('.console').append(msg['logger'] + ': ' + msg['logging'] + '<br/>');
|
||||
$('.console').animate({ scrollTop: $(window).height() }, 'slow');
|
||||
|
||||
default:
|
||||
console.log('Unexpected message!')
|
||||
|
@ -12,13 +12,13 @@
|
||||
*/
|
||||
|
||||
// Private constants
|
||||
var width = window.innerWidth * 0.75,
|
||||
height = window.innerHeight * 4 / 5,
|
||||
focus_opacity = 0.1,
|
||||
var focus_opacity = 0.1,
|
||||
radius = 8;
|
||||
|
||||
// Private variables
|
||||
var graph, // JSON data for the graph
|
||||
var width,
|
||||
height,
|
||||
graph, // JSON data for the graph
|
||||
model, // Definition of the attributes of the nodes
|
||||
linkedByIndex, // Nodes linked by index
|
||||
name, // Name of the graph (id for svg item)
|
||||
@ -260,13 +260,16 @@
|
||||
* @param {object} id The id of the svg item.
|
||||
* @return {object} This class.
|
||||
*/
|
||||
function create(id, callback) {
|
||||
function create(id, n_height, n_width, callback) {
|
||||
name = id;
|
||||
svg = d3.select('svg#' + name)
|
||||
.attr('width', width)
|
||||
.attr('height', height)
|
||||
.attr('width', n_width)
|
||||
.attr('height', n_height)
|
||||
.style('background-color', 'rgba(128,128,128,0.1)');
|
||||
|
||||
height = n_height;
|
||||
width = n_width
|
||||
|
||||
if (callback) { callback(this.GraphVisualization); }
|
||||
else { return this.GraphVisualization }
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ from xml.etree import ElementTree
|
||||
class Model():
|
||||
|
||||
def __init__(self, dump=True, dir_path='output'):
|
||||
self.name = 'soil'
|
||||
self.dump = dump
|
||||
self.dir_path = dir_path
|
||||
|
||||
@ -20,9 +21,10 @@ class Model():
|
||||
sim.dump = self.dump
|
||||
|
||||
print('Dumping results to {} : {}'.format(sim.dir_path, sim.dump))
|
||||
|
||||
|
||||
sim.run_simulation()
|
||||
|
||||
|
||||
def get_trial(self, name, trial):
|
||||
graph = nx.read_gexf(os.path.join(self.dir_path, name, '{}_trial_{}.gexf'.format(name, trial)))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user