1
0
mirror of https://github.com/gsi-upm/soil synced 2024-12-23 00:28:11 +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__":
soil = Model(dump=False)
soil = Model(dump=True)
run(soil)

View File

@ -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()

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 {
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;
}

View File

@ -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">&times;</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">&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>
</html>

View File

@ -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!')

View File

@ -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 }
}

View File

@ -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)))