From cc1187fc7d8f0ae2d1340689279ca0083466cd51 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 4 Jun 2021 13:00:53 -0400 Subject: [PATCH 01/63] Added boundary conditions to the spatial model converter. --- .../handlers/util/stochss_spatial_model.py | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index e0f444ca0e..5e854c884a 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -23,7 +23,7 @@ import numpy import plotly -from spatialpy import Model, Species, Parameter, Reaction, Mesh, MeshError, \ +from spatialpy import Model, Species, Parameter, Reaction, Mesh, MeshError, BoundaryCondition, \ PlaceInitialCondition, UniformInitialCondition, ScatterInitialCondition from .stochss_base import StochSSBase @@ -69,6 +69,23 @@ def __init__(self, path, new=False, model=None): self.model = None + @classmethod + def __build_boundary_condition(cls, boundary_condition): + class NewBC(BoundaryCondition): # pylint: disable=too-few-public-methods + ''' + ######################################################################################## + Custom SpatialPy Boundary Condition + ######################################################################################## + ''' + __class__ = f"__main__.{boundary_condition['name']}" + def expression(self): # pylint: disable=no-self-use + ''' + Custom expression for boundary condition + ''' + return boundary_condition['expression'] + return NewBC() + + @classmethod def __build_stochss_domain(cls, s_domain, data=None): particles = cls.__build_stochss_domain_particles(s_domain=s_domain, data=data) @@ -121,6 +138,17 @@ def __build_stochss_domain_particles(cls, s_domain, data=None): return particles + def __convert_boundary_conditions(self, model): + try: + for boundary_condition in self.model['boundaryConditions']: + s_bound_cond = self.__build_boundary_condition(boundary_condition) + model.add_boundary_condition(s_bound_cond) + except KeyError as err: + message = "Spatial model boundary conditions are not properly formatted or " + message += f"are referenced incorrectly: {str(err)}" + raise StochSSModelFormatError(message, traceback.format_exc()) from err + + def __convert_domain(self, model): try: xlim = tuple(self.model['domain']['x_lim']) @@ -161,7 +189,7 @@ def __convert_initial_conditions(self, model): s_ic = UniformInitialCondition(species, count, types=types) model.add_initial_condition(s_ic) except KeyError as err: - message = "Spatial model domain properties are not properly formatted or " + message = "Spatial model initial conditions are not properly formatted or " message += f"are referenced incorrectly: {str(err)}" raise StochSSModelFormatError(message, traceback.format_exc()) from err @@ -350,6 +378,8 @@ def convert_to_spatialpy(self): s_model = Model(name=name) self.__convert_model_settings(model=s_model) self.__convert_domain(model=s_model) + if "boundaryConditions" in self.model.keys(): + self.__convert_boundary_conditions(model=s_model) self.__convert_species(model=s_model) self.__convert_initial_conditions(model=s_model) self.__convert_parameters(model=s_model) From 48fa06d80c5b95fd052147061bebd3835cec720f Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 7 Jun 2021 13:02:48 -0400 Subject: [PATCH 02/63] Added boundary conditions to the notebook template for spatial models. --- stochss/handlers/util/stochss_notebook.py | 40 +++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/stochss/handlers/util/stochss_notebook.py b/stochss/handlers/util/stochss_notebook.py index 2a02836cd8..bd3db26214 100644 --- a/stochss/handlers/util/stochss_notebook.py +++ b/stochss/handlers/util/stochss_notebook.py @@ -72,6 +72,34 @@ def __init__(self, path, new=False, models=None, settings=None): if changed: self.path = n_path.replace(self.user_dir + '/', "") + def __create_boundary_condition_cells(self): + pad = " " + bc_cells = [] + try: + for boundary_condition in self.s_model['boundaryConditions']: + bc_cell = [f'class {boundary_condition["name"]}(BoundaryCondition):', + f'{pad}def expression(self):', + f'{pad*2}return """{boundary_condition["expression"]}"""'] + bc_cells.append(nbf.new_code_cell("\n".join(bc_cell))) + return bc_cells + except KeyError as err: + message = "Boundary conditions are not properly formatted or " + message += f"are referenced incorrectly for notebooks: {str(err)}" + raise StochSSModelFormatError(message, traceback.format_exc()) from err + + def __create_boundary_condition_string(self, model, pad): + if self.s_model['boundaryConditions']: + bound_conds = ["", f"{pad}# Boundary Conditions"] + try: + for bound_cond in self.s_model['boundaryConditions']: + bc_str = f"{pad}self.add_boundary_condition({bound_cond['name']}())" + bound_conds.append(bc_str) + model.extend(bound_conds) + except KeyError as err: + message = "Boundary conditions are not properly formatted or " + message += f"are referenced incorrectly for notebooks: {str(err)}" + raise StochSSModelFormatError(message, traceback.format_exc()) from err + def __create_common_cells(self, interactive_backend=False): cells = [self.__create_import_cell(interactive_backend=interactive_backend), nbf.new_markdown_cell(f"# {self.get_name()}"), @@ -261,6 +289,7 @@ def __create_model_cell(self): " def __init__(self):", f'{pad}Model.__init__(self, name="{self.get_name()}")'] self.__create_mesh_string(model=model, pad=pad) + self.__create_boundary_condition_string(model=model, pad=pad) self.__create_species_strings(model=model, pad=pad) self.__create_initial_condition_strings(model=model, pad=pad) self.__create_parameter_strings(model=model, pad=pad) @@ -905,9 +934,16 @@ def create_ses_notebook(self): self.nb_type = self.SPATIAL_SIMULATION self.settings['solver'] = "Solver" run_str = "kwargs = configure_simulation()\nresults = model.run(**kwargs)" - species = self.s_model['species'][0]['name'] - plot_str = f"results.plot_species('{species}', animated=True, width=None, height=None)" + if self.s_model['species']: + species = self.s_model['species'][0]['name'] + plot_str = f"results.plot_species('{species}', animated=True, width=None, height=None)" + else: + plot_str = f"results.plot_property('type', animated=True, width=None, height=None)" cells = self.__create_common_cells() + if 'boundaryConditions' in self.s_model.keys(): + bc_cells = self.__create_boundary_condition_cells() + for i, bc_cell in enumerate(bc_cells): + cells.insert(2 + i, bc_cell) cells.extend([nbf.new_code_cell(run_str), nbf.new_markdown_cell("# Visualization"), nbf.new_code_cell(plot_str)]) From 0379792f5876408e67301c9ac7be8778c7c21414 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 7 Jun 2021 13:04:29 -0400 Subject: [PATCH 03/63] Added boundary conditions to the front end model to prevent unwanted deletion when saving the model. --- client/models/boundary-condition.js | 29 ++++++++++++++++++++++++++++ client/models/boundary-conditions.js | 26 +++++++++++++++++++++++++ client/models/model.js | 4 +++- 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 client/models/boundary-condition.js create mode 100644 client/models/boundary-conditions.js diff --git a/client/models/boundary-condition.js b/client/models/boundary-condition.js new file mode 100644 index 0000000000..405d84e800 --- /dev/null +++ b/client/models/boundary-condition.js @@ -0,0 +1,29 @@ +/* +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 . +*/ + +//models +var State = require('ampersand-state'); + +module.exports = State.extend({ + props: { + compID: 'number', + name: 'string', + expression: 'string', + annotation: 'string' + } +}); \ No newline at end of file diff --git a/client/models/boundary-conditions.js b/client/models/boundary-conditions.js new file mode 100644 index 0000000000..aeed723ffe --- /dev/null +++ b/client/models/boundary-conditions.js @@ -0,0 +1,26 @@ +/* +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 . +*/ + +//collections +var Collection = require('ampersand-collection'); +//models +var BoundaryCondition = require('./boundary-condition'); + +module.exports = Collection.extend({ + model: BoundaryCondition, +}); \ No newline at end of file diff --git a/client/models/model.js b/client/models/model.js index b8b59ab441..d5ca4c628c 100644 --- a/client/models/model.js +++ b/client/models/model.js @@ -30,6 +30,7 @@ var Reactions = require('./reactions'); var Rules = require('./rules'); var Events = require('./events'); var FunctionDefinitions = require('./function-definitions'); +var BoundaryCondition = require('./boundary-conditions'); module.exports = Model.extend({ url: function () { @@ -49,7 +50,8 @@ module.exports = Model.extend({ reactions: Reactions, rules: Rules, eventsCollection: Events, - functionDefinitions: FunctionDefinitions + functionDefinitions: FunctionDefinitions, + boundaryConditions: BoundaryCondition }, children: { modelSettings: TimespanSettings, From 33e0cacf45cec895cede25731d28af0f655699cc Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 7 Jun 2021 13:07:42 -0400 Subject: [PATCH 04/63] Added a view for a boundary condition model with a view and edit template to support both modes. --- .../includes/editBoundaryCondition.pug | 30 +++++++ .../includes/viewBoundaryCondition.pug | 18 ++++ client/views/boundary-condition-view.js | 85 +++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 client/templates/includes/editBoundaryCondition.pug create mode 100644 client/templates/includes/viewBoundaryCondition.pug create mode 100644 client/views/boundary-condition-view.js diff --git a/client/templates/includes/editBoundaryCondition.pug b/client/templates/includes/editBoundaryCondition.pug new file mode 100644 index 0000000000..2caa182c6f --- /dev/null +++ b/client/templates/includes/editBoundaryCondition.pug @@ -0,0 +1,30 @@ +div.mx-1 + + if(this.model.collection.indexOf(this.model) !== 0) + hr + + div.row + + div.col-md-3 + + div.pl-2=this.model.name + + div.col-md-5 + + div + + button.btn.btn-outline-secondary(data-hook="expand") View Expression + + div(data-hook="expression" style="display: none;") + + div(style="white-space:pre;")=this.model.expression + + div.col-md-2 + + div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") + + button.btn.btn-outline-secondary.btn-sm(data-hook="edit-annotation-btn") Edit + + div.col-md-2 + + button.btn.btn-outline-secondary(data-hook="remove") X diff --git a/client/templates/includes/viewBoundaryCondition.pug b/client/templates/includes/viewBoundaryCondition.pug new file mode 100644 index 0000000000..a78f94d10b --- /dev/null +++ b/client/templates/includes/viewBoundaryCondition.pug @@ -0,0 +1,18 @@ +div.mx-1 + + if(this.model.collection.indexOf(this.model) !== 0) + hr + + div.row + + div.col-md-3 + + div.pl-2=this.model.name + + div.col-md-7 + + div(style="white-space:pre;")=this.model.expression + + div.col-md-2 + + div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") diff --git a/client/views/boundary-condition-view.js b/client/views/boundary-condition-view.js new file mode 100644 index 0000000000..6c88802b95 --- /dev/null +++ b/client/views/boundary-condition-view.js @@ -0,0 +1,85 @@ +/* +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 . +*/ + +let $ = require('jquery'); +//support files +let modals = require('../modals'); +//views +let View = require('ampersand-view'); +//templates +let editTemplate = require('../templates/includes/editBoundaryCondition.pug'); +let viewTemplate = require('../templates/includes/viewBoundaryCondition.pug'); + +module.exports = View.extend({ + events: { + 'click [data-hook=expand]' : 'toggleExpressionView', + 'click [data-hook=edit-annotation-btn]' : 'editAnnotation', + 'click [data-hook=remove]' : 'removeBoundaryCondition' + }, + initialize: function (attrs, options) { + View.prototype.initialize.apply(this, arguments); + this.viewMode = attrs.viewMode ? attrs.viewMode : false + }, + render: function (attrs, options) { + this.template = this.viewMode ? viewTemplate : editTemplate; + View.prototype.render.apply(this, arguments); + $(document).on('shown.bs.modal', function (e) { + $('[autofocus]', e.target).focus(); + }); + $(document).on('hide.bs.modal', '.modal', function (e) { + e.target.remove() + }); + if(!this.model.annotation){ + $(this.queryByHook('edit-annotation-btn')).text('Add') + } + }, + editAnnotation: function () { + let self = this; + let name = this.model.name; + let annotation = this.model.annotation; + if(document.querySelector('#boundaryConditionAnnotationModal')) { + document.querySelector('#boundaryConditionAnnotationModal').remove(); + } + let modal = $(modals.annotationModalHtml("boundaryCondition", name, annotation)).modal(); + let okBtn = document.querySelector('#boundaryConditionAnnotationModal .ok-model-btn'); + let input = document.querySelector('#boundaryConditionAnnotationModal #boundaryConditionAnnotationInput'); + input.addEventListener("keyup", function (event) { + if(event.keyCode === 13){ + event.preventDefault(); + okBtn.click(); + } + }); + okBtn.addEventListener('click', function (e) { + self.model.annotation = input.value.trim(); + self.parent.renderBoundaryConditionView(); + modal.modal('hide'); + }); + }, + removeBoundaryCondition: function () { + this.model.collection.remove(this.model); + }, + toggleExpressionView: function (e) { + if(e.target.textContent.startsWith("View")){ + $(this.queryByHook("expand")).html("Hide Expression"); + $(this.queryByHook("expression")).css("display", "block"); + }else{ + $(this.queryByHook("expand")).html("View Expression"); + $(this.queryByHook("expression")).css("display", "none"); + } + } +}); \ No newline at end of file From 51f5ce15a12609fbc23fa8d12d3a08d2f055f4ce Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 7 Jun 2021 13:09:29 -0400 Subject: [PATCH 05/63] Added a view for the boundary conditions collection that supports a read only mode for model viewers. --- .../includes/boundaryConditionsEditor.pug | 59 ++++++++++++++ client/views/boundary-conditions-editor.js | 78 +++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 client/templates/includes/boundaryConditionsEditor.pug create mode 100644 client/views/boundary-conditions-editor.js diff --git a/client/templates/includes/boundaryConditionsEditor.pug b/client/templates/includes/boundaryConditionsEditor.pug new file mode 100644 index 0000000000..984a21dcb2 --- /dev/null +++ b/client/templates/includes/boundaryConditionsEditor.pug @@ -0,0 +1,59 @@ +div#boundary-conditions.card + + div.card-header.pb-0 + + h3.inline.mr-3 Boundary Conditions + + div.inline.mr-3 + + ul.nav.nav-tabs.card-header-tabs(id="bc-tabs") + + li.nav-item + + a.nav-link.tab.active(data-hook="bc-edit-tab" data-toggle="tab" href="#edit-boundary-conditions") Edit + + li.nav-item + + a.nav-link.tab(data-hook="bc-view-tab" data-toggle="tab" href="#view-boundary-conditions") View + + button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-boundary-conditions", data-hook="collapse") + + + div.card-body.collapse.tab-content(id="collapse-boundary-conditions") + + div.tab-pane.active(id="edit-boundary-conditions" data-hook="edit-boundary-conditions") + + p Set spatial regions of the domain where a property of particles are held constant. + + hr + + div.mx-1.row.head + + div.col-sm-3: h6 Name + + div.col-sm-5: h6 Expression + + div.col-sm-2 + + div.inline Annotation + + div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation) + + div.col-sm-2: h6 Remove + + div.mt-3(data-hook="edit-boundary-conditions") + + div.tab-pane(id="view-boundary-conditions" data-hook="view-boundary-conditions") + + div.mx-1.row.head + + div.col-sm-3: h6 Name + + div.col-sm-7: h6 Expression + + div.col-sm-2 + + div.inline Annotation + + div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation) + + div.mt-3(data-hook="view-boundary-conditions") diff --git a/client/views/boundary-conditions-editor.js b/client/views/boundary-conditions-editor.js new file mode 100644 index 0000000000..142eb3d425 --- /dev/null +++ b/client/views/boundary-conditions-editor.js @@ -0,0 +1,78 @@ +/* +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 . +*/ + +let $ = require('jquery'); +//support files +let Tooltips = require('../tooltips'); +//views +let View = require('ampersand-view'); +let BoundaryConditionView = require('./boundary-condition-view'); +//templates +let template = require('../templates/includes/boundaryConditionsEditor.pug'); + +module.exports = View.extend({ + template: template, + initialize: function (attrs, options) { + View.prototype.initialize.apply(this, arguments); + this.readOnly = attrs.readOnly ? attrs.readOnly : false; + this.tooltips = Tooltips.boundaryConditionsEditor; + }, + render: function (attrs, options) { + View.prototype.render.apply(this, arguments); + if(this.readOnly) { + $(this.queryByHook('bc-edit-tab')).addClass("disabled"); + $(".nav .disabled>a").on("click", function(e) { + e.preventDefault(); + return false; + }); + $(this.queryByHook('bc-view-tab')).tab('show'); + $(this.queryByHook('edit-boundary-conditions')).removeClass('active'); + $(this.queryByHook('view-boundary-conditions')).addClass('active'); + } + this.renderEditBoundaryConditionView(); + this.renderViewBoundaryConditionView(); + }, + renderEditBoundaryConditionView: function () { + if(this.editBoundaryConditionView) { + this.editBoundaryConditionView.remove(); + } + this.editBoundaryConditionView = this.renderCollection( + this.collection, + BoundaryConditionView, + this.queryByHook("edit-boundary-conditions") + ); + $(document).ready(function () { + $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').click(function () { + $('[data-toggle="tooltip"]').tooltip("hide"); + }); + }); + }, + renderViewBoundaryConditionView: function () { + if(this.viewBoundaryConditionView) { + this.viewBoundaryConditionView.remove(); + } + let options = {viewOptions: {viewMode: true}}; + this.viewBoundaryConditionView = this.renderCollection( + this.collection, + BoundaryConditionView, + this.queryByHook("view-boundary-conditions"), + options + ); + } +}); \ No newline at end of file From 6ec993108dff1007c2e93b649047da0e1d7d4bf3 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 7 Jun 2021 13:10:29 -0400 Subject: [PATCH 06/63] Added boundary condition tooltips to the tooltips file. --- client/tooltips.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/tooltips.js b/client/tooltips.js index 4c426230a2..00cc144e9b 100644 --- a/client/tooltips.js +++ b/client/tooltips.js @@ -178,5 +178,8 @@ module.exports = { pressure: "Atmospheric or background pressure.", speed: "Approximate or artificial speed of sound" + }, + boundaryConditionsEditor: { + annotation: "An optional note about a boundary condition." } } From 9d5af2a439b7539af96c2a88bdbf8224e07c1976 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 7 Jun 2021 13:11:34 -0400 Subject: [PATCH 07/63] Added the boundary conditions section to the model editor page. --- client/pages/model-editor.js | 17 ++++++++++++++++- client/templates/pages/modelEditor.pug | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index ce70b0177e..959c6a4037 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -44,6 +44,7 @@ var SBMLComponentView = require('../views/sbml-component-editor'); var TimespanSettingsView = require('../views/timespan-settings'); var ModelStateButtonsView = require('../views/model-state-buttons'); var QuickviewDomainTypes = require('../views/quickview-domain-types'); +let BoundaryConditionsView = require('../views/boundary-conditions-editor'); //models var Model = require('../models/model'); var Domain = require('../models/domain'); @@ -232,7 +233,12 @@ let ModelEditor = PageView.extend({ app.registerRenderSubview(this, this.modelSettings, 'model-settings-container'); app.registerRenderSubview(this, this.modelStateButtons, 'model-state-buttons-container'); if(this.model.is_spatial) { - $(this.queryByHook("model-editor-advanced-container")).css("display", "none"); + if(this.model.boundaryConditions && this.model.boundaryConditions.length) { + $(this.queryByHook("system-volume-container")).css("display", "none"); + this.renderBoundaryConditionsView(); + }else{ + $(this.queryByHook("model-editor-advanced-container")).css("display", "none"); + } $(this.queryByHook("spatial-beta-message")).css("display", "block"); this.renderDomainViewer(); this.renderInitialConditions(); @@ -260,6 +266,15 @@ let ModelEditor = PageView.extend({ e.target.remove() }); }, + renderBoundaryConditionsView: function() { + if(this.boundaryConditionsView) { + this.boundaryConditionsView.remove(); + } + this.boundaryConditionsView = new BoundaryConditionsView({ + collection: this.model.boundaryConditions + }); + app.registerRenderSubview(this, this.boundaryConditionsView, "boundary-conditions-container"); + }, renderDomainViewer: function(domainPath=null) { if(this.domainViewer) { this.domainViewer.remove() diff --git a/client/templates/pages/modelEditor.pug b/client/templates/pages/modelEditor.pug index eeb3660d85..6d9dda37ee 100644 --- a/client/templates/pages/modelEditor.pug +++ b/client/templates/pages/modelEditor.pug @@ -52,6 +52,8 @@ section.page div(data-hook="sbml-component-container") + div(data-hook="boundary-conditions-container") + div.card.card-body.collapse.show(data-hook="system-volume-container") div From 6437f2759074ddc97693ed00d26e05c4fa6025f0 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 7 Jun 2021 17:24:18 -0400 Subject: [PATCH 08/63] Started setting up a base boundary conditions constructor ui to allow users to build restricted boundary conditions. --- .../includes/boundaryConditionsEditor.pug | 73 ++++++- client/views/boundary-conditions-editor.js | 198 +++++++++++++++++- 2 files changed, 265 insertions(+), 6 deletions(-) diff --git a/client/templates/includes/boundaryConditionsEditor.pug b/client/templates/includes/boundaryConditionsEditor.pug index 984a21dcb2..57efbede60 100644 --- a/client/templates/includes/boundaryConditionsEditor.pug +++ b/client/templates/includes/boundaryConditionsEditor.pug @@ -16,7 +16,7 @@ div#boundary-conditions.card a.nav-link.tab(data-hook="bc-view-tab" data-toggle="tab" href="#view-boundary-conditions") View - button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-boundary-conditions", data-hook="collapse") + + button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-boundary-conditions", data-hook="collapse-bc") + div.card-body.collapse.tab-content(id="collapse-boundary-conditions") @@ -40,7 +40,74 @@ div#boundary-conditions.card div.col-sm-2: h6 Remove - div.mt-3(data-hook="edit-boundary-conditions") + div.mt-3(data-hook="edit-boundary-conditions-list") + + div.card.mt-3 + + div.card-header + + h4.inline New Boundary Condition + + button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-new-boundary-conditions" data-hook="collapse-new-bc") + + + div.card-body.mx-1.collapse(id="collapse-new-boundary-conditions") + + div.row.head + + div.col-sm-2: h6 Name + + div.col-sm-2: h6 Target + + div.col-sm-2: h6 Value + + div.col-sm-6: h6 Conditions + + div.row.mt-3 + + div.col-sm-2(data-hook="new-bc-name" data-target="name") + + div.col-sm-4 + + table.table + tbody + tr + th(scope="row") Target + td(data-hook="new-bc-target") + tr + th(scope="row") Value + td(data-hook="new-bc-value" data-target="value") + tr + th(scope="row") Deterministic + td + input(type="checkbox" checked=this.newBC.deterministic data-hook="new-bc-deterministic") + + div.col-sm-6 + + div + + span.inline.mr-3(for="new-bc-type") Type: + div.inline(id="new-bc-type" data-hook="new-bc-type" data-target="type_id") + + table.table + thead + tr + th(scope="col") + th(scope="col") X-Axis + th(scope="col") Y-Axis + th(scope="col") Z-Axis + tbody + tr + th(scope="row") Min + td: div(data-hook="new-bc-x-min" data-target="xmin") + td: div(data-hook="new-bc-y-min" data-target="ymin") + td: div(data-hook="new-bc-z-min" data-target="zmin") + tr + th(scope="row") Max + td: div(data-hook="new-bc-x-max" data-target="xmax") + td: div(data-hook="new-bc-y-max" data-target="ymax") + td: div(data-hook="new-bc-z-max" data-target="zmax") + + button.btn.btn-outline-primary.box-shadow(data-hook="add-new-bc") Add New Boundary Condition div.tab-pane(id="view-boundary-conditions" data-hook="view-boundary-conditions") @@ -56,4 +123,4 @@ div#boundary-conditions.card div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation) - div.mt-3(data-hook="view-boundary-conditions") + div.mt-3(data-hook="view-boundary-conditions-list") diff --git a/client/views/boundary-conditions-editor.js b/client/views/boundary-conditions-editor.js index 142eb3d425..d2214e7695 100644 --- a/client/views/boundary-conditions-editor.js +++ b/client/views/boundary-conditions-editor.js @@ -18,8 +18,11 @@ along with this program. If not, see . let $ = require('jquery'); //support files +let app = require('../app'); +let tests = require('./tests'); let Tooltips = require('../tooltips'); //views +let InputView = require('./input'); let View = require('ampersand-view'); let BoundaryConditionView = require('./boundary-condition-view'); //templates @@ -27,10 +30,25 @@ let template = require('../templates/includes/boundaryConditionsEditor.pug'); module.exports = View.extend({ template: template, + events: { + 'change [data-hook=new-bc-name]' : 'handleSetValue', + 'change [data-hook=new-bc-type]' : 'handleSetValue', + 'change [data-hook=new-bc-value]' : 'handleSetValue', + 'change [data-hook=new-bc-x-min]' : 'handleSetValue', + 'change [data-hook=new-bc-x-max]' : 'handleSetValue', + 'change [data-hook=new-bc-y-min]' : 'handleSetValue', + 'change [data-hook=new-bc-y-max]' : 'handleSetValue', + 'change [data-hook=new-bc-z-min]' : 'handleSetValue', + 'change [data-hook=new-bc-z-max]' : 'handleSetValue', + 'click [data-hook=collapse-bc]' : 'changeCollapseButtonText', + 'click [data-hook=collapse-new-bc' : 'changeCollapseButtonText', + 'click [data-hook=add-new-bc]' : 'handleAddBCClick' + }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); this.readOnly = attrs.readOnly ? attrs.readOnly : false; this.tooltips = Tooltips.boundaryConditionsEditor; + this.setDefaultBC(); }, render: function (attrs, options) { View.prototype.render.apply(this, arguments); @@ -43,10 +61,31 @@ module.exports = View.extend({ $(this.queryByHook('bc-view-tab')).tab('show'); $(this.queryByHook('edit-boundary-conditions')).removeClass('active'); $(this.queryByHook('view-boundary-conditions')).addClass('active'); + }else{ + this.renderEditBoundaryConditionView(); + this.toggleAddNewBCButton(); } - this.renderEditBoundaryConditionView(); this.renderViewBoundaryConditionView(); }, + changeCollapseButtonText: function (e) { + app.changeCollapseButtonText(this, e); + }, + handleAddBCClick: function (e) { + let newBC = JSON.stringify(this.newBC) + this.setDefaultBC(); + this.resetNewBCViews(); + }, + handleSetValue: function (e) { + let key = e.delegateTarget.dataset.target; + let value = e.target.value; + if(key.endsWith("min") || key.endsWith("max") || key === "type_id"){ + value = this.validateNewBCCondition(key, value); + }else if(key === "value" && value === "") { + value = null; + } + this.newBC[key] = value; + this.toggleAddNewBCButton(); + }, renderEditBoundaryConditionView: function () { if(this.editBoundaryConditionView) { this.editBoundaryConditionView.remove(); @@ -54,7 +93,7 @@ module.exports = View.extend({ this.editBoundaryConditionView = this.renderCollection( this.collection, BoundaryConditionView, - this.queryByHook("edit-boundary-conditions") + this.queryByHook("edit-boundary-conditions-list") ); $(document).ready(function () { $('[data-toggle="tooltip"]').tooltip(); @@ -71,8 +110,161 @@ module.exports = View.extend({ this.viewBoundaryConditionView = this.renderCollection( this.collection, BoundaryConditionView, - this.queryByHook("view-boundary-conditions"), + this.queryByHook("view-boundary-conditions-list"), options ); + }, + resetNewBCViews: function () { + $(this.queryByHook("new-bc-name")).find("input").val(this.newBC.name); + $(this.queryByHook("new-bc-type")).find("input").val(this.newBC.type_id); + $(this.queryByHook("new-bc-value")).find("input").val(this.newBC.value); + $(this.queryByHook("new-bc-x-min")).find("input").val(this.newBC.xmin); + $(this.queryByHook("new-bc-x-max")).find("input").val(this.newBC.xmax); + $(this.queryByHook("new-bc-y-min")).find("input").val(this.newBC.ymin); + $(this.queryByHook("new-bc-y-max")).find("input").val(this.newBC.ymax); + $(this.queryByHook("new-bc-z-min")).find("input").val(this.newBC.zmin); + $(this.queryByHook("new-bc-z-max")).find("input").val(this.newBC.zmax); + this.toggleAddNewBCButton(); + }, + setDefaultBC: function () { + this.newBC = {"name": "", "species": null, "property": null, "value": null, "deterministic": true, "type_id": null, + "xmin": null, "ymin": null, "zmin": null, "xmax": null, "ymax": null, "zmax": null}; + this.setConditions = []; + }, + toggleAddNewBCButton: function () { + let disabled = this.newBC.name === "" || this.newBC.value === null || !this.setConditions.length; + $(this.queryByHook("add-new-bc")).prop("disabled", disabled); + }, + update: function (e) {}, + validateNewBCCondition: function(key, value) { + if((value === 0 && key === "type_id") || value === "") { + value = null + if(this.setConditions.includes(key)){ + let index = this.setConditions.indexOf(key); + this.setConditions.splice(index, 1); + } + }else if(!this.setConditions.includes(key)){ + this.setConditions.push(key); + } + return value; + }, + subviews: { + newBCName: { + hook: "new-bc-name", + prepareView: function (el) { + return new InputView({ + parent: this, + required: true, + name: 'name', + tests: tests.nameTests, + valueType: 'string', + value: this.newBC.name, + }); + } + }, + newBCValue: { + hook: "new-bc-value", + prepareView: function (el) { + return new InputView({ + parent: this, + required: true, + name: 'value', + tests: tests.valueTests, + valueType: 'number', + value: this.newBC.value, + }); + } + }, + newBCxmin: { + hook: "new-bc-x-min", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'xmin', + tests: tests.valueTests, + valueType: 'number', + value: this.newBC.xmin, + }); + } + }, + newBCymin: { + hook: "new-bc-y-min", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'ymin', + tests: tests.valueTests, + valueType: 'number', + value: this.newBC.ymin, + }); + } + }, + newBCzmin: { + hook: "new-bc-z-min", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'zmin', + tests: tests.valueTests, + valueType: 'number', + value: this.newBC.zmin, + }); + } + }, + newBCxmax: { + hook: "new-bc-x-max", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'xmax', + tests: tests.valueTests, + valueType: 'number', + value: this.newBC.xmax, + }); + } + }, + newBCymax: { + hook: "new-bc-y-max", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'ymax', + tests: tests.valueTests, + valueType: 'number', + value: this.newBC.ymax, + }); + } + }, + newBCzmax: { + hook: "new-bc-z-max", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'zmax', + tests: tests.valueTests, + valueType: 'number', + value: this.newBC.zmax, + }); + } + }, + newBCType: { + hook: "new-bc-type", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'type', + tests: tests.valueTests, + valueType: 'number', + value: this.newBC.type_id, + }); + } + } } }); \ No newline at end of file From ce11aafaa2a01101eb52ee486d7e25fd5bada71b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 9 Jun 2021 10:47:18 -0400 Subject: [PATCH 09/63] Added check to add boundary conditions list if missing. --- stochss/handlers/util/stochss_spatial_model.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 5293171c84..c95183c718 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -559,6 +559,8 @@ def load(self): self.model['domain'] = self.get_model_template()['domain'] elif "static" not in self.model['domain'].keys(): self.model['domain']['static'] = True + if "boundaryConditions" not in self.model.keys(): + self.model['boundaryConditions'] = [] for species in self.model['species']: if "types" not in species.keys(): species['types'] = list(range(1, len(self.model['domain']['types']))) From cbcda234a63d1d9342bdf76ee64db60d573f1602 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 9 Jun 2021 10:49:39 -0400 Subject: [PATCH 10/63] Set the model editor to always render the boundary conditions section for spatial models. --- client/pages/model-editor.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 959c6a4037..94b3838b79 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -233,12 +233,8 @@ let ModelEditor = PageView.extend({ app.registerRenderSubview(this, this.modelSettings, 'model-settings-container'); app.registerRenderSubview(this, this.modelStateButtons, 'model-state-buttons-container'); if(this.model.is_spatial) { - if(this.model.boundaryConditions && this.model.boundaryConditions.length) { - $(this.queryByHook("system-volume-container")).css("display", "none"); - this.renderBoundaryConditionsView(); - }else{ - $(this.queryByHook("model-editor-advanced-container")).css("display", "none"); - } + $(this.queryByHook("system-volume-container")).css("display", "none"); + this.renderBoundaryConditionsView(); $(this.queryByHook("spatial-beta-message")).css("display", "block"); this.renderDomainViewer(); this.renderInitialConditions(); From e6a4197b93388402349cb05d8eaf760498f3a65a Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 9 Jun 2021 10:56:54 -0400 Subject: [PATCH 11/63] Corrected the labels and headers in the new boundary condition dection and disabled the concentration input by default. --- client/templates/includes/boundaryConditionsEditor.pug | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/client/templates/includes/boundaryConditionsEditor.pug b/client/templates/includes/boundaryConditionsEditor.pug index 57efbede60..8cfddaea37 100644 --- a/client/templates/includes/boundaryConditionsEditor.pug +++ b/client/templates/includes/boundaryConditionsEditor.pug @@ -56,9 +56,7 @@ div#boundary-conditions.card div.col-sm-2: h6 Name - div.col-sm-2: h6 Target - - div.col-sm-2: h6 Value + div.col-sm-4: h6 Target div.col-sm-6: h6 Conditions @@ -71,15 +69,15 @@ div#boundary-conditions.card table.table tbody tr - th(scope="row") Target + th(scope="row") Property/Variable td(data-hook="new-bc-target") tr th(scope="row") Value td(data-hook="new-bc-value" data-target="value") tr - th(scope="row") Deterministic + th(scope="row") Concentration td - input(type="checkbox" checked=this.newBC.deterministic data-hook="new-bc-deterministic") + input(type="checkbox" checked=this.newBC.deterministic data-hook="new-bc-deterministic" disabled) div.col-sm-6 From 13077659f1e8fd77e5b2112989f168589e1db7c8 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 9 Jun 2021 10:59:21 -0400 Subject: [PATCH 12/63] Separated the name from the other inputs, fixed error reporting, and added function to toggle the disabled property when the target is selected. --- client/views/boundary-conditions-editor.js | 71 ++++++++++++++++++---- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/client/views/boundary-conditions-editor.js b/client/views/boundary-conditions-editor.js index d2214e7695..1c710f6b80 100644 --- a/client/views/boundary-conditions-editor.js +++ b/client/views/boundary-conditions-editor.js @@ -24,6 +24,7 @@ let Tooltips = require('../tooltips'); //views let InputView = require('./input'); let View = require('ampersand-view'); +let SelectView = require('ampersand-select-view'); let BoundaryConditionView = require('./boundary-condition-view'); //templates let template = require('../templates/includes/boundaryConditionsEditor.pug'); @@ -32,6 +33,8 @@ module.exports = View.extend({ template: template, events: { 'change [data-hook=new-bc-name]' : 'handleSetValue', + 'change [data-hook=new-bc-target]' : 'handleSetTarget', + 'change [data-hook=new-bc-deterministic]' : 'handleSetDeterministic', 'change [data-hook=new-bc-type]' : 'handleSetValue', 'change [data-hook=new-bc-value]' : 'handleSetValue', 'change [data-hook=new-bc-x-min]' : 'handleSetValue', @@ -75,15 +78,35 @@ module.exports = View.extend({ this.setDefaultBC(); this.resetNewBCViews(); }, + handleSetDeterministic: function (e) { + this.newBC.deterministic = e.target.checked; + }, + handleSetTarget: function (e) { + let properties = ["v", "nu", "rho"]; + let target = e.target.value; + if(properties.includes(target)) { + this.newBC.property = target; + this.newBC.species = null; + $(this.queryByHook("new-bc-deterministic")).prop("disabled", true); + }else{ + this.newBC.property = null; + this.newBC.species = target; + $(this.queryByHook("new-bc-deterministic")).prop("disabled", false); + } + }, handleSetValue: function (e) { let key = e.delegateTarget.dataset.target; let value = e.target.value; - if(key.endsWith("min") || key.endsWith("max") || key === "type_id"){ - value = this.validateNewBCCondition(key, value); - }else if(key === "value" && value === "") { - value = null; + if(key === "name") { + this.newBCName = value; + }else{ + if(key.endsWith("min") || key.endsWith("max") || key === "type_id"){ + value = this.validateNewBCCondition(key, value); + }else if(key === "value" && value === "") { + value = null; + } + this.newBC[key] = value; } - this.newBC[key] = value; this.toggleAddNewBCButton(); }, renderEditBoundaryConditionView: function () { @@ -115,7 +138,9 @@ module.exports = View.extend({ ); }, resetNewBCViews: function () { - $(this.queryByHook("new-bc-name")).find("input").val(this.newBC.name); + $(this.queryByHook("new-bc-deterministic")).prop("checked", this.newBC.deterministic); + $(this.queryByHook("new-bc-name")).find("input").val(this.newBCName); + $(this.queryByHook("new-bc-target")).find("select").val(this.newBC.property); $(this.queryByHook("new-bc-type")).find("input").val(this.newBC.type_id); $(this.queryByHook("new-bc-value")).find("input").val(this.newBC.value); $(this.queryByHook("new-bc-x-min")).find("input").val(this.newBC.xmin); @@ -124,15 +149,17 @@ module.exports = View.extend({ $(this.queryByHook("new-bc-y-max")).find("input").val(this.newBC.ymax); $(this.queryByHook("new-bc-z-min")).find("input").val(this.newBC.zmin); $(this.queryByHook("new-bc-z-max")).find("input").val(this.newBC.zmax); + $(this.queryByHook("new-bc-deterministic")).prop("disabled", true); this.toggleAddNewBCButton(); }, setDefaultBC: function () { - this.newBC = {"name": "", "species": null, "property": null, "value": null, "deterministic": true, "type_id": null, + this.newBCName = ""; + this.newBC = {"species": null, "property": "v", "value": null, "deterministic": true, "type_id": null, "xmin": null, "ymin": null, "zmin": null, "xmax": null, "ymax": null, "zmax": null}; this.setConditions = []; }, toggleAddNewBCButton: function () { - let disabled = this.newBC.name === "" || this.newBC.value === null || !this.setConditions.length; + let disabled = this.newBCName === "" || this.newBC.value === null || !this.setConditions.length; $(this.queryByHook("add-new-bc")).prop("disabled", disabled); }, update: function (e) {}, @@ -154,11 +181,29 @@ module.exports = View.extend({ prepareView: function (el) { return new InputView({ parent: this, - required: true, + required: false, name: 'name', - tests: tests.nameTests, valueType: 'string', - value: this.newBC.name, + value: this.newBCName + }); + } + }, + newBCTarget: { + hook: "new-bc-target", + prepareView: function (el) { + let species = this.collection.parent.species.map(function (specie) { + return [specie.compID, specie.name] + }); + let properties = [["v", "Velocity"], ["nu", "Viscosity"], ["rho", "Density"]] + let options = [{groupName: "Properties", options: properties}, + {groupName: "Variables", options: species}] + return new SelectView({ + parent: this, + required: false, + name: 'target', + eagerValidate: true, + groupOptions: options, + value: this.newBC.property }); } }, @@ -167,11 +212,11 @@ module.exports = View.extend({ prepareView: function (el) { return new InputView({ parent: this, - required: true, + required: false, name: 'value', tests: tests.valueTests, valueType: 'number', - value: this.newBC.value, + value: this.newBC.value }); } }, From 12012b5f72abd79ce5eeab33900eaf6d6cef3053 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 9 Jun 2021 11:42:25 -0400 Subject: [PATCH 13/63] Added function to create a new boundary condition using the spatialpy boundary condition constructor. --- stochss/handlers/util/stochss_spatial_model.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index c95183c718..7bde9bd8c9 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -388,6 +388,21 @@ def convert_to_spatialpy(self): return s_model + @classmethod + def create_boundary_condition(cls, kwargs): + ''' + Create a new boundary condition using spatialpy.BoundaryCondition + + Attributes + ---------- + kwargs : dict + Arguments passed to the spatialpy.BoundaryCondition constructor + ''' + new_bc = BoundaryCondition(**kwargs) + expression = new_bc.expression() + return {"expression": expression} + + def get_domain(self, path=None, new=False): ''' Get a prospective domain From 79bdc3a7a8622d74bf7bcc79f1e7f75e8dd647a4 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 9 Jun 2021 11:43:21 -0400 Subject: [PATCH 14/63] Added the api handler and route for the new boundary condition requests. --- stochss/handlers/__init__.py | 1 + stochss/handlers/models.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/stochss/handlers/__init__.py b/stochss/handlers/__init__.py index 426635b43e..f1ae51967e 100644 --- a/stochss/handlers/__init__.py +++ b/stochss/handlers/__init__.py @@ -75,6 +75,7 @@ def get_page_handlers(route_start): (r"/stochss/api/model/to-sbml\/?", ModelToSBMLAPIHandler), (r"/stochss/api/model/run\/?", RunModelAPIHandler), (r"/stochss/api/model/exists\/?", ModelExistsAPIHandler), + (r"/stochss/api/model/new-bc\/?", CreateNewBoundCondAPIHandler), (r"/stochss/api/spatial-model/domain-list\/?", LoadExternalDomains), (r"/stochss/api/spatial-model/types-list\/?", LoadParticleTypesDescriptions), (r"/stochss/api/spatial-model/domain-plot\/?", LoadDomainAPIHandler), diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index a55a29a947..12e1a38dfd 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -405,3 +405,31 @@ async def get(self): except StochSSAPIError as err: report_error(self, log, err) self.finish() + + +class CreateNewBoundCondAPIHandler(APIHandler): + ''' + ################################################################################################ + Handler creating new boundary conditions. + ################################################################################################ + ''' + @web.authenticated + async def post(self): + ''' + Creates a new restricted boundary condition. + + Attributes + ---------- + ''' + self.set_header('Content-Type', 'application/json') + kwargs = json.loads(self.request.body.decode()) + log.debug("Args passed to the boundary condition constructor: %s", kwargs) + try: + log.info("Creating the new boundary condition") + resp = StochSSSpatialModel.create_boundary_condition(kwargs) + log.info("Successfully created the new boundary condition") + log.debug("Response Message: %s", resp) + self.write(resp) + except StochSSAPIError as err: + report_error(self, log, err) + self.finish() From 295478293921fb0f61690a19bd607b0799ba1c3d Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 9 Jun 2021 11:44:50 -0400 Subject: [PATCH 15/63] Added function that will add a new boundary condition to the boundary condition collection. --- client/models/boundary-conditions.js | 9 +++++++++ client/models/model.js | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/client/models/boundary-conditions.js b/client/models/boundary-conditions.js index aeed723ffe..c156d8045f 100644 --- a/client/models/boundary-conditions.js +++ b/client/models/boundary-conditions.js @@ -23,4 +23,13 @@ var BoundaryCondition = require('./boundary-condition'); module.exports = Collection.extend({ model: BoundaryCondition, + addNewBoundaryCondition: function (name, expression) { + let id = this.parent.getDefaultID(); + let boundaryCondition = this.add({ + compID: id, + name: name, + expression: expression, + annotation: "" + }); + } }); \ No newline at end of file diff --git a/client/models/model.js b/client/models/model.js index d5ca4c628c..1f98d11757 100644 --- a/client/models/model.js +++ b/client/models/model.js @@ -30,7 +30,7 @@ var Reactions = require('./reactions'); var Rules = require('./rules'); var Events = require('./events'); var FunctionDefinitions = require('./function-definitions'); -var BoundaryCondition = require('./boundary-conditions'); +var BoundaryConditions = require('./boundary-conditions'); module.exports = Model.extend({ url: function () { @@ -51,7 +51,7 @@ module.exports = Model.extend({ rules: Rules, eventsCollection: Events, functionDefinitions: FunctionDefinitions, - boundaryConditions: BoundaryCondition + boundaryConditions: BoundaryConditions }, children: { modelSettings: TimespanSettings, From 709a463f1c339efd696a5580a77a63ae7b9fadcd Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 9 Jun 2021 11:45:59 -0400 Subject: [PATCH 16/63] Added the post xhr request that create and return the expression. --- client/views/boundary-conditions-editor.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/client/views/boundary-conditions-editor.js b/client/views/boundary-conditions-editor.js index 1c710f6b80..5bd4b9cff0 100644 --- a/client/views/boundary-conditions-editor.js +++ b/client/views/boundary-conditions-editor.js @@ -17,6 +17,7 @@ along with this program. If not, see . */ let $ = require('jquery'); +let path = require('path'); //support files let app = require('../app'); let tests = require('./tests'); @@ -74,9 +75,15 @@ module.exports = View.extend({ app.changeCollapseButtonText(this, e); }, handleAddBCClick: function (e) { - let newBC = JSON.stringify(this.newBC) - this.setDefaultBC(); - this.resetNewBCViews(); + let endpoint = path.join(app.getApiPath(), "model/new-bc") + let self = this; + app.postXHR(endpoint, this.newBC, { + success: function (err, response, body) { + self.collection.addNewBoundaryCondition(self.newBCName, body.expression); + self.setDefaultBC(); + self.resetNewBCViews(); + } + }); }, handleSetDeterministic: function (e) { this.newBC.deterministic = e.target.checked; From a76f059d2d407f1651915620c0015a3936c57c5e Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 9 Jun 2021 14:53:29 -0400 Subject: [PATCH 17/63] Added boundary conditions to the model template. --- stochss_templates/nonSpatialModelTemplate.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stochss_templates/nonSpatialModelTemplate.json b/stochss_templates/nonSpatialModelTemplate.json index 248896e2cc..5f95a1c9c5 100644 --- a/stochss_templates/nonSpatialModelTemplate.json +++ b/stochss_templates/nonSpatialModelTemplate.json @@ -40,5 +40,6 @@ "reactions": [], "rules": [], "eventsCollection": [], - "functionDefinitions": [] + "functionDefinitions": [], + "boundaryConditions": [] } From 6a185e1c36fbf498367a8e340dbf1f8a5f30d01f Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 10 Jun 2021 15:27:52 -0400 Subject: [PATCH 18/63] Fixed issue with displaying annotations section when boundary conditions don't have annotations. --- client/templates/includes/boundaryConditionsEditor.pug | 6 ++---- client/templates/includes/viewBoundaryCondition.pug | 4 +++- client/views/boundary-conditions-editor.js | 6 ++++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/client/templates/includes/boundaryConditionsEditor.pug b/client/templates/includes/boundaryConditionsEditor.pug index 8cfddaea37..0e6f1fbfdb 100644 --- a/client/templates/includes/boundaryConditionsEditor.pug +++ b/client/templates/includes/boundaryConditionsEditor.pug @@ -115,10 +115,8 @@ div#boundary-conditions.card div.col-sm-7: h6 Expression - div.col-sm-2 - - div.inline Annotation + div.col-sm-2(data-hook="bc-annotation-header") - div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation) + h6 Annotation div.mt-3(data-hook="view-boundary-conditions-list") diff --git a/client/templates/includes/viewBoundaryCondition.pug b/client/templates/includes/viewBoundaryCondition.pug index a78f94d10b..6ea4db586d 100644 --- a/client/templates/includes/viewBoundaryCondition.pug +++ b/client/templates/includes/viewBoundaryCondition.pug @@ -15,4 +15,6 @@ div.mx-1 div.col-md-2 - div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") + if this.model.annotation + + div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") diff --git a/client/views/boundary-conditions-editor.js b/client/views/boundary-conditions-editor.js index 5bd4b9cff0..1255953dc2 100644 --- a/client/views/boundary-conditions-editor.js +++ b/client/views/boundary-conditions-editor.js @@ -136,6 +136,12 @@ module.exports = View.extend({ if(this.viewBoundaryConditionView) { this.viewBoundaryConditionView.remove(); } + this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0; + if(!this.containsMdlWithAnn) { + $(this.queryByHook("bc-annotation-header")).css("display", "none"); + }else{ + $(this.queryByHook("bc-annotation-header")).css("display", "block"); + } let options = {viewOptions: {viewMode: true}}; this.viewBoundaryConditionView = this.renderCollection( this.collection, From 6e6aa854b7d098c720024483dad23f4a782048fb Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 10 Jun 2021 17:23:19 -0400 Subject: [PATCH 19/63] Moved info block outside of the collapse div. Added missing hr tag in view pane. --- .../includes/boundaryConditionsEditor.pug | 137 +++++++++--------- 1 file changed, 71 insertions(+), 66 deletions(-) diff --git a/client/templates/includes/boundaryConditionsEditor.pug b/client/templates/includes/boundaryConditionsEditor.pug index 0e6f1fbfdb..61dc60bbc7 100644 --- a/client/templates/includes/boundaryConditionsEditor.pug +++ b/client/templates/includes/boundaryConditionsEditor.pug @@ -18,105 +18,110 @@ div#boundary-conditions.card button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-boundary-conditions", data-hook="collapse-bc") + - div.card-body.collapse.tab-content(id="collapse-boundary-conditions") + div.card-body - div.tab-pane.active(id="edit-boundary-conditions" data-hook="edit-boundary-conditions") + p.mb-0 + | Set spatial regions of the domain where a property of particles are held constant. - p Set spatial regions of the domain where a property of particles are held constant. + div.collapse.tab-content(id="collapse-boundary-conditions") - hr + div.tab-pane.active(id="edit-boundary-conditions" data-hook="edit-boundary-conditions") - div.mx-1.row.head + hr - div.col-sm-3: h6 Name + div.mx-1.row.head - div.col-sm-5: h6 Expression + div.col-sm-3: h6 Name - div.col-sm-2 + div.col-sm-5: h6 Expression - div.inline Annotation + div.col-sm-2 - div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation) + div.inline Annotation - div.col-sm-2: h6 Remove + div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation) - div.mt-3(data-hook="edit-boundary-conditions-list") + div.col-sm-2: h6 Remove - div.card.mt-3 + div.mt-3(data-hook="edit-boundary-conditions-list") - div.card-header + div.card.mt-3 - h4.inline New Boundary Condition + div.card-header - button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-new-boundary-conditions" data-hook="collapse-new-bc") + + h4.inline New Boundary Condition - div.card-body.mx-1.collapse(id="collapse-new-boundary-conditions") + button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-new-boundary-conditions" data-hook="collapse-new-bc") + - div.row.head + div.card-body.mx-1.collapse(id="collapse-new-boundary-conditions") - div.col-sm-2: h6 Name + div.row.head - div.col-sm-4: h6 Target + div.col-sm-2: h6 Name - div.col-sm-6: h6 Conditions + div.col-sm-4: h6 Target - div.row.mt-3 + div.col-sm-6: h6 Conditions - div.col-sm-2(data-hook="new-bc-name" data-target="name") + div.row.mt-3 - div.col-sm-4 + div.col-sm-2(data-hook="new-bc-name" data-target="name") - table.table - tbody - tr - th(scope="row") Property/Variable - td(data-hook="new-bc-target") - tr - th(scope="row") Value - td(data-hook="new-bc-value" data-target="value") - tr - th(scope="row") Concentration - td - input(type="checkbox" checked=this.newBC.deterministic data-hook="new-bc-deterministic" disabled) + div.col-sm-4 - div.col-sm-6 + table.table + tbody + tr + th(scope="row") Property/Variable + td(data-hook="new-bc-target") + tr + th(scope="row") Value + td(data-hook="new-bc-value" data-target="value") + tr + th(scope="row") Concentration + td + input(type="checkbox" checked=this.newBC.deterministic data-hook="new-bc-deterministic" disabled) - div + div.col-sm-6 - span.inline.mr-3(for="new-bc-type") Type: - div.inline(id="new-bc-type" data-hook="new-bc-type" data-target="type_id") + div - table.table - thead - tr - th(scope="col") - th(scope="col") X-Axis - th(scope="col") Y-Axis - th(scope="col") Z-Axis - tbody - tr - th(scope="row") Min - td: div(data-hook="new-bc-x-min" data-target="xmin") - td: div(data-hook="new-bc-y-min" data-target="ymin") - td: div(data-hook="new-bc-z-min" data-target="zmin") - tr - th(scope="row") Max - td: div(data-hook="new-bc-x-max" data-target="xmax") - td: div(data-hook="new-bc-y-max" data-target="ymax") - td: div(data-hook="new-bc-z-max" data-target="zmax") + span.inline.mr-3(for="new-bc-type") Type: + div.inline(id="new-bc-type" data-hook="new-bc-type" data-target="type_id") - button.btn.btn-outline-primary.box-shadow(data-hook="add-new-bc") Add New Boundary Condition + table.table + thead + tr + th(scope="col") + th(scope="col") X-Axis + th(scope="col") Y-Axis + th(scope="col") Z-Axis + tbody + tr + th(scope="row") Min + td: div(data-hook="new-bc-x-min" data-target="xmin") + td: div(data-hook="new-bc-y-min" data-target="ymin") + td: div(data-hook="new-bc-z-min" data-target="zmin") + tr + th(scope="row") Max + td: div(data-hook="new-bc-x-max" data-target="xmax") + td: div(data-hook="new-bc-y-max" data-target="ymax") + td: div(data-hook="new-bc-z-max" data-target="zmax") - div.tab-pane(id="view-boundary-conditions" data-hook="view-boundary-conditions") + button.btn.btn-outline-primary.box-shadow(data-hook="add-new-bc") Add New Boundary Condition - div.mx-1.row.head + div.tab-pane(id="view-boundary-conditions" data-hook="view-boundary-conditions") - div.col-sm-3: h6 Name + hr - div.col-sm-7: h6 Expression + div.mx-1.row.head - div.col-sm-2(data-hook="bc-annotation-header") + div.col-sm-3: h6 Name - h6 Annotation + div.col-sm-7: h6 Expression - div.mt-3(data-hook="view-boundary-conditions-list") + div.col-sm-2(data-hook="bc-annotation-header") + + h6 Annotation + + div.mt-3(data-hook="view-boundary-conditions-list") From b6a8d99f7ec700e28f1989b5c3b48aad92bcd3e6 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 10 Jun 2021 17:24:01 -0400 Subject: [PATCH 20/63] Fixed viewer update issue. --- client/views/boundary-condition-view.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/views/boundary-condition-view.js b/client/views/boundary-condition-view.js index 6c88802b95..a5d5a0e05a 100644 --- a/client/views/boundary-condition-view.js +++ b/client/views/boundary-condition-view.js @@ -66,7 +66,8 @@ module.exports = View.extend({ }); okBtn.addEventListener('click', function (e) { self.model.annotation = input.value.trim(); - self.parent.renderBoundaryConditionView(); + self.parent.renderEditBoundaryConditionView(); + self.parent.renderViewBoundaryConditionView(); modal.modal('hide'); }); }, From d4afa33d6ac8f8cbf2ac8a687924b82beb196117 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 22 Jun 2021 15:50:19 -0400 Subject: [PATCH 21/63] Added properties to the spatial model preview target selection modal. --- client/modals.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/client/modals.js b/client/modals.js index c55db1f6b8..db5185cc64 100644 --- a/client/modals.js +++ b/client/modals.js @@ -424,15 +424,26 @@ module.exports = { return templates.select(modalID, selectID, title, label, options) }, - selectSpeciesHTML : (species) => { - let modalID = "speciesSelectModal"; - let selectID = "speciesSelectList"; - let title = "Preview Variable Selection"; - let label = "Select a variable to preview: "; + selectPreviewTargetHTML : (species) => { + let modalID = "previewTargetSelectModal"; + let selectID = "previewTargetSelectList"; + let title = "Preview Target Selection"; + let label = "Select a variable or property to preview: "; var options = species.map(function (name) { return `` }); - options = options.join(" "); + options = ` + ${options.join(" ")} + + + + + + + + + + `; return templates.select(modalID, selectID, title, label, options) }, From 87c2484f0accb81b3410b046fd3f01ffb887549b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 22 Jun 2021 15:51:37 -0400 Subject: [PATCH 22/63] Refactored the spatial model target selection process function to reflect that users can also choose species. --- client/views/model-state-buttons.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index f7d5bebf8a..ff24e5df62 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -63,7 +63,7 @@ module.exports = View.extend({ Plotly.purge(el) $(this.parent.queryByHook('preview-plot-buttons')).css("display", "none"); if(this.model.is_spatial) { - this.saveModel(this.getPreviewSpecies.bind(this)); + this.saveModel(this.getPreviewTarget.bind(this)); }else{ this.saveModel(this.runModel.bind(this)); } @@ -94,19 +94,19 @@ module.exports = View.extend({ window.location.href = endpoint }) }, - getPreviewSpecies: function () { + getPreviewTarget: function () { this.saved(); let species = this.model.species.map(function (species) { return species.name }); let self = this; - let modal = $(modals.selectSpeciesHTML(species)).modal(); - let okBtn = document.querySelector("#speciesSelectModal .ok-model-btn"); - let select = document.querySelector("#speciesSelectModal #speciesSelectList"); + let modal = $(modals.selectPreviewTargetHTML(species)).modal(); + let okBtn = document.querySelector("#previewTargetSelectModal .ok-model-btn"); + let select = document.querySelector("#previewTargetSelectModal #previewTargetSelectList"); okBtn.addEventListener('click', function (e) { modal.modal('hide'); - let specie = select.value; - self.runModel(specie); + let target = select.value; + self.runModel(target); }); }, togglePreviewWorkflowBtn: function () { @@ -149,8 +149,8 @@ module.exports = View.extend({ saved.style.display = "none"; }, 5000); }, - runModel: function (species=null) { - if(typeof species !== "string") { + runModel: function (target=null) { + if(typeof target !== "string") { this.saved(); } this.running(); @@ -158,7 +158,7 @@ module.exports = View.extend({ var model = this.model var queryStr = "?cmd=start&outfile=none&path="+model.directory if(species) { - queryStr += "&species=" + species; + queryStr += "&target=" + target; } var endpoint = path.join(app.getApiPath(), 'model/run')+queryStr; var self = this; From 09265fee00375944aebd4bc781e37284893d86e2 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 22 Jun 2021 16:44:26 -0400 Subject: [PATCH 23/63] renamed species to target for spatial model preview target selections. Refactored the preview ploting to generate either a properties plot or species plot depending on the target. --- client/modals.js | 6 ++--- client/views/model-state-buttons.js | 2 +- stochss/handlers/models.py | 8 +++--- stochss/handlers/util/scripts/run_preview.py | 4 +-- stochss/handlers/util/spatial_simulation.py | 28 +++++++++++++------- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/client/modals.js b/client/modals.js index db5185cc64..54b3aaadf2 100644 --- a/client/modals.js +++ b/client/modals.js @@ -437,9 +437,9 @@ module.exports = { - - - + + + diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index ff24e5df62..4683565571 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -157,7 +157,7 @@ module.exports = View.extend({ $(this.parent.queryByHook('model-run-container')).css("display", "block") var model = this.model var queryStr = "?cmd=start&outfile=none&path="+model.directory - if(species) { + if(target) { queryStr += "&target=" + target; } var endpoint = path.join(app.getApiPath(), 'model/run')+queryStr; diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index b4a4a62755..36d3a4e68e 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -209,14 +209,14 @@ async def get(self): if outfile == 'none': outfile = str(uuid.uuid4()).replace("-", "_") log.debug("Temporary outfile: %s", outfile) - species = self.get_query_argument(name="species", default=None) + target = self.get_query_argument(name="target", default=None) resp = {"Running":False, "Outfile":outfile, "Results":""} if run_cmd == "start": exec_cmd = ['/stochss/stochss/handlers/util/scripts/run_preview.py', f'{path}', f'{outfile}'] - if species is not None: - exec_cmd.insert(1, "--species") - exec_cmd.insert(2, f"{species}") + if target is not None: + exec_cmd.insert(1, "--target") + exec_cmd.insert(2, f"{target}") log.debug("Script commands for running a preview: %s", exec_cmd) subprocess.Popen(exec_cmd) resp['Running'] = True diff --git a/stochss/handlers/util/scripts/run_preview.py b/stochss/handlers/util/scripts/run_preview.py index 013f2b3d91..89cd9c6c1f 100755 --- a/stochss/handlers/util/scripts/run_preview.py +++ b/stochss/handlers/util/scripts/run_preview.py @@ -75,7 +75,7 @@ def get_parsed_args(): parser = argparse.ArgumentParser(description=description) parser.add_argument('path', help="The path from the user directory to the model.") parser.add_argument('outfile', help="The temp file used to hold the results.") - parser.add_argument('--species', help="Spatial species to preview.", default=None) + parser.add_argument('--target', help="Spatial species or property to preview.", default=None) return parser.parse_args() @@ -107,7 +107,7 @@ def run_preview(job): is_spatial = args.path.endswith(".smdl") if is_spatial: model = StochSSSpatialModel(path=args.path) - wkfl = SpatialSimulation(path="", preview=True, species=args.species) + wkfl = SpatialSimulation(path="", preview=True, target=args.target) wkfl.s_py_model = model.convert_to_spatialpy() wkfl.s_model = model.model else: diff --git a/stochss/handlers/util/spatial_simulation.py b/stochss/handlers/util/spatial_simulation.py index c2fd231b00..955af08715 100644 --- a/stochss/handlers/util/spatial_simulation.py +++ b/stochss/handlers/util/spatial_simulation.py @@ -30,7 +30,7 @@ class SpatialSimulation(StochSSJob): TYPE = "spatial" - def __init__(self, path, preview=False, species=None): + def __init__(self, path, preview=False, target=None): ''' Intitialize a spatial ensemble simulation job object @@ -38,13 +38,17 @@ def __init__(self, path, preview=False, species=None): ---------- path : str Path to the spatial ensemble simulation job + preview : bool + Indicates whether or not the simulation is a preview. + target : string + Results data target used for ploting ''' super().__init__(path=path) if not preview: self.settings = self.load_settings() self.s_py_model, self.s_model = self.load_models() else: - self.species = species + self.target = target def __get_run_settings(self): @@ -67,14 +71,20 @@ def run(self, preview=False, verbose=False): if verbose: self.log("info", "Running a preview spatial ensemble simulation") results = self.s_py_model.run(timeout=60) - # if self.species is None: - # self.species = list(self.s_py_model.get_all_species().keys())[0] + properties = ["type", "rho", "mass", "nu"] t_ndx_list = list(range(len(os.listdir(results.result_dir)) - 1)) - plot = results.plot_species(species=self.species, t_ndx_list=t_ndx_list, animated=True, - concentration=self.s_model['defaultMode'] == "continuous", - deterministic=self.s_model['defaultMode'] == "discrete", - width=None, height=None, return_plotly_figure=True, - f_duration=100, t_duration=100) + kwargs = {"t_ndx_list": t_ndx_list, "animated": True, "width": None, "height": None, + "return_plotly_figure": True, "f_duration": 100, "t_duration": 100} + if self.target in properties or self.target.startswith("v["): + if self.target.startswith("v["): + kwargs['p_ndx'] = int(self.target[2]) + self.target = "v" + plot = results.plot_property(property_name=self.target, **kwargs) + else: + concentration = self.s_model['defaultMode'] == "continuous" + deterministic = self.s_model['defaultMode'] == "discrete" + plot = results.plot_species(species=self.target, concentration=concentration, + deterministic=deterministic, **kwargs) plot["layout"]["autosize"] = True plot["config"] = {"responsive": True, "displayModeBar": True} return plot From 7a9a69c78e4c5a0ba2bb923fb1c14b268824c401 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 23 Jun 2021 14:08:18 -0400 Subject: [PATCH 24/63] Re-designed the layout for the domain viewer. --- client/templates/includes/domainViewer.pug | 189 ++++++++++++--------- 1 file changed, 111 insertions(+), 78 deletions(-) diff --git a/client/templates/includes/domainViewer.pug b/client/templates/includes/domainViewer.pug index 296b7a0d7f..cbfe1f2478 100644 --- a/client/templates/includes/domainViewer.pug +++ b/client/templates/includes/domainViewer.pug @@ -1,113 +1,146 @@ -div#domain-viewer.card.card-body +div#domain-viewer.card - div + div.card-header.pb-0 - h3.inline Domain + h3.inline.mr-3 Domain + + div.inline.mr-3 + + ul.nav.nav-tabs.card-header-tabs(id="domain-tabs") + + li.nav-item + + a.nav-link.tab.active(data-hook="domain-edit-tab" data-toggle="tab" href="#edit-domain") Edit + + li.nav-item + + a.nav-link.tab(data-hook="domain-view-tab" data-toggle="tab" href="#view-domain") View button.btn.btn-outline-collapse(id="-btn" data-toggle="collapse" data-target="#collapse-domain" data-hook="collapse") + div.collapse(id="collapse-domain" data-hook="domain-container") - div + div.card-body.tab-content + + div(data-hook="external-domains-container") + + button.btn.btn-outline-secondary.box-shadow.mb-3(data-hook="select-external-domain") View External Domain + + div(data-hook="external-domain-select" style="display: none") + + div.text-info(data-hook="select-location-message" style="display: none") + | There are multiple domain files with that name, please select a location + + span.inline Select External Domain: + + div.inline(data-hook="select-domain") + + div.inline.ml-3(data-hook="select-domain-location" style="display: none") + + span.inline Location: + + div.inline(data-hook="select-location") + + div.row + + div.col-md-4 + + h4 Domain Properties + + hr.mt-2 + div.row + div.col-sm-6: h6.pl-2 Static Domain + div.col-sm-6: input(type="checkbox" id="static-domain" data-hook="static-domain" checked=this.model.static disabled) + + hr.mt-2 + div.row + div.col-sm-6: h6.pl-2 Density + div.col-sm-6=this.model.rho_0 + + hr.mt-2 + div.row + div.col-sm-6: h6.pl-2 Gravity + div.col-sm-6=this.gravity + + hr.mt-2 + div.row + div.col-sm-6: h6.pl-2 Pressure + div.col-sm-6=this.model.p_0 - button.btn.btn-outline-secondary.box-shadow.mb-3(data-hook="select-external-domain") View External Domain + hr.mt-2 + div.row + div.col-sm-6: h6.pl-2 Speed of Sound + div.col-sm-6=this.model.c_0 - div(data-hook="external-domain-select" style="display: none") + div.col-md-8 - div.text-info(data-hook="select-location-message" style="display: none") - | There are multiple domain files with that name, please select a location + h4 Domain Limits - span.inline Select External Domain: + hr.mt-2 + div.row.head.mx-1 + div.col-sm-3 + div.col-sm-3.pb-1: h6 Minimum + div.col-sm-3: h6 Minimum + div.col-sm-3: h6 Reflect - div.inline(data-hook="select-domain") + div.row.mt-3 + div.col-sm-3: h6.pl-2 X-Axis + div.col-sm-3=this.model.x_lim[0] + div.col-sm-3=this.model.x_lim[1] + div.col-sm-3: input(type="checkbox" checked=this.model.boundary_condition.reflect_x disabled) - div.inline.ml-3(data-hook="select-domain-location" style="display: none") + hr.mt-2 + div.row + div.col-sm-3: h6.pl-2 Y-Axis + div.col-sm-3=this.model.y_lim[0] + div.col-sm-3=this.model.y_lim[1] + div.col-sm-3: input(type="checkbox" checked=this.model.boundary_condition.reflect_y disabled) - span.inline Location: + hr.mt-2 + div.row + div.col-sm-3: h6.pl-2 Z-Axis + div.col-sm-3=this.model.z_lim[0] + div.col-sm-3=this.model.z_lim[1] + div.col-sm-3: input(type="checkbox" checked=this.model.boundary_condition.reflect_z disabled) - div.inline(data-hook="select-location") + div.mt-3 - div.row + h4 Types - div.col-md-4 + hr - h4 Domain Properties + h6="Number of Un-Assigned Particles: " + this.model.types.get(0, "typeID").numParticles - table.table - tbody - tr - th(scope="row") Static Domain - td: input(type="checkbox" id="static-domain" data-hook="static-domain" checked=this.model.static disabled) - tr - th(scope="row") Density - td=this.model.rho_0 - tr - th(scope="row") Gravity - td=this.gravity - tr - th(scope="row") Pressure - td=this.model.p_0 - tr - th(scope="row") Speed of Sound - td=this.model.c_0 + div(data-hook="domain-error"): p.text-danger A domain cannot have any un-assigned particles. - div.col-md-8 + hr - h4 Domain Limits + div.mx-1.row.head.align-items-baseline - table.table - thead - tr - th(scope="col") - th(scope="col") Minimum - th(scope="col") Minimum - th(scope="col") Reflect + div.col-sm-2: h6.pl-2 Name - tbody - tr - th(scope="row") X-Axis - td=this.model.x_lim[0] - td=this.model.x_lim[1] - td: input(type="checkbox" checked=this.model.boundary_condition.reflect_x disabled) - tr - th(scope="row") Y-Axis - td=this.model.y_lim[0] - td=this.model.y_lim[1] - td: input(type="checkbox" checked=this.model.boundary_condition.reflect_y disabled) - tr - th(scope="row") Z-Axis - td=this.model.z_lim[0] - td=this.model.z_lim[1] - td: input(type="checkbox" checked=this.model.boundary_condition.reflect_z disabled) + div.col-sm-2: h6 Number of Particles - div + div.col-sm-2: h6 Mass - h4 Types + div.col-sm-2: h6 Volume - hr + div.col-sm-2: h6 Viscosity - h6="Number of Un-Assigned Particles: " + this.model.types.get(0, "typeID").numParticles + div.col-sm-2: h6 Fixed - div(data-hook="domain-error"): p.text-danger A domain cannot have any un-assigned particles. + div(data-hook="domain-types-list") - table.table - thead - tr - th(scope="col") Name - th(scope="col") Number of Particles - th(scope="col") Mass - th(scope="col") Volume - th(scope="col") Viscosity - th(scope="col") Fixed + div.tab-pane.active(id="edit-domain" data-hook="edit-domain") - tbody(data-hook="domain-types-list") + hr - hr + div - div + button.btn.btn-outline-primary.box-shadow(data-hook="edit-domain") Edit Domain - button.btn.btn-outline-primary.box-shadow(data-hook="edit-domain") Edit Domain + button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="create-domain") Build New Domain - button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="create-domain") Build New Domain + button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-to-model" disabled) Import into Model - button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-to-model" disabled) Import into Model + div.tab-pane(id="view-domain" data-hook="view-domain") From 44bbd3f4bea9d2d5fedff65e59533437b1f78ce8 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 23 Jun 2021 14:36:21 -0400 Subject: [PATCH 25/63] Cleaned up the name input subview. Added option viewMode property. Added template selection based on view mode. --- client/views/edit-domain-type.js | 43 ++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/client/views/edit-domain-type.js b/client/views/edit-domain-type.js index 20bba307e3..bd3b028c17 100644 --- a/client/views/edit-domain-type.js +++ b/client/views/edit-domain-type.js @@ -22,10 +22,10 @@ let app = require('../app'); var View = require('ampersand-view'); var InputView = require('./input'); //templates -var template = require('../templates/includes/editDomainType.pug'); +let editTemplate = require('../templates/includes/editDomainType.pug'); +let viewTemplate = require('../templates/includes/viewDomainType.pug'); module.exports = View.extend({ - template: template, events: { 'click [data-hook=unassign-all]' : 'handleUnassignParticles', 'click [data-hook=delete-type]' : 'handleDeleteType', @@ -33,6 +33,15 @@ module.exports = View.extend({ 'click [data-hook=edit-defaults-btn]' : 'handleEditDefaults', 'change [data-target=type-name]' : 'handleRenameType' }, + initialize: function (attrs, options) { + View.prototype.initialize.apply(this, arguments); + this.viewMode = attrs.viewMode ? attrs.viewMode : false; + console.log(this.model.typeID) + }, + render: function (attrs, options) { + this.template = this.viewMode ? viewTemplate : editTemplate; + View.prototype.render.apply(this, arguments); + }, handleDeleteType: function (e) { let type = Number(e.target.dataset.type); this.parent.deleteType(type); @@ -58,19 +67,21 @@ module.exports = View.extend({ this.parent.unassignAllParticles(type); this.parent.renderDomainTypes(); }, - initialize: function (attrs, options) { - View.prototype.initialize.apply(this, arguments); - }, - render: function (attrs, options) { - View.prototype.render.apply(this, arguments); - this.renderNameView(); - }, - renderNameView: function () { - let nameView = new InputView({parent: this, required: true, - name: 'name', valueType: 'string', - value: this.model.name}); - app.registerRenderSubview(this, nameView, "type-" + this.model.typeID); - }, update: function () {}, - updateValid: function () {} + updateValid: function () {}, + subviews: { + inputName: { + waitFor: "model.typeID", + prepareView: function (el) { + return new InputView({ + el: "type-" + this.model.typeID, + parent: this, + required: true, + name: 'name', + valueType: 'string', + value: this.model.name + }); + } + } + } }); \ No newline at end of file From a31b56d839871230644aae9b9c59862b503d962e Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 23 Jun 2021 14:37:36 -0400 Subject: [PATCH 26/63] Refactored the domain viewer to use the edit domain type js file in view mode to render the domain types. --- client/views/domain-viewer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/views/domain-viewer.js b/client/views/domain-viewer.js index edaff605a7..b4fbe8ae3a 100644 --- a/client/views/domain-viewer.js +++ b/client/views/domain-viewer.js @@ -25,7 +25,7 @@ var Plotly = require('../lib/plotly'); var Tooltips = require('../tooltips'); //views var View = require('ampersand-view'); -var TypesViewer = require('./view-domain-types'); +var TypesViewer = require('./edit-domain-type'); var SelectView = require('ampersand-select-view'); var ParticleViewer = require('./view-particle'); //templates @@ -171,9 +171,9 @@ module.exports = View.extend({ this.model.types, TypesViewer, this.queryByHook("domain-types-list"), - {"filter": function (model) { + {filter: function (model) { return model.typeID != 0; - }} + }, viewOptions: {viewMode: true}} ); }, displayDomain: function () { From ce6deb98bda1a1d9ff80ba720f1aa751a2bbc995 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 23 Jun 2021 14:39:11 -0400 Subject: [PATCH 27/63] Removed the dead view-domain-types.js file. Renamed the domain type view file. --- ...mainTypesViewer.pug => viewDomainType.pug} | 0 client/views/view-domain-types.js | 26 ------------------- 2 files changed, 26 deletions(-) rename client/templates/includes/{domainTypesViewer.pug => viewDomainType.pug} (100%) delete mode 100644 client/views/view-domain-types.js diff --git a/client/templates/includes/domainTypesViewer.pug b/client/templates/includes/viewDomainType.pug similarity index 100% rename from client/templates/includes/domainTypesViewer.pug rename to client/templates/includes/viewDomainType.pug diff --git a/client/views/view-domain-types.js b/client/views/view-domain-types.js deleted file mode 100644 index 5b2d8906fa..0000000000 --- a/client/views/view-domain-types.js +++ /dev/null @@ -1,26 +0,0 @@ -/* -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 . -*/ - -//views -var View = require('ampersand-view'); -//templates -var template = require('../templates/includes/domainTypesViewer.pug'); - -module.exports = View.extend({ - template: template, -}); \ No newline at end of file From 324329f418b75853a8b91d752a0c4aa0e9f0299b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 23 Jun 2021 14:47:39 -0400 Subject: [PATCH 28/63] Re-designed the layout for view domain type. --- client/templates/includes/domainViewer.pug | 4 ++-- client/templates/includes/viewDomainType.pug | 23 ++++++++++++++------ client/views/edit-domain-type.js | 1 - 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/client/templates/includes/domainViewer.pug b/client/templates/includes/domainViewer.pug index cbfe1f2478..bc9ba9b3c1 100644 --- a/client/templates/includes/domainViewer.pug +++ b/client/templates/includes/domainViewer.pug @@ -117,7 +117,7 @@ div#domain-viewer.card div.mx-1.row.head.align-items-baseline - div.col-sm-2: h6.pl-2 Name + div.col-sm-2: h6 Name div.col-sm-2: h6 Number of Particles @@ -129,7 +129,7 @@ div#domain-viewer.card div.col-sm-2: h6 Fixed - div(data-hook="domain-types-list") + div.my-3(data-hook="domain-types-list") div.tab-pane.active(id="edit-domain" data-hook="edit-domain") diff --git a/client/templates/includes/viewDomainType.pug b/client/templates/includes/viewDomainType.pug index fab182ab9e..1baecacecc 100644 --- a/client/templates/includes/viewDomainType.pug +++ b/client/templates/includes/viewDomainType.pug @@ -1,13 +1,22 @@ -tr +div.mx-1 - td=this.model.name + if(this.model.collection.indexOf(this.model) !== 1) + hr - td=this.model.numParticles + div.row - td=this.model.mass + div.col-sm-2 - td=this.model.volume + div.pl-2=this.model.name - td=this.model.nu + div.col-sm-2=this.model.numParticles - td: input(type="checkbox" checked=this.model.fixed disabled) \ No newline at end of file + div.col-sm-2=this.model.mass + + div.col-sm-2=this.model.volume + + div.col-sm-2=this.model.nu + + div.col-sm-2 + + input(type="checkbox" checked=this.model.fixed disabled) diff --git a/client/views/edit-domain-type.js b/client/views/edit-domain-type.js index bd3b028c17..455cf02da3 100644 --- a/client/views/edit-domain-type.js +++ b/client/views/edit-domain-type.js @@ -36,7 +36,6 @@ module.exports = View.extend({ initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); this.viewMode = attrs.viewMode ? attrs.viewMode : false; - console.log(this.model.typeID) }, render: function (attrs, options) { this.template = this.viewMode ? viewTemplate : editTemplate; From c24f1e33240f5cdae1bb6dab4b9d2ec049f92efe Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 23 Jun 2021 15:11:47 -0400 Subject: [PATCH 29/63] Fixed conflicting data hooks. Added function to hide the 'View External Domain' button when the view tab is clicked. --- client/templates/includes/domainViewer.pug | 2 +- client/views/domain-viewer.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/client/templates/includes/domainViewer.pug b/client/templates/includes/domainViewer.pug index bc9ba9b3c1..6682a5cf1d 100644 --- a/client/templates/includes/domainViewer.pug +++ b/client/templates/includes/domainViewer.pug @@ -137,7 +137,7 @@ div#domain-viewer.card div - button.btn.btn-outline-primary.box-shadow(data-hook="edit-domain") Edit Domain + button.btn.btn-outline-primary.box-shadow(data-hook="edit-domain-btn") Edit Domain button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="create-domain") Build New Domain diff --git a/client/views/domain-viewer.js b/client/views/domain-viewer.js index b4fbe8ae3a..0efa946f69 100644 --- a/client/views/domain-viewer.js +++ b/client/views/domain-viewer.js @@ -34,8 +34,10 @@ var template = require('../templates/includes/domainViewer.pug'); module.exports = View.extend({ template: template, events: { + 'click [data-hook=domain-edit-tab]' : 'toggleViewExternalDomainBtn', + 'click [data-hook=domain-view-tab]' : 'toggleViewExternalDomainBtn', 'click [data-hook=collapse]' : 'changeCollapseButtonText', - 'click [data-hook=edit-domain]' : 'editDomain', + 'click [data-hook=edit-domain-btn]' : 'editDomain', 'click [data-hook=create-domain]' : 'editDomain', 'click [data-hook=save-to-model]' : 'saveDomainToModel', 'click [data-hook=select-external-domain]' : 'handleLoadExternalDomain', @@ -213,6 +215,16 @@ module.exports = View.extend({ errorMsg.removeClass('component-invalid') } }, + toggleViewExternalDomainBtn: function (e) { + if(e) { + if(!e.target.classList.contains("active")) { + let display = e.target.text === "View" ? "none" : "block" + $(this.queryByHook("external-domains-container")).css("display", display); + } + }else{ + console.log("TODO: handle initial state") + } + }, changeCollapseButtonText: function (e) { app.changeCollapseButtonText(this, e); } From 2f55f2c6f7bc81bc20179b216b741246a08dca6a Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 23 Jun 2021 15:37:52 -0400 Subject: [PATCH 30/63] Added function to support read only mode. --- client/templates/includes/domainViewer.pug | 2 +- client/views/domain-viewer.js | 90 +++++++++++++--------- 2 files changed, 53 insertions(+), 39 deletions(-) diff --git a/client/templates/includes/domainViewer.pug b/client/templates/includes/domainViewer.pug index 6682a5cf1d..14590cd722 100644 --- a/client/templates/includes/domainViewer.pug +++ b/client/templates/includes/domainViewer.pug @@ -111,7 +111,7 @@ div#domain-viewer.card h6="Number of Un-Assigned Particles: " + this.model.types.get(0, "typeID").numParticles - div(data-hook="domain-error"): p.text-danger A domain cannot have any un-assigned particles. + div.component-valid(data-hook="domain-error"): p.text-danger A domain cannot have any un-assigned particles. hr diff --git a/client/views/domain-viewer.js b/client/views/domain-viewer.js index 0efa946f69..0ac2e490bb 100644 --- a/client/views/domain-viewer.js +++ b/client/views/domain-viewer.js @@ -44,6 +44,55 @@ module.exports = View.extend({ 'change [data-hook=select-domain]' : 'handleSelectDomain', 'change [data-hook=select-location]' : 'handleSelectDomainLocation' }, + initialize: function (attrs, options) { + View.prototype.initialize.apply(this, arguments); + this.readOnly = attrs.readOnly ? attrs.readOnly : false; + this.tooltips = Tooltips.domainEditor; + this.domainPath = attrs.domainPath; + let self = this; + this.model.particles.forEach(function (particle) { + self.model.types.get(particle.type, "typeID").numParticles += 1; + }); + this.gravity = this.getGravityString() + }, + render: function () { + View.prototype.render.apply(this, arguments); + let self = this; + var queryStr = "?path=" + this.parent.model.directory + if(this.readOnly) { + $(this.queryByHook('domain-edit-tab')).addClass("disabled"); + $(".nav .disabled>a").on("click", function(e) { + e.preventDefault(); + return false; + }); + $(this.queryByHook('domain-view-tab')).tab('show'); + $(this.queryByHook('edit-domain')).removeClass('active'); + $(this.queryByHook('view-domain')).addClass('active'); + this.toggleViewExternalDomainBtn(); + }else { + this.renderDomainSelectView(); + if(this.domainPath) { + $(this.queryByHook("domain-container")).collapse("show") + $(this.queryByHook("collapse")).text("-") + if(this.domainPath !== "viewing") { + $(this.queryByHook("save-to-model")).prop("disabled", false) + $(this.queryByHook("external-domain-select")).css("display", "block") + $(this.queryByHook("select-external-domain")).text("View Model's Domain") + queryStr += "&domain_path=" + this.domainPath + } + } + this.toggleDomainError(); + } + this.renderTypesViewer(); + this.parent.renderParticleViewer(null); + let endpoint = path.join(app.getApiPath(), "spatial-model/domain-plot") + queryStr; + app.getXHR(endpoint, { + always: function (err, response, body) { + self.plot = body.fig; + self.displayDomain(); + } + }); + }, handleLoadExternalDomain: function (e) { let text = e.target.textContent if(text === "View External Domain") { @@ -80,48 +129,12 @@ module.exports = View.extend({ this.parent.renderDomainViewer(domainPath); } }, - initialize: function (attrs, options) { - View.prototype.initialize.apply(this, arguments); - this.tooltips = Tooltips.domainEditor; - this.domainPath = attrs.domainPath; - let self = this; - this.model.particles.forEach(function (particle) { - self.model.types.get(particle.type, "typeID").numParticles += 1; - }); - this.gravity = this.getGravityString() - }, getGravityString: function () { var gravity = "(X: " + this.model.gravity[0]; gravity += ", Y: " + this.model.gravity[1]; gravity += ", Z: " + this.model.gravity[2] + ")"; return gravity; }, - render: function () { - View.prototype.render.apply(this, arguments); - this.renderDomainSelectView(); - this.renderTypesViewer(); - let self = this; - var queryStr = "?path=" + this.parent.model.directory - if(this.domainPath) { - $(this.queryByHook("domain-container")).collapse("show") - $(this.queryByHook("collapse")).text("-") - if(this.domainPath !== "viewing") { - $(this.queryByHook("save-to-model")).prop("disabled", false) - $(this.queryByHook("external-domain-select")).css("display", "block") - $(this.queryByHook("select-external-domain")).text("View Model's Domain") - queryStr += "&domain_path=" + this.domainPath - } - } - this.parent.renderParticleViewer(null); - let endpoint = path.join(app.getApiPath(), "spatial-model/domain-plot") + queryStr; - app.getXHR(endpoint, { - always: function (err, response, body) { - self.plot = body.fig; - self.displayDomain(); - } - }); - this.toggleDomainError(); - }, renderDomainSelectView: function () { let self = this; let endpoint = path.join(app.getApiPath(), "spatial-model/domain-list"); @@ -218,11 +231,12 @@ module.exports = View.extend({ toggleViewExternalDomainBtn: function (e) { if(e) { if(!e.target.classList.contains("active")) { - let display = e.target.text === "View" ? "none" : "block" + let display = e.target.text === "View" ? "none" : "block"; $(this.queryByHook("external-domains-container")).css("display", display); } }else{ - console.log("TODO: handle initial state") + let display = this.readOnly ? "none" : "block"; + $(this.queryByHook("external-domains-container")).css("display", display); } }, changeCollapseButtonText: function (e) { From 6bd08407bda18ecb09b37bbed21973c95734a7de Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 24 Jun 2021 09:30:35 -0400 Subject: [PATCH 31/63] Added auto save function to the model that saves every two minutes. --- client/models/model.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/models/model.js b/client/models/model.js index b8b59ab441..80cbff9cf0 100644 --- a/client/models/model.js +++ b/client/models/model.js @@ -124,7 +124,10 @@ module.exports = Model.extend({ return id; }, autoSave: function () { - //TODO: implement auto save + let self = this; + setTimeout(function () { + app.postXHR(self.url(), self.toJSON(), { success: self.autoSave }); + }, 120000); }, //called when save button is clicked saveModel: function (cb=null) { From 2c14e27d8cfa9e179f77798546793cf2f922b749 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 24 Jun 2021 09:31:28 -0400 Subject: [PATCH 32/63] Added function to the model editor that starts the autosave process. --- client/pages/model-editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index b3b8160138..9f7300b9db 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -257,7 +257,8 @@ let ModelEditor = PageView.extend({ } this.renderSystemVolumeView(); } - $(document).ready(function () { + this.model.autoSave(); + $(function () { $('[data-toggle="tooltip"]').tooltip(); $('[data-toggle="tooltip"]').click(function () { $('[data-toggle="tooltip"]').tooltip("hide"); From f165accaba237f137b2863ef7f8c154b419e6966 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 24 Jun 2021 12:22:15 -0400 Subject: [PATCH 33/63] Cleaned up the initial conditions render function. Removed the initial conditions viewer." --- client/pages/model-editor.js | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index b3b8160138..48ec39bf49 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -30,7 +30,6 @@ var InputView = require('../views/input'); var DomainViewer = require('../views/domain-viewer'); var SpeciesEditorView = require('../views/species-editor'); var InitialConditionsEditorView = require('../views/initial-conditions-editor'); -var InitialConditionsViewer = require('../views/initial-conditions-viewer'); var ParametersEditorView = require('../views/parameters-editor'); var ParticleViewer = require('../views/view-particle'); var ReactionsEditorView = require('../views/reactions-editor'); @@ -306,22 +305,15 @@ let ModelEditor = PageView.extend({ }); app.registerRenderSubview(this, this.speciesEditor, 'species-editor-container'); }, - renderInitialConditions: function (mode="edit", opened=false) { + renderInitialConditions: function () { if(this.initialConditionsEditor) { this.initialConditionsEditor.remove(); } - if(mode === "edit") { - this.initialConditionsEditor = new InitialConditionsEditorView({ - collection: this.model.initialConditions, - opened: opened - }); - }else{ - this.initialConditionsEditor = new InitialConditionsViewer({ - collection: this.model.initialConditions - }); - } + this.initialConditionsEditor = new InitialConditionsEditorView({ + collection: this.model.initialConditions, + }); app.registerRenderSubview(this, this.initialConditionsEditor, 'initial-conditions-editor-container'); - }, + }, renderParametersView: function () { if(this.parametersEditor) { this.parametersEditor.remove() From b0bc2ea1cf3dfaef8308e4548e412ac6fe35b16b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 24 Jun 2021 13:03:38 -0400 Subject: [PATCH 34/63] Re-designed the layout for initial conditions. --- .../includes/editInitialCondition.pug | 39 +++++---- .../includes/initialConditionsEditor.pug | 85 +++++++++++-------- 2 files changed, 75 insertions(+), 49 deletions(-) diff --git a/client/templates/includes/editInitialCondition.pug b/client/templates/includes/editInitialCondition.pug index 51d9602e52..9b055ac852 100644 --- a/client/templates/includes/editInitialCondition.pug +++ b/client/templates/includes/editInitialCondition.pug @@ -1,21 +1,30 @@ -tr +div.mx-1 - td: div(data-hook="initial-condition-type") + if(this.model.collection.indexOf(this.model) !== 0) + hr - td: div(data-hook="initial-condition-species") + div.row - td: div(data-hook="count-container") + div.col-sm-2 - td + div.pl-2(data-hook="initial-condition-type") - div(data-hook="place-details") - span Location: - div - div.inline(data-hook="x-container") - div.inline(data-hook="y-container") - div.inline(data-hook="z-container") - div(data-hook="scatter-details") - span Active in Types: - div(data-hook="initial-condition-types") + div.col-sm-2(data-hook="initial-condition-species") - td: button.btn.btn-outline-secondary(data-hook="remove") X \ No newline at end of file + div.col-sm-3(data-hook="count-container") + + div.col-sm-3 + + div(data-hook="place-details") + span Location: + div + div.inline(data-hook="x-container") + div.inline(data-hook="y-container") + div.inline(data-hook="z-container") + div(data-hook="scatter-details") + span Active in Types: + div(data-hook="initial-condition-types") + + div.col-sm-2 + + button.btn.btn-outline-secondary(data-hook="remove") X diff --git a/client/templates/includes/initialConditionsEditor.pug b/client/templates/includes/initialConditionsEditor.pug index 935e31f578..385c3a8755 100644 --- a/client/templates/includes/initialConditionsEditor.pug +++ b/client/templates/includes/initialConditionsEditor.pug @@ -1,51 +1,68 @@ -div#initial-conditions.card.card-body +div#initial-conditions.card - div + div.card-header.pb-0 - h3.inline Initial Conditions + h3.inline.mr-3 Initial Conditions - button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#initial-condition" data-hook="initial-condition-button") + + div.inline.mr-3 + + ul.nav.nav-tabs.card-header-tabs(id="initial-conditions-tabs") + + li.nav-item + + a.nav-link.tab.active(data-hook="initial-conditions-edit-tab" data-toggle="tab" href="#edit-initial-conditions") Edit - div.collapse(id="initial-condition" data-hook="initial-conditions") + li.nav-item - p + a.nav-link.tab(data-hook="initial-conditions-view-tab" data-toggle="tab" href="#view-initial-conditions") View + + button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#initial-condition" data-hook="initial-condition-button") + + + div.card-body + p.mb-0 | Define the initial conditions for a spatial simulation - ul + ul.mb-0 li A 'Scatter' initial condition distributes Count particles over the chosen types. li A 'Place' initial condition places Count particles at a given X, Y, Z coordinate. li A 'Distribute Uniformly per Voxel' initial condition puts Count particles in each voxel of the chosen types. - table.table + div.collapse.tab-content(id="initial-condition" data-hook="initial-conditions") + + div.tab-pane.active(id="edit-initial-conditions" data-hook="edit-initial-conditions") + + hr + + div.mx-1.row.head.align-items-baseline + + div.col-sm-2: h6 Type + + div.col-sm-2: h6 Variable + + div.col-sm-3: h6 Count + + div.col-sm-3: h6 Details + + div.col-sm-2: h6 Remove - thead - - tr - - th(scope="col") Type - - th(scope="col") Variable + div.my-3(data-hook="initial-conditions-collection") - th(scope="col") Count - - th(scope="col") Details - - th(scope="col") Remove + div.dropdown.inline - tbody(data-hook="initial-conditions-collection") + button.btn.btn-outline-primary.box-shadow.dropdown-toggle#addInitialConditionBtn( + data-hook='add-initial-condition', + data-toggle='dropdown', + aria-haspopup='true', + aria-expanded='false', + type='button' + ) Add Initial Condition - div.dropdown.inline + ul.dropdown-menu(aria-labelledby='addInitialConditionBtn') + li.dropdown-item(data-hook='scatter') Scatter + li.dropdown-item(data-hook='place') Place + li.dropdown-item(data-hook='distribute-uniformly') Distribute Uniformly per Voxel - button.btn.btn-outline-primary.box-shadow.dropdown-toggle#addInitialConditionBtn( - data-hook='add-initial-condition', - data-toggle='dropdown', - aria-haspopup='true', - aria-expanded='false', - type='button' - ) Add Initial Condition + div.tab-pane(id="view-initial-conditions" data-hook="view-initial-conditions") - ul.dropdown-menu(aria-labelledby='addInitialConditionBtn') - li.dropdown-item(data-hook='scatter') Scatter - li.dropdown-item(data-hook='place') Place - li.dropdown-item(data-hook='distribute-uniformly') Distribute Uniformly per Voxel + hr - button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-initial-conditions") Save Initial Conditions \ No newline at end of file + div.mx-1.row.head.align-items-baseline From 88927d50f97174932693f86d999afb4065ff20e8 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 24 Jun 2021 16:03:57 -0400 Subject: [PATCH 35/63] Added annotation tooltip to the initial conditions editor. --- client/tooltips.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/tooltips.js b/client/tooltips.js index 42e8c77241..1b20ddb2e1 100644 --- a/client/tooltips.js +++ b/client/tooltips.js @@ -40,6 +40,9 @@ module.exports = { "of a variables after a given time step. This value will be used if a 'Minimum Value' not provided.
Minimum Value For Switching - Minimum population value "+ "at which variables will be represented as Concentration." }, + initialConditionsEditor: { + annotation: "An optional note about the initial conditions." + }, parametersEditor: { name: "Unique identifier for Parameter. Cannot share a name with other model components.", From 2d3a6b7a5682d8e4086613338ce1c006c063170f Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 24 Jun 2021 16:05:44 -0400 Subject: [PATCH 36/63] Added the annotations header. Cleaned up the render functions. Added the render function for the view tab. --- .../includes/editInitialCondition.pug | 6 ++- .../includes/initialConditionsEditor.pug | 20 +++++-- client/views/initial-conditions-editor.js | 53 ++++++++++--------- 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/client/templates/includes/editInitialCondition.pug b/client/templates/includes/editInitialCondition.pug index 9b055ac852..839f469b41 100644 --- a/client/templates/includes/editInitialCondition.pug +++ b/client/templates/includes/editInitialCondition.pug @@ -11,9 +11,9 @@ div.mx-1 div.col-sm-2(data-hook="initial-condition-species") - div.col-sm-3(data-hook="count-container") + div.col-sm-2(data-hook="count-container") - div.col-sm-3 + div.col-sm-2 div(data-hook="place-details") span Location: @@ -25,6 +25,8 @@ div.mx-1 span Active in Types: div(data-hook="initial-condition-types") + div.col-sm-2 + div.col-sm-2 button.btn.btn-outline-secondary(data-hook="remove") X diff --git a/client/templates/includes/initialConditionsEditor.pug b/client/templates/includes/initialConditionsEditor.pug index 385c3a8755..c7380d3142 100644 --- a/client/templates/includes/initialConditionsEditor.pug +++ b/client/templates/includes/initialConditionsEditor.pug @@ -38,13 +38,15 @@ div#initial-conditions.card div.col-sm-2: h6 Variable - div.col-sm-3: h6 Count + div.col-sm-2: h6 Count - div.col-sm-3: h6 Details + div.col-sm-2: h6 Details + + div.col-sm-2: h6 Annotation div.col-sm-2: h6 Remove - div.my-3(data-hook="initial-conditions-collection") + div.my-3(data-hook="edit-initial-conditions-collection") div.dropdown.inline @@ -66,3 +68,15 @@ div#initial-conditions.card hr div.mx-1.row.head.align-items-baseline + + div.col-sm-2: h6 Type + + div.col-sm-2: h6 Variable + + div.col-sm-3: h6 Count + + div.col-sm-3: h6 Details + + div.col-sm-2: h6 Annotation + + div.my-3(data-hook="view-initial-conditions-collection") diff --git a/client/views/initial-conditions-editor.js b/client/views/initial-conditions-editor.js index 5e017ecde2..ae35950ea2 100644 --- a/client/views/initial-conditions-editor.js +++ b/client/views/initial-conditions-editor.js @@ -19,6 +19,7 @@ along with this program. If not, see . var $ = require('jquery'); //support files let app = require('../app'); +let Tooltips = require('../tooltips'); //views var View = require('ampersand-view'); var EditInitialCondition = require('./edit-initial-condition'); @@ -36,22 +37,12 @@ module.exports = View.extend({ }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); - this.opened = attrs.opened; + this.tooltips = Tooltips.initialConditionEditor; }, render: function () { View.prototype.render.apply(this, arguments); - this.renderCollection( - this.collection, - EditInitialCondition, - this.queryByHook('initial-conditions-collection') - ); - if(this.opened) { - this.openInitialConditionContainer(); - } - }, - update: function () { - }, - updateValid: function () { + this.renderEditInitialConditionsView(); + this.renderViewInitialConditionsView(); }, addInitialCondition: function (e) { var initialConditionType = e.target.textContent; @@ -63,19 +54,33 @@ module.exports = View.extend({ }else { var types = []; } - console.log(initialConditionType, types) this.collection.addInitialCondition(initialConditionType, types); }, - switchToViewMode: function (e) { - this.parent.modelStateButtons.clickSaveHandler(e); - this.parent.renderInitialConditions(mode="view"); - }, - openInitialConditionContainer: function () { - $(this.queryByHook('initial-conditions')).collapse('show'); - let collapseBtn = $(this.queryByHook('initial-condition-button')) - collapseBtn.trigger('click') - }, changeCollapseButtonText: function (e) { app.changeCollapseButtonText(this, e); - } + }, + renderEditInitialConditionsView: function () { + if(this.editInitialConditionView) { + this.editInitialConditionView.remove() + } + this.editInitialConditionView = this.renderCollection( + this.collection, + EditInitialCondition, + this.queryByHook('edit-initial-conditions-collection') + ); + }, + renderViewInitialConditionsView: function () { + if(this.viewInitialConditionView) { + this.viewInitialConditionView.remove() + } + let options = {viewOptions: {viewMode: true}}; + this.viewInitialConditionView = this.renderCollection( + this.collection, + EditInitialCondition, + this.queryByHook('view-initial-conditions-collection'), + options + ); + }, + update: function () {}, + updateValid: function () {} }); \ No newline at end of file From 4796288de2c81f04430fb37e65103b004d6dd38d Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 24 Jun 2021 16:53:11 -0400 Subject: [PATCH 37/63] Added annotations to the initial conditions model. --- client/models/initial-condition.js | 1 + client/models/initial-conditions.js | 1 + client/templates/includes/editInitialCondition.pug | 6 +++++- client/views/edit-initial-condition.js | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client/models/initial-condition.js b/client/models/initial-condition.js index 8f4801b10f..26c2f1cae1 100644 --- a/client/models/initial-condition.js +++ b/client/models/initial-condition.js @@ -23,6 +23,7 @@ var Specie = require('./specie'); module.exports = State.extend({ props: { icType: 'string', + annotation: 'string', count: 'number', types: 'object', x: 'number', diff --git a/client/models/initial-conditions.js b/client/models/initial-conditions.js index c6984f1a16..ebd1e89ce9 100644 --- a/client/models/initial-conditions.js +++ b/client/models/initial-conditions.js @@ -26,6 +26,7 @@ module.exports = Collection.extend({ addInitialCondition: function (initialConditionType, types) { var initialCondition = new InitialCondition({ icType: initialConditionType, + annotation: "", types: types, count: 0, x: 0, diff --git a/client/templates/includes/editInitialCondition.pug b/client/templates/includes/editInitialCondition.pug index 839f469b41..3b29326c07 100644 --- a/client/templates/includes/editInitialCondition.pug +++ b/client/templates/includes/editInitialCondition.pug @@ -25,7 +25,11 @@ div.mx-1 span Active in Types: div(data-hook="initial-condition-types") - div.col-sm-2 + div.col-sm-2 + + div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") + + button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit div.col-sm-2 diff --git a/client/views/edit-initial-condition.js b/client/views/edit-initial-condition.js index 11089e5efc..e71b463ddc 100644 --- a/client/views/edit-initial-condition.js +++ b/client/views/edit-initial-condition.js @@ -41,6 +41,9 @@ module.exports = View.extend({ }, render: function () { View.prototype.render.apply(this, arguments); + if(!this.model.annotation){ + $(this.queryByHook('edit-annotation-btn')).text('Add') + } var self = this; var options = ['Scatter', 'Place', 'Distribute Uniformly per Voxel']; var typeSelectView = new SelectView({ From 3ec163687fae71872001a4b7845c64a9af974f80 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 24 Jun 2021 17:02:21 -0400 Subject: [PATCH 38/63] Added tooltip icon to initial conditions annotation header. Added function to hide annotations header in view mode if no initial conditions have annotations. --- client/templates/includes/initialConditionsEditor.pug | 8 ++++++-- client/views/initial-conditions-editor.js | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/client/templates/includes/initialConditionsEditor.pug b/client/templates/includes/initialConditionsEditor.pug index c7380d3142..275629091f 100644 --- a/client/templates/includes/initialConditionsEditor.pug +++ b/client/templates/includes/initialConditionsEditor.pug @@ -42,7 +42,11 @@ div#initial-conditions.card div.col-sm-2: h6 Details - div.col-sm-2: h6 Annotation + div.col-sm-2 + + h6.inline Annotation + + div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation) div.col-sm-2: h6 Remove @@ -77,6 +81,6 @@ div#initial-conditions.card div.col-sm-3: h6 Details - div.col-sm-2: h6 Annotation + div.col-sm-2(data-hook="initial-conditions-annotation-header"): h6 Annotation div.my-3(data-hook="view-initial-conditions-collection") diff --git a/client/views/initial-conditions-editor.js b/client/views/initial-conditions-editor.js index ae35950ea2..7177ba2b82 100644 --- a/client/views/initial-conditions-editor.js +++ b/client/views/initial-conditions-editor.js @@ -37,7 +37,7 @@ module.exports = View.extend({ }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); - this.tooltips = Tooltips.initialConditionEditor; + this.tooltips = Tooltips.initialConditionsEditor; }, render: function () { View.prototype.render.apply(this, arguments); @@ -73,6 +73,12 @@ module.exports = View.extend({ if(this.viewInitialConditionView) { this.viewInitialConditionView.remove() } + this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0; + if(!this.containsMdlWithAnn) { + $(this.queryByHook("initial-conditions-annotation-header")).css("display", "none"); + }else{ + $(this.queryByHook("initial-conditions-annotation-header")).css("display", "block"); + } let options = {viewOptions: {viewMode: true}}; this.viewInitialConditionView = this.renderCollection( this.collection, From 20fb5eb861ce41478a2fb5a8571bb36e8e04380e Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 09:25:28 -0400 Subject: [PATCH 39/63] Cleaned up the edit initial coditions view and added functions to allow users to update the annotation. --- client/views/edit-initial-condition.js | 212 +++++++++++++--------- client/views/initial-conditions-editor.js | 12 ++ 2 files changed, 142 insertions(+), 82 deletions(-) diff --git a/client/views/edit-initial-condition.js b/client/views/edit-initial-condition.js index e71b463ddc..231f12ddea 100644 --- a/client/views/edit-initial-condition.js +++ b/client/views/edit-initial-condition.js @@ -20,6 +20,7 @@ let $ = require('jquery'); //support files let app = require('../app'); var tests = require('./tests'); +let modals = require('../modals'); //views var View = require('ampersand-view'); var InputView = require('./input'); @@ -31,9 +32,10 @@ var template = require('../templates/includes/editInitialCondition.pug'); module.exports = View.extend({ template: template, events: { + 'click [data-hook=edit-annotation-btn]' : 'editAnnotation', 'click [data-hook=remove]' : 'removeInitialCondition', 'change [data-hook=initial-condition-type]' : 'selectInitialConditionType', - 'change [data-hook=initial-condition-species]' : 'selectInitialConditionSpecies', + 'change [data-hook=initial-condition-species]' : 'selectInitialConditionSpecies' }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); @@ -41,87 +43,38 @@ module.exports = View.extend({ }, render: function () { View.prototype.render.apply(this, arguments); + $(document).on('shown.bs.modal', function (e) { + $('[autofocus]', e.target).focus(); + }); + $(document).on('hide.bs.modal', '.modal', function (e) { + e.target.remove() + }); if(!this.model.annotation){ $(this.queryByHook('edit-annotation-btn')).text('Add') } + this.toggleDetailsView(); + }, + editAnnotation: function () { var self = this; - var options = ['Scatter', 'Place', 'Distribute Uniformly per Voxel']; - var typeSelectView = new SelectView({ - label: '', - name: 'type', - required: true, - idAttributes: 'cid', - options: options, - value: self.model.icType, + var name = this.model.name; + var annotation = this.model.annotation; + if(document.querySelector('#initialConditionAnnotationModal')) { + document.querySelector('#initialConditionAnnotationModal').remove(); + } + let modal = $(modals.annotationModalHtml("initialCondition", name, annotation)).modal(); + let okBtn = document.querySelector('#initialConditionAnnotationModal .ok-model-btn'); + let input = document.querySelector('#initialConditionAnnotationModal #initialConditionAnnotationInput'); + input.addEventListener("keyup", function (event) { + if(event.keyCode === 13){ + event.preventDefault(); + okBtn.click(); + } }); - var speciesSelectView = new SelectView({ - label: '', - name: 'specie', - required: true, - idAttribute: 'cid', - textAttribute: 'name', - eagerValidate: true, - options: this.model.collection.parent.species, - // For new reactions (with no rate.name) just use the first parameter in the Parameters collection - // Else fetch the right Parameter from Parameters based on existing rate - value: this.model.specie.name ? this.getSpecieFromSpecies(this.model.specie.name) : this.model.collection.parent.species.at(0), + okBtn.addEventListener('click', function (e) { + self.model.annotation = input.value.trim(); + self.parent.renderEditInitialConditionsView(); + modal.modal('hide'); }); - app.registerRenderSubview(this, typeSelectView, 'initial-condition-type'); - app.registerRenderSubview(this, speciesSelectView, 'initial-condition-species'); - this.renderDetailsView(); - }, - update: function () { - }, - updateValid: function () { - }, - renderDetailsView: function () { - if(this.model.icType === "Place") { - $(this.queryByHook("scatter-details")).css("display", "none") - $(this.queryByHook("place-details")).css("display", "block") - this.renderLocation(); - }else { - $(this.queryByHook("place-details")).css("display", "none") - $(this.queryByHook("scatter-details")).css("display", "block") - this.renderTypes(); - } - }, - renderLocation: function () { - if(this.xCoord) { - this.xCoord.remove(); - this.yCoord.remove(); - this.zCoord.remove(); - } - this.xCoord = new InputView({parent: this, required: true, - name: 'X', valueType: 'number', - modelKey: "x", label: 'x: ', - tests: tests.valueTests, - value: this.model.x}); - app.registerRenderSubview(this, this.xCoord, "x-container"); - this.yCoord = new InputView({parent: this, required: true, - name: 'Y', valueType: 'number', - modelKey: "y", label: 'y: ', - tests: tests.valueTests, - value: this.model.y}); - app.registerRenderSubview(this, this.yCoord, "y-container"); - this.zCoord = new InputView({parent: this, required: true, - name: 'Z', valueType: 'number', - modelKey: "z", label: 'z: ', - tests: tests.valueTests, - value: this.model.z}); - app.registerRenderSubview(this, this.zCoord, "z-container"); - }, - renderTypes: function () { - if(this.typesView) { - this.typesView.remove(); - } - this.typesView = this.renderCollection( - this.model.collection.parent.domain.types, - TypesView, - this.queryByHook("initial-condition-types"), - {"filter": function (model) { - return model.typeID != 0; - }} - ); }, getSpecieFromSpecies: function (name) { var species = this.model.collection.parent.species.filter(function (specie) { @@ -132,6 +85,11 @@ module.exports = View.extend({ removeInitialCondition: function () { this.collection.removeInitialCondition(this.model); }, + selectInitialConditionSpecies: function (e) { + var name = e.target.selectedOptions.item(0).text; + var specie = this.getSpecieFromSpecies(name); + this.model.specie = specie || this.model.specie; + }, selectInitialConditionType: function (e) { var currentType = this.model.icType; var newType = e.target.selectedOptions.item(0).text; @@ -140,12 +98,45 @@ module.exports = View.extend({ this.renderDetailsView(); } }, - selectInitialConditionSpecies: function (e) { - var name = e.target.selectedOptions.item(0).text; - var specie = this.getSpecieFromSpecies(name); - this.model.specie = specie || this.model.specie; + toggleDetailsView: function () { + if(this.model.icType === "Place") { + $(this.queryByHook("scatter-details")).css("display", "none") + $(this.queryByHook("place-details")).css("display", "block") + }else { + $(this.queryByHook("place-details")).css("display", "none") + $(this.queryByHook("scatter-details")).css("display", "block") + } }, + update: function () {}, + updateValid: function () {}, subviews: { + selectICType: { + hook: 'initial-condition-type', + prepareView: function (el) { + let options = ['Scatter', 'Place', 'Distribute Uniformly per Voxel']; + return new SelectView({ + name: 'type', + required: true, + idAttributes: 'cid', + options: options, + value: this.model.icType, + }); + } + }, + selectSpecies: { + hook: 'initial-condition-species', + prepareView: function (el) { + return new SelectView({ + name: 'specie', + required: true, + idAttribute: 'cid', + textAttribute: 'name', + eagerValidate: true, + options: this.model.collection.parent.species, + value: this.model.specie.name ? this.getSpecieFromSpecies(this.model.specie.name) : this.model.collection.parent.species.at(0), + }); + } + }, inputCount: { hook: 'count-container', prepareView: function (el) { @@ -153,13 +144,70 @@ module.exports = View.extend({ parent: this, required: true, name: 'count', - label: '', tests: tests.valueTests, modelKey: 'count', valueType: 'number', value: this.model.count, }); - }, + } + }, + typesView: { + hook: 'initial-condition-types', + prepareView: function (el) { + return this.renderCollection( + this.model.collection.parent.domain.types, + TypesView, + this.queryByHook("initial-condition-types"), + {"filter": function (model) { + return model.typeID != 0; + }} + ); + } + }, + inputXCoord: { + hook: 'x-container', + prepareView: function (el) { + return new InputView({ + parent: this, + required: true, + name: 'X', + valueType: 'number', + modelKey: "x", + label: 'x: ', + tests: tests.valueTests, + value: this.model.x + }); + } + }, + inputYCoord: { + hook: 'y-container', + prepareView: function (el) { + return new InputView({ + parent: this, + required: true, + name: 'Y', + valueType: 'number', + modelKey: "y", + label: 'y: ', + tests: tests.valueTests, + value: this.model.y + }); + } + }, + inputZCoord: { + hook: 'z-container', + prepareView: function (el) { + return new InputView({ + parent: this, + required: true, + name: 'Z', + valueType: 'number', + modelKey: "z", + label: 'z: ', + tests: tests.valueTests, + value: this.model.z + }); + } } } }); \ No newline at end of file diff --git a/client/views/initial-conditions-editor.js b/client/views/initial-conditions-editor.js index 7177ba2b82..bbcd21440d 100644 --- a/client/views/initial-conditions-editor.js +++ b/client/views/initial-conditions-editor.js @@ -68,6 +68,12 @@ module.exports = View.extend({ EditInitialCondition, this.queryByHook('edit-initial-conditions-collection') ); + $(function () { + $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').click(function () { + $('[data-toggle="tooltip"]').tooltip("hide"); + }); + }); }, renderViewInitialConditionsView: function () { if(this.viewInitialConditionView) { @@ -86,6 +92,12 @@ module.exports = View.extend({ this.queryByHook('view-initial-conditions-collection'), options ); + $(function () { + $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').click(function () { + $('[data-toggle="tooltip"]').tooltip("hide"); + }); + }); }, update: function () {}, updateValid: function () {} From a8a5b3ff93513e809898b645edd6eef8c0d31875 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 09:33:10 -0400 Subject: [PATCH 40/63] Added the view template and template selection. --- client/views/edit-initial-condition.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/client/views/edit-initial-condition.js b/client/views/edit-initial-condition.js index 231f12ddea..e8290aa59f 100644 --- a/client/views/edit-initial-condition.js +++ b/client/views/edit-initial-condition.js @@ -27,10 +27,10 @@ var InputView = require('./input'); var SelectView = require('ampersand-select-view'); var TypesView = require('./component-types'); //templates -var template = require('../templates/includes/editInitialCondition.pug'); +let editTemplate = require('../templates/includes/editInitialCondition.pug'); +let viewTemplate = require('../templates/includes/viewInitialCondition.pug'); module.exports = View.extend({ - template: template, events: { 'click [data-hook=edit-annotation-btn]' : 'editAnnotation', 'click [data-hook=remove]' : 'removeInitialCondition', @@ -40,8 +40,18 @@ module.exports = View.extend({ initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); this.modelType = "initial-condition"; + this.viewMode = attrs.viewMode ? attrs.viewMode : false; + if(this.viewMode) { + let self = this; + this.types = []; + this.model.types.forEach(function (index) { + let type = self.model.collection.parent.domain.types.get(index, "typeID"); + self.types.push(type.name) + }); + } }, render: function () { + this.template = this.viewMode ? viewTemplate : editTemplate; View.prototype.render.apply(this, arguments); $(document).on('shown.bs.modal', function (e) { $('[autofocus]', e.target).focus(); From fd4455321fb88d961f7e8d6b6a80113c6f3602af Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 09:39:02 -0400 Subject: [PATCH 41/63] Re-designed the layout for view initial condition. --- .../includes/initialConditionsEditor.pug | 4 +- .../includes/viewInitialCondition.pug | 40 +++++++++++++------ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/client/templates/includes/initialConditionsEditor.pug b/client/templates/includes/initialConditionsEditor.pug index 275629091f..bac19f8d8c 100644 --- a/client/templates/includes/initialConditionsEditor.pug +++ b/client/templates/includes/initialConditionsEditor.pug @@ -77,9 +77,9 @@ div#initial-conditions.card div.col-sm-2: h6 Variable - div.col-sm-3: h6 Count + div.col-sm-2: h6 Count - div.col-sm-3: h6 Details + div.col-sm-4: h6 Details div.col-sm-2(data-hook="initial-conditions-annotation-header"): h6 Annotation diff --git a/client/templates/includes/viewInitialCondition.pug b/client/templates/includes/viewInitialCondition.pug index 34f4017019..68d6623a66 100644 --- a/client/templates/includes/viewInitialCondition.pug +++ b/client/templates/includes/viewInitialCondition.pug @@ -1,17 +1,33 @@ -tr +div.mx-1 - td=this.model.icType + if(this.model.collection.indexOf(this.model) !== 0) + hr - td=this.model.specie.name + div.row - td=this.model.count + div.col-sm-2 - td + div.pl-2=this.model.icType - if this.model.icType === "Place" - span Location: - div="(x: "+this.model.x+", y: "+this.model.y+", z: "+this.model.z+")" - - else - span Active in Types: - div=this.types.join(", ") + div.col-sm-2 + + div=this.model.specie.name + + div.col-sm-2 + + div=this.model.count + + div.col-sm-4 + + if this.model.icType === "Place" + span Location: + div="(x: "+this.model.x+", y: "+this.model.y+", z: "+this.model.z+")" + + else + span Active in Types: + div=this.types.join(", ") + + div.col-sm-2 + + if this.model.annotation + div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") From 57b976a45bd886d9642d3eecdeba58513394f2f0 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 09:53:46 -0400 Subject: [PATCH 42/63] Added functions to update the view tap when the model is changed. --- client/views/component-types.js | 4 +--- client/views/edit-initial-condition.js | 10 +++++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/client/views/component-types.js b/client/views/component-types.js index 212ef27413..8c14752568 100644 --- a/client/views/component-types.js +++ b/client/views/component-types.js @@ -46,8 +46,6 @@ module.exports = View.extend({ let index = this.parent.model.types.indexOf(typeID); this.parent.model.types.splice(index, 1); } - if(this.parent.modelType === "species") { - this.parent.model.trigger('change'); - } + this.parent.model.trigger('change'); } }); \ No newline at end of file diff --git a/client/views/edit-initial-condition.js b/client/views/edit-initial-condition.js index e8290aa59f..7430c3a167 100644 --- a/client/views/edit-initial-condition.js +++ b/client/views/edit-initial-condition.js @@ -17,6 +17,7 @@ along with this program. If not, see . */ let $ = require('jquery'); +let _ = require('underscore'); //support files let app = require('../app'); var tests = require('./tests'); @@ -53,6 +54,9 @@ module.exports = View.extend({ render: function () { this.template = this.viewMode ? viewTemplate : editTemplate; View.prototype.render.apply(this, arguments); + if(!this.viewMode) { + this.model.on('change', _.bind(this.updateViewer, this)); + } $(document).on('shown.bs.modal', function (e) { $('[autofocus]', e.target).focus(); }); @@ -99,13 +103,14 @@ module.exports = View.extend({ var name = e.target.selectedOptions.item(0).text; var specie = this.getSpecieFromSpecies(name); this.model.specie = specie || this.model.specie; + this.model.trigger('change'); }, selectInitialConditionType: function (e) { var currentType = this.model.icType; var newType = e.target.selectedOptions.item(0).text; this.model.icType = newType; if(currentType === "Place" || newType === "Place"){ - this.renderDetailsView(); + this.toggleDetailsView(); } }, toggleDetailsView: function () { @@ -119,6 +124,9 @@ module.exports = View.extend({ }, update: function () {}, updateValid: function () {}, + updateViewer: function () { + this.parent.renderViewInitialConditionsView(); + }, subviews: { selectICType: { hook: 'initial-condition-type', From 4a89e2e5c9fe3ae33831a7ede45572aab96272df Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 10:02:59 -0400 Subject: [PATCH 43/63] Added function to support read only mode. --- client/views/initial-conditions-editor.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/client/views/initial-conditions-editor.js b/client/views/initial-conditions-editor.js index bbcd21440d..bfbc38808e 100644 --- a/client/views/initial-conditions-editor.js +++ b/client/views/initial-conditions-editor.js @@ -38,10 +38,22 @@ module.exports = View.extend({ initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); this.tooltips = Tooltips.initialConditionsEditor; + this.readOnly = attrs.readOnly ? attrs.readOnly : false; }, render: function () { View.prototype.render.apply(this, arguments); - this.renderEditInitialConditionsView(); + if(this.readOnly) { + $(this.queryByHook('initial-conditions-edit-tab')).addClass("disabled"); + $(".nav .disabled>a").on("click", function(e) { + e.preventDefault(); + return false; + }); + $(this.queryByHook('initial-conditions-view-tab')).tab('show'); + $(this.queryByHook('edit-initial-conditions')).removeClass('active'); + $(this.queryByHook('view-initial-conditions')).addClass('active'); + }else{ + this.renderEditInitialConditionsView(); + } this.renderViewInitialConditionsView(); }, addInitialCondition: function (e) { From aadad1fac814420745e6dc1f5367bd7379b5ba71 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 11:32:44 -0400 Subject: [PATCH 44/63] Removed empty directories. Updated the model template test. --- .../tests/mock_file_sys/sbml_files/test1.sbml | 137 ------------------ .../tests/mock_file_sys/sbml_files/test2.sbml | 1 - stochss/tests/run_tests.py | 4 +- stochss/tests/test_model_template.py | 23 ++- 4 files changed, 12 insertions(+), 153 deletions(-) delete mode 100644 stochss/tests/mock_file_sys/sbml_files/test1.sbml delete mode 100644 stochss/tests/mock_file_sys/sbml_files/test2.sbml diff --git a/stochss/tests/mock_file_sys/sbml_files/test1.sbml b/stochss/tests/mock_file_sys/sbml_files/test1.sbml deleted file mode 100644 index edd42e3c79..0000000000 --- a/stochss/tests/mock_file_sys/sbml_files/test1.sbml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - x - - - y - - - - x - y - - - - - - - - - - - - - - - - - - - - - - 0.5 - - - - - - - - 8000 - - - s1 - 1 - - - - - - - - - - - - - - - - k2 - - - - - - - - - - - - k1 - s1 - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - t - 50 - - - - - - - - t - 40 - - - - - - 0 - - - - - - 2000 - - - - - - - diff --git a/stochss/tests/mock_file_sys/sbml_files/test2.sbml b/stochss/tests/mock_file_sys/sbml_files/test2.sbml deleted file mode 100644 index a87bc5eb1c..0000000000 --- a/stochss/tests/mock_file_sys/sbml_files/test2.sbml +++ /dev/null @@ -1 +0,0 @@ -{"is_spatial":false,"defaultID":10,"defaultMode":"discrete","modelSettings":{"endSim":20,"timeStep":0.05,"volume":1,"algorithm":"Hybrid-Tau-Leaping","realizations":1},"simulationSettings":{"isAutomatic":true,"relativeTol":0.001,"absoluteTol":0.000001,"realizations":1,"algorithm":"SSA","seed":-1,"tauTol":0.03},"parameterSweepSettings":{"is1D":true,"p1Min":0,"p1Max":0,"p1Steps":11,"p2Min":0,"p2Max":0,"p2Steps":11,"parameterOne":{},"parameterTwo":{},"speciesOfInterest":{"subdomains":[]}},"meshSettings":{"count":2},"species":[{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}],"initialConditions":[],"parameters":[{"compID":2,"name":"k1","expression":"0.5","annotation":""},{"compID":3,"name":"k2","expression":"0.1*500**-5","annotation":""}],"reactions":[{"compID":4,"name":"r1","reactionType":"creation","summary":"\\emptyset \\rightarrow s1","massaction":false,"propensity":"","annotation":"","subdomains":["subdomain 1:","subdomain 2:"],"rate":{"compID":3,"name":"k2","expression":"math.sin(1)","annotation":""},"reactants":[],"products":[{"ratio":1,"specie":{"compID":1,"name":"s1","value":500,"mode":"continuous","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}]},{"compID":5,"name":"r2","reactionType":"destruction","summary":"s1 \\rightarrow \\emptyset","massaction":false,"propensity":"","annotation":"","subdomains":["subdomain 1:","subdomain 2:"],"rate":{"compID":2,"name":"k1","expression":"0.5","annotation":""},"reactants":[{"ratio":1,"specie":{"compID":1,"name":"s1","value":500,"mode":"continuous","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}],"products":[]},{"compID":6,"name":"r3","reactionType":"custom-propensity","summary":"2s1 \\rightarrow 3s1","massaction":false,"propensity":"sin(1)","annotation":"","subdomains":["subdomain 1:","subdomain 2:"],"rate":{},"reactants":[{"ratio":2,"specie":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}],"products":[{"ratio":3,"specie":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}]}],"rules":[{"compID":8,"name":"rr1","type":"Rate Rule","variable":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]},"expression":"sin(0.5)","annotation":""},{"compID":9,"name":"rr2","type":"Assignment Rule","variable":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]},"expression":"8000","annotation":""}],"eventsCollection":[{"compID":7,"name":"e1","annotation":"","delay":"t-40","priority":"1","triggerExpression":"t>50","initialValue":true,"persistent":true,"useValuesFromTriggerTime":true,"eventAssignments":[{"expression":"2000","variable":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}]}],"functionDefinitions":[]} \ No newline at end of file diff --git a/stochss/tests/run_tests.py b/stochss/tests/run_tests.py index 5aa6cce0f0..ea0b657c89 100755 --- a/stochss/tests/run_tests.py +++ b/stochss/tests/run_tests.py @@ -34,7 +34,7 @@ args = parser.parse_args() print(os.path.dirname(__file__)) - # import test_model_template + import test_model_template # import test_settings_template # import test_convert_sbml # import test_upload_file @@ -45,7 +45,7 @@ # import test_duplicate modules = [ - # test_model_template, + test_model_template, # test_settings_template, # test_convert_sbml, # test_rename, diff --git a/stochss/tests/test_model_template.py b/stochss/tests/test_model_template.py index d40e639bd5..94727bb219 100644 --- a/stochss/tests/test_model_template.py +++ b/stochss/tests/test_model_template.py @@ -4,16 +4,17 @@ os.chdir('/stochss') -template_path = "stochss_templates/nonSpatialModelTemplate.json" - - class TestNonSpatialModelTemplate(unittest.TestCase): - def test_model_elements(self): + def setUp(self): + template_path = "stochss_templates/nonSpatialModelTemplate.json" + with open(template_path, "r") as template_file: - template = json.load(template_file) + self.template = json.load(template_file) + - template_keys = sorted(list(template.keys())) + def test_model_elements(self): + template_keys = sorted(list(self.template.keys())) model_path = "client/models/model.js" with open(model_path, "r") as model_file: @@ -24,21 +25,17 @@ def test_model_elements(self): model_keys = list(map(lambda item: item.strip().split(':')[0], props)) model_keys.extend(list(map(lambda item: item.strip().split(':')[0], collections))) model_keys.extend(list(map(lambda item: item.strip().split(':')[0], children))) - + model_keys.sort() self.assertEqual(template_keys, model_keys) def test_model_settings_elements(self): - with open(template_path, "r") as template_file: - template = json.load(template_file) - - template_keys = sorted(list(template['modelSettings'].keys())) + template_keys = sorted(list(self.template['modelSettings'].keys())) mdl_settings_path = "client/models/model-settings.js" - + with open(mdl_settings_path, "r") as mdl_settings_file: data = mdl_settings_file.read().split("props: {").pop().split('}')[0].split(',') mdl_settings_keys = sorted(list(map(lambda item: item.strip().split(':')[0], data))) self.assertEqual(template_keys, mdl_settings_keys) - From 81636cdc0254f479bea03cfab2f0646bbbe4ff91 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 12:13:02 -0400 Subject: [PATCH 45/63] Refactored #if DOCKER_WORKING_DIR is defined and its value does not exist, create a directory at its path and copy Examples into it bash -c "if [ ! -d "/Users/owner/Documents/Undergrade_Research/Dr_Drawert/stochss/local_data" ] && [ -z ]; then mkdir /Users/owner/Documents/Undergrade_Research/Dr_Drawert/stochss/local_data; mkdir /Users/owner/Documents/Undergrade_Research/Dr_Drawert/stochss/local_data/Examples;cp -r public_models/* /Users/owner/Documents/Undergrade_Research/Dr_Drawert/stochss/local_data/Examples;fi" docker run --rm \ --name stochss-lab \ --env-file .env \ -v /Users/owner/Documents/Undergrade_Research/Dr_Drawert/stochss:/stochss \ -v /Users/owner/Documents/Undergrade_Research/Dr_Drawert/stochss/local_data:/home/jovyan/ \ -p 8888:8888 \ stochss-lab:latest \ /stochss/stochss/tests/run_tests.py /stochss/stochss/tests Executing: ====================================================================== to only rebuild the backend before running the unit tests. Add to the make file to rebuild the image and container before running the test. --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2bbfecc7e1..ed4b61a4e7 100644 --- a/Makefile +++ b/Makefile @@ -114,7 +114,7 @@ build: deps webpack --build-arg JUPYTER_CONFIG_DIR=$(JUPYTER_CONFIG_DIR) \ -t $(DOCKER_STOCHSS_IMAGE):latest . -test: build +test: create_working_dir docker run --rm \ --name $(DOCKER_STOCHSS_IMAGE) \ --env-file .env \ @@ -124,6 +124,8 @@ test: build $(DOCKER_STOCHSS_IMAGE):latest \ /stochss/stochss/tests/run_tests.py +build_and_test: build test + run: create_working_dir docker run --rm \ --name $(DOCKER_STOCHSS_IMAGE) \ From 1572cb6b54fd8afef89f3635db8e31c88963e6e7 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 12:15:40 -0400 Subject: [PATCH 46/63] Added a test for the domain in the model template. Pylint changes. --- stochss/tests/test_model_template.py | 59 ++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/stochss/tests/test_model_template.py b/stochss/tests/test_model_template.py index 94727bb219..b8351b42e3 100644 --- a/stochss/tests/test_model_template.py +++ b/stochss/tests/test_model_template.py @@ -1,12 +1,37 @@ +''' +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 . +''' + import unittest import json import os os.chdir('/stochss') -class TestNonSpatialModelTemplate(unittest.TestCase): - +class TestModelTemplate(unittest.TestCase): + ''' + ################################################################################################ + Unit tests for model template complete ness. + ################################################################################################ + ''' def setUp(self): + ''' + Get the model template prior to each test. + ''' template_path = "stochss_templates/nonSpatialModelTemplate.json" with open(template_path, "r") as template_file: @@ -14,6 +39,9 @@ def setUp(self): def test_model_elements(self): + ''' + Check if the model template has all of the properties currently in the model. + ''' template_keys = sorted(list(self.template.keys())) model_path = "client/models/model.js" @@ -30,12 +58,35 @@ def test_model_elements(self): self.assertEqual(template_keys, model_keys) - def test_model_settings_elements(self): + def test_timespan_settings_elements(self): + ''' + Check if the timespan settings in the model template has + all of the properties currently in the timespan settings. + ''' template_keys = sorted(list(self.template['modelSettings'].keys())) - mdl_settings_path = "client/models/model-settings.js" + mdl_settings_path = "client/models/timespan-settings.js" with open(mdl_settings_path, "r") as mdl_settings_file: data = mdl_settings_file.read().split("props: {").pop().split('}')[0].split(',') mdl_settings_keys = sorted(list(map(lambda item: item.strip().split(':')[0], data))) self.assertEqual(template_keys, mdl_settings_keys) + + + def test_model_domain_elements(self): + ''' + Check if the domain in the model template has all of the + properties currently in the domain. + ''' + template_keys = sorted(list(self.template['domain'].keys())) + domain_path = "client/models/domain.js" + + with open(domain_path, "r") as domain_file: + data = domain_file.read() + props = data.split("props: {").pop().split('}')[0].split(',') + collections = data.split("collections: {").pop().split('}')[0].split(',') + domain_keys = list(map(lambda item: item.strip().split(':')[0], props)) + domain_keys.extend(list(map(lambda item: item.strip().split(':')[0], collections))) + + domain_keys.sort() + self.assertEqual(template_keys, domain_keys) From 5140c6224a44f8998deb9798f1d2e099166ca237 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 13:24:24 -0400 Subject: [PATCH 47/63] Cleaned up the settings template tests. Added a test for timespan settings. Pylint updates. --- stochss/tests/test_model_template.py | 8 +-- stochss/tests/test_settings_template.py | 96 ++++++++++++++++++------- 2 files changed, 75 insertions(+), 29 deletions(-) diff --git a/stochss/tests/test_model_template.py b/stochss/tests/test_model_template.py index b8351b42e3..c2bb805551 100644 --- a/stochss/tests/test_model_template.py +++ b/stochss/tests/test_model_template.py @@ -25,7 +25,7 @@ class TestModelTemplate(unittest.TestCase): ''' ################################################################################################ - Unit tests for model template complete ness. + Unit tests for model template completeness. ################################################################################################ ''' def setUp(self): @@ -40,7 +40,7 @@ def setUp(self): def test_model_elements(self): ''' - Check if the model template has all of the properties currently in the model. + Check if the model template has all of the properties currently in the model model. ''' template_keys = sorted(list(self.template.keys())) model_path = "client/models/model.js" @@ -61,7 +61,7 @@ def test_model_elements(self): def test_timespan_settings_elements(self): ''' Check if the timespan settings in the model template has - all of the properties currently in the timespan settings. + all of the properties currently in the timespan settings model. ''' template_keys = sorted(list(self.template['modelSettings'].keys())) mdl_settings_path = "client/models/timespan-settings.js" @@ -76,7 +76,7 @@ def test_timespan_settings_elements(self): def test_model_domain_elements(self): ''' Check if the domain in the model template has all of the - properties currently in the domain. + properties currently in the domain model. ''' template_keys = sorted(list(self.template['domain'].keys())) domain_path = "client/models/domain.js" diff --git a/stochss/tests/test_settings_template.py b/stochss/tests/test_settings_template.py index a53f417704..40b7ee3a98 100644 --- a/stochss/tests/test_settings_template.py +++ b/stochss/tests/test_settings_template.py @@ -1,33 +1,62 @@ +''' +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 . +''' + import unittest import json import os os.chdir('/stochss') -template_path = "stochss_templates/workflowSettingsTemplate.json" - - class TestWorkflowSettingsTemplate(unittest.TestCase): + ''' + ################################################################################################ + Unit tests for settings template completeness. + ################################################################################################ + ''' + def setUp(self): + ''' + Get the settings template prior to each test. + ''' + template_path = "stochss_templates/workflowSettingsTemplate.json" - def test_settings_elements(self): with open(template_path, "r") as template_file: - template = json.load(template_file) + self.template = json.load(template_file) - template_keys = sorted(list(template.keys())) + def test_workflow_settings_elements(self): + ''' + Check if the settings template has all of the properties currently in the settings model. + ''' + template_keys = sorted(list(self.template.keys())) model_path = "client/models/settings.js" with open(model_path, "r") as model_file: children = model_file.read().split("children: {").pop().split('}')[0].split(',') model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], children))) - - self.assertEqual(template_keys, model_keys) + self.assertEqual(template_keys, model_keys) - def test_simulation_settings_elements(self): - with open(template_path, "r") as template_file: - template = json.load(template_file) - template_keys = sorted(list(template['simulationSettings'].keys())) + def test_workflow_simulation_settings_elements(self): + ''' + Check if the simulation settings in the settings template has + all of the properties currently in the simulation settings model. + ''' + template_keys = sorted(list(self.template['simulationSettings'].keys())) sim_settings_path = "client/models/simulation-settings.js" with open(sim_settings_path, "r") as sim_settings_file: @@ -37,29 +66,32 @@ def test_simulation_settings_elements(self): self.assertEqual(template_keys, sim_settings_keys) - def test_psweep_settings_elements(self): - with open(template_path, "r") as template_file: - template = json.load(template_file) - - template_keys = sorted(list(template['parameterSweepSettings'].keys())) + def test_workflow_parameter_sweep_settings_elements(self): + ''' + Check if the parameter sweep settings in the settings template has + all of the properties currently in the parameter sweep settings model. + ''' + template_keys = sorted(list(self.template['parameterSweepSettings'].keys())) psweep_settings_path = "client/models/parameter-sweep-settings.js" with open(psweep_settings_path, "r") as psweep_settings_file: data = psweep_settings_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') + collections = data.split("collections: {").pop().split('}')[0].split(',') children = data.split("children: {").pop().split('}')[0].split(',') - psweep_settings_keys = list(map(lambda item: item.strip().split(':')[0], props)) - psweep_settings_keys.extend(list(map(lambda item: item.strip().split(':')[0], children))) + psweep_settings_keys = list(map(lambda item: item.strip().split(':')[0], collections)) + psweep_settings_keys.extend(list(map(lambda item: item.strip().split(':')[0], + children))) psweep_settings_keys.sort() self.assertEqual(template_keys, psweep_settings_keys) - def test_results_settings_elements(self): - with open(template_path, "r") as template_file: - template = json.load(template_file) - - template_keys = sorted(list(template['resultsSettings'].keys())) + def test_workflow_results_settings_elements(self): + ''' + Check if the results settings in the settings template has + all of the properties currently in the results settings model. + ''' + template_keys = sorted(list(self.template['resultsSettings'].keys())) results_settings_path = "client/models/results-settings.js" with open(results_settings_path, "r") as results_settings_file: @@ -68,3 +100,17 @@ def test_results_settings_elements(self): self.assertEqual(template_keys, results_settings_keys) + + def test_workflow_timespan_settings_elements(self): + ''' + Check if the timespan settings in the model template has + all of the properties currently in the timespan settings model. + ''' + template_keys = sorted(list(self.template['timespanSettings'].keys())) + tspan_settings_path = "client/models/timespan-settings.js" + + with open(tspan_settings_path, "r") as tspan_settings_file: + data = tspan_settings_file.read().split("props: {").pop().split('}')[0].split(',') + tspan_settings_keys = sorted(list(map(lambda item: item.strip().split(':')[0], data))) + + self.assertEqual(template_keys, tspan_settings_keys) From 59f3bcdd624a18fa244425c2b99d1da6239800aa Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 25 Jun 2021 13:25:22 -0400 Subject: [PATCH 48/63] Added the test settings template to the test suite. --- stochss/tests/run_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stochss/tests/run_tests.py b/stochss/tests/run_tests.py index ea0b657c89..2b19ca623f 100755 --- a/stochss/tests/run_tests.py +++ b/stochss/tests/run_tests.py @@ -35,7 +35,7 @@ print(os.path.dirname(__file__)) import test_model_template - # import test_settings_template + import test_settings_template # import test_convert_sbml # import test_upload_file # import test_rename @@ -46,7 +46,7 @@ modules = [ test_model_template, - # test_settings_template, + test_settings_template, # test_convert_sbml, # test_rename, # test_upload_file, From 45d2f3bd7fe5724d8e4aa312a6318318b7fbcc2c Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 28 Jun 2021 08:22:35 -0400 Subject: [PATCH 49/63] Fine tuned the tests for StochSSBase. --- stochss/tests/test_stochss_base.py | 140 +++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 stochss/tests/test_stochss_base.py diff --git a/stochss/tests/test_stochss_base.py b/stochss/tests/test_stochss_base.py new file mode 100644 index 0000000000..9353e47c34 --- /dev/null +++ b/stochss/tests/test_stochss_base.py @@ -0,0 +1,140 @@ +''' +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 . +''' + +import unittest +# import json +import os +import tempfile + +from pathlib import Path + +from stochss.handlers import StochSSBase + +os.chdir('/stochss') + +class TestStochSSBaseObject(unittest.TestCase): + ''' + ################################################################################################ + Unit tests for the StochSS base class. + ################################################################################################ + ''' + def setUp(self): + ''' + Create a temporary directory with a file and folder for each base test. + ''' + self.tempdir = tempfile.TemporaryDirectory() + test_filename = "test_base_file" + test_foldername = "test_bose_folder" + self.test_filepath = os.path.join(self.tempdir.name, test_filename) + Path(self.test_filepath).touch() + self.test_folderpath = os.path.join(self.tempdir.name, test_foldername) + os.mkdir(self.test_folderpath) + + + def tearDown(self): + ''' + Cleanup the temp directory after each test. + ''' + self.tempdir.cleanup() + + ################################################################################################ + # Unit tests for the StochSS base class check_project_format function. + ################################################################################################ + + def test_check_project_format__old_with_mdl(self): + ''' + Check if the project is identified as old when it contains a model. + ''' + test_files = ["test_model.mdl", "test_model.smdl"] + for test_file in test_files: + with self.subTest(test_file=test_file): + test_file_path = os.path.join(self.test_folderpath, test_file) + Path(test_file_path).touch() + self.assertFalse(StochSSBase.check_project_format(path=self.test_folderpath)) + self.tearDown() + self.setUp() + + + def test_check_project_format__old_with_wkgp1(self): + ''' + Check if the project is identified as old when it contains one + workflow group with the name WorkflowGroup1.wkgp. + ''' + test_wkgp = os.path.join(self.test_folderpath, "WorkflowGroup1.wkgp") + os.mkdir(test_wkgp) + self.assertFalse(StochSSBase.check_project_format(path=self.test_folderpath)) + + + def test_check_project_format__new_empty(self): + ''' + Check if the project is identified as new when empty + ''' + self.assertTrue(StochSSBase.check_project_format(path=self.test_folderpath)) + + + def test_check_project_format__new_with_one_wkgp_not_wkgp1(self): + ''' + Check if the project is identified as new with one workflow group + ''' + test_wkgp = os.path.join(self.test_folderpath, "test_wkgp.wkgp") + os.mkdir(test_wkgp) + self.assertTrue(StochSSBase.check_project_format(path=self.test_folderpath)) + + + def test_check_project_format__new_with_x_wkgps(self): + ''' + Check if the project is identified as new with multiple workflow groups + ''' + test_wkgp1 = os.path.join(self.test_folderpath, "test_wkgp1.wkgp") + os.mkdir(test_wkgp1) + test_wkgp2 = os.path.join(self.test_folderpath, "test_wkgp2.wkgp") + os.mkdir(test_wkgp2) + self.assertTrue(StochSSBase.check_project_format(path=self.test_folderpath)) + + ################################################################################################ + # Unit tests for the StochSS base class check_workflow_format function. + ################################################################################################ + + def test_check_workflow_format__old_with_old_files(self): + ''' + Check if the workflow is identified as old when it an old file. + ''' + test_files = ["info.json", "logs.txt", "RUNNING", "ERROR", "COMPLETE", "test_model.mdl"] + for test_file in test_files: + with self.subTest(test_file=test_file): + test_file_path = os.path.join(self.test_folderpath, test_file) + Path(test_file_path).touch() + self.assertFalse(StochSSBase.check_workflow_format(path=self.test_folderpath)) + self.tearDown() + self.setUp() + + + def test_check_workflow_format__old_with_results(self): + ''' + Check if the workflow is identified as old when it a results folder. + ''' + test_dir = os.path.join(self.test_folderpath, "results") + os.mkdir(test_dir) + self.assertFalse(StochSSBase.check_workflow_format(path=self.test_folderpath)) + + + def test_check_workflow_format__new(self): + ''' + Check if the workflow is identified as old. + ''' + self.assertTrue(StochSSBase.check_workflow_format(path=self.test_folderpath)) From d55d7af1a217c55e372d4dd6378794a289c1e64d Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 28 Jun 2021 18:55:07 -0400 Subject: [PATCH 50/63] Made the get_new_path function a classmethod. Fixed bug in get_unique_copy_path. --- stochss/handlers/util/stochss_base.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/stochss/handlers/util/stochss_base.py b/stochss/handlers/util/stochss_base.py index c17075e87f..65a27a6bc0 100644 --- a/stochss/handlers/util/stochss_base.py +++ b/stochss/handlers/util/stochss_base.py @@ -87,7 +87,8 @@ def check_workflow_format(cls, path): return True - def get_new_path(self, dst_path): + @classmethod + def get_new_path(cls, dst_path): ''' Gets the proper destination path for the file object to be moved @@ -96,9 +97,9 @@ def get_new_path(self, dst_path): dst_path : string New path for the file object from the users home directory ''' - new_path = os.path.join(self.user_dir, dst_path) - if dst_path.startswith("trash/") and not "trash" in os.listdir(self.user_dir): - os.mkdir(os.path.join(self.user_dir, "trash")) + new_path = os.path.join(cls.user_dir, dst_path) + if dst_path.startswith("trash/") and not "trash" in os.listdir(cls.user_dir): + os.mkdir(os.path.join(cls.user_dir, "trash")) if new_path.split().pop().replace('.', '', 5).isdigit(): return new_path.replace(new_path.split().pop(), "").strip() if "trash/" in new_path and os.path.exists(new_path): @@ -292,14 +293,16 @@ def get_unique_copy_path(self, path=None): # Check if the file object is an original or at least the second copy if not '-copy' in file or '-copy(' in file: cp_file = ''.join([name, '-copy', ext]) - if cp_file not in os.listdir(dirname if dirname else self.user_dir): + if cp_file not in os.listdir(os.path.join(self.user_dir, dirname) \ + if dirname else self.user_dir): return os.path.join(dirname, cp_file) i = 2 cp_file = ''.join([name, f"-copy({i})", ext]) # Check if a copy exists with '-copy(2)' in the name # If copy_file is still not unique iterate i until a unique name is found - while cp_file in os.listdir(dirname if dirname else self.user_dir): + while cp_file in os.listdir(os.path.join(self.user_dir, dirname) \ + if dirname else self.user_dir): i += 1 cp_file = ''.join([name, f"-copy({i})", ext]) From e01e0b5bc6905f563fd2f74129d1a940a2392246 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 28 Jun 2021 18:56:36 -0400 Subject: [PATCH 51/63] Added tests for StochSSBase functions. --- stochss/tests/run_tests.py | 18 +- stochss/tests/test_stochss_base.py | 781 +++++++++++++++++++++++++++-- 2 files changed, 750 insertions(+), 49 deletions(-) diff --git a/stochss/tests/run_tests.py b/stochss/tests/run_tests.py index 2b19ca623f..e835c00044 100755 --- a/stochss/tests/run_tests.py +++ b/stochss/tests/run_tests.py @@ -36,29 +36,17 @@ import test_model_template import test_settings_template - # import test_convert_sbml - # import test_upload_file - # import test_rename - # import test_generate_zip_file - # import test_workflow_status - # import test_ls - # import test_duplicate + import test_stochss_base modules = [ test_model_template, test_settings_template, - # test_convert_sbml, - # test_rename, - # test_upload_file, - # test_generate_zip_file, - # test_workflow_status, - # test_ls, - # test_duplicate + test_stochss_base ] for module in modules: suite = unittest.TestLoader().loadTestsFromModule(module) - runner = unittest.TextTestRunner(failfast=args.mode == 'staging') + runner = unittest.TextTestRunner(failfast=args.mode == 'staging', verbosity=1) print("Executing: {}".format(module)) result = runner.run(suite) diff --git a/stochss/tests/test_stochss_base.py b/stochss/tests/test_stochss_base.py index 9353e47c34..17cea9c668 100644 --- a/stochss/tests/test_stochss_base.py +++ b/stochss/tests/test_stochss_base.py @@ -16,14 +16,20 @@ along with this program. If not, see . ''' -import unittest -# import json import os +import json +import shutil +import logging +import unittest import tempfile +import datetime +from unittest import mock from pathlib import Path from stochss.handlers import StochSSBase +from stochss.handlers.util.stochss_errors import StochSSFileNotFoundError, FileNotJSONFormatError, \ + StochSSPermissionsError os.chdir('/stochss') @@ -34,12 +40,11 @@ class TestStochSSBaseObject(unittest.TestCase): ################################################################################################ ''' def setUp(self): - ''' - Create a temporary directory with a file and folder for each base test. - ''' + ''' Create a temporary directory with a file and folder for each base test. ''' + self.user_dir = os.path.expanduser("~") self.tempdir = tempfile.TemporaryDirectory() test_filename = "test_base_file" - test_foldername = "test_bose_folder" + test_foldername = "test_base_folder" self.test_filepath = os.path.join(self.tempdir.name, test_filename) Path(self.test_filepath).touch() self.test_folderpath = os.path.join(self.tempdir.name, test_foldername) @@ -47,19 +52,17 @@ def setUp(self): def tearDown(self): - ''' - Cleanup the temp directory after each test. - ''' + ''' Cleanup the temp directory after each test. ''' self.tempdir.cleanup() + if os.path.exists(os.path.join(self.user_dir, "trash")): + shutil.rmtree(os.path.join(self.user_dir, "trash")) ################################################################################################ # Unit tests for the StochSS base class check_project_format function. ################################################################################################ def test_check_project_format__old_with_mdl(self): - ''' - Check if the project is identified as old when it contains a model. - ''' + ''' Check if the project is identified as old when it contains a model. ''' test_files = ["test_model.mdl", "test_model.smdl"] for test_file in test_files: with self.subTest(test_file=test_file): @@ -71,35 +74,27 @@ def test_check_project_format__old_with_mdl(self): def test_check_project_format__old_with_wkgp1(self): - ''' - Check if the project is identified as old when it contains one - workflow group with the name WorkflowGroup1.wkgp. - ''' + ''' Check if the project is identified as old when it contains one + workflow group with the name WorkflowGroup1.wkgp. ''' test_wkgp = os.path.join(self.test_folderpath, "WorkflowGroup1.wkgp") os.mkdir(test_wkgp) self.assertFalse(StochSSBase.check_project_format(path=self.test_folderpath)) def test_check_project_format__new_empty(self): - ''' - Check if the project is identified as new when empty - ''' + ''' Check if the project is identified as new when empty. ''' self.assertTrue(StochSSBase.check_project_format(path=self.test_folderpath)) def test_check_project_format__new_with_one_wkgp_not_wkgp1(self): - ''' - Check if the project is identified as new with one workflow group - ''' + ''' Check if the project is identified as new with one workflow group. ''' test_wkgp = os.path.join(self.test_folderpath, "test_wkgp.wkgp") os.mkdir(test_wkgp) self.assertTrue(StochSSBase.check_project_format(path=self.test_folderpath)) def test_check_project_format__new_with_x_wkgps(self): - ''' - Check if the project is identified as new with multiple workflow groups - ''' + ''' Check if the project is identified as new with multiple workflow groups. ''' test_wkgp1 = os.path.join(self.test_folderpath, "test_wkgp1.wkgp") os.mkdir(test_wkgp1) test_wkgp2 = os.path.join(self.test_folderpath, "test_wkgp2.wkgp") @@ -111,9 +106,7 @@ def test_check_project_format__new_with_x_wkgps(self): ################################################################################################ def test_check_workflow_format__old_with_old_files(self): - ''' - Check if the workflow is identified as old when it an old file. - ''' + ''' Check if the workflow is identified as old when it an old file. ''' test_files = ["info.json", "logs.txt", "RUNNING", "ERROR", "COMPLETE", "test_model.mdl"] for test_file in test_files: with self.subTest(test_file=test_file): @@ -125,16 +118,736 @@ def test_check_workflow_format__old_with_old_files(self): def test_check_workflow_format__old_with_results(self): - ''' - Check if the workflow is identified as old when it a results folder. - ''' + ''' Check if the workflow is identified as old when it a results folder. ''' test_dir = os.path.join(self.test_folderpath, "results") os.mkdir(test_dir) self.assertFalse(StochSSBase.check_workflow_format(path=self.test_folderpath)) def test_check_workflow_format__new(self): - ''' - Check if the workflow is identified as old. - ''' + ''' Check if the workflow is identified as old. ''' self.assertTrue(StochSSBase.check_workflow_format(path=self.test_folderpath)) + + ################################################################################################ + # Unit tests for the StochSS base class get_new_path function. + ################################################################################################ + + def test_get_new_path(self): + ''' Check if the new path is generated correctly. ''' + test_dst_path = os.path.join(self.test_folderpath, "test_file") + test_file_path = StochSSBase.get_new_path(dst_path=test_dst_path) + self.assertEqual(test_file_path, os.path.join(self.user_dir, test_dst_path)) + + + def test_get_new_path__no_trash_folder(self): + ''' Check if the trash directory is created. ''' + test_dst_path = os.path.join("trash", "test_file") + StochSSBase.get_new_path(dst_path=test_dst_path) + self.assertTrue(os.path.exists(os.path.join(self.user_dir, "trash"))) + + + def test_get_new_path__remove_trash_datetime_stamp(self): + ''' Check if the trash datetime stamp is removed from files moving out of trash. ''' + test_dst_path = os.path.join(self.test_folderpath, "trash", "test_file 2021.06.28.08.50.30") + test_file_path = StochSSBase.get_new_path(dst_path=test_dst_path) + expected_path = os.path.join(self.user_dir, os.path.join(self.test_folderpath, "trash", "test_file")) + self.assertEqual(test_file_path, expected_path) + + def test_get_new_path__add_trash_datetime_stamp(self): + ''' Check if the trash datetime stamp is added to duplicate files moved into trash. ''' + os.mkdir(os.path.join(self.test_folderpath, "trash")) + test_dst_path = os.path.join(self.test_folderpath, "trash", "test_file") + Path(test_dst_path).touch() + test_file_path = StochSSBase.get_new_path(dst_path=test_dst_path) + stamp = datetime.datetime.now().strftime(" %y.%m.%d.%H.%M.%S") + expected_path = os.path.join(self.user_dir, os.path.join(self.test_folderpath, "trash", f"test_file{stamp}")) + self.assertEqual(test_file_path, expected_path) + + ################################################################################################ + # Unit tests for the StochSS base class get_file function. + ################################################################################################ + + def test_get_file__no_path_passed(self): + ''' Check if the file from self.path of StochSSBase is returned. ''' + test_base = StochSSBase(path=self.test_folderpath) + self.assertEqual(test_base.get_file(), "test_base_folder") + + + def test_get_file__path_passed(self): + ''' Check is the file from the passed in path is returned. ''' + test_base = StochSSBase(path=self.test_folderpath) + self.assertEqual(test_base.get_file(path=self.test_filepath), "test_base_file") + + ################################################################################################ + # Unit tests for the StochSS base class get_model_template function. + ################################################################################################ + + def test_get_model_template__as_dict(self): + ''' Check if the model template is returned as a dictionary. ''' + test_base = StochSSBase(path=self.test_filepath) + test_template = test_base.get_model_template() + self.assertIsInstance(test_template, dict) + + + def test_get_model_template__as_str(self): + ''' Check is the model template is returned as a string. ''' + test_base = StochSSBase(path=self.test_filepath) + test_template = test_base.get_model_template(as_string=True) + self.assertIsInstance(test_template, str) + + + def test_get_model_template__file_not_found_error(self): + ''' Check if the StochSSFileNotFoundError is raised when the template file is missing. ''' + test_base = StochSSBase(path=self.test_filepath) + with mock.patch("builtins.open", mock.mock_open()) as mock_file: + mock_file.side_effect = FileNotFoundError + with self.assertRaises(StochSSFileNotFoundError): + test_base.get_model_template() + + + def test_get_model_template__json_decoder_error(self): + ''' Check is the FileNotJSONFormatError is raised when the template is not properly formatted. ''' + test_base = StochSSBase(path=self.test_filepath) + with mock.patch("json.load") as mock_load: + mock_load.side_effect = json.decoder.JSONDecodeError(msg="", doc="", pos=1) + with self.assertRaises(FileNotJSONFormatError): + test_base.get_model_template() + + ################################################################################################ + # Unit tests for the StochSS base class get_settings_template function. + ################################################################################################ + + def test_get_settings_template__as_dict(self): + ''' Check if the settings template is returned as a dictionary. ''' + test_base = StochSSBase(path=self.test_filepath) + test_template = test_base.get_settings_template() + self.assertIsInstance(test_template, dict) + + + def test_get_settings_template__as_str(self): + ''' Check is the settings template is returned as a string. ''' + test_base = StochSSBase(path=self.test_filepath) + test_template = test_base.get_settings_template(as_string=True) + self.assertIsInstance(test_template, str) + + + def test_get_settings_template__file_not_found_error(self): + ''' Check if the StochSSFileNotFoundError is raised when the template file is missing. ''' + test_base = StochSSBase(path=self.test_filepath) + with mock.patch("builtins.open", mock.mock_open()) as mock_file: + mock_file.side_effect = FileNotFoundError + with self.assertRaises(StochSSFileNotFoundError): + test_base.get_settings_template() + + + def test_get_settings_template__json_decoder_error(self): + ''' Check is the FileNotJSONFormatError is raised when the template is not properly formatted. ''' + test_base = StochSSBase(path=self.test_filepath) + with mock.patch("json.load") as mock_load: + mock_load.side_effect = json.decoder.JSONDecodeError(msg="", doc="", pos=1) + with self.assertRaises(FileNotJSONFormatError): + test_base.get_settings_template() + + ################################################################################################ + # Unit tests for the StochSS base class get_name function. + ################################################################################################ + + def test_get_name__no_path_passed(self): + ''' Check in the names are return correctly when a path is not passed in. ''' + test_paths = ["test_file", "test_file/", "test_folder/test_file", "test_file.txt"] + for test_path in test_paths: + with self.subTest(test_path=test_path): + test_base = StochSSBase(path=test_path) + self.assertEqual(test_base.get_name(), "test_file") + + + def test_get_name__path_passed(self): + ''' Check in the names are return correctly when a path is passed in. ''' + test_paths = ["test_file", "test_file/", "test_folder/test_file", "test_file.txt"] + test_base = StochSSBase(path=self.test_folderpath) + for test_path in test_paths: + with self.subTest(test_path=test_path): + self.assertEqual(test_base.get_name(path=test_path), "test_file") + + ################################################################################################ + # Unit tests for the StochSS base class get_path function. + ################################################################################################ + + def test_get_path__with_out_user_dir(self): + ''' Check if the path is returned w/o the user directory. ''' + test_base = StochSSBase(path=self.test_filepath) + self.assertEqual(test_base.get_path(), self.test_filepath) + + def test_get_path__with_user_dir(self): + ''' Check if the path is returneded with the user directory. ''' + test_base = StochSSBase(path=self.test_filepath) + self.assertEqual(test_base.get_path(full=True), os.path.join(self.user_dir, self.test_filepath)) + + ################################################################################################ + # Unit tests for the StochSS base class get_dir_name function. + ################################################################################################ + + def test_get_dir_name__with_out_user_dir__root(self): + ''' Check if the dirname is an empty string. ''' + test_base = StochSSBase(path="test_file") + self.assertEqual(test_base.get_dir_name(), "") + + + def test_get_dir_name__with_out_user_dir__not_root(self): + ''' Check if the dirname is returned w/o the user directory. ''' + test_base = StochSSBase(path="test_folder/test_file") + self.assertEqual(test_base.get_dir_name(), "test_folder") + + + def test_get_dir_name__with_user_dir__root(self): + ''' Check if the dirname is the user directory. ''' + test_base = StochSSBase(path="test_file") + self.assertEqual(test_base.get_dir_name(full=True), self.user_dir) + + + def test_get_dir_name__with_user_dir__not_root(self): + ''' Check if the dirname is returned with the user directory. ''' + test_base = StochSSBase(path="test_folder/test_file") + self.assertEqual(test_base.get_dir_name(full=True), os.path.join(self.user_dir, "test_folder")) + + ################################################################################################ + # Unit tests for the StochSS base class get_status function. + ################################################################################################ + + def test_get_status__ready__no_path_passed(self): + ''' Check if ready status is returned when no status file are found and no path is passed in. ''' + test_base = StochSSBase(path=self.test_folderpath) + self.assertEqual(test_base.get_status(), "ready") + + + def test_get_status__ready__path_passed(self): + ''' Check if ready status is returned when no status file are found and a path is passed in. ''' + test_base = StochSSBase(path=self.test_filepath) + self.assertEqual(test_base.get_status(path=self.test_folderpath), "ready") + + + def test_get_status__other__no_path_passed(self): + ''' Check if the status is returned correctly for status files when no path is passed in. ''' + test_files = ["COMPLETE", "ERROR", "RUNNING"] + expected_results = ["complete", "error", "running"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + test_path = os.path.join(self.test_folderpath, test_file) + Path(test_path).touch() + test_base = StochSSBase(path=self.test_folderpath) + self.assertEqual(test_base.get_status(), expected_results[i]) + self.tearDown() + self.setUp() + + + def test_get_status__other__path_passed(self): + ''' Check if the status is returned correctly for status files when no path is passed in. ''' + test_files = ["COMPLETE", "ERROR", "RUNNING"] + expected_results = ["complete", "error", "running"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + test_path = os.path.join(self.test_folderpath, test_file) + Path(test_path).touch() + test_base = StochSSBase(path=self.test_filepath) + self.assertEqual(test_base.get_status(path=self.test_folderpath), expected_results[i]) + self.tearDown() + self.setUp() + + + def test_get_status__file_not_found_error(self): + ''' Check if the StochSSFileNotFoundError is raised when the job is missing. ''' + test_base = StochSSBase(path=self.test_folderpath) + with mock.patch("os.listdir") as mock_folder: + mock_folder.side_effect = FileNotFoundError + with self.assertRaises(StochSSFileNotFoundError): + test_base.get_status() + + + ################################################################################################ + # Unit tests for the StochSS base class get_unique_path function. + ################################################################################################ + + def test_get_unique_path__with_out_dirname__dirname_is_root__unique(self): + ''' Check if you get the correct unique name for a file in root. ''' + test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt", + "test_file(2)", "test_file(2).txt", "test_file(one)", "test_file(one).txt"] + for test_file in test_files: + with self.subTest(test_file=test_file): + test_base = StochSSBase(path="test_base_file") + test_base.user_dir = self.test_folderpath + unique_path, changed = test_base.get_unique_path(name=test_file) + self.assertFalse(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, test_file)) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_out_dirname__dirname_is_root__one_iter(self): + ''' Check if you get the correct unique name for a file in root when file already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt", + "test_file(one)", "test_file(one).txt"] + expected_results = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt", + "test_file(one)(1)", "test_file(one)(1).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + Path(os.path.join(self.test_folderpath, test_file)).touch() + test_base = StochSSBase(path="test_base_file") + test_base.user_dir = self.test_folderpath + unique_path, changed = test_base.get_unique_path(name=test_file) + self.assertTrue(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_out_dirname__dirname_is_root__two_iter(self): + ''' Check if you get the correct unique name for a file in root when a file and iter already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt", + "test_file(one)", "test_file(one).txt"] + test_preqs = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt", + "test_file(one)(1)", "test_file(one)(1).txt"] + expected_results = ["test_file(2)", "test_file(2).txt", "test_file(3)", "test_file(3).txt", + "test_file(one)(2)", "test_file(one)(2).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + Path(os.path.join(self.test_folderpath, test_file)).touch() + Path(os.path.join(self.test_folderpath, test_preqs[i])).touch() + test_base = StochSSBase(path="test_base_file") + test_base.user_dir = self.test_folderpath + unique_path, changed = test_base.get_unique_path(name=test_file) + self.assertTrue(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_out_dirname__dirname_is_root__first_iter_removed(self): + ''' Check if you get the correct unique name for a file in root when a iter already exists. ''' + test_files = ["test_file(2)", "test_file(2).txt", "test_file(one)(2)", "test_file(one)(2).txt"] + test_preqs = ["test_file", "test_file.txt", "test_file(one)", "test_file(one).txt"] + expected_results = ["test_file(1)", "test_file(1).txt", "test_file(one)(1)", "test_file(one)(1).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + Path(os.path.join(self.test_folderpath, test_file)).touch() + Path(os.path.join(self.test_folderpath, test_preqs[1])).touch() + test_base = StochSSBase(path="test_base_file") + test_base.user_dir = self.test_folderpath + unique_path, changed = test_base.get_unique_path(name=test_file) + self.assertTrue(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_out_dirname__dirname_not_root__unique(self): + ''' Check if you get the correct unique name for a file not in root. ''' + test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt", + "test_file(2)", "test_file(2).txt", "test_file(one)", "test_file(one).txt"] + for test_file in test_files: + with self.subTest(test_file=test_file): + os.mkdir(os.path.join(self.test_folderpath, "test_folder")) + test_base = StochSSBase(path=os.path.join("test_folder/test_base_file")) + test_base.user_dir = self.test_folderpath + unique_path, changed = test_base.get_unique_path(name=test_file) + self.assertFalse(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, "test_folder", test_file)) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_out_dirname__dirname_not_root__one_iter(self): + ''' Check if you get the correct unique name for a file not in root when file already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt", + "test_file(one)", "test_file(one).txt"] + expected_results = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt", + "test_file(one)(1)", "test_file(one)(1).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + os.mkdir(os.path.join(self.test_folderpath, "test_folder")) + Path(os.path.join(self.test_folderpath, "test_folder", test_file)).touch() + test_base = StochSSBase(path=os.path.join("test_folder/test_base_file")) + test_base.user_dir = self.test_folderpath + unique_path, changed = test_base.get_unique_path(name=test_file) + self.assertTrue(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, "test_folder", expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_out_dirname__dirname_not_root__two_iter(self): + ''' Check if you get the correct unique name for a file not in root when a file and iter already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt", + "test_file(one)", "test_file(one).txt"] + test_preqs = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt", + "test_file(one)(1)", "test_file(one)(1).txt"] + expected_results = ["test_file(2)", "test_file(2).txt", "test_file(3)", "test_file(3).txt", + "test_file(one)(2)", "test_file(one)(2).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + os.mkdir(os.path.join(self.test_folderpath, "test_folder")) + Path(os.path.join(self.test_folderpath, "test_folder", test_file)).touch() + Path(os.path.join(self.test_folderpath, "test_folder", test_preqs[i])).touch() + test_base = StochSSBase(path=os.path.join("test_folder/test_base_file")) + test_base.user_dir = self.test_folderpath + unique_path, changed = test_base.get_unique_path(name=test_file) + self.assertTrue(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, "test_folder", expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_out_dirname__dirname_not_root__first_iter_removed(self): + ''' Check if you get the correct unique name for a file not in root when a iter already exists. ''' + test_files = ["test_file(2)", "test_file(2).txt", "test_file(one)(2)", "test_file(one)(2).txt"] + test_preqs = ["test_file", "test_file.txt", "test_file(one)", "test_file(one).txt"] + expected_results = ["test_file(1)", "test_file(1).txt", "test_file(one)(1)", "test_file(one)(1).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + os.mkdir(os.path.join(self.test_folderpath, "test_folder")) + Path(os.path.join(self.test_folderpath, "test_folder", test_file)).touch() + Path(os.path.join(self.test_folderpath, "test_folder", test_preqs[1])).touch() + test_base = StochSSBase(path="test_folder/test_base_file") + test_base.user_dir = self.test_folderpath + unique_path, changed = test_base.get_unique_path(name=test_file) + self.assertTrue(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, "test_folder", expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_dirname__unique(self): + ''' Check if you get the correct unique name for a file. ''' + test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt", + "test_file(2)", "test_file(2).txt", "test_file(one)", "test_file(one).txt"] + for test_file in test_files: + with self.subTest(test_file=test_file): + test_base = StochSSBase(path=self.test_filepath) + unique_path, changed = test_base.get_unique_path(name=test_file, + dirname=self.test_folderpath) + self.assertFalse(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, test_file)) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_dirname__one_iter(self): + ''' Check if you get the correct unique name for a file when file already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt", + "test_file(one)", "test_file(one).txt"] + expected_results = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt", + "test_file(one)(1)", "test_file(one)(1).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + Path(os.path.join(self.test_folderpath, test_file)).touch() + test_base = StochSSBase(path=self.test_filepath) + unique_path, changed = test_base.get_unique_path(name=test_file, + dirname=self.test_folderpath) + self.assertTrue(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_dirname__two_iter(self): + ''' Check if you get the correct unique name for a file when a file and iter already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt", + "test_file(one)", "test_file(one).txt"] + test_preqs = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt", + "test_file(one)(1)", "test_file(one)(1).txt"] + expected_results = ["test_file(2)", "test_file(2).txt", "test_file(3)", "test_file(3).txt", + "test_file(one)(2)", "test_file(one)(2).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + Path(os.path.join(self.test_folderpath, test_file)).touch() + Path(os.path.join(self.test_folderpath, test_preqs[i])).touch() + test_base = StochSSBase(path=self.test_filepath) + unique_path, changed = test_base.get_unique_path(name=test_file, + dirname=self.test_folderpath) + self.assertTrue(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_path__with_dirname__dirname__first_iter_removed(self): + ''' Check if you get the correct unique name for a file in root when a iter already exists. ''' + test_files = ["test_file(2)", "test_file(2).txt", "test_file(one)(2)", "test_file(one)(2).txt"] + test_preqs = ["test_file", "test_file.txt", "test_file(one)", "test_file(one).txt"] + expected_results = ["test_file(1)", "test_file(1).txt", "test_file(one)(1)", "test_file(one)(1).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + Path(os.path.join(self.test_folderpath, test_file)).touch() + Path(os.path.join(self.test_folderpath, test_preqs[1])).touch() + test_base = StochSSBase(path=self.test_filepath) + unique_path, changed = test_base.get_unique_path(name=test_file, + dirname=self.test_folderpath) + self.assertTrue(changed) + self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i])) + self.tearDown() + self.setUp() + + ################################################################################################ + # Unit tests for the StochSS base class get_unique_copy_path function. + ################################################################################################ + + def test_get_unique_copy_path__with_out_path__dirname_is_root__one_iter(self): + ''' Check if you get the correct copy path for a file in root when path already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"] + expected_results = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + test_base = StochSSBase(path=test_file) + test_base.user_dir = self.test_folderpath + unique_copy_path = test_base.get_unique_copy_path() + self.assertEqual(unique_copy_path, expected_results[i]) + self.tearDown() + self.setUp() + + + def test_get_unique_copy_path__with_out_path__dirname_is_root__two_iter(self): + ''' Check if you get the correct copy path for a file in root when path and iter already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"] + test_preqs = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"] + expected_results = ["test_file-copy(2)", "test_file-copy(2).txt", "test_file-copy(3)", "test_file-copy(3).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + Path(os.path.join(self.test_folderpath, test_preqs[i])).touch() + test_base = StochSSBase(path=test_file) + test_base.user_dir = self.test_folderpath + unique_copy_path = test_base.get_unique_copy_path() + self.assertEqual(unique_copy_path, expected_results[i]) + self.tearDown() + self.setUp() + + + def test_get_unique_copy_path__with_out_path__dirname_is_root__first_iter_removed(self): + ''' Check if you get the correct copy path for a file in root when a iter already exists. ''' + test_files = ["test_file-copy(2)", "test_file-copy(2).txt"] + expected_results = ["test_file-copy", "test_file-copy.txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + test_base = StochSSBase(path=test_file) + test_base.user_dir = self.test_folderpath + unique_copy_path = test_base.get_unique_copy_path() + self.assertEqual(unique_copy_path, expected_results[i]) + self.tearDown() + self.setUp() + + + def test_get_unique_copy_path__with_out_path__dirname_not_root__one_iter(self): + ''' Check if you get the correct copy path for a file not in root when path already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"] + expected_results = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + os.mkdir(os.path.join(self.test_folderpath, "test_folder")) + test_base = StochSSBase(path=os.path.join("test_folder", test_file)) + test_base.user_dir = self.test_folderpath + unique_copy_path = test_base.get_unique_copy_path() + self.assertEqual(unique_copy_path, os.path.join("test_folder", expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_copy_path__with_out_path__dirname_not_root__two_iter(self): + ''' Check if you get the correct copy path for a file not in root when path and iter already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"] + test_preqs = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"] + expected_results = ["test_file-copy(2)", "test_file-copy(2).txt", "test_file-copy(3)", "test_file-copy(3).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + os.mkdir(os.path.join(self.test_folderpath, "test_folder")) + Path(os.path.join(self.test_folderpath, "test_folder", test_preqs[i])).touch() + test_base = StochSSBase(path=os.path.join("test_folder", test_file)) + test_base.user_dir = self.test_folderpath + unique_copy_path = test_base.get_unique_copy_path() + self.assertEqual(unique_copy_path, os.path.join("test_folder", expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_copy_path__with_out_path__dirname_not_root__first_iter_removed(self): + ''' Check if you get the correct copy for a file not in root when a iter already exists. ''' + test_files = ["test_file-copy(2)", "test_file-copy(2).txt"] + expected_results = ["test_file-copy", "test_file-copy.txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + os.mkdir(os.path.join(self.test_folderpath, "test_folder")) + test_base = StochSSBase(path=os.path.join("test_folder", test_file)) + test_base.user_dir = self.test_folderpath + unique_copy_path = test_base.get_unique_copy_path() + self.assertEqual(unique_copy_path, os.path.join("test_folder", expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_copy_path__with_path__one_iter(self): + ''' Check if you get the correct copy path for a file when path already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"] + expected_results = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + test_base = StochSSBase(path=self.test_filepath) + unique_copy_path = test_base.get_unique_copy_path(path=os.path.join(self.test_folderpath, test_file)) + self.assertEqual(unique_copy_path, os.path.join(self.test_folderpath, expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_copy_path__with_path__two_iter(self): + ''' Check if you get the correct copy path for a file when path and iter already exists. ''' + test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"] + test_preqs = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"] + expected_results = ["test_file-copy(2)", "test_file-copy(2).txt", "test_file-copy(3)", "test_file-copy(3).txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + Path(os.path.join(self.test_folderpath, test_preqs[i])).touch() + test_base = StochSSBase(path=self.test_filepath) + unique_copy_path = test_base.get_unique_copy_path(path=os.path.join(self.test_folderpath, test_file)) + self.assertEqual(unique_copy_path, os.path.join(self.test_folderpath, expected_results[i])) + self.tearDown() + self.setUp() + + + def test_get_unique_copy_path__with_path__first_iter_removed(self): + ''' Check if you get the correct copy for a file when a iter already exists. ''' + test_files = ["test_file-copy(2)", "test_file-copy(2).txt"] + expected_results = ["test_file-copy", "test_file-copy.txt"] + for i, test_file in enumerate(test_files): + with self.subTest(test_file=test_file): + test_base = StochSSBase(path=self.test_filepath) + unique_copy_path = test_base.get_unique_copy_path(path=os.path.join(self.test_folderpath, test_file)) + self.assertEqual(unique_copy_path, os.path.join(self.test_folderpath, expected_results[i])) + self.tearDown() + self.setUp() + + ################################################################################################ + # Unit tests for the StochSS base class log function. + ################################################################################################ + + def test_log(self): + ''' Check if log is added correctly ''' + test_base = StochSSBase(path=self.test_filepath) + test_log = {"level": "debug", "message": "testing base log"} + test_base.log("debug", "testing base log") + self.assertIn(test_log, test_base.logs) + + ################################################################################################ + # Unit tests for the StochSS base class make_parent_dirs function. + ################################################################################################ + + def test_make_parent_dirs__one_missing_dir(self): + ''' Check if the parent directories are made correctly. ''' + test_path = os.path.join(self.test_folderpath, "test_folder") + test_base = StochSSBase(path=self.test_folderpath) + with mock.patch('stochss.handlers.util.StochSSBase.get_dir_name') as mock_get_dir_name: + mock_get_dir_name.return_value = test_path + test_base.make_parent_dirs() + self.assertIn("test_folder", os.listdir(self.test_folderpath)) + + + def test_make_parent_dirs__multiple_missing_dir(self): + ''' Check if the parent directories are made correctly. ''' + test_path = os.path.join(self.test_folderpath, "test_folder1", "test_folder2") + test_base = StochSSBase(path=self.test_folderpath) + with mock.patch('stochss.handlers.util.StochSSBase.get_dir_name') as mock_get_dir_name: + mock_get_dir_name.return_value = test_path + test_base.make_parent_dirs() + self.assertIn("test_folder1", os.listdir(self.test_folderpath)) + self.assertIn("test_folder2", os.listdir(os.path.join(self.test_folderpath, "test_folder1"))) + + ################################################################################################ + # Unit tests for the StochSS base class print_logs function. + ################################################################################################ + + def test_print_logs__debug(self): + ''' Check if debug log is logged correctly. ''' + log = logging.getLogger('stochss') + test_base = StochSSBase(path=self.test_folderpath) + test_base.log("debug", "testing debug log") + with mock.patch("stochss.handlers.log.log.debug") as mock_debug_log: + test_base.print_logs(log) + mock_debug_log.assert_called_once_with("testing debug log") + + + def test_print_logs__info(self): + ''' Check if info log is logged correctly. ''' + log = logging.getLogger('stochss') + test_base = StochSSBase(path=self.test_folderpath) + test_base.log("info", "testing info log") + with mock.patch("stochss.handlers.log.log.info") as mock_debug_log: + test_base.print_logs(log) + mock_debug_log.assert_called_once_with("testing info log") + + + def test_print_logs__warning(self): + ''' Check if warning log is logged correctly. ''' + log = logging.getLogger('stochss') + test_base = StochSSBase(path=self.test_folderpath) + test_base.log("warning", "testing warning log") + with mock.patch("stochss.handlers.log.log.warning") as mock_debug_log: + test_base.print_logs(log) + mock_debug_log.assert_called_once_with("testing warning log") + + + def test_print_logs__error(self): + ''' Check if error log is logged correctly. ''' + log = logging.getLogger('stochss') + test_base = StochSSBase(path=self.test_folderpath) + test_base.log("error", "testing error log") + with mock.patch("stochss.handlers.log.log.error") as mock_debug_log: + test_base.print_logs(log) + mock_debug_log.assert_called_once_with("testing error log") + + + def test_print_logs__critical(self): + ''' Check if critical log is logged correctly. ''' + log = logging.getLogger('stochss') + test_base = StochSSBase(path=self.test_folderpath) + test_base.log("critical", "testing critical log") + with mock.patch("stochss.handlers.log.log.critical") as mock_debug_log: + test_base.print_logs(log) + mock_debug_log.assert_called_once_with("testing critical log") + + ################################################################################################ + # Unit tests for the StochSS base class rename function. + ################################################################################################ + + def test_rename__unique_name(self): + ''' Check if file was renamed to the given name. ''' + test_path = os.path.join(self.test_folderpath, "test_file") + Path(test_path).touch() + test_base = StochSSBase(path=test_path) + resp = test_base.rename(name="new_test_file") + self.assertIsInstance(resp, dict) + self.assertFalse(resp['changed']) + self.assertEqual(resp['_path'], os.path.join(self.test_folderpath, "new_test_file")) + + + def test_rename__name_already_exists(self): + ''' Check if file was renamed correctly when name is in use. ''' + test_path = os.path.join(self.test_folderpath, "test_file") + Path(test_path).touch() + test_preq = os.path.join(self.test_folderpath, "new_test_file") + Path(test_preq).touch() + test_base = StochSSBase(path=test_path) + resp = test_base.rename(name="new_test_file") + self.assertIsInstance(resp, dict) + self.assertTrue(resp['changed']) + self.assertEqual(resp['_path'], os.path.join(self.test_folderpath, "new_test_file(1)")) + + + def test_rename__file_not_found_error(self): + ''' Check if the StochSSFileNotFoundError is raised when the file is missing. ''' + test_base = StochSSBase(path="test_file") + with self.assertRaises(StochSSFileNotFoundError): + test_base.rename(name="new_test_file") + + + def test_rename_permission_error(self): + ''' Check if the StochSSPermissionsError is raised when the user doesn't have the correct permissions. ''' + test_base = StochSSBase(path="test_file") + with mock.patch("shutil.move") as mock_move: + mock_move.side_effect = PermissionError + with self.assertRaises(StochSSPermissionsError): + test_base.rename(name="new_test_file") From 4ba9be47124c51b7ad4319f5b680ce06f6b7a083 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 28 Jun 2021 18:58:08 -0400 Subject: [PATCH 52/63] Removed old test files. --- stochss/tests/test_convert_sbml.py | 205 --------------- stochss/tests/test_duplicate.py | 325 ------------------------ stochss/tests/test_generate_zip_file.py | 68 ----- stochss/tests/test_ls.py | 228 ----------------- stochss/tests/test_rename.py | 130 ---------- stochss/tests/test_upload_file.py | 115 --------- stochss/tests/test_workflow_status.py | 52 ---- 7 files changed, 1123 deletions(-) delete mode 100644 stochss/tests/test_convert_sbml.py delete mode 100644 stochss/tests/test_duplicate.py delete mode 100644 stochss/tests/test_generate_zip_file.py delete mode 100644 stochss/tests/test_ls.py delete mode 100644 stochss/tests/test_rename.py delete mode 100644 stochss/tests/test_upload_file.py delete mode 100644 stochss/tests/test_workflow_status.py diff --git a/stochss/tests/test_convert_sbml.py b/stochss/tests/test_convert_sbml.py deleted file mode 100644 index 1c5f940eda..0000000000 --- a/stochss/tests/test_convert_sbml.py +++ /dev/null @@ -1,205 +0,0 @@ -import unittest, sys, os, inspect -import tempfile -from gillespy2 import Model -from gillespy2.solvers.numpy.basic_ode_solver import BasicODESolver - -currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) -parentdir = os.path.dirname(currentdir) -sys.path.insert(0,parentdir) - -from handlers.util.convert_sbml_to_model import * -from handlers.util.stochss_errors import StochSSAPIError, StochSSFileNotFoundError - -class TestConvertSBMLToModel(unittest.TestCase): - - def test_sbml_to_gillespy_success_with_stochss_model(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - self.assertIsInstance(gillespy2_model, Model) - self.assertIsInstance(errors, list) - - - def test_sbml_to_gillespy_convert_error(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test2.sbml" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - self.assertIsNone(gillespy2_model) - self.assertIsInstance(errors, list) - - - def test_sbml_to_gillespy_file_not_found_error(self): - expected = StochSSFileNotFoundError("") - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test3.sbml" - - try: - resp = convert_to_gillespy_model(sbml_file) - self.assertNotIsInstance(resp, tuple) - except StochSSAPIError as err: - self.assertIsInstance(err, StochSSFileNotFoundError) - self.assertEqual(err.status_code, expected.status_code) - self.assertEqual(err.reason, expected.reason) - - - def test_build_stochss_species_from_gillespy_species(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/specie.js" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props))) - - species_keys = sorted(list(get_species(gillespy2_model.listOfSpecies, 1)[0][0].keys())) - self.assertEqual(species_keys, model_keys) - - - def test_build_stochss_parameter_from_gillespy_parameter(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/parameter.js" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props))) - - parameter_keys = sorted(list(get_parameters(gillespy2_model.listOfParameters, 1)[0][0].keys())) - self.assertEqual(parameter_keys, model_keys) - - - def test_build_stochss_reaction_from_gillespy_reaction(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/reaction.js" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - collections = data.split("collections: {").pop().split('}')[0].split(',') - children = data.split("children: {").pop().split('}')[0].split(',') - model_keys = list(map(lambda item: item.strip().split(':')[0], props)) - model_keys.extend(list(map(lambda item: item.strip().split(':')[0], collections))) - model_keys.extend(list(map(lambda item: item.strip().split(':')[0], children))) - model_keys.sort() - - species = get_species(gillespy2_model.listOfSpecies, 1)[0] - reaction_keys = sorted(list(get_reactions(gillespy2_model.listOfReactions, species, 1)[0][0].keys())) - self.assertEqual(reaction_keys, model_keys) - - - def test_build_stochss_reactant_from_gillespy_reactant(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/stoich-specie.js" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - children = data.split("children: {").pop().split('}')[0].split(',') - model_keys = list(map(lambda item: item.strip().split(':')[0], props)) - model_keys.extend(list(map(lambda item: item.strip().split(':')[0], children))) - model_keys.sort() - - species = get_species(gillespy2_model.listOfSpecies, 1)[0] - reactant_keys = sorted(list(get_reactants(list(gillespy2_model.listOfReactions.popitem(last=False)).pop().reactants, species)[0].keys())) - self.assertEqual(reactant_keys, model_keys) - - - def test_build_stochss_product_from_gillespy_product(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/stoich-specie.js" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - children = data.split("children: {").pop().split('}')[0].split(',') - model_keys = list(map(lambda item: item.strip().split(':')[0], props)) - model_keys.extend(list(map(lambda item: item.strip().split(':')[0], children))) - model_keys.sort() - - species = get_species(gillespy2_model.listOfSpecies, 1)[0] - product_keys = sorted(list(get_products(list(gillespy2_model.listOfReactions.popitem(last=False)).pop().products, species)[0].keys())) - self.assertEqual(product_keys, model_keys) - - - def test_build_stochss_event_from_gillespy_event(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/event.js" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - collections = data.split("collections: {").pop().split('}')[0].split(',') - model_keys = list(map(lambda item: item.strip().split(':')[0], props)) - model_keys.extend(list(map(lambda item: item.strip().split(':')[0], collections))) - model_keys.sort() - - species = get_species(gillespy2_model.listOfSpecies, 1)[0] - parameters = get_parameters(gillespy2_model.listOfParameters, 1)[0] - event_keys = sorted(list(get_events(gillespy2_model.listOfEvents, species, parameters, 1)[0][0].keys())) - self.assertEqual(event_keys, model_keys) - - - def test_build_stochss_event_assignment_from_gillespy_event_assignment(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/event-assignment.js" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props))) - - species = get_species(gillespy2_model.listOfSpecies, 1)[0] - parameters = get_parameters(gillespy2_model.listOfParameters, 1)[0] - assignment_keys = sorted(list(get_event_assignment(list(gillespy2_model.listOfEvents.popitem(last=False)).pop().assignments, species, parameters)[0].keys())) - self.assertEqual(assignment_keys, model_keys) - - - def test_build_stochss_rate_rule_from_gillespy_rate_rule(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/rule.js" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props))) - - species = get_species(gillespy2_model.listOfSpecies, 1)[0] - parameters = get_parameters(gillespy2_model.listOfParameters, 1)[0] - rate_rule_keys = sorted(list(get_rate_rules(gillespy2_model.listOfRateRules, species, parameters, 1)[0][0].keys())) - self.assertEqual(rate_rule_keys, model_keys) - - - def test_build_stochss_assignment_rule_from_gillespy_assignment_rule(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/rule.js" - gillespy2_model, errors = convert_to_gillespy_model(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props))) - - species = get_species(gillespy2_model.listOfSpecies, 1)[0] - parameters = get_parameters(gillespy2_model.listOfParameters, 1)[0] - assignment_rule_keys = sorted(list(get_assignment_rules(gillespy2_model.listOfAssignmentRules, species, parameters, 1)[0][0].keys())) - self.assertEqual(assignment_rule_keys, model_keys) - - - def test_build_stochss_function_definition_from_sbml_function_definition(self): - sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml" - model_path = "client/models/function-definition.js" - function_definitions = get_sbml_function_definitions(sbml_file) - - with open(model_path, "r") as model_file: - data = model_file.read() - props = data.split("props: {").pop().split('}')[0].split(',') - model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props))) - - function_definition_keys = sorted(list(get_function_definitions(function_definitions, 1)[0][0].keys())) - self.assertEqual(function_definition_keys, model_keys) - diff --git a/stochss/tests/test_duplicate.py b/stochss/tests/test_duplicate.py deleted file mode 100644 index 80449c7cfa..0000000000 --- a/stochss/tests/test_duplicate.py +++ /dev/null @@ -1,325 +0,0 @@ -import unittest, os, tempfile -from pathlib import Path -from handlers.util.duplicate import * - -class TestDuplicate(unittest.TestCase): - - #unit tests for method get_unique_file_name - - def test_get_unique_file_name_notcopy_noext(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filename = "test_file" - test_filepath = os.path.join(tempdir, test_filename) - assert get_unique_file_name(test_filepath) == os.path.join(tempdir,"test_file-copy") - - def test_get_unique_file_name_iscopy_noext(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filename = "test_file-copy" - test_filepath = os.path.join(tempdir, test_filename) - assert get_unique_file_name(test_filepath) == os.path.join(tempdir, 'test_file-copy(2)') - - def test_get_unique_file_name_notcopy_hasext(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filename = "test_file.sample" - test_filepath = os.path.join(tempdir, test_filename) - assert get_unique_file_name(test_filepath) == os.path.join(tempdir, 'test_file-copy.sample') - - def test_get_unique_file_name_iscopy_hasext(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filename = "test_file-copy.sample" - test_filepath = os.path.join(tempdir, test_filename) - assert get_unique_file_name(test_filepath) == os.path.join(tempdir,"test_file-copy(2).sample") - - def test_get_unique_file_name_multiple_copies(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filename = "test_file" - test_filepath = os.path.join(tempdir, test_filename) - for i in range(2): - test_filepath = get_unique_file_name(test_filepath) - assert test_filepath == os.path.join(tempdir,"test_file-copy(2)") - - #unit tests for method duplicate - - def test_duplicate_file_not_found_raise_error(self): - from handlers.util.stochss_errors import StochSSFileNotFoundError - with tempfile.TemporaryDirectory() as tempdir: - test_filepath = os.path.join(tempdir,"nonexistent_file") - with self.assertRaises(StochSSFileNotFoundError): - duplicate(test_filepath) - - def test_duplicate_file_not_found_no_new_file(self): - from handlers.util.stochss_errors import StochSSFileNotFoundError - with tempfile.TemporaryDirectory() as tempdir: - test_filepath = os.path.join(tempdir,"nonexistent_file") - try: - duplicate(test_filepath) - except StochSSFileNotFoundError: - pass - tempdir_contents = os.listdir(tempdir) - assert len(tempdir_contents) == 0 - - def test_duplicate_permission_not_granted_raise_error(self): - from handlers.util.stochss_errors import StochSSPermissionsError - with tempfile.TemporaryDirectory() as tempdir: - test_filepath = os.path.join(tempdir,"existent_file") - Path(test_filepath).touch() - os.chmod(test_filepath,000) - with self.assertRaises(StochSSPermissionsError): - duplicate(test_filepath) - - def test_duplicate_permission_not_granted_no_new_file(self): - from handlers.util.stochss_errors import StochSSPermissionsError - with tempfile.TemporaryDirectory() as tempdir: - test_filepath = os.path.join(tempdir,"existent_file") - Path(test_filepath).touch() - os.chmod(test_filepath,000) - try: - duplicate(test_filepath) - except StochSSPermissionsError: - pass - tempdir_contents = os.listdir(tempdir) - assert len(tempdir_contents) == 1 - - - def test_duplicate_copy_successful(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filepath = os.path.join(tempdir,"existent_file") - Path(test_filepath).touch() - duplicate(test_filepath) - tempdir_contents = os.listdir(tempdir) - assert os.path.isfile(os.path.join(tempdir,'existent_file-copy')) - - #unit tests for method extract_wkfl_model - - def test_extract_wkfl_model_path_changed(self): - with tempfile.TemporaryDirectory() as tempdir: - test_model_path=os.path.join(tempdir,"test_model") - Path(test_model_path).touch() - class Test_Workflow: - wkfl_mdl_path = "" - test_wkfl= Test_Workflow() - setattr(test_wkfl,"wkfl_mdl_path",test_model_path) - test_extract_target="test_model" - extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file=test_extract_target) - assert os.path.isfile(os.path.join(tempdir,"test_model(1)")) - - def test_extract_wkfl_model_path_not_changed(self): - with tempfile.TemporaryDirectory() as tempdir: - test_model_path=os.path.join(tempdir,"test_model") - Path(test_model_path).touch() - class Test_Workflow: - wkfl_mdl_path = "" - test_wkfl= Test_Workflow() - setattr(test_wkfl,"wkfl_mdl_path",test_model_path) - test_extract_target="test_model_extracted" - extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file=test_extract_target) - assert os.path.isfile(os.path.join(tempdir,test_extract_target)) - - def test_extract_wkfl_model_file_not_found_raise_error(self): - from handlers.util.stochss_errors import ModelNotFoundError - with tempfile.TemporaryDirectory() as tempdir: - test_model_path=os.path.join(tempdir,"test_model") - class Test_Workflow: - wkfl_mdl_path = "" - test_wkfl= Test_Workflow() - setattr(test_wkfl,"wkfl_mdl_path",test_model_path) - with self.assertRaises(ModelNotFoundError): - extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file="test_model") - - def test_extract_wkfl_model_file_not_found_no_new_file(self): - with tempfile.TemporaryDirectory() as tempdir: - test_model_path=os.path.join(tempdir,"test_model") - class Test_Workflow: - wkfl_mdl_path = "" - test_wkfl= Test_Workflow() - setattr(test_wkfl,"wkfl_mdl_path",test_model_path) - tempdir_contents = os.listdir(tempdir) - assert len(tempdir_contents) == 0 - - def test_extract_wkfl_model_permission_not_granted_raise_error(self): - from handlers.util.stochss_errors import StochSSPermissionsError - with tempfile.TemporaryDirectory() as tempdir: - test_model_path=os.path.join(tempdir,"test_model") - Path(test_model_path).touch() - class Test_Workflow: - wkfl_mdl_path = "" - test_wkfl= Test_Workflow() - setattr(test_wkfl,"wkfl_mdl_path",test_model_path) - os.chmod(test_model_path,000) - with self.assertRaises(StochSSPermissionsError): - extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file="test_model") - - def test_extract_wkfl_model_permission_not_granted_no_new_file(self): - from handlers.util.stochss_errors import StochSSPermissionsError - with tempfile.TemporaryDirectory() as tempdir: - test_model_path=os.path.join(tempdir,"test_model") - Path(test_model_path).touch() - class Test_Workflow: - wkfl_mdl_path = "" - test_wkfl= Test_Workflow() - setattr(test_wkfl,"wkfl_mdl_path",test_model_path) - os.chmod(test_model_path,000) - try: - extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file="test_model") - except StochSSPermissionsError: - pass - tempdir_contents = os.listdir(tempdir) - assert len(tempdir_contents) == 1 - - #unit tests for method get_wkfl_model_parent_path - - def test_get_wkfl_model_parent_path_model_only(self): - assert get_wkfl_model_parent_path("test_path", True, "no wkfl") == "test_path" - - def test_get_wkfl_model_parent_path_does_not_exist(self): - with tempfile.TemporaryDirectory() as tempdir: - test_model_path=os.path.join(tempdir,"test_model") - class Test_Workflow: - wkfl_mdl_path = "" - mdl_path = "" - test_wkfl= Test_Workflow() - setattr(test_wkfl, "",test_model_path) - assert get_wkfl_model_parent_path("path_does_not_exist", False, test_wkfl) == "path_does_not_exist" - - def test_get_wkfl_model_parent_path_exists(self): - with tempfile.TemporaryDirectory() as tempdir: - test_dir_path=os.path.join(tempdir,'test_directory') - os.mkdir(test_dir_path) - test_file_path = os.path.join(test_dir_path,"test_file") - class Test_Workflow: - mdl_path = "" - test_wkfl= Test_Workflow() - setattr(test_wkfl, "mdl_path", test_file_path) - Path(test_file_path).touch() - assert get_wkfl_model_parent_path("path_does_not_exist", False, test_wkfl) == test_dir_path - - #unit tests for method get_model_path - - def test_get_model_path_only_model(self): - assert get_model_path("test_wkfl_parent_path", "test_mdl_parent_path", "test_mdl_file", True) == (os.path.join("test_wkfl_parent_path","test_mdl_file"), "") - - def test_get_model_path_wkfl_parent_path_equals_mdl_parent_path_and_exists(self): - with tempfile.TemporaryDirectory() as tempdir: - test_dual_parent_dir = os.path.join(tempdir, "test_dual_parent_dir") - test_model_path = os.path.join(test_dual_parent_dir,"test_model") - os.mkdir(test_dual_parent_dir) - Path(test_model_path).touch() - assert get_model_path(test_dual_parent_dir, test_dual_parent_dir, "test_model", False) == (os.path.join(test_dual_parent_dir,"test_model"), "") - - def test_get_model_path_mdl_file_in_wkfl_parent_path_directory(self): - with tempfile.TemporaryDirectory() as tempdir: - test_wkfl_parent_dir = os.path.join(tempdir, "test_wkfl_parent_dir") - os.mkdir(test_wkfl_parent_dir) - test_model_parent_dir = os.path.join(tempdir, "test_model_parent_dir") - os.mkdir(test_model_parent_dir) - test_model_path = os.path.join(test_wkfl_parent_dir,"test_model") - Path(test_model_path).touch() - assert get_model_path(test_wkfl_parent_dir, "", "test_model", False) == (os.path.join(test_wkfl_parent_dir,"test_model"), "") - - - def test_get_model_path_mdl_file_in_mdl_parent_path_directory(self): - with tempfile.TemporaryDirectory() as tempdir: - test_wkfl_parent_dir = os.path.join(tempdir, "test_wkfl_parent_dir") - os.mkdir(test_wkfl_parent_dir) - test_model_parent_dir = os.path.join(tempdir, "test_model_parent_dir") - os.mkdir(test_model_parent_dir) - test_model_path = os.path.join(test_model_parent_dir,"test_model") - Path(test_model_path).touch() - assert get_model_path(test_wkfl_parent_dir, test_model_parent_dir, "test_model", False) == (os.path.join(test_model_parent_dir,"test_model"), "") - - - def test_get_model_path_mdl_file_in_mdl_and_wkfl_parent_path_directory(self): - with tempfile.TemporaryDirectory() as tempdir: - test_wkfl_parent_dir = os.path.join(tempdir, "test_wkfl_parent_dir") - os.mkdir(test_wkfl_parent_dir) - test_model_parent_dir = os.path.join(tempdir, "test_model_parent_dir") - os.mkdir(test_model_parent_dir) - test_model_path = os.path.join(test_model_parent_dir,"test_model") - Path(test_model_path).touch() - test_model_path2 = os.path.join(test_wkfl_parent_dir,"test_model") - Path(test_model_path2).touch() - assert get_model_path(test_wkfl_parent_dir, test_model_parent_dir, "test_model", False) == (os.path.join(test_wkfl_parent_dir,"test_model"), "") - - - def test_get_model_path_mdl_file_not_found(self): - with tempfile.TemporaryDirectory() as tempdir: - test_wkfl_parent_dir = os.path.join(tempdir, "test_wkfl_parent_dir") - os.mkdir(test_wkfl_parent_dir) - test_model_parent_dir = os.path.join(tempdir, "test_model_parent_dir") - os.mkdir(test_model_parent_dir) - assert get_model_path(test_wkfl_parent_dir, test_model_parent_dir, "test_model", False) == (os.path.join(test_wkfl_parent_dir,"test_model"), "The model file {0} could not be found. To edit the model or run the workflow you will need to update the path to the model or extract the model from the workflow.".format("test_model")) - - - #unit tests for method duplicate_wkfl_as_new - - def test_duplicate_wkfl_as_new_wkfl_file_not_found(self): - from handlers.util.stochss_errors import StochSSFileNotFoundError - with tempfile.TemporaryDirectory() as tempdir: - with self.assertRaises(StochSSFileNotFoundError): - duplicate_wkfl_as_new(os.path.join(tempdir,"nonexistent_wkfl"), False, "timestamp") - - def test_duplicate_wkfl_as_new_not_JSON_decodable(self): - from handlers.util.stochss_errors import FileNotJSONFormatError - with tempfile.TemporaryDirectory() as tempdir: - Path(os.path.join(tempdir,"info.json")).touch() - with self.assertRaises(FileNotJSONFormatError): - duplicate_wkfl_as_new(os.path.join(tempdir), False, "timestamp") - - - def test_duplicate_wkfl_as_new_only_model(self): - #from json import load - from unittest import mock - from handlers.util.run_model import GillesPy2Workflow - from handlers.util.stochss_errors import FileNotJSONFormatError - with tempfile.TemporaryDirectory() as tempdir: - test_dict={"type":"gillespy","source_model":"test_source_model"} - test_path = os.path.join(tempdir,"test_wkfl_dir") - os.mkdir(test_path) - Path(os.path.join(test_path,"info.json")).touch() - test_source_model_path = os.path.join(test_path,"test_source_model") - Path(test_source_model_path).touch() - with mock.patch("handlers.util.run_model.GillesPy2Workflow.get_settings") as mock_settings: - mock_settings.return_value = None - with mock.patch("json.load") as mock_json: - mock_json.return_value = test_dict - test_return = duplicate_wkfl_as_new(test_path, True, "timestamp") - assert test_return == {'message': 'A copy of the model in {0} has been created'.format(test_path),"mdlPath":os.path.join(tempdir,"test_source_model"),"File":"test_source_model"} - - def test_duplicate_wkfl_as_new_model_file_not_found(self): - #from json import load - from unittest import mock - from handlers.util.run_model import GillesPy2Workflow - from handlers.util.stochss_errors import FileNotJSONFormatError - with tempfile.TemporaryDirectory() as tempdir: - test_dict={"type":"gillespy","source_model":"test_source_model"} - test_path = os.path.join(tempdir,"test_wkfl_dir") - os.mkdir(test_path) - Path(os.path.join(test_path,"info.json")).touch() - test_source_model_path = os.path.join(test_path,"test_source_model") - Path(test_source_model_path).touch() - with mock.patch("handlers.util.run_model.GillesPy2Workflow.get_settings") as mock_settings: - mock_settings.return_value = None - with mock.patch("json.load") as mock_json: - mock_json.return_value = test_dict - test_return = duplicate_wkfl_as_new(test_path, False, "timestamp") - assert test_return == {'message': 'A new workflow has been created from {0}'.format(test_path), 'wkflPath': test_path+"timestamp.wkfl", 'mdlPath': os.path.join(tempdir,"test_source_model"), 'File': 'test_wkfl_dirtimestamp.wkfl', 'mdl_file': 'test_source_model', 'error': 'The model file test_source_model could not be found. To edit the model or run the workflow you will need to update the path to the model or extract the model from the workflow.'} - - def test_duplicate_wkfl_as_new_model_file_exists(self): - #from json import load - from unittest import mock - from handlers.util.run_model import GillesPy2Workflow - from handlers.util.stochss_errors import FileNotJSONFormatError - with tempfile.TemporaryDirectory() as tempdir: - test_dict={"type":"gillespy","source_model":"test_source_model"} - test_path = os.path.join(tempdir,"test_wkfl_dir") - os.mkdir(test_path) - Path(os.path.join(test_path,"info.json")).touch() - test_source_model_path = os.path.join(test_path,"test_source_model") - Path(test_source_model_path).touch() - Path(os.path.join(tempdir,"test_source_model")).touch() - with mock.patch("handlers.util.run_model.GillesPy2Workflow.get_settings") as mock_settings: - mock_settings.return_value = None - with mock.patch("json.load") as mock_json: - mock_json.return_value = test_dict - test_return = duplicate_wkfl_as_new(test_path, False, "timestamp") - assert test_return == {'message': 'A new workflow has been created from {0}'.format(test_path), 'wkflPath': test_path+"timestamp.wkfl", 'mdlPath': os.path.join(tempdir,"test_source_model"), 'File': 'test_wkfl_dirtimestamp.wkfl', 'mdl_file': 'test_source_model'} diff --git a/stochss/tests/test_generate_zip_file.py b/stochss/tests/test_generate_zip_file.py deleted file mode 100644 index 4806ad9173..0000000000 --- a/stochss/tests/test_generate_zip_file.py +++ /dev/null @@ -1,68 +0,0 @@ -import os -import unittest -import tempfile -import handlers.util.generate_zip_file as generate_zip_file -import handlers.util.stochss_errors as stochss_errors - -class TestGenerateZipFile(unittest.TestCase): - - #unit tests for method generate_zip_file - - def test_generate_zip_file(self): - test_file = "test_file.foo" - test_path = os.path.join("test_path", test_file) - test_dir = "test_dir" - test_target = "test_target" - with unittest.mock.patch("shutil.make_archive") as mock_make_archive: - generate_zip_file.generate_zip_file(test_path, test_dir, test_target) - correct_filepath = os.path.join(test_dir, "test_file") - mock_make_archive.assert_called_with(correct_filepath, 'zip', test_dir, test_target) - - #unit tests for method get_zip_file_data - - def test_get_zip_file_data(self): - with unittest.mock.patch("builtins.open", unittest.mock.mock_open(read_data="foo")): - assert generate_zip_file.get_zip_file_data("placeholder") == "foo" - - #unit tests for method get_results_csv_dir - - def test_get_results_csv_dir_not_found(self): - test_file = "results_csv" - test_path = "placeholder" - assert generate_zip_file.get_results_csv_dir(test_file, test_path) is None - - def test_get_results_csv_dir_is_found(self): - with tempfile.TemporaryDirectory() as tempdir: - test_dir = os.path.join(tempdir, "results_csv") - os.mkdir(test_dir) - assert generate_zip_file.get_results_csv_dir(test_dir, tempdir) == test_dir - - #unit tests for method download_zip - - def test_download_zip_file_invalid_path(self): - with self.assertRaises(stochss_errors.StochSSFileNotFoundError): - generate_zip_file.download_zip("placeholder_path", "placeholder_action") - - def test_download_zip_file_calls_generate_zip_file(self): - test_path = "test_dir/test_path.foo" - test_action = "generate" - with unittest.mock.patch("os.path.exists"): - with unittest.mock.patch("handlers.util.generate_zip_file.get_unique_file_name",\ - return_value="test_path"): - with unittest.mock.patch("handlers.util.generate_zip_file.generate_zip_file")\ - as mock_generate: - generate_zip_file.download_zip(test_path, test_action) - mock_generate.assert_called_with("t", os.path.join("/home/jovyan", "test_dir"), \ - os.path.join("/home/jovyan", test_path)) - - def test_download_zip_file_action_generate(self): - test_path = "test_dir/test_path.foo" - test_action = "generate" - test_resp = {"Message":"Successfully created t", "Path":"t",} - with unittest.mock.patch("os.path.exists"): - with unittest.mock.patch("handlers.util.generate_zip_file.get_unique_file_name",\ - return_value="test_path"): - with unittest.mock.patch("handlers.util.generate_zip_file.generate_zip_file"): - assert generate_zip_file.download_zip(test_path, test_action) == test_resp - - #download_zip action resultscsv is not covered pending refactor of user dir from /home/jovyan diff --git a/stochss/tests/test_ls.py b/stochss/tests/test_ls.py deleted file mode 100644 index e5d6f3b7e9..0000000000 --- a/stochss/tests/test_ls.py +++ /dev/null @@ -1,228 +0,0 @@ -"""Unit tests for handlers.util.ls.py""" -import unittest -import os -import tempfile -from pathlib import Path - -import handlers.util.ls as ls -from handlers.util.stochss_errors import StochSSFileNotFoundError - -class TestLS(unittest.TestCase): - """Unit test container for handlers.util.ls.py""" - - #unit tests for method get_file_system_data - - def test_get_file_system_data_dir_not_found(self): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "nonexistent_dir") - with self.assertRaises(StochSSFileNotFoundError): - ls.get_file_system_data(test_path, tempdir) - - @classmethod - def test_get_file_system_data_no_children(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "empty_dir") - os.mkdir(test_path) - children = ls.get_file_system_data(test_path, tempdir) - assert len(children) == 0 - - @classmethod - def test_get_file_system_data_child_is_wkfl(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_file_path = os.path.join(test_path, "test_file.wkfl") - Path(test_file_path).touch() - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with \ - (text="test_file.wkfl", f_type="workflow", p_path=tempdir) - - @classmethod - def test_get_file_system_data_child_is_mdl(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_file_path = os.path.join(test_path, "test_file.mdl") - Path(test_file_path).touch() - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with\ - (text="test_file.mdl", f_type="nonspatial", p_path=tempdir) - - @classmethod - def test_get_file_system_data_child_is_smdl(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_file_path = os.path.join(test_path, "test_file.smdl") - Path(test_file_path).touch() - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with\ - (text="test_file.smdl", f_type="spatial", p_path=tempdir) - - @classmethod - def test_get_file_system_data_child_is_mesh(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_file_path = os.path.join(test_path, "test_file.mesh") - Path(test_file_path).touch() - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with\ - (text="test_file.mesh", f_type="mesh", p_path=tempdir) - - @classmethod - def test_get_file_system_data_child_is_ipynb(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_file_path = os.path.join(test_path, "test_file.ipynb") - Path(test_file_path).touch() - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with\ - (text="test_file.ipynb", f_type="notebook", p_path=tempdir) - - @classmethod - def test_get_file_system_data_child_is_sbml(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_file_path = os.path.join(test_path, "test_file.sbml") - Path(test_file_path).touch() - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with\ - (text="test_file.sbml", f_type="sbml-model", p_path=tempdir) - - @classmethod - def test_get_file_system_data_child_is_dir(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_dir_path = os.path.join(test_path, "test_dir") - os.mkdir(test_dir_path) - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with\ - (text="test_dir", f_type="folder", p_path=tempdir) - - @classmethod - def test_get_file_system_data_child_is_other(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_file_path = os.path.join(test_path, "test_file.foo") - Path(test_file_path).touch() - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with\ - (text="test_file.foo", f_type="other", p_path=tempdir) - - @classmethod - def test_get_file_system_data_child_is_exp(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_dir_path = os.path.join(test_path, "test_dir.wkgp") - os.mkdir(test_dir_path) - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with\ - (text="test_dir.wkgp", f_type="workflow-group", p_path=tempdir) - - @classmethod - def test_get_file_system_data_child_is_proj(cls): - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "parent_dir") - os.mkdir(test_path) - test_dir_path = os.path.join(test_path, "test_dir.proj") - os.mkdir(test_dir_path) - with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child: - ls.get_file_system_data(test_path, tempdir) - mock_build_child.assert_called_once_with\ - (text="test_dir.proj", f_type="project", p_path=tempdir) - - #unit tests for method build_child - - @classmethod - def test_build_child_top_level(cls): - with tempfile.TemporaryDirectory(): - test_p_path = "none" - test_text = "test_text" - test_f_type = "test_f_type" - assert ls.build_child(text=test_text, f_type=test_f_type, p_path=test_p_path) ==\ - {"text" : "test_text", "type" : "test_f_type", \ - "_path" : "test_text", "children" : False} - - @classmethod - def test_build_child_sub_level(cls): - with tempfile.TemporaryDirectory(): - test_p_path = "test_p_path" - test_text = "test_text" - test_f_type = "test_f_type" - assert ls.build_child(text=test_text, f_type=test_f_type, p_path=test_p_path) == \ - {"text" : "test_text", "type" : "test_f_type", \ - "_path" : os.path.join(test_p_path, test_text), "children" : False} - - @classmethod - def test_build_child_wkfl_calls_get_status(cls): - with tempfile.TemporaryDirectory(): - test_p_path = "test_p_path" - test_text = "test_text" - test_f_type = "workflow" - with unittest.mock.patch("handlers.util.ls.get_status") as mock_get_status: - ls.build_child(text=test_text, p_path=test_p_path, f_type=test_f_type) - mock_get_status.assert_called() - - #unit tests for method build_root - - @classmethod - def test_build_root(cls): - test_children = "test_children" - assert ls.build_root(test_children) ==\ - [{"text":"/", "type":"root", "_path":"/", \ - "children":"test_children", "state":{"opened":True}}] - - #unit tests for method check_extension - - @classmethod - def test_check_extension_true(cls): - test_str = "test" - test_target = "target" - test_name = test_str + test_target - assert ls.check_extension(test_name, test_target) - - @classmethod - def test_check_extension_false(cls): - test_str = "test" - test_target = "target" - test_name = test_str - assert not ls.check_extension(test_name, test_target) - - #unit tests for method list_files - - @classmethod - def test_ls_p_path_none(cls): - test_p_path = "none" - with unittest.mock.patch("handlers.util.ls.build_root") as mock_build_root: - with unittest.mock.patch("handlers.util.ls.get_file_system_data", \ - return_value="test_return") as mock_get_file_system_data: - with unittest.mock.patch("json.dumps"): - ls.list_files(p_path=test_p_path) - mock_get_file_system_data.assert_called() - mock_build_root.assert_called_with("test_return") - - @classmethod - def test_ls_p_path_not_none(cls): - test_p_path = "test_p_path" - test_full_path = os.path.join("/home/jovyan", test_p_path) - with unittest.mock.patch("handlers.util.ls.build_root"): - with unittest.mock.patch("handlers.util.ls.get_file_system_data", \ - return_value="test_return") as mock_get_file_system_data: - with unittest.mock.patch("json.dumps"): - ls.list_files(p_path=test_p_path) - mock_get_file_system_data.assert_called_with(test_full_path, test_p_path) diff --git a/stochss/tests/test_rename.py b/stochss/tests/test_rename.py deleted file mode 100644 index 7940647080..0000000000 --- a/stochss/tests/test_rename.py +++ /dev/null @@ -1,130 +0,0 @@ -import unittest, os, tempfile -from pathlib import Path -from handlers.util.rename import * - -class TestRename(unittest.TestCase): - - #unit tests for method get_unique_file_name - - def test_get_unique_file_name_target_does_not_exist(self): - with tempfile.TemporaryDirectory() as tempdir: - gufn_return_filepath = os.path.join(tempdir,"nonexistent_file") - gufn_return_tuple = (gufn_return_filepath, False) - assert get_unique_file_name("nonexistent_file", tempdir) == (gufn_return_tuple) - - def test_get_unique_file_name_target_exists(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filepath = os.path.join(tempdir,"existent_file") - Path(test_filepath).touch() - gufn_return_filepath = os.path.join(tempdir,"existent_file(1)") - gufn_return_tuple = (gufn_return_filepath, True) - assert get_unique_file_name("existent_file", tempdir) == gufn_return_tuple - - def test_get_unique_file_name_numbered_target_exists(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filepath = os.path.join(tempdir,"existent_file(1)") - Path(test_filepath).touch() - gufn_return_filepath = os.path.join(tempdir,"existent_file(2)") - gufn_return_tuple = (gufn_return_filepath, True) - assert get_unique_file_name("existent_file(1)", tempdir) == gufn_return_tuple - - def test_get_unique_file_name_with_extension_target_does_not_exist(self): - with tempfile.TemporaryDirectory() as tempdir: - gufn_return_filepath = os.path.join(tempdir,"nonexistent_file.foo") - gufn_return_tuple = (gufn_return_filepath, False) - assert get_unique_file_name("nonexistent_file.foo", tempdir) == (gufn_return_tuple) - - def test_get_unique_file_name_with_extension_target_exists(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filename = "existent_file.foo" - test_filepath = os.path.join(tempdir,test_filename) - Path(test_filepath).touch() - gufn_return_filepath = os.path.join(tempdir,"existent_file(1).foo") - gufn_return_tuple = (gufn_return_filepath, True) - assert get_unique_file_name(test_filename, tempdir) == gufn_return_tuple - - - def test_get_unique_file_name_iterated(self): - with tempfile.TemporaryDirectory() as tempdir: - test_filename = "existent_file" - test_filepath = os.path.join(tempdir, test_filename) - Path(test_filepath).touch() - for i in range(3): - test_filename, placeholder = get_unique_file_name(test_filename, tempdir) - Path(test_filename).touch() - test_filename = test_filename.split('/').pop() - assert len(os.listdir(tempdir)) == 4 - - def test_get_unique_file_name_invalid_path(self): - with tempfile.TemporaryDirectory() as tempdir: - test_dirpath = os.path.join(tempdir,"invalid_directory") - with self.assertRaises(FileNotFoundError): - get_unique_file_name("nonexistent_file", test_dirpath) - - #unit tests for method rename - - def test_rename_file(self): - with tempfile.TemporaryDirectory() as tempdir: - test_file = "test_file" - test_path = os.path.join(tempdir,test_file) - Path(test_path).touch() - rename(test_path, "test_file2") - test_new_path = os.path.join(tempdir, "test_file2") - assert os.path.isfile(test_new_path) - - def test_rename_directory(self): - with tempfile.TemporaryDirectory() as tempdir: - test_dir = "test_dir" - test_path = os.path.join(tempdir, test_dir) - os.mkdir(test_path) - rename(test_path, "test_dir2") - test_new_path = os.path.join(tempdir, "test_dir2") - assert os.path.isdir(test_new_path) - - def test_rename_permission_error(self): - from handlers.util.stochss_errors import StochSSPermissionsError - from unittest import mock - with tempfile.TemporaryDirectory() as tempdir: - test_dir = "test_dir" - test_file = "test_file" - test_dir_path = os.path.join(tempdir,test_dir) - os.mkdir(test_dir_path) - test_path = os.path.join(test_dir_path,test_file) - Path(test_path).touch() - with mock.patch("shutil.move", side_effect=StochSSPermissionsError('test_error')) as mock_shutil: - with self.assertRaises(StochSSPermissionsError): - rename(test_path, "test_file2") - - def test_rename_file_not_found_error(self): - from handlers.util.stochss_errors import StochSSFileNotFoundError - with tempfile.TemporaryDirectory() as tempdir: - test_file = "test_file" - test_path = os.path.join(tempdir,test_file) - with self.assertRaises(StochSSFileNotFoundError): - rename(test_path, "test_file2") - - def test_rename_target_exists(self): - with tempfile.TemporaryDirectory() as tempdir: - test_file = "test_file" - test_path = os.path.join(tempdir, test_file) - Path(test_path).touch() - test_file2 = "test_file2" - test_path2 = os.path.join(tempdir, test_file2) - Path(test_path2).touch() - resp = rename(test_path, "test_file2") - assert resp["changed"] == True - - def test_rename_running_wkfl(self): - from unittest import mock - with tempfile.TemporaryDirectory() as tempdir: - with mock.patch("json.dump") as mock_dump: - with mock.patch("json.load") as mock_json: - with mock.patch('builtins.open', mock.mock_open(read_data="foo")) as m: - test_file = "test_file.wkfl" - test_path = os.path.join(tempdir, test_file) - target_path = os.path.join(tempdir, "test_file2") - os.mkdir(test_path) - os.mkdir(target_path) - Path(os.path.join(target_path,"RUNNING")).touch() - rename(test_path, "test_file2") - m.assert_called_with(os.path.join(target_path, "info.json"), 'r+') diff --git a/stochss/tests/test_upload_file.py b/stochss/tests/test_upload_file.py deleted file mode 100644 index 404c863166..0000000000 --- a/stochss/tests/test_upload_file.py +++ /dev/null @@ -1,115 +0,0 @@ -import os -import unittest -from unittest import mock -import tempfile -from pathlib import Path - -from handlers.util.upload_file import * - -class TestUploadFile(unittest.TestCase): - - #unit tests for method validate_model - - def test_validate_model_json_decode_error(self): - with tempfile.TemporaryDirectory() as tempdir: - test_file = "non_json_file" - test_path = os.path.join(tempdir, test_file) - Path(test_path).touch() - assert validate_model(test_path, test_file) == \ - (False, False, "The file {0} is not in JSON format.".format(test_file)) - - def test_validate_model_valid_keys(self): - test_keys = ("is_spatial", "defaultID", "defaultMode", "modelSettings", - "simulationSettings", "parameterSweepSettings", "species", - "parameters", "reactions", "eventsCollection", "rules", - "functionDefinitions", "meshSettings", "initialConditions") - class TestKeychain(): - def keys(self): - return test_keys - - complete_keychain = TestKeychain() - with mock.patch("json.loads", return_value=complete_keychain): - assert validate_model("", "") == (True, True, "") - - def test_validate_model_missing_keys(self): - test_keys = ("species","parameters","reactions","eventsCollection", - "rules","functionDefinitions") - - class TestKeychain(): - def keys(self): - return () - - complete_keychain = TestKeychain() - with mock.patch("json.loads", return_value=complete_keychain): - assert validate_model("", "") == (False, True, \ - "The following keys are missing from {0}: {1}".format("", ", ".join(test_keys))) - - #unit tests for method upload_model_file - - def test_upload_model_file_is_valid(self): - test_valid = True - test_json = False - test_error = "" - predicted_name = ".".join(["some_name", "mdl"]) - with mock.patch("handlers.util.upload_file.get_unique_file_name",\ - return_value=("some_path", False)): - with mock.patch("handlers.util.upload_file.validate_model",\ - return_value=(test_valid, test_json, test_error)): - with mock.patch("builtins.open", mock.mock_open(read_data="foo")): - assert upload_model_file("some_path", "some_file_name", "some_name", None)\ - ['message'] == "{0} was successfully uploaded to {1}".format(\ - predicted_name, "some_path") - - def test_upload_model_file_not_valid(self): - test_valid = False - test_json = False - test_error = "" - predicted_name = ".".join(["some_name", "json"]) - with mock.patch("handlers.util.upload_file.get_unique_file_name",\ - return_value=("some_path", False)): - with mock.patch("handlers.util.upload_file.validate_model",\ - return_value=(test_valid, test_json, test_error)): - with mock.patch("builtins.open", mock.mock_open(read_data="foo")): - assert upload_model_file("some_path",\ - "some_file_name", "some_name", None)['message'] ==\ - "{0} could not be validated as a Model file and was uploaded as {1} to {2}"\ - .format("some_file_name", predicted_name, "some_path") - - def test_upload_model_file_error(self): - test_valid = False - test_json = False - test_error = "test_error" - with mock.patch("handlers.util.upload_file.get_unique_file_name",\ - return_value=("some_path", False)): - with mock.patch("handlers.util.upload_file.validate_model", return_value=\ - (test_valid, test_json, test_error)): - with mock.patch("builtins.open", mock.mock_open(read_data="foo")): - assert upload_model_file("some_path", "some_file_name", "some_name", None)\ - ['errors'] == ['test_error'] - - def test_upload_model_file_name_changed(self): - test_valid = False - test_json = False - test_error = "" - predicted_name = "some_file" - with mock.patch("handlers.util.upload_file.get_unique_file_name",\ - return_value=(os.path.join("some_parent", "some_file"), True)): - with mock.patch("handlers.util.upload_file.validate_model", \ - return_value=(test_valid, test_json, test_error)): - with mock.patch("builtins.open", mock.mock_open(read_data="foo")): - assert upload_model_file("some_path", "some_file_name", "some_name", None)['message'] ==\ - "{0} could not be validated as a Model file and was uploaded as {1} to {2}"\ - .format("some_file_name", predicted_name, "some_path") - - def test_upload_model_file_json(self): - test_valid = True - test_json = True - test_error = "" - with mock.patch("handlers.util.upload_file.get_unique_file_name",\ - return_value=("some_path", False)): - with mock.patch("handlers.util.upload_file.validate_model", return_value=\ - (test_valid, test_json, test_error)): - with mock.patch("builtins.open", mock.mock_open(read_data="foo")): - with mock.patch("json.loads", return_value="mock_return") as mock_json_loads: - upload_model_file("some_path", "some_file_name", "some_name", None) - mock_json_loads.assert_called() diff --git a/stochss/tests/test_workflow_status.py b/stochss/tests/test_workflow_status.py deleted file mode 100644 index 36e890c31e..0000000000 --- a/stochss/tests/test_workflow_status.py +++ /dev/null @@ -1,52 +0,0 @@ -import os -import unittest -import tempfile -from pathlib import Path - -from handlers.util.workflow_status import get_status - -class TestWorkflow_Status(unittest.TestCase): - - #unit tests for method get_status - - def test_get_status_complete(self): - from unittest import mock - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "test_dir") - os.mkdir(test_path) - test_status = "COMPLETE" - test_file = os.path.join(test_path, test_status) - Path(test_file).touch() - with mock.patch("os.path.join",return_value = test_path) as mock_join: - assert get_status("") == "complete" - - - def test_get_status_error(self): - from unittest import mock - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "test_dir") - os.mkdir(test_path) - test_status = "ERROR" - test_file = os.path.join(test_path, test_status) - Path(test_file).touch() - with mock.patch("os.path.join",return_value = test_path) as mock_join: - assert get_status("") == "error" - - def test_get_status_running(self): - from unittest import mock - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "test_dir") - os.mkdir(test_path) - test_status = "RUNNING" - test_file = os.path.join(test_path, test_status) - Path(test_file).touch() - with mock.patch("os.path.join",return_value = test_path) as mock_join: - assert get_status("") == "running" - - def test_get_status_ready(self): - from unittest import mock - with tempfile.TemporaryDirectory() as tempdir: - test_path = os.path.join(tempdir, "test_dir") - os.mkdir(test_path) - with mock.patch("os.path.join",return_value = test_path) as mock_join: - assert get_status("") == "ready" From accaf186fca7db4d3ecfb927d143ee8ff0b3b10e Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 29 Jun 2021 08:59:25 -0400 Subject: [PATCH 53/63] Fixed test. --- stochss/tests/test_stochss_base.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/stochss/tests/test_stochss_base.py b/stochss/tests/test_stochss_base.py index 17cea9c668..d4f0bbee7e 100644 --- a/stochss/tests/test_stochss_base.py +++ b/stochss/tests/test_stochss_base.py @@ -54,8 +54,8 @@ def setUp(self): def tearDown(self): ''' Cleanup the temp directory after each test. ''' self.tempdir.cleanup() - if os.path.exists(os.path.join(self.user_dir, "trash")): - shutil.rmtree(os.path.join(self.user_dir, "trash")) + if StochSSBase.user_dir != os.path.expanduser("~"): + StochSSBase.user_dir = os.path.expanduser("~") ################################################################################################ # Unit tests for the StochSS base class check_project_format function. @@ -142,8 +142,10 @@ def test_get_new_path(self): def test_get_new_path__no_trash_folder(self): ''' Check if the trash directory is created. ''' test_dst_path = os.path.join("trash", "test_file") + StochSSBase.user_dir = self.test_folderpath StochSSBase.get_new_path(dst_path=test_dst_path) - self.assertTrue(os.path.exists(os.path.join(self.user_dir, "trash"))) + self.assertTrue(os.path.exists(os.path.join(self.test_folderpath, "trash"))) + def test_get_new_path__remove_trash_datetime_stamp(self): From e9c2610e3b881244d4fd9d8e1e5c5c50962e9568 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 29 Jun 2021 09:52:32 -0400 Subject: [PATCH 54/63] Refactored the timestep size slider to use log scale values from 1e-5 to 1. --- client/templates/includes/timespanSettings.pug | 16 ++++++++-------- client/views/timespan-settings.js | 6 ++++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/client/templates/includes/timespanSettings.pug b/client/templates/includes/timespanSettings.pug index 34401ab4e3..e49fe14c96 100644 --- a/client/templates/includes/timespanSettings.pug +++ b/client/templates/includes/timespanSettings.pug @@ -59,9 +59,9 @@ div#preview-settings.card div.row - div.col-sm-3 + div.col-sm-1 - span.inline 1e-5 + span.inline 1 div.col-sm-8 @@ -69,16 +69,16 @@ div#preview-settings.card div.inline(data-hook="timestep-size-value") - div.col-sm-1.d-flex.justify-content-end + div.col-sm-3.d-flex.justify-content-end - span.inline 1 + span.inline 1e-5 input.custom-range( type="range" - min="1e-5" - max="1" - step="1e-5" - value=this.model.timestepSize + min="0" + max="5" + step="1" + value=this.tssValue data-hook="timestep-size-slider" ) diff --git a/client/views/timespan-settings.js b/client/views/timespan-settings.js index fa5f87cb4b..47ae7d6446 100644 --- a/client/views/timespan-settings.js +++ b/client/views/timespan-settings.js @@ -40,6 +40,8 @@ module.exports = View.extend({ View.prototype.initialize.apply(this, arguments); this.readOnly = attrs.readOnly ? attrs.readOnly : false; this.tooltips = Tooltips.modelSettings + let tssValues = {1e-5: 5, 1e-4: 4, 1e-3: 3, 1e-2: 2, 1e-1: 1, 1: 0} + this.tssValue = tssValues[this.model.timestepSize] }, render: function () { View.prototype.render.apply(this, arguments); @@ -64,7 +66,7 @@ module.exports = View.extend({ app.changeCollapseButtonText(this, e); }, setTimestepSize: function (e) { - this.model.timestepSize = Number(e.target.value); + this.model.timestepSize = Number("1e-" + e.target.value); $(this.queryByHook("view-timestep-size")).html(this.model.timestepSize); }, updateViewer: function (e) { @@ -72,7 +74,7 @@ module.exports = View.extend({ $(this.queryByHook("view-time-step")).html(this.model.timeStep); }, viewTimestepValue: function (e) { - let value = e.target.value; + let value = Number("1e-" + e.target.value); $(this.queryByHook("timestep-size-value")).html(value); }, subviews: { From bc8c80ccad7074960d795d9b4331a12b048cc1a0 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 29 Jun 2021 09:59:05 -0400 Subject: [PATCH 55/63] Refactored the load and model convert to spatial function to use ie-5 for the timestep size. --- stochss/handlers/util/stochss_model.py | 2 +- stochss/handlers/util/stochss_spatial_model.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stochss/handlers/util/stochss_model.py b/stochss/handlers/util/stochss_model.py index 6b617b2385..95d3be5e28 100644 --- a/stochss/handlers/util/stochss_model.py +++ b/stochss/handlers/util/stochss_model.py @@ -381,7 +381,7 @@ def convert_to_spatial(self): model = self.load() model['is_spatial'] = True if "timestepSize" not in self.model['modelSettings'].keys(): - self.model['modelSettings']['timestepSize'] = self.model['modelSettings']['timeStep'] + self.model['modelSettings']['timestepSize'] = 1e-5 if "domain" not in model.keys(): model['domain'] = self.get_model_template()['domain'] for species in model['species']: diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 99f607d217..13602e7c28 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -572,7 +572,7 @@ def load(self): if not self.model['defaultMode']: self.model['defaultMode'] = "discrete" if "timestepSize" not in self.model['modelSettings'].keys(): - self.model['modelSettings']['timestepSize'] = self.model['modelSettings']['timeStep'] + self.model['modelSettings']['timestepSize'] = 1e-5 if "domain" not in self.model.keys() or len(self.model['domain'].keys()) < 6: self.model['domain'] = self.get_model_template()['domain'] elif "static" not in self.model['domain'].keys(): From 460dc626fc1dc5739a394410b3fd13a8b2a04d13 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 29 Jun 2021 12:50:53 -0400 Subject: [PATCH 56/63] Updated copyright to 2021. --- COPYRIGHT | 2 +- client/app.js | 2 +- client/config.js | 2 +- client/graphics.js | 2 +- client/modals.js | 2 +- client/models/boundary-condition.js | 2 +- client/models/boundary-conditions.js | 2 +- client/models/creator.js | 2 +- client/models/creators.js | 2 +- client/models/domain-type.js | 2 +- client/models/domain-types.js | 2 +- client/models/domain.js | 2 +- client/models/event-assignment.js | 2 +- client/models/event-assignments.js | 2 +- client/models/event.js | 2 +- client/models/events.js | 2 +- client/models/function-definition.js | 2 +- client/models/function-definitions.js | 2 +- client/models/initial-condition.js | 2 +- client/models/initial-conditions.js | 2 +- client/models/job.js | 2 +- client/models/jobs.js | 2 +- client/models/me.js | 2 +- client/models/metadata.js | 2 +- client/models/model.js | 2 +- client/models/parameter-sweep-settings.js | 2 +- client/models/parameter.js | 2 +- client/models/parameters.js | 2 +- client/models/particle.js | 2 +- client/models/particles.js | 2 +- client/models/project.js | 2 +- client/models/reaction.js | 2 +- client/models/reactions.js | 2 +- client/models/results-settings.js | 2 +- client/models/rule.js | 2 +- client/models/rules.js | 2 +- client/models/settings.js | 2 +- client/models/simulation-settings.js | 2 +- client/models/specie.js | 2 +- client/models/species.js | 2 +- client/models/stoich-specie.js | 2 +- client/models/stoich-species.js | 2 +- client/models/sweep-parameter.js | 2 +- client/models/sweep-parameters.js | 2 +- client/models/timespan-settings.js | 2 +- client/models/workflow-group.js | 2 +- client/models/workflow-groups.js | 2 +- client/models/workflow.js | 2 +- client/models/workflows.js | 2 +- client/page-help.js | 2 +- client/pages/base.js | 2 +- client/pages/domain-editor.js | 2 +- client/pages/file-browser.js | 2 +- client/pages/home.js | 2 +- client/pages/loading-page.js | 2 +- client/pages/model-editor.js | 2 +- client/pages/multiple-plots.js | 2 +- client/pages/page.js | 2 +- client/pages/project-browser.js | 2 +- client/pages/project-manager.js | 2 +- client/pages/quickstart.js | 2 +- client/pages/users-home.js | 2 +- client/pages/workflow-manager.js | 2 +- client/pages/workflow-selection.js | 2 +- client/reaction-types.js | 2 +- client/styles/styles.css | 2 +- client/tooltips.js | 2 +- client/views/archive-listing.js | 2 +- client/views/boundary-condition-view.js | 2 +- client/views/boundary-conditions-editor.js | 2 +- client/views/component-types.js | 2 +- client/views/creator-listing.js | 2 +- client/views/domain-viewer.js | 2 +- client/views/edit-3D-domain.js | 2 +- client/views/edit-custom-stoich-specie.js | 2 +- client/views/edit-domain-type.js | 2 +- client/views/edit-event-assignment.js | 2 +- client/views/edit-function-definition.js | 2 +- client/views/edit-initial-condition.js | 2 +- client/views/edit-parameter.js | 2 +- client/views/edit-particle.js | 2 +- client/views/edit-project.js | 2 +- client/views/edit-rule.js | 2 +- client/views/edit-species.js | 2 +- client/views/edit-stoich-specie.js | 2 +- client/views/event-assignments-editor.js | 2 +- client/views/event-details.js | 2 +- client/views/event-listings.js | 2 +- client/views/events-editor.js | 2 +- client/views/file-browser-view.js | 2 +- client/views/initial-conditions-editor.js | 2 +- client/views/initial-conditions-viewer.js | 2 +- client/views/input.js | 2 +- client/views/job-listing.js | 2 +- client/views/main.js | 2 +- client/views/mesh-editor.js | 2 +- client/views/meta-data.js | 2 +- client/views/model-listing.js | 2 +- client/views/model-state-buttons.js | 2 +- client/views/model-viewer.js | 2 +- client/views/parameter-settings.js | 2 +- client/views/parameters-editor.js | 2 +- client/views/quickview-domain-types.js | 2 +- client/views/reactant-product.js | 2 +- client/views/reaction-details.js | 2 +- client/views/reaction-listing.js | 2 +- client/views/reaction-types.js | 2 +- client/views/reactions-editor.js | 2 +- client/views/rules-editor.js | 2 +- client/views/sbml-component-editor.js | 2 +- client/views/settings-viewer.js | 2 +- client/views/settings.js | 2 +- client/views/simulation-settings.js | 2 +- client/views/species-editor.js | 2 +- client/views/sweep-parameter-range.js | 2 +- client/views/sweep-parameter.js | 2 +- client/views/tests.js | 2 +- client/views/timespan-settings.js | 2 +- client/views/view-initial-condition.js | 2 +- client/views/view-particle.js | 2 +- client/views/view-sweep-parameter.js | 2 +- client/views/workflow-group-listing.js | 2 +- client/views/workflow-info.js | 2 +- client/views/workflow-listing.js | 2 +- client/views/workflow-results.js | 2 +- client/views/workflow-status.js | 2 +- stochss/handlers/__init__.py | 2 +- stochss/handlers/file_browser.py | 2 +- stochss/handlers/log.py | 2 +- stochss/handlers/models.py | 2 +- stochss/handlers/pages.py | 2 +- stochss/handlers/project.py | 2 +- stochss/handlers/util/__init__.py | 2 +- stochss/handlers/util/ensemble_simulation.py | 2 +- stochss/handlers/util/parameter_scan.py | 2 +- stochss/handlers/util/parameter_sweep.py | 2 +- stochss/handlers/util/parameter_sweep_1d.py | 2 +- stochss/handlers/util/parameter_sweep_2d.py | 2 +- stochss/handlers/util/scripts/run_preview.py | 2 +- stochss/handlers/util/scripts/start_job.py | 2 +- stochss/handlers/util/scripts/upload_remote_file.py | 2 +- stochss/handlers/util/spatial_simulation.py | 2 +- stochss/handlers/util/stochss_base.py | 2 +- stochss/handlers/util/stochss_errors.py | 2 +- stochss/handlers/util/stochss_file.py | 2 +- stochss/handlers/util/stochss_folder.py | 2 +- stochss/handlers/util/stochss_job.py | 2 +- stochss/handlers/util/stochss_model.py | 2 +- stochss/handlers/util/stochss_notebook.py | 2 +- stochss/handlers/util/stochss_project.py | 2 +- stochss/handlers/util/stochss_sbml.py | 2 +- stochss/handlers/util/stochss_spatial_model.py | 2 +- stochss/handlers/util/stochss_workflow.py | 2 +- stochss/handlers/workflows.py | 2 +- stochss/tests/run_tests.py | 2 +- 155 files changed, 155 insertions(+), 155 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 99000953fe..7d089c27ab 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,5 +1,5 @@ StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/app.js b/client/app.js index 9aac1d1023..e809e61721 100644 --- a/client/app.js +++ b/client/app.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/config.js b/client/config.js index 8fb86111be..824477f41d 100644 --- a/client/config.js +++ b/client/config.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/graphics.js b/client/graphics.js index 3f0299ce16..33042874c4 100644 --- a/client/graphics.js +++ b/client/graphics.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/modals.js b/client/modals.js index 54b3aaadf2..93a5e044d9 100644 --- a/client/modals.js +++ b/client/modals.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/boundary-condition.js b/client/models/boundary-condition.js index 405d84e800..d8e893bfec 100644 --- a/client/models/boundary-condition.js +++ b/client/models/boundary-condition.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/boundary-conditions.js b/client/models/boundary-conditions.js index c156d8045f..667af7cd85 100644 --- a/client/models/boundary-conditions.js +++ b/client/models/boundary-conditions.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/creator.js b/client/models/creator.js index ee9d3be24d..d39dd3cf98 100644 --- a/client/models/creator.js +++ b/client/models/creator.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/creators.js b/client/models/creators.js index df67172530..7b23fb84e7 100644 --- a/client/models/creators.js +++ b/client/models/creators.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/domain-type.js b/client/models/domain-type.js index 2362909609..9c88aa284f 100644 --- a/client/models/domain-type.js +++ b/client/models/domain-type.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/domain-types.js b/client/models/domain-types.js index 0b4ad9e1bf..693625ae8a 100644 --- a/client/models/domain-types.js +++ b/client/models/domain-types.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/domain.js b/client/models/domain.js index 73c34cbe6a..725212644a 100644 --- a/client/models/domain.js +++ b/client/models/domain.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/event-assignment.js b/client/models/event-assignment.js index 7e621a7caf..b1452025b4 100644 --- a/client/models/event-assignment.js +++ b/client/models/event-assignment.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/event-assignments.js b/client/models/event-assignments.js index 62733ea5bf..21ed3349f1 100644 --- a/client/models/event-assignments.js +++ b/client/models/event-assignments.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/event.js b/client/models/event.js index a20050481e..6f30f26b6c 100644 --- a/client/models/event.js +++ b/client/models/event.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/events.js b/client/models/events.js index 25729358f1..904df78a1d 100644 --- a/client/models/events.js +++ b/client/models/events.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/function-definition.js b/client/models/function-definition.js index eef7d7caae..1ebd991677 100644 --- a/client/models/function-definition.js +++ b/client/models/function-definition.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/function-definitions.js b/client/models/function-definitions.js index 4dab2ad8bc..824c2634ad 100644 --- a/client/models/function-definitions.js +++ b/client/models/function-definitions.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/initial-condition.js b/client/models/initial-condition.js index 8f4801b10f..814c33048a 100644 --- a/client/models/initial-condition.js +++ b/client/models/initial-condition.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/initial-conditions.js b/client/models/initial-conditions.js index c6984f1a16..cd4fdd0604 100644 --- a/client/models/initial-conditions.js +++ b/client/models/initial-conditions.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/job.js b/client/models/job.js index d519da4f3c..33e0a37883 100644 --- a/client/models/job.js +++ b/client/models/job.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/jobs.js b/client/models/jobs.js index 01ecde1afb..9699ee7a10 100644 --- a/client/models/jobs.js +++ b/client/models/jobs.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/me.js b/client/models/me.js index 5fdbe15e6c..4bc370dc9d 100644 --- a/client/models/me.js +++ b/client/models/me.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/metadata.js b/client/models/metadata.js index 2a80da336c..873e4c9e96 100644 --- a/client/models/metadata.js +++ b/client/models/metadata.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/model.js b/client/models/model.js index 8802902eb4..b09b3a6540 100644 --- a/client/models/model.js +++ b/client/models/model.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/parameter-sweep-settings.js b/client/models/parameter-sweep-settings.js index 1b746a5b2e..e1a09f5b93 100644 --- a/client/models/parameter-sweep-settings.js +++ b/client/models/parameter-sweep-settings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/parameter.js b/client/models/parameter.js index e8d0c0c5fe..1d460ecfa5 100644 --- a/client/models/parameter.js +++ b/client/models/parameter.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/parameters.js b/client/models/parameters.js index 5091fa2a45..76848f5a00 100644 --- a/client/models/parameters.js +++ b/client/models/parameters.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/particle.js b/client/models/particle.js index 5cb54d5e06..948633c14c 100644 --- a/client/models/particle.js +++ b/client/models/particle.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/particles.js b/client/models/particles.js index ec599b1024..388f50fe24 100644 --- a/client/models/particles.js +++ b/client/models/particles.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/project.js b/client/models/project.js index 404e84bc9f..6a168b6a12 100644 --- a/client/models/project.js +++ b/client/models/project.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/reaction.js b/client/models/reaction.js index 8802ef112d..94bfff06c4 100644 --- a/client/models/reaction.js +++ b/client/models/reaction.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/reactions.js b/client/models/reactions.js index e225df46fb..10b26f5d1b 100644 --- a/client/models/reactions.js +++ b/client/models/reactions.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/results-settings.js b/client/models/results-settings.js index ffae215597..e7d13203fe 100644 --- a/client/models/results-settings.js +++ b/client/models/results-settings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/rule.js b/client/models/rule.js index 9113bd7ea5..afe82692b8 100644 --- a/client/models/rule.js +++ b/client/models/rule.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/rules.js b/client/models/rules.js index cc6c9afac8..955c85a9fb 100644 --- a/client/models/rules.js +++ b/client/models/rules.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/settings.js b/client/models/settings.js index fe6911dcaa..9817082956 100644 --- a/client/models/settings.js +++ b/client/models/settings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/simulation-settings.js b/client/models/simulation-settings.js index a67ede077b..af8c55a560 100644 --- a/client/models/simulation-settings.js +++ b/client/models/simulation-settings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/specie.js b/client/models/specie.js index d2c4f99d4b..8f1f8375b5 100644 --- a/client/models/specie.js +++ b/client/models/specie.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/species.js b/client/models/species.js index b9ee6dc508..8cde7ff383 100644 --- a/client/models/species.js +++ b/client/models/species.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/stoich-specie.js b/client/models/stoich-specie.js index a11311f9f5..6e109c8dc4 100644 --- a/client/models/stoich-specie.js +++ b/client/models/stoich-specie.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/stoich-species.js b/client/models/stoich-species.js index 53d398197f..0bfdbb44f9 100644 --- a/client/models/stoich-species.js +++ b/client/models/stoich-species.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/sweep-parameter.js b/client/models/sweep-parameter.js index e9efdf0a38..288c68c832 100644 --- a/client/models/sweep-parameter.js +++ b/client/models/sweep-parameter.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/sweep-parameters.js b/client/models/sweep-parameters.js index eb60b7f7c0..c421f54339 100644 --- a/client/models/sweep-parameters.js +++ b/client/models/sweep-parameters.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/timespan-settings.js b/client/models/timespan-settings.js index b467a2b125..0978e7eb46 100644 --- a/client/models/timespan-settings.js +++ b/client/models/timespan-settings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/workflow-group.js b/client/models/workflow-group.js index 2ba66cc014..364ac6f49b 100644 --- a/client/models/workflow-group.js +++ b/client/models/workflow-group.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/workflow-groups.js b/client/models/workflow-groups.js index a33b2dce18..3f416dedbd 100644 --- a/client/models/workflow-groups.js +++ b/client/models/workflow-groups.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/workflow.js b/client/models/workflow.js index 36427fdfd9..b015eb1389 100644 --- a/client/models/workflow.js +++ b/client/models/workflow.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/models/workflows.js b/client/models/workflows.js index 194fe9b0da..ac1af588a4 100644 --- a/client/models/workflows.js +++ b/client/models/workflows.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/page-help.js b/client/page-help.js index 855a2618fc..6207aaa081 100644 --- a/client/page-help.js +++ b/client/page-help.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/base.js b/client/pages/base.js index 4e295992ed..05cb8dec34 100644 --- a/client/pages/base.js +++ b/client/pages/base.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/domain-editor.js b/client/pages/domain-editor.js index 4160ab3d44..ef6bc1e3ab 100644 --- a/client/pages/domain-editor.js +++ b/client/pages/domain-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/file-browser.js b/client/pages/file-browser.js index 94dc7d5c75..080cc866dd 100644 --- a/client/pages/file-browser.js +++ b/client/pages/file-browser.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/home.js b/client/pages/home.js index 4b1b4121f4..039614d8b2 100644 --- a/client/pages/home.js +++ b/client/pages/home.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/loading-page.js b/client/pages/loading-page.js index f6ba556d4f..1710f889b0 100644 --- a/client/pages/loading-page.js +++ b/client/pages/loading-page.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 01a6c1fccb..e15c3506d8 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/multiple-plots.js b/client/pages/multiple-plots.js index ad54c5b373..108f9b60ce 100644 --- a/client/pages/multiple-plots.js +++ b/client/pages/multiple-plots.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/page.js b/client/pages/page.js index 3e434457ef..d9c6743cc0 100644 --- a/client/pages/page.js +++ b/client/pages/page.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/project-browser.js b/client/pages/project-browser.js index 1b65377b8d..6286c611a8 100644 --- a/client/pages/project-browser.js +++ b/client/pages/project-browser.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/project-manager.js b/client/pages/project-manager.js index 67f45073ba..0ac554d7ce 100644 --- a/client/pages/project-manager.js +++ b/client/pages/project-manager.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/quickstart.js b/client/pages/quickstart.js index bf64e271f7..5fdd276d9c 100644 --- a/client/pages/quickstart.js +++ b/client/pages/quickstart.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/users-home.js b/client/pages/users-home.js index c5fa5b81c5..2eb2e8ee93 100644 --- a/client/pages/users-home.js +++ b/client/pages/users-home.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/workflow-manager.js b/client/pages/workflow-manager.js index 3dd79cdc2e..0e1696a6b0 100644 --- a/client/pages/workflow-manager.js +++ b/client/pages/workflow-manager.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/pages/workflow-selection.js b/client/pages/workflow-selection.js index 71846a1d2b..3d28c8c114 100644 --- a/client/pages/workflow-selection.js +++ b/client/pages/workflow-selection.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/reaction-types.js b/client/reaction-types.js index 503db760d3..ada8f44efb 100644 --- a/client/reaction-types.js +++ b/client/reaction-types.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/styles/styles.css b/client/styles/styles.css index e5b21c765d..f437041f88 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/tooltips.js b/client/tooltips.js index 18fce2f456..8149af6490 100644 --- a/client/tooltips.js +++ b/client/tooltips.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/archive-listing.js b/client/views/archive-listing.js index e5bb93c18b..9aacef63b1 100644 --- a/client/views/archive-listing.js +++ b/client/views/archive-listing.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/boundary-condition-view.js b/client/views/boundary-condition-view.js index a5d5a0e05a..a91cf1b9fb 100644 --- a/client/views/boundary-condition-view.js +++ b/client/views/boundary-condition-view.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/boundary-conditions-editor.js b/client/views/boundary-conditions-editor.js index 1255953dc2..60a27794cd 100644 --- a/client/views/boundary-conditions-editor.js +++ b/client/views/boundary-conditions-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/component-types.js b/client/views/component-types.js index 212ef27413..f6001e6b88 100644 --- a/client/views/component-types.js +++ b/client/views/component-types.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/creator-listing.js b/client/views/creator-listing.js index 847f8f1b92..016b6e5d21 100644 --- a/client/views/creator-listing.js +++ b/client/views/creator-listing.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/domain-viewer.js b/client/views/domain-viewer.js index 0ac2e490bb..2ff51bcc60 100644 --- a/client/views/domain-viewer.js +++ b/client/views/domain-viewer.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-3D-domain.js b/client/views/edit-3D-domain.js index 5513d14991..e1161faf3f 100644 --- a/client/views/edit-3D-domain.js +++ b/client/views/edit-3D-domain.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-custom-stoich-specie.js b/client/views/edit-custom-stoich-specie.js index 5db31730e7..0e842387eb 100644 --- a/client/views/edit-custom-stoich-specie.js +++ b/client/views/edit-custom-stoich-specie.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-domain-type.js b/client/views/edit-domain-type.js index 455cf02da3..5460f753ba 100644 --- a/client/views/edit-domain-type.js +++ b/client/views/edit-domain-type.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-event-assignment.js b/client/views/edit-event-assignment.js index 8e48f4931f..8bb53ad728 100644 --- a/client/views/edit-event-assignment.js +++ b/client/views/edit-event-assignment.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-function-definition.js b/client/views/edit-function-definition.js index bb7146befb..d582b9dba6 100644 --- a/client/views/edit-function-definition.js +++ b/client/views/edit-function-definition.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-initial-condition.js b/client/views/edit-initial-condition.js index 11089e5efc..757d2c7ca5 100644 --- a/client/views/edit-initial-condition.js +++ b/client/views/edit-initial-condition.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-parameter.js b/client/views/edit-parameter.js index e8b342f24c..bc2bec13e9 100644 --- a/client/views/edit-parameter.js +++ b/client/views/edit-parameter.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-particle.js b/client/views/edit-particle.js index 099e0a099a..8dc1f0d2da 100644 --- a/client/views/edit-particle.js +++ b/client/views/edit-particle.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-project.js b/client/views/edit-project.js index 042dddc754..2dcf7d3f90 100644 --- a/client/views/edit-project.js +++ b/client/views/edit-project.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-rule.js b/client/views/edit-rule.js index de9884510f..66e36128b8 100644 --- a/client/views/edit-rule.js +++ b/client/views/edit-rule.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-species.js b/client/views/edit-species.js index 2aad005f6c..39a7e6f744 100644 --- a/client/views/edit-species.js +++ b/client/views/edit-species.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/edit-stoich-specie.js b/client/views/edit-stoich-specie.js index 162806b2e6..4f276620aa 100644 --- a/client/views/edit-stoich-specie.js +++ b/client/views/edit-stoich-specie.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/event-assignments-editor.js b/client/views/event-assignments-editor.js index 7f790869f5..3640c137e9 100644 --- a/client/views/event-assignments-editor.js +++ b/client/views/event-assignments-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/event-details.js b/client/views/event-details.js index b0cc2aca09..a4cf72f6c9 100644 --- a/client/views/event-details.js +++ b/client/views/event-details.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/event-listings.js b/client/views/event-listings.js index 658828a165..0a7c7866fe 100644 --- a/client/views/event-listings.js +++ b/client/views/event-listings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/events-editor.js b/client/views/events-editor.js index 189c16fad5..ff6b3b34f8 100644 --- a/client/views/events-editor.js +++ b/client/views/events-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/file-browser-view.js b/client/views/file-browser-view.js index de8ef0e6d2..b60f2bf2b9 100644 --- a/client/views/file-browser-view.js +++ b/client/views/file-browser-view.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/initial-conditions-editor.js b/client/views/initial-conditions-editor.js index 5e017ecde2..fbebfda626 100644 --- a/client/views/initial-conditions-editor.js +++ b/client/views/initial-conditions-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/initial-conditions-viewer.js b/client/views/initial-conditions-viewer.js index 777c445851..66bfc3e51f 100644 --- a/client/views/initial-conditions-viewer.js +++ b/client/views/initial-conditions-viewer.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/input.js b/client/views/input.js index 4f4ee98a1a..7516be3463 100644 --- a/client/views/input.js +++ b/client/views/input.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/job-listing.js b/client/views/job-listing.js index 2398dc5861..e24c2166c9 100644 --- a/client/views/job-listing.js +++ b/client/views/job-listing.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/main.js b/client/views/main.js index d432a10296..a62a9a4c2c 100644 --- a/client/views/main.js +++ b/client/views/main.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/mesh-editor.js b/client/views/mesh-editor.js index c3054cd9db..b9e9945025 100644 --- a/client/views/mesh-editor.js +++ b/client/views/mesh-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/meta-data.js b/client/views/meta-data.js index 37180ea829..f2f459e2a6 100644 --- a/client/views/meta-data.js +++ b/client/views/meta-data.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/model-listing.js b/client/views/model-listing.js index 5d753e17fe..24a37cc6a4 100644 --- a/client/views/model-listing.js +++ b/client/views/model-listing.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index 4683565571..82f4e40412 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/model-viewer.js b/client/views/model-viewer.js index b1563030d3..c1919f2440 100644 --- a/client/views/model-viewer.js +++ b/client/views/model-viewer.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/parameter-settings.js b/client/views/parameter-settings.js index 50f47229df..dcaba4fce5 100644 --- a/client/views/parameter-settings.js +++ b/client/views/parameter-settings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/parameters-editor.js b/client/views/parameters-editor.js index aa72c100c5..d7623c1a93 100644 --- a/client/views/parameters-editor.js +++ b/client/views/parameters-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/quickview-domain-types.js b/client/views/quickview-domain-types.js index 5b003200d3..967715448c 100644 --- a/client/views/quickview-domain-types.js +++ b/client/views/quickview-domain-types.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/reactant-product.js b/client/views/reactant-product.js index 7bd3858693..8a982bcc03 100644 --- a/client/views/reactant-product.js +++ b/client/views/reactant-product.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/reaction-details.js b/client/views/reaction-details.js index aa074e024b..00f27574a7 100644 --- a/client/views/reaction-details.js +++ b/client/views/reaction-details.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/reaction-listing.js b/client/views/reaction-listing.js index 6de8a56d3e..2503be8ee3 100644 --- a/client/views/reaction-listing.js +++ b/client/views/reaction-listing.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/reaction-types.js b/client/views/reaction-types.js index f931b17510..e57eddcc06 100644 --- a/client/views/reaction-types.js +++ b/client/views/reaction-types.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/reactions-editor.js b/client/views/reactions-editor.js index dc9b56ed77..e6539a856e 100644 --- a/client/views/reactions-editor.js +++ b/client/views/reactions-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/rules-editor.js b/client/views/rules-editor.js index 6c0145acad..489a41e770 100644 --- a/client/views/rules-editor.js +++ b/client/views/rules-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/sbml-component-editor.js b/client/views/sbml-component-editor.js index e7f58940ab..678984682d 100644 --- a/client/views/sbml-component-editor.js +++ b/client/views/sbml-component-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/settings-viewer.js b/client/views/settings-viewer.js index 918bfddf2b..bb45c043a6 100644 --- a/client/views/settings-viewer.js +++ b/client/views/settings-viewer.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/settings.js b/client/views/settings.js index 3cec47d4f8..4905e37461 100644 --- a/client/views/settings.js +++ b/client/views/settings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/simulation-settings.js b/client/views/simulation-settings.js index 024c7d381b..f6300beac2 100644 --- a/client/views/simulation-settings.js +++ b/client/views/simulation-settings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/species-editor.js b/client/views/species-editor.js index 6eb3a6b445..9ac3ae456e 100644 --- a/client/views/species-editor.js +++ b/client/views/species-editor.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/sweep-parameter-range.js b/client/views/sweep-parameter-range.js index 9b297388dc..00faa0a625 100644 --- a/client/views/sweep-parameter-range.js +++ b/client/views/sweep-parameter-range.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/sweep-parameter.js b/client/views/sweep-parameter.js index 29a092bdf3..1aebd9a482 100644 --- a/client/views/sweep-parameter.js +++ b/client/views/sweep-parameter.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/tests.js b/client/views/tests.js index 057fcf283a..ebee33007a 100644 --- a/client/views/tests.js +++ b/client/views/tests.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/timespan-settings.js b/client/views/timespan-settings.js index fa5f87cb4b..62b59c1a21 100644 --- a/client/views/timespan-settings.js +++ b/client/views/timespan-settings.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/view-initial-condition.js b/client/views/view-initial-condition.js index 451e5356e0..49ae01f0ae 100644 --- a/client/views/view-initial-condition.js +++ b/client/views/view-initial-condition.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/view-particle.js b/client/views/view-particle.js index 7126ff21fe..4948a2804d 100644 --- a/client/views/view-particle.js +++ b/client/views/view-particle.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/view-sweep-parameter.js b/client/views/view-sweep-parameter.js index bc64a1dab2..10d6b01fa3 100644 --- a/client/views/view-sweep-parameter.js +++ b/client/views/view-sweep-parameter.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/workflow-group-listing.js b/client/views/workflow-group-listing.js index 1e1d322211..c51e723eea 100644 --- a/client/views/workflow-group-listing.js +++ b/client/views/workflow-group-listing.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/workflow-info.js b/client/views/workflow-info.js index cefad55a32..526ddc3514 100644 --- a/client/views/workflow-info.js +++ b/client/views/workflow-info.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/workflow-listing.js b/client/views/workflow-listing.js index 7ee0006b89..cde0be60b9 100644 --- a/client/views/workflow-listing.js +++ b/client/views/workflow-listing.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/workflow-results.js b/client/views/workflow-results.js index adc075079f..b0a9d8a153 100644 --- a/client/views/workflow-results.js +++ b/client/views/workflow-results.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/client/views/workflow-status.js b/client/views/workflow-status.js index c4d0947c39..ee221168f5 100644 --- a/client/views/workflow-status.js +++ b/client/views/workflow-status.js @@ -1,6 +1,6 @@ /* StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/__init__.py b/stochss/handlers/__init__.py index f1ae51967e..ce3865a3a9 100644 --- a/stochss/handlers/__init__.py +++ b/stochss/handlers/__init__.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/file_browser.py b/stochss/handlers/file_browser.py index 50fbbb523f..2afb26ca41 100644 --- a/stochss/handlers/file_browser.py +++ b/stochss/handlers/file_browser.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/log.py b/stochss/handlers/log.py index 550e2473be..9d6d78bcd8 100644 --- a/stochss/handlers/log.py +++ b/stochss/handlers/log.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index 67a5042ff5..545c69c0b4 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/pages.py b/stochss/handlers/pages.py index 23cece06b1..e2961bb4fa 100644 --- a/stochss/handlers/pages.py +++ b/stochss/handlers/pages.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/project.py b/stochss/handlers/project.py index b0b727364a..fe1e95f962 100644 --- a/stochss/handlers/project.py +++ b/stochss/handlers/project.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/__init__.py b/stochss/handlers/util/__init__.py index eda8912745..d7351abbfc 100644 --- a/stochss/handlers/util/__init__.py +++ b/stochss/handlers/util/__init__.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/ensemble_simulation.py b/stochss/handlers/util/ensemble_simulation.py index 2b220e21fb..d2697e06db 100644 --- a/stochss/handlers/util/ensemble_simulation.py +++ b/stochss/handlers/util/ensemble_simulation.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/parameter_scan.py b/stochss/handlers/util/parameter_scan.py index be84dd7ef4..67e72e85a6 100644 --- a/stochss/handlers/util/parameter_scan.py +++ b/stochss/handlers/util/parameter_scan.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/parameter_sweep.py b/stochss/handlers/util/parameter_sweep.py index d1a4a909c2..43251bfabd 100644 --- a/stochss/handlers/util/parameter_sweep.py +++ b/stochss/handlers/util/parameter_sweep.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/parameter_sweep_1d.py b/stochss/handlers/util/parameter_sweep_1d.py index 33c580e115..e1744532a8 100644 --- a/stochss/handlers/util/parameter_sweep_1d.py +++ b/stochss/handlers/util/parameter_sweep_1d.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/parameter_sweep_2d.py b/stochss/handlers/util/parameter_sweep_2d.py index 0c909181de..b9718cc710 100644 --- a/stochss/handlers/util/parameter_sweep_2d.py +++ b/stochss/handlers/util/parameter_sweep_2d.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/scripts/run_preview.py b/stochss/handlers/util/scripts/run_preview.py index 89cd9c6c1f..97c07c6253 100755 --- a/stochss/handlers/util/scripts/run_preview.py +++ b/stochss/handlers/util/scripts/run_preview.py @@ -2,7 +2,7 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/scripts/start_job.py b/stochss/handlers/util/scripts/start_job.py index fa880431a8..50996c50a7 100755 --- a/stochss/handlers/util/scripts/start_job.py +++ b/stochss/handlers/util/scripts/start_job.py @@ -2,7 +2,7 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/scripts/upload_remote_file.py b/stochss/handlers/util/scripts/upload_remote_file.py index 5db60cc1b8..e92073cdd7 100755 --- a/stochss/handlers/util/scripts/upload_remote_file.py +++ b/stochss/handlers/util/scripts/upload_remote_file.py @@ -2,7 +2,7 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/spatial_simulation.py b/stochss/handlers/util/spatial_simulation.py index 955af08715..3741e1dbf5 100644 --- a/stochss/handlers/util/spatial_simulation.py +++ b/stochss/handlers/util/spatial_simulation.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_base.py b/stochss/handlers/util/stochss_base.py index c17075e87f..b08ba39b44 100644 --- a/stochss/handlers/util/stochss_base.py +++ b/stochss/handlers/util/stochss_base.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_errors.py b/stochss/handlers/util/stochss_errors.py index 3ee1cbd411..076916205c 100644 --- a/stochss/handlers/util/stochss_errors.py +++ b/stochss/handlers/util/stochss_errors.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_file.py b/stochss/handlers/util/stochss_file.py index fbe99c91d3..2c621494fc 100644 --- a/stochss/handlers/util/stochss_file.py +++ b/stochss/handlers/util/stochss_file.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_folder.py b/stochss/handlers/util/stochss_folder.py index d9dbc44d4c..70a7a20bb9 100644 --- a/stochss/handlers/util/stochss_folder.py +++ b/stochss/handlers/util/stochss_folder.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_job.py b/stochss/handlers/util/stochss_job.py index 612c513b62..b9beeaa818 100644 --- a/stochss/handlers/util/stochss_job.py +++ b/stochss/handlers/util/stochss_job.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_model.py b/stochss/handlers/util/stochss_model.py index 6b617b2385..1eca031ec1 100644 --- a/stochss/handlers/util/stochss_model.py +++ b/stochss/handlers/util/stochss_model.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_notebook.py b/stochss/handlers/util/stochss_notebook.py index 62654a378c..ee84eaf346 100644 --- a/stochss/handlers/util/stochss_notebook.py +++ b/stochss/handlers/util/stochss_notebook.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_project.py b/stochss/handlers/util/stochss_project.py index 3b2c9327a4..215039b760 100644 --- a/stochss/handlers/util/stochss_project.py +++ b/stochss/handlers/util/stochss_project.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_sbml.py b/stochss/handlers/util/stochss_sbml.py index 7f3cf29486..4d4f334880 100644 --- a/stochss/handlers/util/stochss_sbml.py +++ b/stochss/handlers/util/stochss_sbml.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 99f607d217..1455c38792 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/util/stochss_workflow.py b/stochss/handlers/util/stochss_workflow.py index c4646e5304..176c2a29e8 100644 --- a/stochss/handlers/util/stochss_workflow.py +++ b/stochss/handlers/util/stochss_workflow.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/handlers/workflows.py b/stochss/handlers/workflows.py index cb37ad715a..ae8bbc4c63 100644 --- a/stochss/handlers/workflows.py +++ b/stochss/handlers/workflows.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/tests/run_tests.py b/stochss/tests/run_tests.py index 5aa6cce0f0..56a10113f8 100755 --- a/stochss/tests/run_tests.py +++ b/stochss/tests/run_tests.py @@ -2,7 +2,7 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 From 9f3f4b536ccdfe678abeba1a459aee03f5a8b634 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 29 Jun 2021 14:02:46 -0400 Subject: [PATCH 57/63] Updated the copyright to 2021. --- stochss/tests/test_model_template.py | 2 +- stochss/tests/test_settings_template.py | 2 +- stochss/tests/test_stochss_base.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stochss/tests/test_model_template.py b/stochss/tests/test_model_template.py index c2bb805551..3e6812f079 100644 --- a/stochss/tests/test_model_template.py +++ b/stochss/tests/test_model_template.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/tests/test_settings_template.py b/stochss/tests/test_settings_template.py index 40b7ee3a98..8db314b230 100644 --- a/stochss/tests/test_settings_template.py +++ b/stochss/tests/test_settings_template.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 diff --git a/stochss/tests/test_stochss_base.py b/stochss/tests/test_stochss_base.py index d4f0bbee7e..81c5c979d3 100644 --- a/stochss/tests/test_stochss_base.py +++ b/stochss/tests/test_stochss_base.py @@ -1,6 +1,6 @@ ''' StochSS is a platform for simulating biochemical systems -Copyright (C) 2019-2020 StochSS developers. +Copyright (C) 2019-2021 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 From 24a3ba24ab315f4067a13706e2022d9998339833 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 29 Jun 2021 14:53:14 -0400 Subject: [PATCH 58/63] Added css to darken the background color of the card header class. --- client/styles/styles.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/styles/styles.css b/client/styles/styles.css index f437041f88..64935dff14 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -702,3 +702,7 @@ span.checkbox { overflow-y: hidden; white-space: nowrap; } + +.card-header { + background-color: rgba(0, 0, 0, 0.1); +} From ed61c9323d2eb48b7f4bee76d6565f04cbef310f Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 29 Jun 2021 15:08:28 -0400 Subject: [PATCH 59/63] Updated the type for initial condition properties to fix type set conflicts. --- client/models/initial-condition.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/models/initial-condition.js b/client/models/initial-condition.js index b6fcf8d7d2..97c03bbec8 100644 --- a/client/models/initial-condition.js +++ b/client/models/initial-condition.js @@ -24,11 +24,11 @@ module.exports = State.extend({ props: { icType: 'string', annotation: 'string', - count: 'number', + count: 'any', types: 'object', - x: 'number', - y: 'number', - z: 'number', + x: 'any', + y: 'any', + z: 'any', }, children: { specie: Specie, From c22c7331437be63a36d988911d8b3a62fee4e85e Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 29 Jun 2021 16:54:06 -0400 Subject: [PATCH 60/63] Refactored the boundary condition front end to send the model path to the api handler. Refactored the boundary condition api hander and create boundary condition function to pass the model to the spatialpy boundary condition constructor. Refactored the value inputs to support vector inputs for velocity. --- .../includes/boundaryConditionsEditor.pug | 8 +- client/views/boundary-conditions-editor.js | 83 +++++++++++++++++-- stochss/handlers/models.py | 7 +- .../handlers/util/stochss_spatial_model.py | 6 +- 4 files changed, 90 insertions(+), 14 deletions(-) diff --git a/client/templates/includes/boundaryConditionsEditor.pug b/client/templates/includes/boundaryConditionsEditor.pug index 61dc60bbc7..ef9ea6aa1e 100644 --- a/client/templates/includes/boundaryConditionsEditor.pug +++ b/client/templates/includes/boundaryConditionsEditor.pug @@ -76,7 +76,13 @@ div#boundary-conditions.card td(data-hook="new-bc-target") tr th(scope="row") Value - td(data-hook="new-bc-value" data-target="value") + td + div(data-hook="new-bc-velocity-value") + div(data-hook="new-bc-value-x" data-target="value") + div(data-hook="new-bc-value-y" data-target="value") + div(data-hook="new-bc-value-z" data-target="value") + div(data-hook="new-bc-other-value" style="display: none") + div(data-hook="new-bc-value" data-target="value") tr th(scope="row") Concentration td diff --git a/client/views/boundary-conditions-editor.js b/client/views/boundary-conditions-editor.js index 60a27794cd..d362d96798 100644 --- a/client/views/boundary-conditions-editor.js +++ b/client/views/boundary-conditions-editor.js @@ -38,6 +38,9 @@ module.exports = View.extend({ 'change [data-hook=new-bc-deterministic]' : 'handleSetDeterministic', 'change [data-hook=new-bc-type]' : 'handleSetValue', 'change [data-hook=new-bc-value]' : 'handleSetValue', + 'change [data-hook=new-bc-value-x]' : 'handleSetValue', + 'change [data-hook=new-bc-value-y]' : 'handleSetValue', + 'change [data-hook=new-bc-value-z]' : 'handleSetValue', 'change [data-hook=new-bc-x-min]' : 'handleSetValue', 'change [data-hook=new-bc-x-max]' : 'handleSetValue', 'change [data-hook=new-bc-y-min]' : 'handleSetValue', @@ -77,7 +80,13 @@ module.exports = View.extend({ handleAddBCClick: function (e) { let endpoint = path.join(app.getApiPath(), "model/new-bc") let self = this; - app.postXHR(endpoint, this.newBC, { + if(this.newBC.property === "v") { + this.newBC.value = this.newBCVector + } + let data = {model_path: this.collection.parent.directory, + kwargs: this.newBC} + console.log(data) + app.postXHR(endpoint, data, { success: function (err, response, body) { self.collection.addNewBoundaryCondition(self.newBCName, body.expression); self.setDefaultBC(); @@ -92,12 +101,22 @@ module.exports = View.extend({ let properties = ["v", "nu", "rho"]; let target = e.target.value; if(properties.includes(target)) { + if(target === "v") { + $(this.queryByHook("new-bc-other-value")).css("display", "none"); + $(this.queryByHook("new-bc-velocity-value")).css("display", "block"); + }else { + $(this.queryByHook("new-bc-velocity-value")).css("display", "none"); + $(this.queryByHook("new-bc-other-value")).css("display", "block"); + } this.newBC.property = target; this.newBC.species = null; $(this.queryByHook("new-bc-deterministic")).prop("disabled", true); }else{ + let species = this.collection.parent.species.filter(function (specie) { + return specie.compID === Number(target) + })[0].name; this.newBC.property = null; - this.newBC.species = target; + this.newBC.species = species; $(this.queryByHook("new-bc-deterministic")).prop("disabled", false); } }, @@ -108,11 +127,18 @@ module.exports = View.extend({ this.newBCName = value; }else{ if(key.endsWith("min") || key.endsWith("max") || key === "type_id"){ - value = this.validateNewBCCondition(key, value); - }else if(key === "value" && value === "") { - value = null; + this.newBC[key] = this.validateNewBCCondition(key, value); + }else if(key === "value") { + if(e.delegateTarget.dataset.hook.endsWith("x")) { + this.newBCVector[0] = value === "" ? 0 : value + }else if(e.delegateTarget.dataset.hook.endsWith("y")) { + this.newBCVector[1] = value === "" ? 0 : value + }else if(e.delegateTarget.dataset.hook.endsWith("z")) { + this.newBCVector[2] = value === "" ? 0 : value + }else{ + this.newBC[key] = value === "" ? null : value + } } - this.newBC[key] = value; } this.toggleAddNewBCButton(); }, @@ -169,10 +195,13 @@ module.exports = View.extend({ this.newBCName = ""; this.newBC = {"species": null, "property": "v", "value": null, "deterministic": true, "type_id": null, "xmin": null, "ymin": null, "zmin": null, "xmax": null, "ymax": null, "zmax": null}; + this.newBCVector = [0, 0, 0] this.setConditions = []; }, toggleAddNewBCButton: function () { - let disabled = this.newBCName === "" || this.newBC.value === null || !this.setConditions.length; + let invalidName = this.newBCName === "" + let invalidValue = this.newBC.property === "v" ? this.newBCVector === [0, 0, 0] : this.newBC.value === null + let disabled = invalidName || invalidValue || !this.setConditions.length; $(this.queryByHook("add-new-bc")).prop("disabled", disabled); }, update: function (e) {}, @@ -229,7 +258,45 @@ module.exports = View.extend({ name: 'value', tests: tests.valueTests, valueType: 'number', - value: this.newBC.value + }); + } + }, + newBCValueX: { + hook: "new-bc-value-x", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'value-x', + tests: tests.valueTests, + valueType: 'number', + label: "X: " + }); + } + }, + newBCValueY: { + hook: "new-bc-value-y", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'value-y', + tests: tests.valueTests, + valueType: 'number', + label: "Y: " + }); + } + }, + newBCValueZ: { + hook: "new-bc-value-z", + prepareView: function (el) { + return new InputView({ + parent: this, + required: false, + name: 'value-z', + tests: tests.valueTests, + valueType: 'number', + label: "Z: " }); } }, diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index 545c69c0b4..04c210ad94 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -423,11 +423,14 @@ async def post(self): ---------- ''' self.set_header('Content-Type', 'application/json') - kwargs = json.loads(self.request.body.decode()) + data = json.loads(self.request.body.decode()) + path = data['model_path'] + kwargs = data['kwargs'] log.debug("Args passed to the boundary condition constructor: %s", kwargs) try: log.info("Creating the new boundary condition") - resp = StochSSSpatialModel.create_boundary_condition(kwargs) + model = StochSSSpatialModel(path=path) + resp = model.create_boundary_condition(kwargs) log.info("Successfully created the new boundary condition") log.debug("Response Message: %s", resp) self.write(resp) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 1455c38792..ab481090d2 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -389,8 +389,7 @@ def convert_to_spatialpy(self): return s_model - @classmethod - def create_boundary_condition(cls, kwargs): + def create_boundary_condition(self, kwargs): ''' Create a new boundary condition using spatialpy.BoundaryCondition @@ -399,7 +398,8 @@ def create_boundary_condition(cls, kwargs): kwargs : dict Arguments passed to the spatialpy.BoundaryCondition constructor ''' - new_bc = BoundaryCondition(**kwargs) + model = self.convert_to_spatialpy() + new_bc = BoundaryCondition(model=model, **kwargs) expression = new_bc.expression() return {"expression": expression} From 2105d0d4848e3b017dcbacc131aa0ffae796161d Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 29 Jun 2021 17:12:27 -0400 Subject: [PATCH 61/63] Fixed autosave function. --- client/models/model.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/models/model.js b/client/models/model.js index b09b3a6540..9799e6e4f2 100644 --- a/client/models/model.js +++ b/client/models/model.js @@ -16,6 +16,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +let _ = require('underscore'); +//support files var app = require('../app'); var path = require('path'); //models @@ -128,7 +130,7 @@ module.exports = Model.extend({ autoSave: function () { let self = this; setTimeout(function () { - app.postXHR(self.url(), self.toJSON(), { success: self.autoSave }); + app.postXHR(self.url(), self.toJSON(), { success: _.bind(self.autoSave, self) }); }, 120000); }, //called when save button is clicked From 486bc024b94c3dd73973c1d25fad499d8944a0a6 Mon Sep 17 00:00:00 2001 From: BryanRumsey <44621966+BryanRumsey@users.noreply.github.com> Date: Wed, 30 Jun 2021 13:38:51 -0400 Subject: [PATCH 62/63] Fixed error display css --- client/templates/includes/boundaryConditionsEditor.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/templates/includes/boundaryConditionsEditor.pug b/client/templates/includes/boundaryConditionsEditor.pug index ef9ea6aa1e..fea9fc7d4b 100644 --- a/client/templates/includes/boundaryConditionsEditor.pug +++ b/client/templates/includes/boundaryConditionsEditor.pug @@ -90,7 +90,7 @@ div#boundary-conditions.card div.col-sm-6 - div + div(style="display: flex;") span.inline.mr-3(for="new-bc-type") Type: div.inline(id="new-bc-type" data-hook="new-bc-type" data-target="type_id") From 8693d747c239fa9ad9cc77edeee2fe233278f8a4 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 30 Jun 2021 13:45:49 -0400 Subject: [PATCH 63/63] Resolved review comments. --- client/views/boundary-conditions-editor.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client/views/boundary-conditions-editor.js b/client/views/boundary-conditions-editor.js index d362d96798..bfc9607a00 100644 --- a/client/views/boundary-conditions-editor.js +++ b/client/views/boundary-conditions-editor.js @@ -85,7 +85,6 @@ module.exports = View.extend({ } let data = {model_path: this.collection.parent.directory, kwargs: this.newBC} - console.log(data) app.postXHR(endpoint, data, { success: function (err, response, body) { self.collection.addNewBoundaryCondition(self.newBCName, body.expression);