Template:Team:Paris Saclay/simbox

From 2013.igem.org

(Difference between revisions)
 
(32 intermediate revisions not shown)
Line 1: Line 1:
-
<html>
+
<html><div class="simbox" data-width="785" data-height="300" data-load="https://2013.igem.org/Team:Paris_Saclay/</html>{{{load}}}<html>">Loading simulation...</div></html>
-
<script>
+
-
simulations= new Array();
+
-
 
+
-
function simboxes_load()
+
-
{
+
-
var simboxes= document.getElementsByClassName("simbox");
+
-
 
+
-
for(var i=0 ; i < simboxes.length ; ++i)
+
-
  init_simbox(simboxes[i], i);
+
-
}
+
-
 
+
-
function molecule()
+
-
{
+
-
this.name= undefined;
+
-
this.init_qtty= 0;
+
-
this.quantity= 0;
+
-
this.curve_show= false;
+
-
this.curve_color= "#000000";
+
-
this.const= false;
+
-
this.adjustable= false;
+
-
this.history= new Array();
+
-
}
+
-
 
+
-
function reaction()
+
-
{
+
-
this.inputs= new Array();
+
-
this.outputs= new Array();
+
-
this.probability= 0.0;
+
-
}
+
-
 
+
-
function simulation()
+
-
{
+
-
this.id= undefined;
+
-
this.volume= undefined;
+
-
this.timestep= undefined;
+
-
this.cfactor= undefined;
+
-
this.molecules= new Array();
+
-
this.reactions= new Array();
+
-
this.reac_order= new Array();
+
-
this.running= false;
+
-
this.refresh_run_time= 60;
+
-
this.refresh_interval= 100;
+
-
this.timeout= null;
+
-
this.curtime= 0.0;
+
-
this.curstep= 0;
+
-
 
+
-
this.canv= null;
+
-
this.ctx= null;
+
-
this.draw_min_t= 0.0;
+
-
this.draw_max_t= 100.0;
+
-
this.draw_min_v= 0.0;
+
-
this.draw_max_v= 10000.0;
+
-
}
+
-
 
+
-
function simbox_get_molecule_id(simid, name)
+
-
{
+
-
for(var i= 0 ; i < simulations[simid].molecules.length ; ++i)
+
-
{
+
-
  if(simulations[simid].molecules[i].name == name)
+
-
  return i;
+
-
}
+
-
return null;
+
-
}
+
-
 
+
-
function init_simbox(sb, id)
+
-
{
+
-
simulations[id]= new simulation();
+
-
 
+
-
//Get parameters
+
-
var xmlfile= 'https://2013.igem.org/Team:Paris_Saclay/'+sb.getAttribute('data-load')+'?action=raw&ctype=text/css';
+
-
var width= parseInt(sb.getAttribute('data-width'));
+
-
var height= parseInt(sb.getAttribute('data-height'));
+
-
 
+
-
//Open XML data file
+
-
var xmldata= null;
+
-
try
+
-
{
+
-
  var xhr= new XMLHttpRequest();
+
-
  xhr.open("GET", xmlfile, false);
+
-
  xhr.send();
+
-
  var parser= new DOMParser();
+
-
  xmldata= parser.parseFromString(xhr.responseText, "application/xml");
+
-
  if(xmldata.documentElement.nodeName != 'sim')
+
-
  throw 'XML parsing error';
+
-
}
+
-
catch(err)
+
-
{
+
-
  sb.innerHTML='Error : ' + err;
+
-
  return false;
+
-
}
+
-
 
+
-
//Load simulation parameters
+
-
simulations[id].volume= parseFloat(xmldata.getElementsByTagName("volume")[0].childNodes[0].nodeValue);
+
-
simulations[id].timestep= parseFloat(xmldata.getElementsByTagName("timestep")[0].childNodes[0].nodeValue);
+
-
simulations[id].cfactor= parseFloat(xmldata.getElementsByTagName("concentration_factor")[0].childNodes[0].nodeValue);
+
-
 
+
-
//Load molecules
+
-
var molecule_tags= xmldata.getElementsByTagName("molecule");
+
-
for(var i= 0 ; i < molecule_tags.length ; ++i)
+
-
{
+
-
  simulations[id].molecules[i]= new molecule();
+
-
  simulations[id].molecules[i].name= molecule_tags[i].getAttribute('name');
+
-
  if(molecule_tags[i].hasAttribute('quantity'))
+
-
  {
+
-
  simulations[id].molecules[i].init_qtty= parseFloat(molecule_tags[i].getAttribute('quantity'));
+
-
  simulations[id].molecules[i].quantity= parseFloat(molecule_tags[i].getAttribute('quantity'));
+
-
  }
+
-
  if(molecule_tags[i].hasAttribute('curve_show'))
+
-
  simulations[id].molecules[i].curve_show= (molecule_tags[i].getAttribute('curve_show') == 'true');
+
-
  if(molecule_tags[i].hasAttribute('curve_color'))
+
-
  simulations[id].molecules[i].curve_color= molecule_tags[i].getAttribute('curve_color');
+
-
  if(molecule_tags[i].hasAttribute('const'))
+
-
  simulations[id].molecules[i].const= (molecule_tags[i].getAttribute('const') == 'true');
+
-
  if(molecule_tags[i].hasAttribute('adjustable'))
+
-
  simulations[id].molecules[i].adjustable= (molecule_tags[i].getAttribute('adjustable') == 'true');
+
-
}
+
-
 
+
-
//Load reactions
+
-
var reaction_tags= xmldata.getElementsByTagName("reaction");
+
-
for(var i= 0 ; i < reaction_tags.length ; ++i)
+
-
{
+
-
  simulations[id].reactions[i]= new reaction();
+
-
  if(reaction_tags[i].hasAttribute('probability'))
+
-
  simulations[id].reactions[i].probability= parseFloat(reaction_tags[i].getAttribute('probability'));
+
-
 
+
-
  var input_tags= reaction_tags[i].getElementsByTagName("in");
+
-
  for(var j= 0 ; j < input_tags.length ; ++j)
+
-
  {
+
-
    var tmpid= simbox_get_molecule_id(id, input_tags[j].childNodes[0].nodeValue);
+
-
    if(tmpid == null)
+
-
    {
+
-
    sb.innerHTML='Error : molecule "'+input_tags[j].childNodes[0].nodeValue+'" not defined.';
+
-
    return false;
+
-
    }
+
-
    simulations[id].reactions[i].inputs[j]= tmpid;
+
-
  }
+
-
 
+
-
  var output_tags= reaction_tags[i].getElementsByTagName("out");
+
-
  for(var j= 0 ; j < output_tags.length ; ++j)
+
-
  {
+
-
    var tmpid= simbox_get_molecule_id(id, output_tags[j].childNodes[0].nodeValue);
+
-
    if(tmpid == null)
+
-
    {
+
-
    sb.innerHTML='Error : molecule "'+output_tags[j].childNodes[0].nodeValue+'" not defined.';
+
-
    return false;
+
-
    }
+
-
    simulations[id].reactions[i].outputs[j]= tmpid;
+
-
  }
+
-
 
+
-
  //precompute index array for easy shuffling
+
-
  simulations[id].reac_order[i]= i;
+
-
}
+
-
+
-
 
+
-
//Create canvas
+
-
simulations[id].canv= document.createElement('canvas');
+
-
simulations[id].ctx= simulations[id].canv.getContext("2d");
+
-
simulations[id].canv.id= "simbox_canv_"+id;
+
-
simulations[id].canv.width= width;
+
-
simulations[id].canv.height= height;
+
-
sb.appendChild(simulations[id].canv);
+
-
+
-
//Init param box
+
-
var paramdiv= document.createElement('div');
+
-
sb.appendChild(paramdiv);
+
-
//legend
+
-
var reshtmlparamdiv= '';
+
-
for(var i= 0 ; i < simulations[id].molecules.length ; ++i)
+
-
{
+
-
  if(simulations[id].molecules[i].curve_show)
+
-
  reshtmlparamdiv += '<span style="font-weight:bold;padding:0.1em 0.3em;color:#FFFFFF;background-color:'+simulations[id].molecules[i].curve_color+';">'+simulations[id].molecules[i].name+'</span>&nbsp;';
+
-
}
+
-
reshtmlparamdiv += '<span id="simbox_time_'+id+'">t = 0</span>';
+
-
//quantity controls
+
-
for(var i= 0 ; i < simulations[id].molecules.length ; ++i)
+
-
{
+
-
  if(simulations[id].molecules[i].adjustable)
+
-
  {
+
-
  reshtmlparamdiv += '<br /><br />';
+
-
  reshtmlparamdiv += simulations[id].molecules[i].name + ' = <input id="simbox_ctl_'+id+'_'+i+'" type="number" min="0" value="'+simulations[id].molecules[i].quantity+'"/>';
+
-
  }
+
-
}
+
-
reshtmlparamdiv += '<br /><br />';
+
-
//controls
+
-
reshtmlparamdiv += '<button onclick="simbox_startclick(this,'+id+')" id="simbox_start_'+id+'">PLAY</button><button onclick="simbox_resetclick(this,'+id+')" id="simbox_reset_'+id+'">RESET</button>';
+
-
//about
+
-
reshtmlparamdiv += '<br/>Programmed by Damir Vodenicarevic, based on the work of Patrick Amar and Loïc Paulevé [HSIM: an hybrid stochastic simulation system for systems biology, Electronic Notes in Theoretical Computer Science www.elsevier.nl/locate/entcs]';
+
-
 
+
-
paramdiv.innerHTML= reshtmlparamdiv;
+
-
 
+
-
return true;
+
-
}
+
-
 
+
-
function is_posint(str)
+
-
{
+
-
  var parsed= parseInt(str);
+
-
  if(isNaN(parsed)) return false;
+
-
  if(!isFinite(parsed)) return false;
+
-
  if(parsed < 0) return false;
+
-
  return true;
+
-
}
+
-
 
+
-
function simbox_startclick(btn, simid)
+
-
{
+
-
if(simulations[simid].running)
+
-
{
+
-
  window.clearTimeout(simulations[simid].timeout);
+
-
  simulations[simid].running= false;
+
-
  btn.innerHTML= 'PLAY';
+
-
}
+
-
else
+
-
{
+
-
  for(var i= 0 ; i < simulations[simid].molecules.length ; ++i)
+
-
  {
+
-
  if(simulations[simid].molecules[i].adjustable)
+
-
  {
+
-
    var tmpval= document.getElementById('simbox_ctl_'+simid+'_'+i).value;
+
-
    if(!is_posint(tmpval))
+
-
    {
+
-
    alert('Invalid quantity set for molecule "'+simulations[simid].molecules[i].name+'".');
+
-
    return false;
+
-
    }
+
-
    simulations[simid].molecules[i].quantity= parseInt(tmpval);
+
-
  }
+
-
  }
+
-
  simulations[simid].running= true;
+
-
  btn.innerHTML= 'PAUSE';
+
-
  simbox_refresh(simid);
+
-
}
+
-
simbox_update_controls(simid);
+
-
return true;
+
-
}
+
-
 
+
-
function simbox_resetclick(btn, simid)
+
-
{
+
-
if(simulations[simid].running)
+
-
{
+
-
  window.clearTimeout(simulations[simid].timeout);
+
-
  simulations[simid].running= false;
+
-
  document.getElementById('simbox_start_'+simid).innerHTML= 'PLAY';
+
-
}
+
-
+
-
//Reset quantities, clear curves
+
-
simulations[simid].curtime= 0;
+
-
simulations[simid].curstep= 0;
+
-
for(var i= 0 ; i < simulations[simid].molecules.length ; ++i)
+
-
{
+
-
  simulations[simid].molecules[i].quantity= simulations[simid].molecules[i].init_qtty;
+
-
  simulations[simid].molecules[i].history.length= 0;
+
-
}
+
-
 
+
-
//Update controls
+
-
simbox_update_controls(simid);
+
-
}
+
-
 
+
-
function simbox_update_controls(simid)
+
-
{
+
-
for(var i= 0 ; i < simulations[simid].molecules.length ; ++i)
+
-
{
+
-
  if(simulations[simid].molecules[i].adjustable)
+
-
  {
+
-
  document.getElementById('simbox_ctl_'+simid+'_'+i).value= simulations[simid].molecules[i].quantity;
+
-
  document.getElementById('simbox_ctl_'+simid+'_'+i).disabled= simulations[simid].running;
+
-
  }
+
-
}
+
-
document.getElementById('simbox_time_'+simid).innerHTML= 't = ' + simulations[simid].curtime.toPrecision(5) + ' [step n°'+simulations[simid].curstep+']';
+
-
}
+
-
 
+
-
function simbox_refresh(simid)
+
-
{
+
-
var tmpdate= new Date();
+
-
var time1= tmpdate.getTime();
+
-
 
+
-
while(tmpdate.getTime() - time1 < simulations[simid].refresh_run_time)
+
-
{
+
-
  simulation_step(simid);
+
-
  tmpdate= new Date();
+
-
}
+
-
+
-
simulations[simid].draw_max_t= simulations[simid].curtime;
+
-
simbox_draw_graph(simid);
+
-
simbox_update_controls(simid);
+
-
 
+
-
simulations[simid].timeout= setTimeout(function() {simbox_refresh(simid);}, simulations[simid].refresh_interval);
+
-
}
+
-
 
+
-
function shuffle_array(array)
+
-
{
+
-
for(var i= array.length-1; i > 0 ; --i)
+
-
{
+
-
  var j= Math.floor(Math.random() * (i + 1));
+
-
  var tmp= array[i];
+
-
  array[i]= array[j];
+
-
  array[j]= tmp;
+
-
}
+
-
}
+
-
 
+
-
function simulation_step(simid)
+
-
{
+
-
var sim= simulations[simid];
+
-
 
+
-
//Shuffle reaction order
+
-
shuffle_array(sim.reac_order);
+
-
 
+
-
for(var i= 0 ; i < sim.reac_order.length ; ++i)
+
-
{
+
-
  var usedmols= new Array();
+
-
 
+
-
  var reac= sim.reactions[sim.reac_order[i]];
+
-
  var proba= reac.probability * sim.timestep;
+
-
  for(var j= 0 ; j < reac.inputs.length ; ++j)
+
-
  {
+
-
  var inid= reac.inputs[j];
+
-
  if(!sim.molecules[inid].const)
+
-
  {
+
-
    if(usedmols[inid] == undefined)
+
-
    usedmols[inid]= 1;
+
-
    else
+
-
    usedmols[inid] ++;
+
-
  }
+
-
  proba *= sim.molecules[inid].quantity;
+
-
  }
+
-
  for(var j= 0 ; j < reac.outputs.length ; ++j)
+
-
  {
+
-
  var outid= reac.outputs[j];
+
-
  if(usedmols[outid] != undefined)
+
-
    usedmols[outid]--;
+
-
  }
+
-
  proba *= Math.pow(sim.cfactor/sim.volume, reac.inputs.length);
+
-
 
+
-
  //alert('BEFORE : reac '+i+ ' proba=' + proba);
+
-
 
+
-
  var entier= Math.floor(proba);
+
-
  var frac= proba - entier;
+
-
  for(var elt in usedmols)
+
-
  {
+
-
  if( entier * usedmols[elt] >= sim.molecules[elt].quantity )
+
-
  {
+
-
    var tmpe= Math.floor(sim.molecules[elt].quantity / usedmols[elt]);
+
-
    if(tmpe < entier)
+
-
    entier= tmpe;
+
-
    frac= 0;
+
-
  }
+
-
  }
+
-
 
+
-
  //alert('AFTER : reac '+i+ ' proba=' + (entier+frac));
+
-
 
+
-
  for(var j= 0 ; j < reac.inputs.length ; ++j)
+
-
  {
+
-
  if(!sim.molecules[reac.inputs[j]].const)
+
-
    sim.molecules[reac.inputs[j]].quantity -= entier;
+
-
  }
+
-
  for(var j= 0 ; j < reac.outputs.length ; ++j)
+
-
  {
+
-
  if(!sim.molecules[reac.outputs[j]].const)
+
-
    sim.molecules[reac.outputs[j]].quantity += entier;
+
-
  }
+
-
 
+
-
  var lastone= false;
+
-
  if(frac > 0)
+
-
  lastone= (Math.random() < frac);
+
-
  if(lastone)
+
-
  {
+
-
  for(var j= 0 ; j < reac.inputs.length ; ++j)
+
-
  {
+
-
    if(!sim.molecules[reac.inputs[j]].const)
+
-
    sim.molecules[reac.inputs[j]].quantity --;
+
-
  }
+
-
  for(var j= 0 ; j < reac.outputs.length ; ++j)
+
-
  {
+
-
    if(!sim.molecules[reac.outputs[j]].const)
+
-
    sim.molecules[reac.outputs[j]].quantity ++;
+
-
  }
+
-
  }
+
-
}
+
-
 
+
-
for(var i= 0 ; i < sim.molecules.length ; ++i)
+
-
  sim.molecules[i].history.push(sim.molecules[i].quantity);
+
-
 
+
-
sim.curtime += sim.timestep;
+
-
sim.curstep++;
+
-
}
+
-
 
+
-
function simbox_drawXcoord(simid, t)
+
-
{
+
-
var tmin= simulations[simid].draw_min_t;
+
-
var tmax= simulations[simid].draw_max_t;
+
-
return simulations[simid].canv.width*(t-tmin)/(tmax-tmin);
+
-
}
+
-
function simbox_drawYcoord(simid, v)
+
-
{
+
-
var vmin= simulations[simid].draw_min_v;
+
-
var vmax= simulations[simid].draw_max_v;
+
-
return simulations[simid].canv.height*(1.0 - (v-vmin)/(vmax-vmin));
+
-
}
+
-
 
+
-
function simbox_draw_graph(simid)
+
-
{
+
-
var sim= simulations[simid];
+
-
var canv= sim.canv;
+
-
var ctx= sim.ctx;
+
-
 
+
-
ctx.clearRect(0, 0, canv.width, canv.height);
+
-
 
+
-
for(var i= 0 ; i < sim.molecules.length ; ++i)
+
-
{
+
-
  if(sim.molecules[i].curve_show)
+
-
  {
+
-
  var dta= sim.molecules[i].history;
+
-
  var tstart= Math.floor(sim.draw_min_t/sim.timestep);
+
-
  var tend= Math.ceil(sim.draw_max_t/sim.timestep);
+
-
  if(tstart > dta.length)
+
-
    tstart= dta.length;
+
-
  if(tend > dta.length)
+
-
    tend= dta.length;
+
-
 
+
-
  var step= Math.ceil((tend-tstart)/(500));
+
-
 
+
-
  ctx.beginPath();
+
-
  for(var ti= tstart ; ti < tend ; ti += step)
+
-
  {
+
-
    if(ti > tstart)
+
-
    ctx.lineTo( simbox_drawXcoord(simid, ti*sim.timestep), simbox_drawYcoord(simid, dta[ti]) );
+
-
    else
+
-
    ctx.moveTo( simbox_drawXcoord(simid, ti*sim.timestep), simbox_drawYcoord(simid, dta[ti]) );
+
-
  }
+
-
  ctx.strokeStyle= sim.molecules[i].curve_color;
+
-
  ctx.stroke();
+
-
  }
+
-
}
+
-
}
+
-
 
+
-
 
+
-
window.addEventListener("load", simboxes_load, false);
+
-
</script>
+
-
 
+
-
<div class="simbox" data-width="</html>{{{width}}}<html>" data-height="</html>{{{height}}}<html>" data-load="</html>{{{load}}}<html>"></div>
+
-
 
+
-
</html>
+

Latest revision as of 20:48, 27 September 2013

Loading simulation...