Skip to content

Commit

Permalink
aligning with other simulators
Browse files Browse the repository at this point in the history
  • Loading branch information
jonrkarr committed Jan 5, 2021
1 parent ce6a7fb commit e84ce70
Show file tree
Hide file tree
Showing 16 changed files with 249 additions and 2,634 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
- name: Install libXML2
run: |
sudo apt-get update -y
sudo apt-get install -y -no-install-recommends libxml2
sudo apt-get install -y -no-install-recommends libxml2 libncurses5
# install package
- name: Install the package
Expand Down
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# Base OS
FROM python:3.7.9-slim-buster

ARG VERSION="0.0.1"
ARG VERSION="0.1.0"
ARG SIMULATOR_VERSION="2.2.0"

# metadata
Expand Down Expand Up @@ -60,7 +60,8 @@ RUN pip install /root/Biosimulators_tellurium \
RUN pip install tellurium==${SIMULATOR_VERSION}

# Configure matplotlib backend
ENV MPLBACKEND=PDF \
ENV PLOTTING_ENGINE=matplotlib \
MPLBACKEND=PDF \
PYTHONWARNINGS="ignore:The 'warn' parameter of use():UserWarning:tellurium.tellurium,ignore:Matplotlib is currently using agg:UserWarning:tellurium.plotting.engine_mpl"

# Entrypoint
Expand Down
2 changes: 1 addition & 1 deletion biosimulators_tellurium/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.0.1'
__version__ = '0.1.0'
29 changes: 29 additions & 0 deletions biosimulators_tellurium/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
""" Configuration
:Author: Jonathan Karr <karr@mssm.edu>
:Date: 2021-01-04
:Copyright: 2021, Center for Reproducible Biomedical Modeling
:License: MIT
"""

from .data_model import PlottingEngine
import os

__all__ = ['Config']


class Config(object):
""" Configuration
Attributes:
plotting_engine (:obj:`PlottingEngine`): plotting engine
"""

def __init__(self):
plotting_engine = os.getenv('PLOTTING_ENGINE', 'matplotlib')
if plotting_engine not in PlottingEngine.__members__:
raise NotImplementedError(('`{}` is a not a valid plotting engine for tellurium. '
'tellurium supports the following plotting engines:\n - {}').format(
plotting_engine, '\n - '.join(sorted('`' + name + '`' for name in PlottingEngine.__members__.keys()))))

self.plotting_engine = PlottingEngine[plotting_engine]
140 changes: 109 additions & 31 deletions biosimulators_tellurium/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,27 @@
:License: MIT
"""

from .data_model import PlottingEngine
from .utils import get_sedml_locations_in_combine_archive, exec_sed_doc
from .config import Config
from biosimulators_utils.combine.exec import exec_sedml_docs_in_archive
from biosimulators_utils.exec_status.data_model import ExecutionStatus, SedDocumentExecutionStatus # noqa: F401
from biosimulators_utils.plot.data_model import PlotFormat # noqa: F401
from biosimulators_utils.report.data_model import OutputResults, ReportFormat # noqa: F401
from biosimulators_utils.report.io import ReportWriter
from tellurium.sedml.tesedml import SEDMLCodeFactory
import glob
import os
import pandas
import shutil
import tellurium
import tellurium.sedml.tesedml
import tellurium.utils.omex
import tempfile
import zipfile

import libsedml
import importlib
importlib.reload(libsedml)


__all__ = ['exec_sedml_docs_in_combine_archive']


def exec_sedml_docs_in_combine_archive(archive_filename, out_dir,
report_formats=None, plot_formats=None,
bundle_outputs=None, keep_individual_outputs=None,
plotting_engine=PlottingEngine.matplotlib):
bundle_outputs=None, keep_individual_outputs=None):
""" Execute the SED tasks defined in a COMBINE/OMEX archive and save the outputs
Args:
Expand All @@ -43,30 +42,109 @@ def exec_sedml_docs_in_combine_archive(archive_filename, out_dir,
plot_formats (:obj:`list` of :obj:`PlotFormat`, optional): report format (e.g., pdf)
bundle_outputs (:obj:`bool`, optional): if :obj:`True`, bundle outputs into archives for reports and plots
keep_individual_outputs (:obj:`bool`, optional): if :obj:`True`, keep individual output files
plotting_engine (:obj:`PlottingEngine`, optional): engine for generating plots
"""
# Check that the COMBINE/OMEX archive exists, and that it is in zip format
if not os.path.isfile(archive_filename):
raise FileNotFoundError("The COMBINE/OMEX archive file `{}` does not exist".format(archive_filename))

if not zipfile.is_zipfile(archive_filename):
raise IOError("COMBINE/OMEX archive `{}` is not in the zip format".format(archive_filename))
exec_sedml_docs_in_archive(exec_sed_doc, archive_filename, out_dir,
apply_xml_model_changes=True,
report_formats=report_formats,
plot_formats=plot_formats,
bundle_outputs=bundle_outputs,
keep_individual_outputs=keep_individual_outputs)

# Create a temporary directory for the contents of the COMBINE/OMEX archive
archive_dirname = tempfile.mkdtemp()

# Extract the contents of the COMBINE/OMEX archive
tellurium.utils.omex.extractCombineArchive(omexPath=archive_filename, directory=archive_dirname)
def exec_sed_doc(filename, working_dir, base_out_path, rel_out_path=None,
apply_xml_model_changes=True, report_formats=None, plot_formats=None,
exec_status=None, indent=0):
"""
Args:
filename (:obj:`str`): a path to SED-ML file which defines a SED document
working_dir (:obj:`str`): working directory of the SED document (path relative to which models are located)
# Get the locations of the SED-ML files within the COMBINE/OMEX archive
sedml_locations = get_sedml_locations_in_combine_archive(archive_filename)
out_path (:obj:`str`): path to store the outputs
# Execute each SED-ML file
for sedml_location in sedml_locations:
exec_sed_doc(archive_dirname, sedml_location, out_dir, plotting_engine)
* CSV: directory in which to save outputs to files
``{out_path}/{rel_out_path}/{report.id}.csv``
* HDF5: directory in which to save a single HDF5 file (``{out_path}/reports.h5``),
with reports at keys ``{rel_out_path}/{report.id}`` within the HDF5 file
# bundle the outputs of the SED-ML files
# TODO
rel_out_path (:obj:`str`, optional): path relative to :obj:`out_path` to store the outputs
apply_xml_model_changes (:obj:`bool`, optional): if :obj:`True`, apply any model changes specified in the SED-ML file before
calling :obj:`task_executer`.
report_formats (:obj:`list` of :obj:`ReportFormat`, optional): report format (e.g., csv or h5)
plot_formats (:obj:`list` of :obj:`PlotFormat`, optional): plot format (e.g., pdf)
exec_status (:obj:`SedDocumentExecutionStatus`, optional): execution status of document
indent (:obj:`int`, optional): degree to indent status messages
# clean up the temporary directory for the contents of the COMBINE/OMEX archive
shutil.rmtree(archive_dirname)
Returns:
:obj:`OutputResults`: results of each report
"""
# update status
if exec_status:
exec_status.status = ExecutionStatus.RUNNING
exec_status.export()

# Set the engine that tellurium uses for plotting
tellurium.setDefaultPlottingEngine(Config().plotting_engine.value)

# Create a temporary for tellurium's outputs
# - Reports: CSV (Rows: time, Columns: data sets)
# - Plots: PDF
tmp_out_dir = tempfile.mkdtemp()

# Use tellurium to execute the SED document and generate the specified outputs
try:
factory = SEDMLCodeFactory(filename,
workingDir=working_dir,
createOutputs=True,
saveOutputs=True,
outputDir=tmp_out_dir,
)
for plot_format in plot_formats:
factory.reportFormat = 'csv'
factory.plotFormat = plot_format.value
factory.executePython()
except Exception:
shutil.rmtree(tmp_out_dir)
raise

# Convert tellurium's CSV reports to the desired BioSimulators format(s)
# - Transpose rows/columns
# - Encode into PyTables dialect of HDF5
report_results = OutputResults()
for report_filename in glob.glob(os.path.join(tmp_out_dir, '*.csv')):
report_id = os.path.splitext(os.path.basename(report_filename))[0]

# read report from CSV file produced by tellurium
report_df = pandas.read_csv(report_filename).transpose()

# append to data structure of report results
report_results[report_id] = report_df

# save file in desired BioSimulators format(s)
for report_format in report_formats:
ReportWriter().run(report_df,
base_out_path,
os.path.join(rel_out_path, report_id) if rel_out_path else report_id,
format=report_format)

# Move the plot outputs to the permanent output directory
out_dir = base_out_path
if rel_out_path:
out_dir = os.path.join(out_dir, rel_out_path)

if not os.path.isdir(out_dir):
os.makedirs(out_dir)

for plot_format in plot_formats:
for plot_filename in glob.glob(os.path.join(tmp_out_dir, '*.' + plot_format.value)):
shutil.move(plot_filename, out_dir)

# Clean up the temporary directory for tellurium's outputs
shutil.rmtree(tmp_out_dir)

# update status
if exec_status:
exec_status.status = ExecutionStatus.SUCCEEDED
exec_status.export()

# Return a data structure with the results of the reports
return report_results
82 changes: 0 additions & 82 deletions biosimulators_tellurium/utils.py

This file was deleted.

8 changes: 2 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
biosimulators_utils >= 0.1.28
matplotlib
numpy
python_libcombine
biosimulators_utils >= 0.1.30
pandas
tellurium
tesedml

Binary file added tests/fixtures/BIOMD0000000297-with-plots.omex
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit e84ce70

Please # to comment.