Skip to content

Commit

Permalink
Merge pull request #1106 from StochSS/develop
Browse files Browse the repository at this point in the history
2.3.1 Release
  • Loading branch information
seanebum authored May 25, 2021
2 parents 65df61b + 3a5309b commit cb3a544
Show file tree
Hide file tree
Showing 19 changed files with 392 additions and 140 deletions.
3 changes: 3 additions & 0 deletions client/models/sweep-parameter.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
/*
StochSS is a platform for simulating biochemical systems
Copyright (C) 2019-2020 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
Expand Down
3 changes: 3 additions & 0 deletions client/models/sweep-parameters.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
/*
StochSS is a platform for simulating biochemical systems
Copyright (C) 2019-2020 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
Expand Down
33 changes: 33 additions & 0 deletions client/pages/file-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,24 @@ let FileBrowser = PageView.extend({
}
});
},
extractAll: function (o) {
let self = this;
let queryStr = "?path=" + o.original._path;
let endpoint = path.join(app.getApiPath(), "file/unzip") + queryStr;
app.getXHR(endpoint, {
success: function (err, response, body) {
let node = $('#models-jstree').jstree().get_node(o.parent);
if(node.type === "root"){
self.refreshJSTree();
}else{
$('#models-jstree').jstree().refresh_node(node);
}
},
error: function (err, response, body) {
let modal = $(modals.newProjectModelErrorHtml(body.Reason, body.message)).modal();
}
});
},
setupJstree: function () {
var self = this;
$.jstree.defaults.contextmenu.items = (o, cb) => {
Expand Down Expand Up @@ -1235,6 +1253,18 @@ let FileBrowser = PageView.extend({
}
}
}
//Specific to zip archives
let extractAll = {
"extractAll" : {
"label" : "Extract All",
"_disabled" : false,
"separator_before" : false,
"separator_after" : false,
"action" : function (data) {
self.extractAll(o);
}
}
}
if (o.type === 'root'){
return folder
}
Expand All @@ -1253,6 +1283,9 @@ let FileBrowser = PageView.extend({
if (o.type === 'workflow') {
return $.extend(open, workflow, common)
}
if (o.text.endsWith(".zip")) {
return $.extend(open, extractAll, common)
}
if (o.type === 'notebook' || o.type === "other") {
return $.extend(open, common)
}
Expand Down
18 changes: 18 additions & 0 deletions client/styles/styles.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
StochSS is a platform for simulating biochemical systems
Copyright (C) 2019-2020 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

body {
min-width: 650px
}
Expand Down
2 changes: 2 additions & 0 deletions client/templates/includes/reactionsEditor.pug
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ div#reactions-editor.card.card-body
tbody(data-hook="reaction-list")

div.col-md-5.container-part(data-hook="reaction-details-container")

div(data-hook="massaction-message"): p.text-info To add a mass action reaction the model must have at least one parameter

div(data-hook="process-component-error"): p.text-danger A model must have at least one reaction, event, or rule

Expand Down
33 changes: 33 additions & 0 deletions client/views/file-browser-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,24 @@ module.exports = View.extend({
}
});
},
extractAll: function (o) {
let self = this;
let queryStr = "?path=" + o.original._path;
let endpoint = path.join(app.getApiPath(), "file/unzip") + queryStr;
app.getXHR(endpoint, {
success: function (err, response, body) {
let node = $('#models-jstree-view').jstree().get_node(o.parent);
if(node.type === "root"){
self.refreshJSTree();
}else{
$('#models-jstree-view').jstree().refresh_node(node);
}
},
error: function (err, response, body) {
let modal = $(modals.newProjectModelErrorHtml(body.Reason, body.message)).modal();
}
});
},
setupJstree: function () {
var self = this;
$.jstree.defaults.contextmenu.items = (o, cb) => {
Expand Down Expand Up @@ -1343,6 +1361,18 @@ module.exports = View.extend({
}
}
}
//Specific to zip archives
let extractAll = {
"extractAll" : {
"label" : "Extract All",
"_disabled" : false,
"separator_before" : false,
"separator_after" : false,
"action" : function (data) {
self.extractAll(o);
}
}
}
if (o.type === 'root'){
return $.extend(refresh, project, commonFolder, downloadWCombine, {"Rename": common.Rename})
}
Expand All @@ -1367,6 +1397,9 @@ module.exports = View.extend({
if (o.type === 'workflow') {
return $.extend(open, workflow, downloadWCombine, common)
}
if (o.text.endsWith(".zip")) {
return $.extend(open, extractAll, download, common)
}
if (o.type === 'notebook' || o.type === "other") {
return $.extend(open, download, common)
}
Expand Down
2 changes: 2 additions & 0 deletions client/views/reactions-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ module.exports = View.extend({
},
toggleReactionTypes: function (e, prev, curr) {
if(curr && curr.add && this.collection.parent.parameters.length === 1){
$(this.queryByHook('massaction-message')).prop('hidden', true);
$(this.queryByHook('add-reaction-full')).prop('hidden', false);
$(this.queryByHook('add-reaction-partial')).prop('hidden', true);
}else if(curr && !curr.add && this.collection.parent.parameters.length === 0){
$(this.queryByHook('massaction-message')).prop('hidden', false);
$(this.queryByHook('add-reaction-full')).prop('hidden', true);
$(this.queryByHook('add-reaction-partial')).prop('hidden', false);
}
Expand Down
1 change: 1 addition & 0 deletions stochss/handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def get_page_handlers(route_start):
(r"/stochss/api/file/download-zip\/?", DownloadZipFileAPIHandler),
(r"/stochss/api/file/json-data\/?", JsonFileAPIHandler),
(r"/stochss/api/file/duplicate\/?", DuplicateModelHandler),
(r"/stochss/api/file/unzip\/?", UnzipFileAPIHandler),
(r"/stochss/api/directory/duplicate\/?", DuplicateDirectoryHandler),
(r"/stochss/api/directory/create\/?", CreateDirectoryHandler),
(r"/stochss/api/spatial/to-model\/?", ConvertToModelAPIHandler),
Expand Down
27 changes: 27 additions & 0 deletions stochss/handlers/file_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,3 +674,30 @@ async def get(self):
log.debug("Response: %s", resp)
self.write(resp)
self.finish()


class UnzipFileAPIHandler(APIHandler):
'''
################################################################################################
Handler for unzipping zip archives.
################################################################################################
'''

async def get(self):
'''
Unzip a zip archive.
Attributes
----------
'''
self.set_header('Content-Type', 'application/json')
path = self.get_query_argument(name="path")
log.debug("The path to the zip archive: %s", path)
try:
file = StochSSFile(path=path)
resp = file.unzip(from_upload=False)
log.debug("Response Message: %s", resp)
self.write(resp)
except StochSSAPIError as err:
report_error(self, log, err)
self.finish()
87 changes: 58 additions & 29 deletions stochss/handlers/util/ensemble_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@
import json
import pickle
import logging
import traceback

import numpy
import plotly
from gillespy2 import TauLeapingSolver, TauHybridSolver, SSACSolver, ODESolver
from gillespy2 import TauHybridSolver

from .stochss_job import StochSSJob
from .stochss_errors import StochSSAPIError
from .stochss_errors import StochSSAPIError, StochSSJobResultsError

log = logging.getLogger("stochss")

Expand Down Expand Up @@ -59,36 +60,57 @@ def __init__(self, path, preview=False):


def __get_run_settings(self):
solver_map = {"SSA":SSACSolver, "Tau-Leaping":TauLeapingSolver,
"ODE":ODESolver, "Hybrid-Tau-Leaping":TauHybridSolver}
solver_map = {"ODE":self.g_model.get_best_solver_algo("ODE"),
"SSA":self.g_model.get_best_solver_algo("SSA"),
"Tau-Leaping":self.g_model.get_best_solver_algo("Tau-Leaping"),
"Hybrid-Tau-Leaping":TauHybridSolver}
run_settings = self.get_run_settings(settings=self.settings, solver_map=solver_map)
if run_settings['solver'].name == "SSACSolver":
instance_solvers = ["SSACSolver", "TauLeapingCSolver", "ODECSolver"]
if run_settings['solver'].name in instance_solvers :
run_settings['solver'] = run_settings['solver'](model=self.g_model)
return run_settings


def __store_csv_results(self, results):
try:
results.to_csv(path="results", nametag="results_csv", stamp=self.get_time_stamp())
except Exception as err:
log.error("Error storing csv results: %s\n%s",
str(err), traceback.format_exc())


@classmethod
def __plot_results(cls, results):
plots = {"trajectories":results.plotplotly(return_plotly_figure=True)}
if len(results) > 1:
plots['stddevran'] = results.plotplotly_std_dev_range(return_plotly_figure=True)
std_res = results.stddev_ensemble()
plots['stddev'] = std_res.plotplotly(return_plotly_figure=True)
avg_res = results.average_ensemble()
plots['avg'] = avg_res.plotplotly(return_plotly_figure=True)
for _, plot in plots.items():
plot["config"] = {"responsive":True}
with open('results/plots.json', 'w') as plots_file:
json.dump(plots, plots_file, cls=plotly.utils.PlotlyJSONEncoder,
indent=4, sort_keys=True)


def __store_results(self, results):
if not 'results' in os.listdir():
os.mkdir('results')
with open('results/results.p', 'wb') as results_file:
pickle.dump(results, results_file)
results.to_csv(path="results", nametag="results_csv", stamp=self.get_time_stamp())
def __store_pickled_results(cls, results):
try:
with open('results/results.p', 'wb') as results_file:
pickle.dump(results, results_file)
except Exception as err:
message = f"Error storing pickled results: {err}\n{traceback.format_exc()}"
log.error(message)
return message
return False


@classmethod
def __store_result_plots(cls, results):
try:
plots = {"trajectories":results.plotplotly(return_plotly_figure=True)}
if len(results) > 1:
plots['stddevran'] = results.plotplotly_std_dev_range(return_plotly_figure=True)
std_res = results.stddev_ensemble()
plots['stddev'] = std_res.plotplotly(return_plotly_figure=True)
avg_res = results.average_ensemble()
plots['avg'] = avg_res.plotplotly(return_plotly_figure=True)
for _, plot in plots.items():
plot["config"] = {"responsive":True}
with open('results/plots.json', 'w') as plots_file:
json.dump(plots, plots_file, cls=plotly.utils.PlotlyJSONEncoder,
indent=4, sort_keys=True)
except Exception as err:
message = f"Error storing result plots: {err}\n{traceback.format_exc()}"
log.error(message)
return message
return False


def __update_timespan(self):
Expand Down Expand Up @@ -126,7 +148,7 @@ def run(self, preview=False, verbose=True):
log.info("Running the ensemble simulation")
if self.settings['simulationSettings']['isAutomatic']:
self.__update_timespan()
is_ode = self.g_model.get_best_solver().name == "ODESolver"
is_ode = self.g_model.get_best_solver().name in ["ODESolver", "ODECSolver"]
results = self.g_model.run(number_of_trajectories=1 if is_ode else 100)
else:
kwargs = self.__get_run_settings()
Expand All @@ -135,8 +157,15 @@ def run(self, preview=False, verbose=True):
if verbose:
log.info("The ensemble simulation has completed")
log.info("Storing the results as pickle and csv")
self.__store_results(results=results)
if not 'results' in os.listdir():
os.mkdir('results')
self.__store_csv_results(results=results)
pkl_err = self.__store_pickled_results(results=results)
if verbose:
log.info("Storing the polts of the results")
self.__plot_results(results=results)
plt_err = self.__store_result_plots(results=results)
if pkl_err and plt_err:
message = "An unexpected error occured with the result object"
trace = f"{pkl_err}\n{plt_err}"
raise StochSSJobResultsError(message, trace)
return None
Loading

0 comments on commit cb3a544

Please sign in to comment.