1
0
mirror of https://github.com/gsi-upm/soil synced 2024-11-23 03:32:28 +00:00

Model progress info

This commit is contained in:
Tasio Mendez 2017-12-20 18:10:14 +01:00
parent 722a82c21c
commit 459b9a771b
7 changed files with 269 additions and 112 deletions

2
run.py
View File

@ -11,5 +11,5 @@ def run(model, params=None):
if __name__ == "__main__": if __name__ == "__main__":
soil = Model(dump=False) soil = Model(dump=True)
run(soil) run(soil)

View File

@ -9,6 +9,12 @@ import webbrowser
import yaml import yaml
import logging import logging
import logging
import threading
import io
from datetime import timedelta
from contextlib import contextmanager
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
@ -55,6 +61,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
if self.application.verbose: if self.application.verbose:
logger.info('Socket opened!') logger.info('Socket opened!')
def check_origin(self, origin): def check_origin(self, origin):
return True return True
@ -79,9 +86,12 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
return return
else: else:
config = config[0] config = config[0]
self.send_log('INFO.soil', 'Using config: {name}'.format(name=config['name']))
self.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 = [] trials = []
for i in range(config['num_trials']): for i in range(config['num_trials']):
@ -92,6 +102,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
elif msg['type'] == 'get_trial': elif msg['type'] == 'get_trial':
if self.application.verbose: if self.application.verbose:
logger.info('Trial {} requested!'.format(msg['data'])) logger.info('Trial {} requested!'.format(msg['data']))
self.send_log('INFO.user', 'Trial {} requested!'.format(msg['data']))
self.write_message({'type': 'get_trial', self.write_message({'type': 'get_trial',
'data': self.application.model.get_trial(self.name, msg['data']) }) 'data': self.application.model.get_trial(self.name, msg['data']) })
@ -99,6 +110,41 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
if self.application.verbose: if self.application.verbose:
logger.info('Unexpected message!') 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): class ModularServer(tornado.web.Application):
""" Main visualization application. """ """ Main visualization application. """
@ -110,7 +156,6 @@ class ModularServer(tornado.web.Application):
page_handler = (r'/', PageHandler) page_handler = (r'/', PageHandler)
socket_handler = (r'/ws', SocketHandler) socket_handler = (r'/ws', SocketHandler)
static_handler = (r'/(.*)', tornado.web.StaticFileHandler, static_handler = (r'/(.*)', tornado.web.StaticFileHandler,
# {'path': os.path.dirname(__file__)})
{'path': 'templates'}) {'path': 'templates'})
local_handler = (r'/local/(.*)', tornado.web.StaticFileHandler, local_handler = (r'/local/(.*)', tornado.web.StaticFileHandler,
{'path': ''}) {'path': ''})
@ -133,7 +178,6 @@ class ModularServer(tornado.web.Application):
self.model = model self.model = model
self.model_args = args self.model_args = args
self.model_kwargs = kwargs self.model_kwargs = kwargs
#self.reset_model() #self.reset_model()
# Initializing the application itself: # Initializing the application itself:
@ -155,5 +199,5 @@ class ModularServer(tornado.web.Application):
url = 'http://127.0.0.1:{PORT}'.format(PORT=self.port) url = 'http://127.0.0.1:{PORT}'.format(PORT=self.port)
print('Interface starting at {url}'.format(url=url)) print('Interface starting at {url}'.format(url=url))
self.listen(self.port) self.listen(self.port)
webbrowser.open(url) # webbrowser.open(url)
tornado.ioloop.IOLoop.instance().start() tornado.ioloop.IOLoop.instance().start()

View File

@ -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 { .node {
stroke: #fff; stroke: #fff;
stroke-width: 1.5px; stroke-width: 1.5px;
@ -236,3 +252,42 @@ table#link-distance .min,
table#link-distance .max { table#link-distance .max {
font-weight: normal !important; 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;
}

View File

@ -28,13 +28,14 @@
<!-- STYLESHEETS --> <!-- STYLESHEETS -->
<link rel="stylesheet" type="text/css" href="css/main.css"> <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="css/timeline.css">
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Ubuntu+Mono" />
<title>{{ model_name }}</title> <title>{{ model_name }}</title>
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
var width = window.innerWidth * 0.75, var width = window.innerWidth * 0.75,
height = window.innerHeight * 4 / 5, height = window.innerHeight * 3 / 5,
speed = 1000, speed = 1000,
play, play,
slider; slider;
@ -43,7 +44,7 @@
"use strict"; "use strict";
// Create svg, timeline and settings // 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); $('<div>').attr('id', 'load').appendTo('#graph_container').css('left', width / 2 - 25).css('top', height / 2);
$('#configuration').css("height", height); $('#configuration').css("height", height);
d3.select('#slider3').attr("width", width).call( d3.select('#slider3').attr("width", width).call(
@ -51,7 +52,7 @@
); );
// Load a file // Load a file
$('#configuration #file').change(function() { $('#update #file').change(function() {
var file = $('#file')[0].files[0]; var file = $('#file')[0].files[0];
self.GraphVisualization.reset(); self.GraphVisualization.reset();
@ -93,6 +94,8 @@
}) })
}); });
$('[data-toggle="tooltip"]').tooltip()
} }
///]] ///]]
@ -103,13 +106,17 @@
<body> <body>
<div class="container-fluid"> <div class="container-fluid fixed">
<div id="graph_container"> <!-- CONSOLE -->
<svg id="graph" class="col-sm-9"></svg> <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> </div>
<!-- //CONSOLE -->
<div id="configuration" class="col-sm-3"> <div id="update" class="col-sm-3">
<!-- Load File --> <!-- Load File -->
<form enctype="multipart/form-data"> <form enctype="multipart/form-data">
<label class="custom-file"> <label class="custom-file">
@ -117,7 +124,6 @@
<span class="custom-file-control" data-content="Choose file..."></span> <span class="custom-file-control" data-content="Choose file..."></span>
</label> </label>
</form> </form>
<hr />
<!-- //Load File --> <!-- //Load File -->
<!-- TRIALS --> <!-- TRIALS -->
@ -126,101 +132,142 @@
<select id="trials" class="form-control form-control-sm"> <select id="trials" class="form-control form-control-sm">
</select> </select>
</div> </div>
<hr />
<!-- //TRIALS --> <!-- //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> </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">&times;</a>
<strong>Error! </strong><span id="error-message"></span>
</div>
<!-- //ERROR ALERT -->
</div> </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">&times;</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> </body>
</html> </html>

View File

@ -34,6 +34,12 @@ ws.onmessage = function(message) {
console.log(msg['error']); console.log(msg['error']);
_socket.error(msg['error']); _socket.error(msg['error']);
$('#load').removeClass('loader'); $('#load').removeClass('loader');
break;
case 'log':
console.log(msg['logging'])
$('.console').append(msg['logger'] + ': ' + msg['logging'] + '<br/>');
$('.console').animate({ scrollTop: $(window).height() }, 'slow');
default: default:
console.log('Unexpected message!') console.log('Unexpected message!')

View File

@ -12,13 +12,13 @@
*/ */
// Private constants // Private constants
var width = window.innerWidth * 0.75, var focus_opacity = 0.1,
height = window.innerHeight * 4 / 5,
focus_opacity = 0.1,
radius = 8; radius = 8;
// Private variables // 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 model, // Definition of the attributes of the nodes
linkedByIndex, // Nodes linked by index linkedByIndex, // Nodes linked by index
name, // Name of the graph (id for svg item) name, // Name of the graph (id for svg item)
@ -260,13 +260,16 @@
* @param {object} id The id of the svg item. * @param {object} id The id of the svg item.
* @return {object} This class. * @return {object} This class.
*/ */
function create(id, callback) { function create(id, n_height, n_width, callback) {
name = id; name = id;
svg = d3.select('svg#' + name) svg = d3.select('svg#' + name)
.attr('width', width) .attr('width', n_width)
.attr('height', height) .attr('height', n_height)
.style('background-color', 'rgba(128,128,128,0.1)'); .style('background-color', 'rgba(128,128,128,0.1)');
height = n_height;
width = n_width
if (callback) { callback(this.GraphVisualization); } if (callback) { callback(this.GraphVisualization); }
else { return this.GraphVisualization } else { return this.GraphVisualization }
} }

View File

@ -8,6 +8,7 @@ from xml.etree import ElementTree
class Model(): class Model():
def __init__(self, dump=True, dir_path='output'): def __init__(self, dump=True, dir_path='output'):
self.name = 'soil'
self.dump = dump self.dump = dump
self.dir_path = dir_path self.dir_path = dir_path
@ -23,6 +24,7 @@ class Model():
sim.run_simulation() sim.run_simulation()
def get_trial(self, name, trial): def get_trial(self, name, trial):
graph = nx.read_gexf(os.path.join(self.dir_path, name, '{}_trial_{}.gexf'.format(name, trial))) graph = nx.read_gexf(os.path.join(self.dir_path, name, '{}_trial_{}.gexf'.format(name, trial)))