From bf800e909be20e09c932103444f6fa28a1519eab Mon Sep 17 00:00:00 2001 From: Brian Drawert Date: Wed, 8 Sep 2021 08:53:31 -0700 Subject: [PATCH 01/60] launching webbrowser now has a timeout --- launch_webbrowser.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/launch_webbrowser.py b/launch_webbrowser.py index e9f892e27b..0cf64c63a0 100755 --- a/launch_webbrowser.py +++ b/launch_webbrowser.py @@ -4,6 +4,9 @@ import sys import time import webbrowser + +MAX_WAIT_TIME = 60 + try: import docker except ImportError: @@ -25,11 +28,15 @@ #time.sleep(10) print("Checking for running StochSS container: stochss-lab") container_started = False +poll_start_time = time.time() while not container_started: + if (time.time() - MAX_WAIT_TIME) > poll_start_time: + print(f"Stopped checking for running StochSS container after {MAX_WAIT_TIME}s") + sys.exit(1) time.sleep(1) try: stochss_container=docker_client.containers.get("stochss-lab") - print("Generating StochSS webpage...") + print("Checking to see if the server is active.") jupyter_url_generator=stochss_container.exec_run("jupyter notebook list", demux=False) url_regex = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))" jupyter_url_bytes = jupyter_url_generator.output From 6f11e63795cce780d9bf415e3f9b5f0bb8f31e74 Mon Sep 17 00:00:00 2001 From: Brian Drawert Date: Tue, 14 Sep 2021 12:54:12 -0700 Subject: [PATCH 02/60] adding a 1 second pause before opening the broswer --- launch_webbrowser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/launch_webbrowser.py b/launch_webbrowser.py index 0cf64c63a0..9524b9c75e 100755 --- a/launch_webbrowser.py +++ b/launch_webbrowser.py @@ -47,6 +47,7 @@ jupyter_url=jupyter_url_sequence[0] jupyter_url=jupyter_url.replace('0.0.0.0','127.0.0.1') print(f"Opening StochSS webpage...\n") + time.sleep(1) webbrowser.open_new_tab(jupyter_url) print("Welcome to StochSS!\n\nYou can access your local StochSS service with this URL:\n\n") print(jupyter_url+"\n") From 5bbe5d83f77a69769cf4b4dbcadf768b86109dbf Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 22 Sep 2021 13:14:37 -0400 Subject: [PATCH 03/60] Fixed issue with the notebook context menu in projects. --- client/project-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/project-config.js b/client/project-config.js index edf1cef1b0..9c0629e0ff 100644 --- a/client/project-config.js +++ b/client/project-config.js @@ -151,7 +151,7 @@ let getNotebookContext = (view, node) => { open: open, publish: view.getPublishNotebookContext(node), download: download, rename: rename, - duplicate: duplicate, delete: deleteFile + duplicate: duplicate, moveToTrash: moveToTrash } } From 8429294ffe898125d1c71b8eb20c782d43fa2318 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 22 Sep 2021 13:29:20 -0400 Subject: [PATCH 04/60] Fixed issue with the copy button for notebook presentations. --- client/views/jstree-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/jstree-view.js b/client/views/jstree-view.js index 5bed5b9f8b..1fe55f6ab8 100644 --- a/client/views/jstree-view.js +++ b/client/views/jstree-view.js @@ -900,7 +900,7 @@ module.exports = View.extend({ msg.html(reason); msg.css("display", "inline-block"); } - app.copyToClipboard(links.presentation, onFulfilled, onReject); + app.copyToClipboard(body.links.presentation, onFulfilled, onReject); }); }, error: (err, response, body) => { From 6ec07363a6300e3268ec6efbc6624ca68fa20e79 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 22 Sep 2021 13:39:20 -0400 Subject: [PATCH 05/60] Updated the version number. --- __version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__version__.py b/__version__.py index 93d8b3f6da..06125f64be 100644 --- a/__version__.py +++ b/__version__.py @@ -5,7 +5,7 @@ # @website https://github.com/stochss/stochss # ============================================================================= -__version__ = '2.4.1' +__version__ = '2.4.2' __title__ = 'StochSS' __description__ = 'StochSS is an integrated development environment (IDE) \ for simulation of biochemical networks.' From 1792dfbb383d1f2dd9337ef3e7afda0837eead5b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 22 Sep 2021 16:00:57 -0400 Subject: [PATCH 06/60] Added the creation date for presentations to the presentation data and replaced the file name with the presentation name. --- stochss/handlers/util/stochss_folder.py | 43 +++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/stochss/handlers/util/stochss_folder.py b/stochss/handlers/util/stochss_folder.py index 3c49af47e1..c7ec6f384e 100644 --- a/stochss/handlers/util/stochss_folder.py +++ b/stochss/handlers/util/stochss_folder.py @@ -21,6 +21,7 @@ import shutil import string import zipfile +import datetime import traceback import requests @@ -98,6 +99,21 @@ def __build_jstree_node(self, path, file): return node + @classmethod + def __get_presentation_model_name(cls, file_path): + with open(file_path, "r") as model_file: + name = json.load(model_file)['name'] + return name + + + @classmethod + def __get_presentation_notebook_name(cls, file_path): + with open(file_path, "r") as nb_file: + file = json.load(nb_file)['file'] + name = cls.get_name(cls, path=file) + return name + + @classmethod def __overwrite(cls, path, ext): if ext == "zip": @@ -363,10 +379,17 @@ def get_presentations(cls): presentations = [] if not os.path.isdir(path): return presentations + if os.path.exists(os.path.join(path, ".presentation_names.json")): + with open(os.path.join(path, ".presentation_names.json"), "r") as names_file: + names = json.load(names_file) + else: + names = {} + need_names = not bool(names) safe_chars = set(string.ascii_letters + string.digits) hostname = escape(os.environ.get('JUPYTERHUB_USER'), safe=safe_chars) for file in os.listdir(path): file_path = os.path.join(path, file) + ctime = os.path.getctime(file_path) query_str = f"?owner={hostname}&file={file}" routes = { "smdl": "present-model", @@ -374,10 +397,26 @@ def get_presentations(cls): "job": "present-job", "ipynb": "present-notebook" } - route = routes[file.split('.').pop()] + ext = file.split('.').pop() + if file in names.keys(): + name = names[file] + else: + if ext in ("mdl", "smdl"): + name = cls.__get_presentation_model_name(file_path) + elif ext == "job": + name = cls.__get_presentation_job_name(file_path) + elif ext == "ipynb": + name = cls.__get_presentation_notebook_name(file_path) + names[file] = name + if need_names: + with open(os.path.join(path, ".presentation_names.json"), "w") as names_file: + json.dump(names, names_file) + route = routes[ext] link = f"/stochss/{route}{query_str}" presentation = { - "file": file, "link": link, "size": os.path.getsize(file_path) + "file": file, "link": link, "name": name, + "size": os.path.getsize(file_path), + "ctime": datetime.datetime.fromtimestamp(ctime).strftime("%b %d, %Y") } presentations.append(presentation) return presentations From 0ca9d6b1aa710d9ad6c08a7ae29b428ea2371fd0 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 22 Sep 2021 16:28:49 -0400 Subject: [PATCH 07/60] Added helper function to get the name of a job presentation if the presentation names file does not exist. --- stochss/handlers/util/stochss_folder.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/stochss/handlers/util/stochss_folder.py b/stochss/handlers/util/stochss_folder.py index c7ec6f384e..48f1e13571 100644 --- a/stochss/handlers/util/stochss_folder.py +++ b/stochss/handlers/util/stochss_folder.py @@ -18,6 +18,7 @@ import os import json +import pickle import shutil import string import zipfile @@ -99,6 +100,14 @@ def __build_jstree_node(self, path, file): return node + @classmethod + def __get_presentation_job_name(cls, file_path): + with open(file_path, "rb") as job_file: + job = pickle.load(job_file) + name = job['name'] + return name + + @classmethod def __get_presentation_model_name(cls, file_path): with open(file_path, "r") as model_file: @@ -390,7 +399,6 @@ def get_presentations(cls): for file in os.listdir(path): file_path = os.path.join(path, file) ctime = os.path.getctime(file_path) - query_str = f"?owner={hostname}&file={file}" routes = { "smdl": "present-model", "mdl": "present-model", @@ -411,10 +419,9 @@ def get_presentations(cls): if need_names: with open(os.path.join(path, ".presentation_names.json"), "w") as names_file: json.dump(names, names_file) - route = routes[ext] - link = f"/stochss/{route}{query_str}" presentation = { - "file": file, "link": link, "name": name, + "file": f"{name}.{ext}", + "link": f"/stochss/{routes[ext]}?owner={hostname}&file={file}", "size": os.path.getsize(file_path), "ctime": datetime.datetime.fromtimestamp(ctime).strftime("%b %d, %Y") } From 8c23672c844cfaa00206bfc792c670206740ef54 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 22 Sep 2021 16:30:56 -0400 Subject: [PATCH 08/60] Added function to handle adding and removing names from the presentation names file. --- stochss/handlers/util/stochss_base.py | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/stochss/handlers/util/stochss_base.py b/stochss/handlers/util/stochss_base.py index 43a5b73ea8..f8727ad40b 100644 --- a/stochss/handlers/util/stochss_base.py +++ b/stochss/handlers/util/stochss_base.py @@ -46,6 +46,28 @@ def __init__(self, path): self.logs = [] + def add_presentation_name(self, file, name): + ''' + Add a new presentation to the presentation names file. + + Attributes + ---------- + file : str + Name of the presentation file + name : str + Name of the presentation + ''' + path = os.path.join(self.user_dir, ".presentations", ".presentation_names.json") + if os.path.exists(path): + with open(path, "r") as names_file: + names = json.load(names_file) + else: + names = {} + names[file] = name + with open(path, "w") as names_file: + json.dump(names, names_file) + + @classmethod def check_project_format(cls, path): ''' @@ -87,6 +109,23 @@ def check_workflow_format(cls, path): return True + def delete_presentation_name(self, file): + ''' + Remove a presentation name from the presentation names file. + + Attributes + ---------- + file : str + Name of the presentation file to remove + ''' + path = os.path.join(self.user_dir, ".presentations", ".presentation_names.json") + with open(path, "r") as names_file: + names = json.load(names_file) + del names[file] + with open(path, "w") as names_file: + json.dump(names, names_file) + + @classmethod def get_new_path(cls, dst_path): ''' From 24dbd225b5bd3e77959749cacb282001e50eddff Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 22 Sep 2021 16:39:53 -0400 Subject: [PATCH 09/60] Added function calls to add names of presentations to the presentation names file for new presentations. --- stochss/handlers/util/stochss_job.py | 1 + stochss/handlers/util/stochss_model.py | 1 + stochss/handlers/util/stochss_notebook.py | 1 + stochss/handlers/util/stochss_spatial_model.py | 1 + 4 files changed, 4 insertions(+) diff --git a/stochss/handlers/util/stochss_job.py b/stochss/handlers/util/stochss_job.py index 61663da1b4..11dd944084 100644 --- a/stochss/handlers/util/stochss_job.py +++ b/stochss/handlers/util/stochss_job.py @@ -746,6 +746,7 @@ def publish_presentation(self, name=None): else: exists = False name = self.get_file() if name is None else name + self.add_presentation_name(file, name) path = os.path.join(self.__get_results_path(), "results.p") with open(path, "rb") as results_file: results = pickle.load(results_file) diff --git a/stochss/handlers/util/stochss_model.py b/stochss/handlers/util/stochss_model.py index 3bfe947995..48c196916b 100644 --- a/stochss/handlers/util/stochss_model.py +++ b/stochss/handlers/util/stochss_model.py @@ -485,6 +485,7 @@ def publish_presentation(self): if os.path.exists(dst): data = None else: + self.add_presentation_name(file, self.model['name']) data = {"path": dst, "new":True, "model":self.model} query_str = f"?owner={hostname}&file={file}" present_link = f"/stochss/present-model{query_str}" diff --git a/stochss/handlers/util/stochss_notebook.py b/stochss/handlers/util/stochss_notebook.py index bc0731e057..fffdead4bd 100644 --- a/stochss/handlers/util/stochss_notebook.py +++ b/stochss/handlers/util/stochss_notebook.py @@ -604,6 +604,7 @@ def publish_presentation(self): if os.path.exists(dst): exists = True else: + self.add_presentation_name(file, self.get_name()) exists = False with open(dst, "w") as presentation_file: json.dump(notebook_pres, presentation_file) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 6e2ea225f9..75422c62c3 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -615,6 +615,7 @@ def publish_presentation(self): if os.path.exists(dst): data = None else: + self.add_presentation_name(file, self.model['name']) data = {"path": dst, "new":True, "model":self.model} query_str = f"?owner={hostname}&file={file}" present_link = f"/stochss/present-model{query_str}" From 49bc850d0a86d682dd8efc1e7dabccd2ef37e736 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 22 Sep 2021 16:46:51 -0400 Subject: [PATCH 10/60] Added function call to remove a presentation name from the presentation names file when a presentation is deleted. --- stochss/handlers/util/stochss_file.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stochss/handlers/util/stochss_file.py b/stochss/handlers/util/stochss_file.py index 2c621494fc..2e7cb3f815 100644 --- a/stochss/handlers/util/stochss_file.py +++ b/stochss/handlers/util/stochss_file.py @@ -60,6 +60,8 @@ def delete(self): ''' path = self.get_path(full=True) try: + if ".presentations" in path: + self.delete_presentation_name(self.get_file()) os.remove(path) return "The file {0} was successfully deleted.".format(self.get_file()) except FileNotFoundError as err: From 451e3d29ea68ebb7eeb84bc433bc6dfa5c8150d2 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 22 Sep 2021 17:07:52 -0400 Subject: [PATCH 11/60] Fixed bugs. --- stochss/handlers/util/stochss_folder.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stochss/handlers/util/stochss_folder.py b/stochss/handlers/util/stochss_folder.py index 48f1e13571..391e9e37c9 100644 --- a/stochss/handlers/util/stochss_folder.py +++ b/stochss/handlers/util/stochss_folder.py @@ -396,7 +396,7 @@ def get_presentations(cls): need_names = not bool(names) safe_chars = set(string.ascii_letters + string.digits) hostname = escape(os.environ.get('JUPYTERHUB_USER'), safe=safe_chars) - for file in os.listdir(path): + for file in [file for file in os.listdir(path) if not file.startswith('.')]: file_path = os.path.join(path, file) ctime = os.path.getctime(file_path) routes = { @@ -416,16 +416,16 @@ def get_presentations(cls): elif ext == "ipynb": name = cls.__get_presentation_notebook_name(file_path) names[file] = name - if need_names: - with open(os.path.join(path, ".presentation_names.json"), "w") as names_file: - json.dump(names, names_file) presentation = { - "file": f"{name}.{ext}", + "file": file, "name": f"{name}.{ext}", "link": f"/stochss/{routes[ext]}?owner={hostname}&file={file}", "size": os.path.getsize(file_path), "ctime": datetime.datetime.fromtimestamp(ctime).strftime("%b %d, %Y") } presentations.append(presentation) + if need_names: + with open(os.path.join(path, ".presentation_names.json"), "w") as names_file: + json.dump(names, names_file) return presentations From 02de6ed4ee63a5a3fdeac131151d0c99e0e74164 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 24 Sep 2021 13:51:36 -0400 Subject: [PATCH 12/60] Added the creation time and name properties to the presentations model. --- client/models/presentation.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/models/presentation.js b/client/models/presentation.js index 17a07f2295..3e027ade20 100644 --- a/client/models/presentation.js +++ b/client/models/presentation.js @@ -20,8 +20,10 @@ let State = require('ampersand-state'); module.exports = State.extend({ session: { + ctime: 'string', file: 'string', link: 'string', + name: 'string', size: 'number', tag: 'string' }, From 585a5bb62dd152bbe2a7be58f52f6f5e4de00e12 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Fri, 24 Sep 2021 14:51:02 -0400 Subject: [PATCH 13/60] Changed the file name for presentations to the presentation name. Added the creation date to the presentations listing. --- client/templates/includes/presentationView.pug | 8 ++++++-- client/templates/pages/browser.pug | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/client/templates/includes/presentationView.pug b/client/templates/includes/presentationView.pug index 113ec43540..9b14ffa957 100644 --- a/client/templates/includes/presentationView.pug +++ b/client/templates/includes/presentationView.pug @@ -5,14 +5,18 @@ div.mx-1 div.row - div.col-sm-6 + div.col-sm-4 - a.pl-2(href=this.model.link)=this.model.file + a.pl-2(href=this.model.link)=this.model.name div.col-sm-2 button.btn.btn-outline-secondary.box-shadow(data-hook="copy-link") Copy Link + div.col-sm-2 + + div=this.model.ctime + div.col-sm-2 div=this.model.size + " " + this.model.tag diff --git a/client/templates/pages/browser.pug b/client/templates/pages/browser.pug index a634614fe5..a0b9dc16eb 100644 --- a/client/templates/pages/browser.pug +++ b/client/templates/pages/browser.pug @@ -36,7 +36,9 @@ section.page div.mx-1.row.head.align-items-baseline - div.col-sm-8: h6 File + div.col-sm-6: h6 File + + div.col-sm-2: h6 Date div.col-sm-2: h6 Size From bd826076d88e3db4ab8c5e7c0c5354394b270e5f Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 27 Sep 2021 14:32:52 -0400 Subject: [PATCH 14/60] Added tests for new functions. --- stochss/tests/test_stochss_base.py | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/stochss/tests/test_stochss_base.py b/stochss/tests/test_stochss_base.py index 11e2f1f920..89cbc2e068 100644 --- a/stochss/tests/test_stochss_base.py +++ b/stochss/tests/test_stochss_base.py @@ -59,6 +59,30 @@ def tearDown(self): if StochSSBase.user_dir != os.path.expanduser("~"): StochSSBase.user_dir = os.path.expanduser("~") + ################################################################################################ + # Unit tests for the StochSS base class add_presentation_name function. + ################################################################################################ + + def test_add_presentation_name__file_exists(self): + ''' Check if the presentation name is add to the presentation names file. ''' + StochSSBase.user_dir = self.tempdir.name + test_base = StochSSBase(path="") + with mock.patch("os.path.exists", return_value=True): + with mock.patch("builtins.open", mock.mock_open(read_data="{}")): + with mock.patch("json.dump") as mock_json_dump: + test_base.add_presentation_name("foo", "bar") + mock_json_dump.assert_called_once_with({'foo': 'bar'}, mock.ANY) + + + def test_add_presentation_name__file_does_not_exists(self): + ''' Check if the presentation names file was created with the given entry. ''' + StochSSBase.user_dir = self.tempdir.name + test_base = StochSSBase(path="") + with mock.patch("builtins.open", mock.mock_open()): + with mock.patch("json.dump") as mock_json_dump: + test_base.add_presentation_name("foo", "bar") + mock_json_dump.assert_called_once_with({'foo': 'bar'}, mock.ANY) + ################################################################################################ # Unit tests for the StochSS base class check_project_format function. ################################################################################################ @@ -130,6 +154,19 @@ 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)) + ################################################################################################ + # Unit tests for the StochSS base class delete_presentation_name function. + ################################################################################################ + + def test_delete_presentation_name(self): + ''' Check if the target presentation was removed from the presentation names file. ''' + StochSSBase.user_dir = self.tempdir.name + test_base = StochSSBase(path="") + with mock.patch("builtins.open", mock.mock_open(read_data='{"foo": "bar"}')): + with mock.patch("json.dump") as mock_json_dump: + test_base.delete_presentation_name("foo") + mock_json_dump.assert_called_once_with({}, mock.ANY) + ################################################################################################ # Unit tests for the StochSS base class get_new_path function. ################################################################################################ From 364a6d0b5e9155e5edbcd76049035642cffc2c24 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 27 Sep 2021 15:18:26 -0400 Subject: [PATCH 15/60] Added checks to ensure the names file remains in sync with the presentations. --- stochss/handlers/util/stochss_folder.py | 52 ++++++++++++++++--------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/stochss/handlers/util/stochss_folder.py b/stochss/handlers/util/stochss_folder.py index 391e9e37c9..fc3329f0c0 100644 --- a/stochss/handlers/util/stochss_folder.py +++ b/stochss/handlers/util/stochss_folder.py @@ -115,6 +115,33 @@ def __get_presentation_model_name(cls, file_path): return name + @classmethod + def __get_presentation_name(cls, names, file, file_path): + ext = file.split('.').pop() + if file in names.keys(): + name = names[file] + else: + if ext in ("mdl", "smdl"): + name = cls.__get_presentation_model_name(file_path) + elif ext == "job": + name = cls.__get_presentation_job_name(file_path) + elif ext == "ipynb": + name = cls.__get_presentation_notebook_name(file_path) + names[file] = name + return name, ext + + + @classmethod + def __get_names_from_file(cls, path, files): + if not os.path.exists(os.path.join(path, ".presentation_names.json")): + return {} + with open(os.path.join(path, ".presentation_names.json"), "r") as names_file: + names = json.load(names_file) + if len(names.keys()) != len(files): + return {} + return names + + @classmethod def __get_presentation_notebook_name(cls, file_path): with open(file_path, "r") as nb_file: @@ -385,18 +412,15 @@ def get_presentations(cls): ---------- ''' path = os.path.join(cls.user_dir, ".presentations") + files = [file for file in os.listdir(path) if not file.startswith('.')] presentations = [] - if not os.path.isdir(path): + if not files: return presentations - if os.path.exists(os.path.join(path, ".presentation_names.json")): - with open(os.path.join(path, ".presentation_names.json"), "r") as names_file: - names = json.load(names_file) - else: - names = {} + names = cls.__get_names_from_file(path, files) need_names = not bool(names) safe_chars = set(string.ascii_letters + string.digits) hostname = escape(os.environ.get('JUPYTERHUB_USER'), safe=safe_chars) - for file in [file for file in os.listdir(path) if not file.startswith('.')]: + for file in files: file_path = os.path.join(path, file) ctime = os.path.getctime(file_path) routes = { @@ -405,17 +429,7 @@ def get_presentations(cls): "job": "present-job", "ipynb": "present-notebook" } - ext = file.split('.').pop() - if file in names.keys(): - name = names[file] - else: - if ext in ("mdl", "smdl"): - name = cls.__get_presentation_model_name(file_path) - elif ext == "job": - name = cls.__get_presentation_job_name(file_path) - elif ext == "ipynb": - name = cls.__get_presentation_notebook_name(file_path) - names[file] = name + name, ext = cls.__get_presentation_name(names, file, file_path) presentation = { "file": file, "name": f"{name}.{ext}", "link": f"/stochss/{routes[ext]}?owner={hostname}&file={file}", @@ -423,7 +437,7 @@ def get_presentations(cls): "ctime": datetime.datetime.fromtimestamp(ctime).strftime("%b %d, %Y") } presentations.append(presentation) - if need_names: + if need_names or len(names.keys()) != len(files): with open(os.path.join(path, ".presentation_names.json"), "w") as names_file: json.dump(names, names_file) return presentations From 53d64a40d2a681c1ba46a4a1f96dbd4ccedec0dd Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 27 Sep 2021 15:39:46 -0400 Subject: [PATCH 16/60] Updated the gillespy2 version. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a5b7759e21..d58cc96aff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ python-libsbml==5.18.0 python-libsedml==2.0.9 python-libcombine==0.2.7 escapism==1.0.1 -gillespy2==1.6.3 +gillespy2==1.6.4 sciope==0.4 pygmsh==5.0.2 meshio==2.3.10 From 870d0ded32bbb314853d80aff91f23a7fb32ea4f Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 29 Sep 2021 09:51:32 -0400 Subject: [PATCH 17/60] Added live graphing to preview. --- stochss/handlers/util/ensemble_simulation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stochss/handlers/util/ensemble_simulation.py b/stochss/handlers/util/ensemble_simulation.py index 949fe70b36..d07a754d19 100644 --- a/stochss/handlers/util/ensemble_simulation.py +++ b/stochss/handlers/util/ensemble_simulation.py @@ -104,7 +104,8 @@ def run(self, preview=False, verbose=True): if preview: if verbose: log.info(f"Running {self.g_model.name} preview simulation") - results = self.g_model.run(timeout=5) + options = {"file_path": f".{self.g_model.name}-preview.json"} + results = self.g_model.run(timeout=5, live_output="graph", live_output_options=options) if verbose: log.info(f"{self.g_model.name} preview simulation has completed") log.info(f"Generate result plot for {self.g_model.name} preview") From 7206de19fda26e92c252495eacddc96fd5210885 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 29 Sep 2021 10:15:58 -0400 Subject: [PATCH 18/60] Added function to get the live output figure from the file. --- stochss/handlers/util/stochss_model.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/stochss/handlers/util/stochss_model.py b/stochss/handlers/util/stochss_model.py index 3bfe947995..00f632303e 100644 --- a/stochss/handlers/util/stochss_model.py +++ b/stochss/handlers/util/stochss_model.py @@ -406,6 +406,25 @@ def convert_to_spatial(self): return {"Message":message, "File":s_file}, {"spatial":model, "path":s_path} + def get_live_results(self): + ''' + Get the live output figure for the preview. + + Attributes + ---------- + ''' + file_name = f".{self.get_name()}-preview.json" + if not os.path.exists(file_name): + return "" + with open(file_name, "r") as live_fig: + fig = json.load(live_fig) + fig["config"] = { + "displayModeBar": True, + "responsive": True + } + return {"results": fig, "timeout":False} + + def get_notebook_data(self): ''' Get the needed data for converting to notebook From 777ca1e76778245fef2b76c279e16401cc094557 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 29 Sep 2021 10:17:01 -0400 Subject: [PATCH 19/60] Added live output figure to the run model api handler response. --- stochss/handlers/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index 5c4152c8f7..b0cab6d728 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -229,6 +229,7 @@ async def get(self): log.debug(f"Results for the model preview: {results}") if results is None: resp['Running'] = True + resp['Results'] = model.get_live_results() log.info("The preview is still running") else: resp['Results'] = results From 72a60b79aef671fd09b2c4ec9384fdc47b61f123 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 29 Sep 2021 10:32:10 -0400 Subject: [PATCH 20/60] Added block to render the live output figure. --- client/pages/model-editor.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 850b8a9946..fcb2e630a9 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -197,11 +197,16 @@ let ModelEditor = PageView.extend({ errorCB(err, response, body); } else if(!body.Running){ + Plotly.purge(this.queryByHook('preview-plot-container')); if(body.Results.timeout){ $(this.queryByHook('model-timeout-message')).collapse('show'); } this.plotResults(body.Results.results); }else{ + if(body.Results) { + Plotly.purge(this.queryByHook('preview-plot-container')); + this.plotResults(body.Results.results); + } this.getResults(); } }, From d82363ae4cfdbc5e84b4c548b0c7a695399c2d43 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 29 Sep 2021 10:34:25 -0400 Subject: [PATCH 21/60] Added line to cleanup the live figure file. --- stochss/handlers/util/ensemble_simulation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stochss/handlers/util/ensemble_simulation.py b/stochss/handlers/util/ensemble_simulation.py index d07a754d19..72ead6f0be 100644 --- a/stochss/handlers/util/ensemble_simulation.py +++ b/stochss/handlers/util/ensemble_simulation.py @@ -106,6 +106,7 @@ def run(self, preview=False, verbose=True): log.info(f"Running {self.g_model.name} preview simulation") options = {"file_path": f".{self.g_model.name}-preview.json"} results = self.g_model.run(timeout=5, live_output="graph", live_output_options=options) + os.remove(f".{self.g_model.name}-preview.json") if verbose: log.info(f"{self.g_model.name} preview simulation has completed") log.info(f"Generate result plot for {self.g_model.name} preview") From d29c4be390712ccf1dc2381999d0472e2f79a687 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 29 Sep 2021 10:36:42 -0400 Subject: [PATCH 22/60] Added race condition catch. --- stochss/handlers/util/stochss_model.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/stochss/handlers/util/stochss_model.py b/stochss/handlers/util/stochss_model.py index 00f632303e..2194f7a83f 100644 --- a/stochss/handlers/util/stochss_model.py +++ b/stochss/handlers/util/stochss_model.py @@ -416,13 +416,16 @@ def get_live_results(self): file_name = f".{self.get_name()}-preview.json" if not os.path.exists(file_name): return "" - with open(file_name, "r") as live_fig: - fig = json.load(live_fig) - fig["config"] = { - "displayModeBar": True, - "responsive": True - } - return {"results": fig, "timeout":False} + try: + with open(file_name, "r") as live_fig: + fig = json.load(live_fig) + fig["config"] = { + "displayModeBar": True, + "responsive": True + } + return {"results": fig, "timeout":False} + except json.decoder.JSONDecodeError: + return "" def get_notebook_data(self): From 7b5e635a2b831cc66a24db902173ac98c580d90f Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 29 Sep 2021 10:54:31 -0400 Subject: [PATCH 23/60] Updated the interval at which stochss checks for preview results. --- client/pages/model-editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index fcb2e630a9..78a13d5d68 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -212,7 +212,7 @@ let ModelEditor = PageView.extend({ }, error: errorCB }); - }, 2000); + }, 1000); }, handlePresentationClick: function (e) { let errorMsg = $(this.queryByHook("error-detected-msg")); From 56342b47a49603a0111f3cedaec36e1c866f7e5b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 4 Oct 2021 12:13:00 -0400 Subject: [PATCH 24/60] Refactored the checkout for the live output file to happen as part of the try catch block. --- stochss/handlers/util/stochss_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stochss/handlers/util/stochss_model.py b/stochss/handlers/util/stochss_model.py index 2194f7a83f..65bbeb76ad 100644 --- a/stochss/handlers/util/stochss_model.py +++ b/stochss/handlers/util/stochss_model.py @@ -414,8 +414,6 @@ def get_live_results(self): ---------- ''' file_name = f".{self.get_name()}-preview.json" - if not os.path.exists(file_name): - return "" try: with open(file_name, "r") as live_fig: fig = json.load(live_fig) @@ -424,6 +422,8 @@ def get_live_results(self): "responsive": True } return {"results": fig, "timeout":False} + except FileNotFoundError: + return "" except json.decoder.JSONDecodeError: return "" From 45fe541425b39c37531a304fb2e5046b89a79ecf Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 4 Oct 2021 12:40:21 -0400 Subject: [PATCH 25/60] Refactored the preview block to cleanup the live output file prior to running a new preview. --- stochss/handlers/util/ensemble_simulation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stochss/handlers/util/ensemble_simulation.py b/stochss/handlers/util/ensemble_simulation.py index 72ead6f0be..3958da422e 100644 --- a/stochss/handlers/util/ensemble_simulation.py +++ b/stochss/handlers/util/ensemble_simulation.py @@ -104,9 +104,11 @@ def run(self, preview=False, verbose=True): if preview: if verbose: log.info(f"Running {self.g_model.name} preview simulation") - options = {"file_path": f".{self.g_model.name}-preview.json"} + live_file = f".{self.g_model.name}-preview.json" + if os.path.exists(live_file): + os.remove(live_file) + options = {"file_path": live_file} results = self.g_model.run(timeout=5, live_output="graph", live_output_options=options) - os.remove(f".{self.g_model.name}-preview.json") if verbose: log.info(f"{self.g_model.name} preview simulation has completed") log.info(f"Generate result plot for {self.g_model.name} preview") From ed6833edf0dfc4803db0558f95d20487eb4264bd Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 25 Oct 2021 12:47:05 -0400 Subject: [PATCH 26/60] Spaces are now removed when generating the class name for models. --- stochss/handlers/util/stochss_notebook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stochss/handlers/util/stochss_notebook.py b/stochss/handlers/util/stochss_notebook.py index bc0731e057..214ef3a551 100644 --- a/stochss/handlers/util/stochss_notebook.py +++ b/stochss/handlers/util/stochss_notebook.py @@ -564,7 +564,7 @@ def get_class_name(self): return f"M{name}" if l_char in string.ascii_lowercase: return name.replace(l_char, l_char.upper(), 1) - return name + return name.replace(" ", "") def get_gillespy2_solver_name(self): From d1d2b82846e4ce6a2ed9219daa02caa36e8f7f78 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 25 Oct 2021 13:17:15 -0400 Subject: [PATCH 27/60] Fixed issue with upload file call in project manager, --- client/pages/project-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/pages/project-manager.js b/client/pages/project-manager.js index ccae2200b1..80f26819b1 100644 --- a/client/pages/project-manager.js +++ b/client/pages/project-manager.js @@ -314,7 +314,7 @@ let ProjectManager = PageView.extend({ } }, handleUploadModelClick: function (e) { - this.projectFileBrowser.uploadFile(undefined, "model") + this.projectFileBrowser.uploadFile(null, this.model.directory, "model", true) }, renderArchiveCollection: function () { if(this.archiveCollectionView) { From 838562070de149d42fe30f9fb36bc9bef5544809 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 26 Oct 2021 10:38:29 -0400 Subject: [PATCH 28/60] Fixed issue with projects add existing model option. --- client/pages/project-manager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/pages/project-manager.js b/client/pages/project-manager.js index ccae2200b1..cffd25f7b4 100644 --- a/client/pages/project-manager.js +++ b/client/pages/project-manager.js @@ -92,8 +92,8 @@ let ProjectManager = PageView.extend({ always: function (err, response, body) { let modal = $(modals.importModelHtml(body.files)).modal(); let okBtn = document.querySelector('#importModelModal .ok-model-btn'); - let select = document.querySelector('#importModelModal #modelFileInput'); - let location = document.querySelector('#importModelModal #modelPathInput'); + let select = document.querySelector('#importModelModal #modelFileSelect'); + let location = document.querySelector('#importModelModal #modelPathSelect'); select.addEventListener("change", function (e) { okBtn.disabled = e.target.value && body.paths[e.target.value].length >= 2; if(body.paths[e.target.value].length >= 2) { From 0d6f1b00dd079f42907b0495ee2e42311a1ceb96 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 26 Oct 2021 11:07:58 -0400 Subject: [PATCH 29/60] Refactored the exclusion test to exclude model presentations form the add existing model drop down. --- stochss/handlers/project.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stochss/handlers/project.py b/stochss/handlers/project.py index db3d3d44e0..ccb04bb69f 100644 --- a/stochss/handlers/project.py +++ b/stochss/handlers/project.py @@ -171,7 +171,8 @@ def get(self): folder = StochSSFolder(path="") # file will be excluded if test passes test = lambda ext, root, file: bool(".wkfl" in root or f"{path}" in root or \ - "trash" in root.split("/")) + "trash" in root.split("/") or \ + ".presentations" in root) data = folder.get_file_list(ext=[".mdl", ".smdl"], test=test) log.debug(f"List of models: {data}") self.write(data) From 4847dd7277747bc7e33a4552de304f52b1e9f5e6 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 26 Oct 2021 11:26:20 -0400 Subject: [PATCH 30/60] Added button to allow users to be able to clear their user logs. --- client/templates/body.pug | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/templates/body.pug b/client/templates/body.pug index 7cab6d1365..a2ab6c0467 100644 --- a/client/templates/body.pug +++ b/client/templates/body.pug @@ -64,6 +64,8 @@ body button.my-0.btn.btn-outline-collapse.inline(data-hook="user-logs-collapse") + + button.my-0.btn.btn-light.inline(data-hook="clear-user-logs" style="float: right;") clear + div.pl-1.overflow-auto(id="user-logs") main.col-sm-12.col-md-10.col-xl-9.col-xxl-6.body(role="main" data-hook="page-main") From ddb8265cf5442fd36bdc4d213cf85d1558a6aedd Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 26 Oct 2021 11:27:14 -0400 Subject: [PATCH 31/60] Added event listener to fire the clear logs function when clicked. --- client/views/main.js | 68 ++++---------------------------------------- 1 file changed, 5 insertions(+), 63 deletions(-) diff --git a/client/views/main.js b/client/views/main.js index c77d0ce9ce..d907c8d1a2 100644 --- a/client/views/main.js +++ b/client/views/main.js @@ -38,67 +38,6 @@ String.prototype.toHtmlEntities = function() { }); }; -let operationInfoModalHtml = (infoKey) => { - let fileBrowserInfo = ` -

In StochSS we use custom file extensions for a number of files we work with. Here is a list of our extentions with the files they are associated with:

- - - - - - - - - - - - - - - - - -
StochSS Model .mdl
StochSS Spatial Model .smdl
SBML Model .sbml
Workflows .wkfl
-
-

Other useful file extensions include the following:

- - - - - -
Jupyter Notebook .ipynb
- `; - let modelInfo = ` - Model Information - `; - let workflowInfo = ` - Workflow Information - `; - - let infoList = {"File Browser":fileBrowserInfo, "Models":modelInfo, "Workflows":workflowInfo} - - return ` - - ` -} - module.exports = View.extend({ template: bodyTemplate, autoRender: true, @@ -109,8 +48,8 @@ module.exports = View.extend({ }, events: { 'click [data-hook=registration-link-button]' : 'handleRegistrationLinkClick', - 'click [data-hook=user-logs-collapse]' : 'collapseExpandLogs' - //'click a[href]': 'handleLinkClick' + 'click [data-hook=user-logs-collapse]' : 'collapseExpandLogs', + 'click [data-hook=clear-user-logs]' : 'clearUserLogs' }, render: function () { @@ -172,6 +111,9 @@ module.exports = View.extend({ }); this.addNewLogBlock(); }, + clearUserLogs: function (e) { + console.log("Clearing the user logs"); + }, collapseExpandLogs: function (e) { let logs = $("#user-logs"); let classes = logs.attr("class").split(/\s+/); From b53b01794248e739d1d62723543f74ad5a104ff5 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 26 Oct 2021 11:37:46 -0400 Subject: [PATCH 32/60] Added an api handler and route to clear user logs. --- stochss/handlers/__init__.py | 1 + stochss/handlers/pages.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/stochss/handlers/__init__.py b/stochss/handlers/__init__.py index 30adcddd42..512ece0016 100644 --- a/stochss/handlers/__init__.py +++ b/stochss/handlers/__init__.py @@ -53,6 +53,7 @@ def get_page_handlers(route_start): ## API Handlers # (r'/stochss/api/user-logs\/?', UserLogsAPIHandler), + (r'/stochss/api/clear-user-logs\/?', ClearUserLogsAPIHandler), (r"/stochss/api/file/browser-list\/?", ModelBrowserFileList), (r"/stochss/api/file/upload\/?", UploadFileAPIHandler), (r"/stochss/api/file/upload-from-link\/?", UploadFileFromLinkAPIHandler), diff --git a/stochss/handlers/pages.py b/stochss/handlers/pages.py index 7ca148a5c0..fc1c5d660b 100644 --- a/stochss/handlers/pages.py +++ b/stochss/handlers/pages.py @@ -274,3 +274,21 @@ async def get(self): logs = [] self.write({"logs":logs}) self.finish() + + +class ClearUserLogsAPIHandler(APIHandler): + ''' + ################################################################################################ + Handler for clearing the user logs + ################################################################################################ + ''' + @web.authenticated + async def get(self): + ''' + Clear contents of the user log file. + + Attributes + ---------- + ''' + open(os.path.join(os.path.expanduser("~"), ".user-logs.txt"), "w").close() + self.finish() From a8523ae656d7266d59e3761a9fec165857717e94 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 26 Oct 2021 11:56:41 -0400 Subject: [PATCH 33/60] Added an xhr request to link client and server functions. --- client/views/main.js | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/client/views/main.js b/client/views/main.js index d907c8d1a2..22a5f4a9cd 100644 --- a/client/views/main.js +++ b/client/views/main.js @@ -71,18 +71,7 @@ module.exports = View.extend({ if(app.getBasePath() === "/") { $("#presentation-nav-link").css("display", "none"); } - let self = this; - let message = app.getBasePath() === "/" ? "Welcome to StochSS!" : "Welcome to StochSS Live!"; - $("#user-logs").html(message) - this.logBlock = []; - this.logs = []; - this.getUserLogs(); - this.scrolled = false; - this.scrollCount = 0; - $("#user-logs").on("mousewheel", function(e) { - self.scrolled = true; - self.scrollCount = 0; - }); + this.setupUserLogs(); return this; }, addNewLogBlock: function () { @@ -112,7 +101,12 @@ module.exports = View.extend({ this.addNewLogBlock(); }, clearUserLogs: function (e) { - console.log("Clearing the user logs"); + let endpoint = path.join(app.getApiPath(), "clear-user-logs"); + app.getXHR(endpoint, { + success: (err, response, body) => { + this.setupUserLogs({getLogs: false}); + } + }); }, collapseExpandLogs: function (e) { let logs = $("#user-logs"); @@ -191,6 +185,21 @@ module.exports = View.extend({ navigate: function (page) { window.location = url; }, + setupUserLogs: function ({getLogs = true}={}) { + let message = app.getBasePath() === "/" ? "Welcome to StochSS!" : "Welcome to StochSS Live!"; + $("#user-logs").html(message) + this.logBlock = []; + this.logs = []; + this.scrolled = false; + this.scrollCount = 0; + if(getLogs) { + this.getUserLogs(); + $("#user-logs").on("mousewheel", (e) => { + this.scrolled = true; + this.scrollCount = 0; + }); + } + }, updateUserLogs: function () { setTimeout(_.bind(this.getUserLogs, this), 1000); } From bf371baf6651fcecc80710a5e1fb3c7ad067dfc8 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 26 Oct 2021 13:20:10 -0400 Subject: [PATCH 34/60] Fixed issue with tokens in file names. Files issue with 404 errors being written as file bodies. --- stochss/handlers/util/stochss_folder.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/stochss/handlers/util/stochss_folder.py b/stochss/handlers/util/stochss_folder.py index fc3329f0c0..1e21d5afd6 100644 --- a/stochss/handlers/util/stochss_folder.py +++ b/stochss/handlers/util/stochss_folder.py @@ -539,6 +539,13 @@ def upload_from_link(self, remote_path, overwrite=False): body = json.dumps(json.loads(body)['notebook']) else: file = self.get_file(path=remote_path) + if "404: Not Found" in body.decode(): + message = f"Could not upload this file as {file} was not found." + if "?token=" in file: + message += " The token for this file may be out of date." + return {"message": message, "reason":"File Not Found"} + if "?token=" in file: + file = file.split("?token=")[0] path = self.get_new_path(dst_path=file) if os.path.exists(path): if not overwrite: @@ -575,6 +582,8 @@ def validate_upload_link(self, remote_path): body = json.dumps(json.loads(body)['notebook']) else: file = self.get_file(path=remote_path) + if "?token=" in file: + file = file.split("?token=")[0] path = self.get_new_path(dst_path=file) if ext == "zip": with zipfile.ZipFile(path, "r") as zip_file: From 72d613776fdfe1804416c6b75dcb39ef890d6313 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 26 Oct 2021 13:20:53 -0400 Subject: [PATCH 35/60] Fixed issue with homelink navigation. --- client/pages/loading-page.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/pages/loading-page.js b/client/pages/loading-page.js index 1b553faef3..be496cdced 100644 --- a/client/pages/loading-page.js +++ b/client/pages/loading-page.js @@ -91,7 +91,7 @@ let LoadingPage = PageView.extend({ $(self.queryByHook("loading-spinner")).css("display", "none"); let modal = $(modals.errorHtml(body.reason, body.message)).modal(); modal.on('hidden.bs.modal', function (e) { - window.location.href = this.homeLink; + window.location.href = self.homeLink; }); } app.getXHR(endpoint, { From b71bee665d21031e7d45c60348d1386fdb049afa Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 27 Oct 2021 08:52:58 -0400 Subject: [PATCH 36/60] Switch the logging FileHandler to RotatingFileHandler to allow for log file size control. Moved the location of the log files to /var/log. --- stochss/handlers/log.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stochss/handlers/log.py b/stochss/handlers/log.py index b8717443c2..a7a6b2fe77 100644 --- a/stochss/handlers/log.py +++ b/stochss/handlers/log.py @@ -57,7 +57,8 @@ def setup_file_handler(): Attributes ---------- ''' - handler = logging.FileHandler(".user-logs.txt") + handler = logging.RotatingFileHandler("/var/log/.user-logs.txt", + maxBytes=500000, backupCount=1) fmt = '%(asctime)s$ %(message)s' formatter = LogFormatter(fmt=fmt, datefmt="%b %d, %Y %I:%M %p UTC") handler.setFormatter(formatter) From 3e4221c6f42a43af7a4793964397f22c1ce7574b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 27 Oct 2021 10:58:08 -0400 Subject: [PATCH 37/60] Added function to relocate old log file to the new location and with the proper file size constraints. --- stochss/handlers/log.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/stochss/handlers/log.py b/stochss/handlers/log.py index a7a6b2fe77..e635f509d4 100644 --- a/stochss/handlers/log.py +++ b/stochss/handlers/log.py @@ -28,12 +28,46 @@ def init_log(): Attributes ---------- ''' + relocate_old_logs() setup_stream_handler() setup_file_handler() log.setLevel(logging.DEBUG) log.propagate = False +def relocate_old_logs(): + ''' + Move the user log file to its new location (/var/log). + ''' + src = os.path.join(os.path.expanduser("~"), ".user-logs.txt") + if not os.path.exists(src): + return + + src_size = os.path.getsize(src) + if src_size < 500000: + os.rename(src, "/var/log/user-logs.txt") + return + + with open(src, "r") as log_file: + logs = log_file.read().rstrip().split('\n') + os.remove(src) + + mlog_size = src_size % 500000 + mlogs = [logs.pop()] + while sys.getsizeof("\n".join(mlogs)) < mlog_size: + mlogs.insert(0, logs.pop()) + with open("/var/log/.user-logs.txt", "w") as main_log_file: + main_log_file.write("\n".join(mlogs)) + + blogs = [logs.pop()] + nlog_size = sys.getsizeof(f"\n{logs[-1]}") + while logs and sys.getsizeof("\n".join(blogs)) + nlog_size < 500000: + blogs.insert(0, logs.pop()) + nlog_size = sys.getsizeof(f"\n{logs[-1]}") + with open("/var/log/.user-logs.txt.bak", "w") as backup_log_file: + backup_log_file.write("\n".join(blogs)) + + def setup_stream_handler(): ''' Initialize the StochSS stream handler From f86bffc40719baa26cc7f3d10cdfb192cadd4df1 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 27 Oct 2021 11:01:55 -0400 Subject: [PATCH 38/60] Refactored the user logs api handler to pull from the new log file locations. --- stochss/handlers/pages.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/stochss/handlers/pages.py b/stochss/handlers/pages.py index fc1c5d660b..b5fe1e1947 100644 --- a/stochss/handlers/pages.py +++ b/stochss/handlers/pages.py @@ -264,11 +264,15 @@ async def get(self): ''' self.set_header('Content-Type', 'application/json') log_num = self.get_query_arguments(name="logNum")[0] - user_dir = os.path.expanduser("~") - path = os.path.join(user_dir, ".user-logs.txt") + path = os.path.join("/var/logs/.user-logs.txt") try: + if os.path.exists(f"{path}.bak"): + with open(path, "r") as log_file: + logs = log_file.read().strip().split("\n") + else: + logs = [] with open(path, "r") as log_file: - logs = log_file.read().strip().split("\n")[int(log_num):] + logs = logs.extend(log_file.read().strip().split("\n"))[int(log_num):] except FileNotFoundError: open(path, "w").close() logs = [] From 2fb17ad5e95d173fc7a080c3a4bf2c4af896715b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 27 Oct 2021 11:13:00 -0400 Subject: [PATCH 39/60] Added custom namer and rotator functions. --- stochss/handlers/log.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/stochss/handlers/log.py b/stochss/handlers/log.py index e635f509d4..80424fb30c 100644 --- a/stochss/handlers/log.py +++ b/stochss/handlers/log.py @@ -91,8 +91,37 @@ def setup_file_handler(): Attributes ---------- ''' + def namer(name): + ''' + Namer function for the RotatingFileHandler + + Attributes + ---------- + name : str + Default name of the log file. + ''' + return f"{name}.bak" + + def rotator(src, dst): + ''' + Rotator function for the RotatingFileHandler + + Attributes + ---------- + src : str + Path to the main log file. + dst : str + Path to the backup log file. + ''' + if os.path.exists(dst): + os.remove(dst) + os.rename(src, dst) + os.remove(src) + handler = logging.RotatingFileHandler("/var/log/.user-logs.txt", maxBytes=500000, backupCount=1) + handler.namer = namer + handler.rotator = rotator fmt = '%(asctime)s$ %(message)s' formatter = LogFormatter(fmt=fmt, datefmt="%b %d, %Y %I:%M %p UTC") handler.setFormatter(formatter) From f9b8fcd012f702b0f6bccb35e21dc05bdb829034 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 27 Oct 2021 11:44:38 -0400 Subject: [PATCH 40/60] Refactored the clear user logs api handler to remove the files in their new location. --- stochss/handlers/pages.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stochss/handlers/pages.py b/stochss/handlers/pages.py index b5fe1e1947..59f3e7b10f 100644 --- a/stochss/handlers/pages.py +++ b/stochss/handlers/pages.py @@ -294,5 +294,7 @@ async def get(self): Attributes ---------- ''' - open(os.path.join(os.path.expanduser("~"), ".user-logs.txt"), "w").close() + if os.path.exists("/var/log/.user-logs.txt.bak"): + os.remove("/var/log/.user-logs.txt.bak") + open("/var/log/.user-logs.txt", "w").close() self.finish() From d5410488dfa457030d6b4d6c11179c701b6cc109 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 27 Oct 2021 11:46:08 -0400 Subject: [PATCH 41/60] Added missing imports. Added missing handlers reference. --- stochss/handlers/log.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/stochss/handlers/log.py b/stochss/handlers/log.py index 80424fb30c..84760427d8 100644 --- a/stochss/handlers/log.py +++ b/stochss/handlers/log.py @@ -16,6 +16,8 @@ along with this program. If not, see . ''' +import os +import sys import logging from tornado.log import LogFormatter @@ -42,16 +44,16 @@ def relocate_old_logs(): src = os.path.join(os.path.expanduser("~"), ".user-logs.txt") if not os.path.exists(src): return - + src_size = os.path.getsize(src) if src_size < 500000: os.rename(src, "/var/log/user-logs.txt") return - + with open(src, "r") as log_file: logs = log_file.read().rstrip().split('\n') os.remove(src) - + mlog_size = src_size % 500000 mlogs = [logs.pop()] while sys.getsizeof("\n".join(mlogs)) < mlog_size: @@ -118,8 +120,8 @@ def rotator(src, dst): os.rename(src, dst) os.remove(src) - handler = logging.RotatingFileHandler("/var/log/.user-logs.txt", - maxBytes=500000, backupCount=1) + handler = logging.handlers.RotatingFileHandler("/var/log/.user-logs.txt", + maxBytes=500000, backupCount=1) handler.namer = namer handler.rotator = rotator fmt = '%(asctime)s$ %(message)s' From 69fd1a1787ced402d617c2c4ae05dd69a2958c95 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 27 Oct 2021 12:39:36 -0400 Subject: [PATCH 42/60] Moved the log location back to the users home directory to fix permission errors. Fixed TypeError. --- stochss/handlers/log.py | 15 +++++++-------- stochss/handlers/pages.py | 12 +++++++----- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/stochss/handlers/log.py b/stochss/handlers/log.py index 84760427d8..c082d97c90 100644 --- a/stochss/handlers/log.py +++ b/stochss/handlers/log.py @@ -41,24 +41,23 @@ def relocate_old_logs(): ''' Move the user log file to its new location (/var/log). ''' - src = os.path.join(os.path.expanduser("~"), ".user-logs.txt") + user_dir = os.path.expanduser("~") + src = os.path.join(user_dir, ".user-logs.txt") if not os.path.exists(src): return src_size = os.path.getsize(src) if src_size < 500000: - os.rename(src, "/var/log/user-logs.txt") return with open(src, "r") as log_file: logs = log_file.read().rstrip().split('\n') - os.remove(src) - + mlog_size = src_size % 500000 mlogs = [logs.pop()] while sys.getsizeof("\n".join(mlogs)) < mlog_size: mlogs.insert(0, logs.pop()) - with open("/var/log/.user-logs.txt", "w") as main_log_file: + with open(os.path.join(user_dir, ".user-logs.txt"), "w") as main_log_file: main_log_file.write("\n".join(mlogs)) blogs = [logs.pop()] @@ -66,7 +65,7 @@ def relocate_old_logs(): while logs and sys.getsizeof("\n".join(blogs)) + nlog_size < 500000: blogs.insert(0, logs.pop()) nlog_size = sys.getsizeof(f"\n{logs[-1]}") - with open("/var/log/.user-logs.txt.bak", "w") as backup_log_file: + with open(os.path.join(user_dir, ".user-logs.txt.bak"), "w") as backup_log_file: backup_log_file.write("\n".join(blogs)) @@ -120,8 +119,8 @@ def rotator(src, dst): os.rename(src, dst) os.remove(src) - handler = logging.handlers.RotatingFileHandler("/var/log/.user-logs.txt", - maxBytes=500000, backupCount=1) + path = os.path.join(os.path.expanduser("~"), ".user-logs.txt") + handler = logging.handlers.RotatingFileHandler(path, maxBytes=500000, backupCount=1) handler.namer = namer handler.rotator = rotator fmt = '%(asctime)s$ %(message)s' diff --git a/stochss/handlers/pages.py b/stochss/handlers/pages.py index 59f3e7b10f..ba03c27060 100644 --- a/stochss/handlers/pages.py +++ b/stochss/handlers/pages.py @@ -264,7 +264,7 @@ async def get(self): ''' self.set_header('Content-Type', 'application/json') log_num = self.get_query_arguments(name="logNum")[0] - path = os.path.join("/var/logs/.user-logs.txt") + path = os.path.join(os.path.expanduser("~"), ".user-logs.txt") try: if os.path.exists(f"{path}.bak"): with open(path, "r") as log_file: @@ -272,7 +272,8 @@ async def get(self): else: logs = [] with open(path, "r") as log_file: - logs = logs.extend(log_file.read().strip().split("\n"))[int(log_num):] + logs.extend(log_file.read().strip().split("\n")) + logs = logs[int(log_num):] except FileNotFoundError: open(path, "w").close() logs = [] @@ -294,7 +295,8 @@ async def get(self): Attributes ---------- ''' - if os.path.exists("/var/log/.user-logs.txt.bak"): - os.remove("/var/log/.user-logs.txt.bak") - open("/var/log/.user-logs.txt", "w").close() + path = os.path.join(os.path.expanduser("~"), ".user-logs.txt") + if os.path.exists(f'{path}.bak'): + os.remove(f'{path}.bak') + open(path, "w").close() self.finish() From 97c87840d500fe70fe9db297037ab841fe1db78b Mon Sep 17 00:00:00 2001 From: seanebum Date: Wed, 27 Oct 2021 13:37:32 -0400 Subject: [PATCH 43/60] added directory of GillesPy2 and SpatialPy examples --- EXAMPLE_DIRECTORY.md | 90 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 EXAMPLE_DIRECTORY.md diff --git a/EXAMPLE_DIRECTORY.md b/EXAMPLE_DIRECTORY.md new file mode 100644 index 0000000000..973c55f43c --- /dev/null +++ b/EXAMPLE_DIRECTORY.md @@ -0,0 +1,90 @@ +#Example Directory + +This file contains a directory to all GillesPy2 and SpatialPy example notebooks. + +##GillesPy2 + +["Start Here" Model](https://github.com/StochSS/GillesPy2/blob/main/examples/StartHere.ipynb) + +###Starting Models + +- [Michaelis Menten](https://github.com/StochSS/GillesPy2/tree/main/examples/StartingModels/MichaelisMenten) + - [SSA C Solver](https://github.com/StochSS/GillesPy2/blob/main/examples/StartingModels/MichaelisMenten/Michaelis-Menten_SSA_C.ipynb) + - [SSA NumPy Solver](https://github.com/StochSS/GillesPy2/blob/main/examples/StartingModels/MichaelisMenten/Michaelis-Menten_NumPy_SSA.ipynb) + - [Tau Leaping NumPy](https://github.com/StochSS/GillesPy2/blob/main/examples/StartingModels/MichaelisMenten/Michaelis-Menten_Basic_Tau_Leaping.ipynb) + - [Tau Hybrid NumPy](https://github.com/StochSS/GillesPy2/blob/main/examples/StartingModels/MichaelisMenten/Michaelis-Menten_Basic_Tau_Hybrid.ipynb) + +- [Vilar Oscillator](https://github.com/StochSS/GillesPy2/tree/main/examples/StartingModels/VilarOscillator) + - [SSA](https://github.com/StochSS/GillesPy2/blob/main/examples/StartingModels/VilarOscillator/VilarOscillator_SSA.ipynb) + - [Tau Leaping](https://github.com/StochSS/GillesPy2/blob/main/examples/StartingModels/VilarOscillator/VilarOscillator_Tau_Leaping.ipynb) + - [Tau Hybrid](https://github.com/StochSS/GillesPy2/blob/main/examples/StartingModels/VilarOscillator/VilarOscillator_Tau_Hybrid.ipynb) + + +###Results Management + +- [Basic Results Management](https://github.com/StochSS/GillesPy2/blob/main/examples/ResultsManagement/basic-results-management.ipynb) +- [Single Trajectory to CSV](https://github.com/StochSS/GillesPy2/blob/main/examples/ResultsManagement/to_csv-single-trajectory.ipynb) +- [Multiple Trajectories to CSV](https://github.com/StochSS/GillesPy2/blob/main/examples/ResultsManagement/to_csv-multi-trajectory.ipynb) +- [Using Pickle](https://github.com/StochSS/GillesPy2/blob/main/examples/ResultsManagement/using-pickle.ipynb) + + +###Data Visualization + +- [Data Visualization](https://github.com/StochSS/GillesPy2/blob/main/examples/DataVisualization/DataVisualization.ipynb) +- [Live Output](https://github.com/StochSS/GillesPy2/blob/main/examples/DataVisualization/LiveOutput.ipynb) + + +###Advanced Features + +- [Events](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/Events.ipynb) +- [Kinetic Model for Styrene Polymerization](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/KineticModelForStyrenePolymerization.ipynb) +- [Photosynthesis](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/Photosynthesis.ipynb) +- [GillesPy2 in Parallel](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/Run%20GillesPy2%20Simulations%20in%20Parallel.ipynb) +- [SBML Import](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/SBML_Import_Test.ipynb) +- [Variable Inputs (SSA)](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/Variable_SSA_C_Example.ipynb) +- [Volume Test](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/Volume_test.py) +- [Hybrid Continuous Species](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/hybrid_continuous_species.ipynb) +- [Hybrid Switching](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/hybrid_switching_example.ipynb) +- [Parameter Changing](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/parameter_changing.py) + + +###Extra Models + +- [Brusselator](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/Brusselator.ipynb) +- [Genetic Toggle Switch](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/GeneticToggleSwitch.ipynb) +- [Opioid Model](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/Opioid_Model.ipynb) +- [Oregonator](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/Oregonator.ipynb) +- [Tyson Oscillator](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/Tyson%20Oscillator.ipynb) +- [Degradation Model](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/degradation_example.py) +- [Dimer Model](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/dimer_example.py) +- [Tyson Oscillator](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/tyson_oscillator.py) + + + +##SpatialPy + +###General Examples + +- [Bistable Elf Ehrenberg](https://github.com/StochSS/SpatialPy/blob/develop/examples/Bistable_Biochem_Elf_Ehrenberg/Bistable_Biochem_Elf_Ehrenberg.ipynb) +- [Boundary Conditions](https://github.com/StochSS/SpatialPy/blob/develop/examples/BoundaryCondition/BoundaryCondition.ipynb) +- [SpatialPy Gravity](https://github.com/StochSS/SpatialPy/blob/develop/examples/Gravity/Spatialpy_gravity.ipynb) +- [Coral Reef](https://github.com/StochSS/SpatialPy/blob/develop/examples/coral_reef/CoralModel.ipynb) +- [3D Cylinder Diffusion](https://github.com/StochSS/SpatialPy/blob/develop/examples/cylinderDemo/SpatialPy_cylinderDemo3D.ipynb) +- [hes1](https://github.com/StochSS/SpatialPy/blob/develop/examples/hes1/hes1.ipynb) +- [Lid Driven Cavity](https://github.com/StochSS/SpatialPy/blob/develop/examples/lid_driven_cavity/Lid%20driven%20cavity.ipynb) +- [MinCDE](https://github.com/StochSS/SpatialPy/blob/develop/examples/mincde/mincde.ipynb) +- [Turing Pattern (Old)](https://github.com/StochSS/SpatialPy/blob/develop/examples/turing_pattern/turing_pattern.ipynb) +- [Turing Pattern (New)](https://github.com/StochSS/SpatialPy/blob/develop/examples/turing_pattern/new_turing_pattern.ipynb) +- [Weir](https://github.com/StochSS/SpatialPy/blob/develop/examples/weir/weir.ipynb) +- [Yeast Polarization](https://github.com/StochSS/SpatialPy/tree/develop/examples/yeast_polarization) + - [G-Protein 1D](https://github.com/StochSS/SpatialPy/blob/develop/examples/yeast_polarization/G-Protein_1D.ipynb) + - [Polarisome 1D](https://github.com/StochSS/SpatialPy/blob/develop/examples/yeast_polarization/Polarisome_1D.ipynb) + - [cdc42](https://github.com/StochSS/SpatialPy/blob/develop/examples/yeast_polarization/cdc42.ipynb) + +###Tests + +- [Diffusion Validation](https://github.com/StochSS/SpatialPy/blob/develop/examples/tests/Diffusion_validation.ipynb) +- [Spatial Birth-Death](https://github.com/StochSS/SpatialPy/blob/develop/examples/tests/Spatial_Birth_Death.ipynb) +- [Compile Time Test](https://github.com/StochSS/SpatialPy/blob/develop/examples/tests/compile_time_comparison.ipynb) +- [Read Meshes](https://github.com/StochSS/SpatialPy/blob/develop/examples/tests/read_meshes.ipynb) + From d630ec01b2f3aa41692d5cb75497b89ec8e8b78f Mon Sep 17 00:00:00 2001 From: Sean Matthew Date: Wed, 27 Oct 2021 13:41:27 -0400 Subject: [PATCH 44/60] fixed some spacing --- EXAMPLE_DIRECTORY.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/EXAMPLE_DIRECTORY.md b/EXAMPLE_DIRECTORY.md index 973c55f43c..03713a95fc 100644 --- a/EXAMPLE_DIRECTORY.md +++ b/EXAMPLE_DIRECTORY.md @@ -1,12 +1,12 @@ -#Example Directory +# Example Directory This file contains a directory to all GillesPy2 and SpatialPy example notebooks. -##GillesPy2 +## GillesPy2 ["Start Here" Model](https://github.com/StochSS/GillesPy2/blob/main/examples/StartHere.ipynb) -###Starting Models +### Starting Models - [Michaelis Menten](https://github.com/StochSS/GillesPy2/tree/main/examples/StartingModels/MichaelisMenten) - [SSA C Solver](https://github.com/StochSS/GillesPy2/blob/main/examples/StartingModels/MichaelisMenten/Michaelis-Menten_SSA_C.ipynb) @@ -20,7 +20,7 @@ This file contains a directory to all GillesPy2 and SpatialPy example notebooks. - [Tau Hybrid](https://github.com/StochSS/GillesPy2/blob/main/examples/StartingModels/VilarOscillator/VilarOscillator_Tau_Hybrid.ipynb) -###Results Management +### Results Management - [Basic Results Management](https://github.com/StochSS/GillesPy2/blob/main/examples/ResultsManagement/basic-results-management.ipynb) - [Single Trajectory to CSV](https://github.com/StochSS/GillesPy2/blob/main/examples/ResultsManagement/to_csv-single-trajectory.ipynb) @@ -28,13 +28,13 @@ This file contains a directory to all GillesPy2 and SpatialPy example notebooks. - [Using Pickle](https://github.com/StochSS/GillesPy2/blob/main/examples/ResultsManagement/using-pickle.ipynb) -###Data Visualization +### Data Visualization - [Data Visualization](https://github.com/StochSS/GillesPy2/blob/main/examples/DataVisualization/DataVisualization.ipynb) - [Live Output](https://github.com/StochSS/GillesPy2/blob/main/examples/DataVisualization/LiveOutput.ipynb) -###Advanced Features +### Advanced Features - [Events](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/Events.ipynb) - [Kinetic Model for Styrene Polymerization](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/KineticModelForStyrenePolymerization.ipynb) @@ -48,7 +48,7 @@ This file contains a directory to all GillesPy2 and SpatialPy example notebooks. - [Parameter Changing](https://github.com/StochSS/GillesPy2/blob/main/examples/AdvancedFeatures/parameter_changing.py) -###Extra Models +### Extra Models - [Brusselator](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/Brusselator.ipynb) - [Genetic Toggle Switch](https://github.com/StochSS/GillesPy2/blob/main/examples/ExtraModels/GeneticToggleSwitch.ipynb) @@ -61,9 +61,9 @@ This file contains a directory to all GillesPy2 and SpatialPy example notebooks. -##SpatialPy +## SpatialPy -###General Examples +### General Examples - [Bistable Elf Ehrenberg](https://github.com/StochSS/SpatialPy/blob/develop/examples/Bistable_Biochem_Elf_Ehrenberg/Bistable_Biochem_Elf_Ehrenberg.ipynb) - [Boundary Conditions](https://github.com/StochSS/SpatialPy/blob/develop/examples/BoundaryCondition/BoundaryCondition.ipynb) @@ -81,7 +81,7 @@ This file contains a directory to all GillesPy2 and SpatialPy example notebooks. - [Polarisome 1D](https://github.com/StochSS/SpatialPy/blob/develop/examples/yeast_polarization/Polarisome_1D.ipynb) - [cdc42](https://github.com/StochSS/SpatialPy/blob/develop/examples/yeast_polarization/cdc42.ipynb) -###Tests +### Tests - [Diffusion Validation](https://github.com/StochSS/SpatialPy/blob/develop/examples/tests/Diffusion_validation.ipynb) - [Spatial Birth-Death](https://github.com/StochSS/SpatialPy/blob/develop/examples/tests/Spatial_Birth_Death.ipynb) From 3a348cd12182ad04db3e13ec61a3be71959c5c4e Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 08:51:35 -0400 Subject: [PATCH 45/60] Updated the GillesPy2 version. Switched Sciope to the github master branch. Switched SpatialPy to the github develop branch. --- requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index a5b7759e21..ef68e8a1a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,8 @@ python-libsbml==5.18.0 python-libsedml==2.0.9 python-libcombine==0.2.7 escapism==1.0.1 -gillespy2==1.6.3 -sciope==0.4 +gillespy2==1.6.5 +git+https://github.com/StochSS/sciope.git@master pygmsh==5.0.2 meshio==2.3.10 -git+https://github.com/spatialpy/SpatialPy.git@main +git+https://github.com/StochSS/SpatialPy.git@develop From f4f74719fc76dcaa993ef09d2cccfa928713a648 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 09:16:18 -0400 Subject: [PATCH 46/60] Replaced uses of deprecated 'Parameter.set_expression()' with 'Parameter.expression = '. --- stochss/handlers/util/parameter_scan.py | 2 +- stochss/handlers/util/parameter_sweep_1d.py | 2 +- stochss/handlers/util/parameter_sweep_2d.py | 4 ++-- stochss/handlers/util/parameter_sweep_notebook.py | 6 +++--- stochss/handlers/util/sciope_notebook.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/stochss/handlers/util/parameter_scan.py b/stochss/handlers/util/parameter_scan.py index f1871b6138..a3c914b277 100644 --- a/stochss/handlers/util/parameter_scan.py +++ b/stochss/handlers/util/parameter_scan.py @@ -86,7 +86,7 @@ def __setup_model(self, variables): return self.model tmp_mdl = copy.deepcopy(self.model) for name, value in variables.items(): - tmp_mdl.listOfParameters[name].set_expression(value) + tmp_mdl.listOfParameters[name].expression = value return tmp_mdl diff --git a/stochss/handlers/util/parameter_sweep_1d.py b/stochss/handlers/util/parameter_sweep_1d.py index 14e0d2b3df..f93feaa49b 100644 --- a/stochss/handlers/util/parameter_sweep_1d.py +++ b/stochss/handlers/util/parameter_sweep_1d.py @@ -150,7 +150,7 @@ def run(self, job_id, verbose=False): self.settings['variables'] = {self.param['parameter']:val} else: tmp_mdl = copy.deepcopy(self.model) - tmp_mdl.listOfParameters[self.param['parameter']].set_expression(val) + tmp_mdl.listOfParameters[self.param['parameter']].expression = val if verbose: log.info(f"{job_id} --> running: {self.param['parameter']}={val}") try: diff --git a/stochss/handlers/util/parameter_sweep_2d.py b/stochss/handlers/util/parameter_sweep_2d.py index f4cd173d57..abbee80cfd 100644 --- a/stochss/handlers/util/parameter_sweep_2d.py +++ b/stochss/handlers/util/parameter_sweep_2d.py @@ -153,8 +153,8 @@ def run(self, job_id, verbose=False): self.settings['variables'] = variables else: tmp_mdl = copy.deepcopy(self.model) - tmp_mdl.listOfParameters[self.params[0]['parameter']].set_expression(val1) - tmp_mdl.listOfParameters[self.params[1]['parameter']].set_expression(val2) + tmp_mdl.listOfParameters[self.params[0]['parameter']].expression = val1 + tmp_mdl.listOfParameters[self.params[1]['parameter']].expression = val2 if verbose: message = f"{job_id} --> running: {self.params[0]['parameter']}={val1}, " message += f"{self.params[1]['parameter']}={val2}" diff --git a/stochss/handlers/util/parameter_sweep_notebook.py b/stochss/handlers/util/parameter_sweep_notebook.py index 75f586e1c3..165790df63 100644 --- a/stochss/handlers/util/parameter_sweep_notebook.py +++ b/stochss/handlers/util/parameter_sweep_notebook.py @@ -128,7 +128,7 @@ def __create_1d_run_str(self): else: res_str += "tmp_model.run(**kwargs)" run_strs.extend([f"{pad*3}tmp_model = c.ps_class()", - f"{pad*3}tmp_model.listOfParameters[c.p1].set_expression(v1)"]) + f"{pad*3}tmp_model.listOfParameters[c.p1].expression = v1"]) run_strs.extend([f"{pad*3}if c.verbose:", pad * 4 + "print(f'running {c.p1}={v1}')", f"{pad*3}if(c.number_of_trajectories > 1):", @@ -252,8 +252,8 @@ def __create_2d_run_str(self): else: res_str += "tmp_model.run(**kwargs)" run_strs.extend([f"{pad*4}tmp_model = c.ps_class()", - f"{pad*4}tmp_model.listOfParameters[c.p1].set_expression(v1)", - f"{pad*4}tmp_model.listOfParameters[c.p2].set_expression(v2)"]) + f"{pad*4}tmp_model.listOfParameters[c.p1].expression = v1", + f"{pad*4}tmp_model.listOfParameters[c.p2].expression = v2"]) run_strs.extend([f"{pad*4}if c.verbose:", pad * 5 + "print(f'running {c.p1}={v1}, {c.p2}={v2}')", f"{pad*4}if(c.number_of_trajectories > 1):", diff --git a/stochss/handlers/util/sciope_notebook.py b/stochss/handlers/util/sciope_notebook.py index a3ec3b7625..ecfbc87234 100644 --- a/stochss/handlers/util/sciope_notebook.py +++ b/stochss/handlers/util/sciope_notebook.py @@ -141,7 +141,7 @@ def __create_mi_simulator_cell(self): run = f"{pad}res = model.run(**kwargs, variables=variables)" else: func_def = "def set_model_parameters(params, model):" - body = f"{pad*2}model.get_parameter(pname).set_expression(params[e])" + body = f"{pad*2}model.get_parameter(pname).expression = params[e]" return_str = f"{pad}return model" call = f"{pad}model_update = set_model_parameters(params, model)" run = f"{pad}res = model_update.run(**kwargs)" From 88b20a482db9360cf7734e821ac5bac6f06d70a6 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 09:45:53 -0400 Subject: [PATCH 47/60] Updated the 'Mesh' to 'Domain' and added 'rho' and 'c' to the domain builder function . --- .../handlers/util/stochss_spatial_model.py | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 75422c62c3..d16f7979ef 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -26,7 +26,7 @@ import numpy import plotly from escapism import escape -from spatialpy import Model, Species, Parameter, Reaction, Mesh, MeshError, BoundaryCondition, \ +from spatialpy import Model, Species, Parameter, Reaction, Domain, DomainError, BoundaryCondition, \ PlaceInitialCondition, UniformInitialCondition, ScatterInitialCondition from .stochss_base import StochSSBase @@ -163,9 +163,9 @@ def __convert_domain(self, model): gravity = self.model['domain']['gravity'] if gravity == [0, 0, 0]: gravity = None - mesh = Mesh(0, xlim, ylim, zlim, rho0=rho0, c0=c_0, P0=p_0, gravity=gravity) - self.__convert_particles(mesh=mesh) - model.add_mesh(mesh) + domain = Domain(0, xlim, ylim, zlim, rho0=rho0, c0=c_0, P0=p_0, gravity=gravity) + self.__convert_particles(domain=domain) + model.add_domain(domain) model.staticDomain = self.model['domain']['static'] except KeyError as err: message = "Spatial model domain properties are not properly formatted or " @@ -221,11 +221,12 @@ def __convert_parameters(self, model): raise StochSSModelFormatError(message, traceback.format_exc()) from err - def __convert_particles(self, mesh): + def __convert_particles(self, domain): try: for particle in self.model['domain']['particles']: - mesh.add_point(particle['point'], particle['volume'], particle['mass'], - particle['type'], particle['nu'], particle['fixed']) + domain.add_point(particle['point'], particle['volume'], particle['mass'], + particle['type'], particle['nu'], particle['fixed'], + particle['rho'], particle['c']) except KeyError as err: message = "Spatial model domain particle properties are not properly formatted or " message += f"are referenced incorrectly: {str(err)}" @@ -321,7 +322,7 @@ def __load_domain_from_file(self, path): if path.endswith(".domn"): with open(path, "r") as domain_file: return json.load(domain_file) - s_domain = Mesh.read_xml_mesh(filename=path) + s_domain = Domain.read_xml_mesh(filename=path) return self.__build_stochss_domain(s_domain=s_domain) except FileNotFoundError as err: message = f"Could not find the domain file: {str(err)}" @@ -329,7 +330,7 @@ def __load_domain_from_file(self, path): except json.decoder.JSONDecodeError as err: message = f"The domain file is not JSON decobable: {str(err)}" raise FileNotJSONFormatError(message, traceback.format_exc()) from err - except MeshError as err: + except DomainError as err: message = f"The domain file is not in proper format: {str(err)}" raise DomainFormatError(message, traceback.format_exc()) from err @@ -346,6 +347,18 @@ def __read_model_file(self): raise FileNotJSONFormatError(message, traceback.format_exc()) from err + def __update_domain(self): + 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(): + self.model['domain']['static'] = True + if "rho" not in self.model['domain']['particles'][0].keys() or \ + "c" not in self.model['domain']['particles'][0].keys(): + for particle in self.model['domain']['particles']: + particle['rho'] = particle['mass']/particle['vol'] + particle['c'] = 10 + + def convert_to_model(self): ''' Convert a spatial model to a non_spatial model @@ -490,8 +503,8 @@ def get_particles_from_3d_domain(cls, data): xlim = [coord + data['transformation'][0] for coord in data['xLim']] ylim = [coord + data['transformation'][1] for coord in data['yLim']] zlim = [coord + data['transformation'][2] for coord in data['zLim']] - s_domain = Mesh.create_3D_domain(xlim=xlim, ylim=ylim, zlim=zlim, nx=data['nx'], - ny=data['ny'], nz=data['nz'], **data['type']) + s_domain = Domain.create_3D_domain(xlim=xlim, ylim=ylim, zlim=zlim, nx=data['nx'], + ny=data['ny'], nz=data['nz'], **data['type']) domain = cls.__build_stochss_domain(s_domain=s_domain) limits = {"x_lim":domain['x_lim'], "y_lim":domain['y_lim'], "z_lim":domain['z_lim']} return {"particles":domain['particles'], "limits":limits} @@ -512,9 +525,9 @@ def get_particles_from_remote(cls, mesh, data, types): List of type discriptions (lines from an uploaded file) ''' file = tempfile.NamedTemporaryFile() - with open(file.name, "w") as mesh_file: - mesh_file.write(mesh) - s_domain = Mesh.read_xml_mesh(filename=file.name) + with open(file.name, "w") as domain_file: + domain_file.write(mesh) + s_domain = Domain.read_xml_mesh(filename=file.name) domain = cls.__build_stochss_domain(s_domain=s_domain, data=data) if types is not None: type_data = cls.get_types_from_file(lines=types) @@ -576,10 +589,7 @@ def load(self): self.model['defaultMode'] = "discrete" if "timestepSize" not in self.model['modelSettings'].keys(): 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(): - self.model['domain']['static'] = True + self.__update_domain() if "boundaryConditions" not in self.model.keys(): self.model['boundaryConditions'] = [] for species in self.model['species']: From a67726d18cb4b5f22768fbabbeb5d62e25821490 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 09:48:04 -0400 Subject: [PATCH 48/60] Replaced the 'mesh' reference with 'domain' in docs. --- stochss/handlers/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index 5c4152c8f7..acd9986323 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -265,7 +265,7 @@ async def get(self): class ImportMeshAPIHandler(APIHandler): ''' ################################################################################################ - Handler for importing mesh particles from remote file. + Handler for importing domain particles from remote file. ################################################################################################ ''' @web.authenticated From ef776765062d4909291c04351d1e1119e0f32e3b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 09:53:51 -0400 Subject: [PATCH 49/60] Updated notebook class to use 'Domain', instead of 'Mesh'. --- stochss/handlers/util/stochss_notebook.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/stochss/handlers/util/stochss_notebook.py b/stochss/handlers/util/stochss_notebook.py index 5403f9da5d..cfd722dd0d 100644 --- a/stochss/handlers/util/stochss_notebook.py +++ b/stochss/handlers/util/stochss_notebook.py @@ -222,8 +222,8 @@ def __create_import_cell(self): imports = ["import numpy as np"] if self.s_model['is_spatial']: imports.append("import spatialpy") - imports.append("from spatialpy import Model, Species, Parameter, Reaction, Mesh,\\") - imports.append(" PlaceInitialCondition, \\") + imports.append("from spatialpy import Model, Species, Parameter, Reaction,\\") + imports.append(" Domain, PlaceInitialCondition, \\") imports.append(" UniformInitialCondition, \\") imports.append(" ScatterInitialCondition") return nbf.new_code_cell("\n".join(imports)) @@ -275,12 +275,12 @@ def __create_initial_condition_strings(self, model, pad): raise StochSSModelFormatError(message, traceback.format_exc()) from err - def __create_mesh_string(self, model, pad): - mesh = ["", f"{pad}# Domain", - f"{pad}mesh = Mesh.read_stochss_domain('{self.s_model['path']}')", - f"{pad}self.add_mesh(mesh)", - "", f"{pad}self.staticDomain = {self.s_model['domain']['static']}"] - model.extend(mesh) + def __create_domain_string(self, model, pad): + domain = ["", f"{pad}# Domain", + f"{pad}domain = Domain.read_stochss_domain('{self.s_model['path']}')", + f"{pad}self.add_mesh(domain)", + "", f"{pad}self.staticDomain = {self.s_model['domain']['static']}"] + model.extend(domain) def __create_model_cell(self): @@ -289,7 +289,7 @@ def __create_model_cell(self): model = [f"class {self.get_class_name()}(Model):", " def __init__(self):", f'{pad}Model.__init__(self, name="{self.get_name()}")'] - self.__create_mesh_string(model=model, pad=pad) + self.__create_domain_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) From f0ce895655b0ce704740b8440b4db187dc27b4d4 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 10:02:38 -0400 Subject: [PATCH 50/60] Additional updates to domain. --- .../handlers/util/stochss_spatial_model.py | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index d16f7979ef..f4b7f84279 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -93,7 +93,7 @@ def expression(self): # pylint: disable=no-self-use def __build_stochss_domain(cls, s_domain, data=None): particles = cls.__build_stochss_domain_particles(s_domain=s_domain, data=data) gravity = [0] * 3 if s_domain.gravity is None else s_domain.gravity - domain = {"size":s_domain.mesh_size, + domain = {"size":s_domain.domain_size, "rho_0":s_domain.rho0, # density "c_0":s_domain.c0, # approx./artificial speed of sound "p_0":s_domain.P0, # atmos/background pressure @@ -136,6 +136,8 @@ def __build_stochss_domain_particles(cls, s_domain, data=None): "mass":s_domain.mass[i], "type":type_id, "nu":viscosity, + "rho":s_domain.rho[i], + "c":s_domain[i], "fixed":fixed} particles.append(particle) return particles @@ -438,37 +440,26 @@ def get_domain(self, path=None, new=False): return self.__load_domain_from_file(path=path) - def get_domain_plot(self, domain=None, path=None, new=False): + def get_domain_plot(self, path=None, new=False): ''' Get a plotly plot of the models domain or a prospective domain Attributes ---------- - domain : dict - The domain to be plotted path : str Path to a prospective domain new : bool Indicates whether or not to load an new domain ''' - if domain is None: - domain = self.get_domain(path=path, new=new) - trace_list = [] - for i, d_type in enumerate(domain['types']): - if len(domain['types']) > 1: - particles = list(filter(lambda particle, key=i: particle['type'] == key, - domain['particles'])) - else: - particles = domain['particles'] - trace = self.__get_trace_data(particles=particles, name=d_type['name']) - trace_list.append(trace) - layout = {"scene":{"aspectmode":'data'}, "autosize":True} - if len(domain['x_lim']) == 2: - layout["xaxis"] = {"range":domain['x_lim']} - if len(domain['y_lim']) == 2: - layout["yaxis"] = {"range":domain['y_lim']} - return json.dumps({"data":trace_list, "layout":layout, "config":{"responsive":True}}, - cls=plotly.utils.PlotlyJSONEncoder) + if new: + path = '/stochss/stochss_templates/nonSpatialModelTemplate.json' + elif path is None: + path = self.path + domain = Domain.read_stochss_domain(path) + fig = domain.plot_types(return_plotly_figure=True) + fig['layout']['autosize'] = True + fig['config'] = {"responsive":True} + return json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder) def get_notebook_data(self): From b946366130fa1480aa11e946304fd11b05f06f61 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 10:30:35 -0400 Subject: [PATCH 51/60] Fixed domain plot issue. --- stochss/handlers/util/stochss_spatial_model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index f4b7f84279..76de0c5a60 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -357,7 +357,7 @@ def __update_domain(self): if "rho" not in self.model['domain']['particles'][0].keys() or \ "c" not in self.model['domain']['particles'][0].keys(): for particle in self.model['domain']['particles']: - particle['rho'] = particle['mass']/particle['vol'] + particle['rho'] = particle['mass']/particle['volume'] particle['c'] = 10 @@ -457,6 +457,8 @@ def get_domain_plot(self, path=None, new=False): path = self.path domain = Domain.read_stochss_domain(path) fig = domain.plot_types(return_plotly_figure=True) + if not fig['data']: + self.__get_trace_data(particles=[], name="Un-Assigned") fig['layout']['autosize'] = True fig['config'] = {"responsive":True} return json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder) From 90ba7719f4f43a899c5e7dbb15b064fa605442a4 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 10:34:34 -0400 Subject: [PATCH 52/60] Fixed domain plot issue take two. --- stochss/handlers/util/stochss_spatial_model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 76de0c5a60..bb57535bea 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -458,7 +458,9 @@ def get_domain_plot(self, path=None, new=False): domain = Domain.read_stochss_domain(path) fig = domain.plot_types(return_plotly_figure=True) if not fig['data']: - self.__get_trace_data(particles=[], name="Un-Assigned") + fig['data'].append(self.__get_trace_data(particles=[], name="Un-Assigned")) + fig['width'] = None + fig['height'] = None fig['layout']['autosize'] = True fig['config'] = {"responsive":True} return json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder) From 68b9899d601d974b164aa720a632aee1dc20003d Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 10:37:24 -0400 Subject: [PATCH 53/60] Fixed domain plot layout issue. --- stochss/handlers/util/stochss_spatial_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index bb57535bea..422ac5f7db 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -459,8 +459,8 @@ def get_domain_plot(self, path=None, new=False): fig = domain.plot_types(return_plotly_figure=True) if not fig['data']: fig['data'].append(self.__get_trace_data(particles=[], name="Un-Assigned")) - fig['width'] = None - fig['height'] = None + fig['layout']['width'] = None + fig['layout']['height'] = None fig['layout']['autosize'] = True fig['config'] = {"responsive":True} return json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder) From 1762aecff207069f6bb6ca21c9ded833bb7fd4b5 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 10:40:55 -0400 Subject: [PATCH 54/60] Fixed issue with per particle speed of sound ref. --- stochss/handlers/util/stochss_spatial_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 422ac5f7db..86ce8237b7 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -137,7 +137,7 @@ def __build_stochss_domain_particles(cls, s_domain, data=None): "type":type_id, "nu":viscosity, "rho":s_domain.rho[i], - "c":s_domain[i], + "c":s_domain.c[i], "fixed":fixed} particles.append(particle) return particles From 75320f5b5f2aa55c94d292a0a997b098df9ba830 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 2 Nov 2021 13:07:37 -0400 Subject: [PATCH 55/60] Fixed species init function. --- stochss/handlers/util/stochss_notebook.py | 2 +- stochss/handlers/util/stochss_spatial_model.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stochss/handlers/util/stochss_notebook.py b/stochss/handlers/util/stochss_notebook.py index cfd722dd0d..3d3bcae94a 100644 --- a/stochss/handlers/util/stochss_notebook.py +++ b/stochss/handlers/util/stochss_notebook.py @@ -403,7 +403,7 @@ def __create_species_strings(self, model, pad): if self.s_model['is_spatial']: names.append(spec["name"]) spec_str = f'{pad}{spec["name"]} = Species(name="{spec["name"]}", ' - spec_str += f"diffusion_constant={spec['diffusionConst']})" + spec_str += f"diffusion_coefficient={spec['diffusionConst']})" if len(spec['types']) < len(self.s_model['domain']['types']) - 1: type_str = f"{pad}self.restrict({spec['name']}, {str(spec['types'])})" types_str.append(type_str) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 86ce8237b7..4641d38d1f 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -267,7 +267,7 @@ def __convert_species(self, model): try: for species in self.model['species']: name = species['name'] - s_species = Species(name=name, diffusion_constant=species['diffusionConst']) + s_species = Species(name=name, diffusion_coefficient=species['diffusionConst']) model.add_species(s_species) model.restrict(s_species, species['types']) except KeyError as err: From ce00a819f7a00e408928422c0af33edb6967e5a4 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 10 Nov 2021 09:14:31 -0500 Subject: [PATCH 56/60] Moved the preview.json cleanup block to the handler to fix incorrect results from being loaded as a result of a race condition. --- stochss/handlers/models.py | 3 +++ stochss/handlers/util/ensemble_simulation.py | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index 292a732874..406595e0c3 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -212,6 +212,9 @@ async def get(self): target = self.get_query_argument(name="target", default=None) resp = {"Running":False, "Outfile":outfile, "Results":""} if run_cmd == "start": + model = StochSSModel(path=path) + if os.path.exists(f".{model.get_name()}-preview.json"): + os.remove(f".{model.get_name()}-preview.json") exec_cmd = ['/stochss/stochss/handlers/util/scripts/run_preview.py', f'{path}', f'{outfile}'] if target is not None: diff --git a/stochss/handlers/util/ensemble_simulation.py b/stochss/handlers/util/ensemble_simulation.py index 3958da422e..ef57e8e16d 100644 --- a/stochss/handlers/util/ensemble_simulation.py +++ b/stochss/handlers/util/ensemble_simulation.py @@ -105,8 +105,6 @@ def run(self, preview=False, verbose=True): if verbose: log.info(f"Running {self.g_model.name} preview simulation") live_file = f".{self.g_model.name}-preview.json" - if os.path.exists(live_file): - os.remove(live_file) options = {"file_path": live_file} results = self.g_model.run(timeout=5, live_output="graph", live_output_options=options) if verbose: From d75bb6647733697674345558ea193027643cee37 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 10 Nov 2021 10:28:40 -0500 Subject: [PATCH 57/60] Fixed issues with updating domain. Added 2D domain creation to allow for custom 2D domains. --- .../handlers/util/stochss_spatial_model.py | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 4641d38d1f..395347856b 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -354,11 +354,12 @@ def __update_domain(self): self.model['domain'] = self.get_model_template()['domain'] elif "static" not in self.model['domain'].keys(): self.model['domain']['static'] = True - if "rho" not in self.model['domain']['particles'][0].keys() or \ - "c" not in self.model['domain']['particles'][0].keys(): - for particle in self.model['domain']['particles']: - particle['rho'] = particle['mass']/particle['volume'] - particle['c'] = 10 + if self.model['domain']['particles']: + if "rho" not in self.model['domain']['particles'][0].keys() or \ + "c" not in self.model['domain']['particles'][0].keys(): + for particle in self.model['domain']['particles']: + particle['rho'] = particle['mass']/particle['volume'] + particle['c'] = 10 def convert_to_model(self): @@ -498,8 +499,15 @@ def get_particles_from_3d_domain(cls, data): xlim = [coord + data['transformation'][0] for coord in data['xLim']] ylim = [coord + data['transformation'][1] for coord in data['yLim']] zlim = [coord + data['transformation'][2] for coord in data['zLim']] - s_domain = Domain.create_3D_domain(xlim=xlim, ylim=ylim, zlim=zlim, nx=data['nx'], - ny=data['ny'], nz=data['nz'], **data['type']) + dimensions = bool(xlim[1] - xlim[0]) + dimensions += bool(ylim[1] - ylim[0]) + dimensions += bool(zlim[1] - zlim[0]) + if dimensions > 2: + s_domain = Domain.create_3D_domain(xlim=xlim, ylim=ylim, zlim=zlim, nx=data['nx'], + ny=data['ny'], nz=data['nz'], **data['type']) + else: + s_domain = Domain.create_2D_domain(xlim=xlim, ylim=ylim, + nx=data['nx'], ny=data['ny'], **data['type']) domain = cls.__build_stochss_domain(s_domain=s_domain) limits = {"x_lim":domain['x_lim'], "y_lim":domain['y_lim'], "z_lim":domain['z_lim']} return {"particles":domain['particles'], "limits":limits} From b94c52e0df78bd17056aad0c46a5ae7b355d89d6 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 10 Nov 2021 11:41:20 -0500 Subject: [PATCH 58/60] Fixed issue with particle ids missing from plot figs. --- stochss/handlers/util/stochss_spatial_model.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py index 395347856b..552c765eaf 100644 --- a/stochss/handlers/util/stochss_spatial_model.py +++ b/stochss/handlers/util/stochss_spatial_model.py @@ -460,6 +460,20 @@ def get_domain_plot(self, path=None, new=False): fig = domain.plot_types(return_plotly_figure=True) if not fig['data']: fig['data'].append(self.__get_trace_data(particles=[], name="Un-Assigned")) + else: + s_domain = self.load()['domain'] + for i, d_type in enumerate(s_domain['types']): + if len(s_domain['types']) > 1: + particles = list(filter(lambda partictle, key=i: particle['type'] == key, + s_domain['particles'])) + else: + particles = s_domain['particles'] + ids = list(map(lambda particle: particle['particle_id'], particles)) + index = fig['data'].index( + list(filter(lambda trace: trace['name'].endswith(str(d_type['typeID'])), fig['data']))[0] + ) + fig['data'][index]['name'] = d_type['name'] + fig['data'][index]['ids'] = ids fig['layout']['width'] = None fig['layout']['height'] = None fig['layout']['autosize'] = True From edc2c4055a5db2ae0628444900a0b96802c04fb9 Mon Sep 17 00:00:00 2001 From: BryanRumsey <44621966+BryanRumsey@users.noreply.github.com> Date: Wed, 10 Nov 2021 14:27:45 -0500 Subject: [PATCH 59/60] Addressed review comment --- stochss/handlers/util/stochss_notebook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stochss/handlers/util/stochss_notebook.py b/stochss/handlers/util/stochss_notebook.py index 3d3bcae94a..9db45a860d 100644 --- a/stochss/handlers/util/stochss_notebook.py +++ b/stochss/handlers/util/stochss_notebook.py @@ -278,7 +278,7 @@ def __create_initial_condition_strings(self, model, pad): def __create_domain_string(self, model, pad): domain = ["", f"{pad}# Domain", f"{pad}domain = Domain.read_stochss_domain('{self.s_model['path']}')", - f"{pad}self.add_mesh(domain)", + f"{pad}self.add_domain(domain)", "", f"{pad}self.staticDomain = {self.s_model['domain']['static']}"] model.extend(domain) From eafbfd2ff1dea21b382f6cccf6c5947fa8dc9094 Mon Sep 17 00:00:00 2001 From: BryanRumsey <44621966+BryanRumsey@users.noreply.github.com> Date: Wed, 10 Nov 2021 14:29:38 -0500 Subject: [PATCH 60/60] Increased time to 60 seconds --- stochss/handlers/util/ensemble_simulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stochss/handlers/util/ensemble_simulation.py b/stochss/handlers/util/ensemble_simulation.py index ef57e8e16d..31ed2c8253 100644 --- a/stochss/handlers/util/ensemble_simulation.py +++ b/stochss/handlers/util/ensemble_simulation.py @@ -106,7 +106,7 @@ def run(self, preview=False, verbose=True): log.info(f"Running {self.g_model.name} preview simulation") live_file = f".{self.g_model.name}-preview.json" options = {"file_path": live_file} - results = self.g_model.run(timeout=5, live_output="graph", live_output_options=options) + results = self.g_model.run(timeout=60, live_output="graph", live_output_options=options) if verbose: log.info(f"{self.g_model.name} preview simulation has completed") log.info(f"Generate result plot for {self.g_model.name} preview")