Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added higher level conversion function to exec method #150

Open
wants to merge 34 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4045980
added higher level conversion function to exec method
AlexPatrie Oct 3, 2023
991892e
feat: added spatial library for simularium smoldyn conversion
AlexPatrie Oct 4, 2023
19490d9
feat: updated optional requirements to reflect new spatial library
AlexPatrie Oct 4, 2023
4179522
added immutable instance-metadata parameter
AlexPatrie Oct 4, 2023
aea6635
chore: added optional default io format to high level util function
AlexPatrie Oct 4, 2023
02b8cf9
fix: finished falsy eval
AlexPatrie Oct 4, 2023
b939471
chore: updated args and type annotations
AlexPatrie Oct 4, 2023
3a3946a
chore: updated method signature
AlexPatrie Oct 4, 2023
0882d2e
fix: linting fixes
AlexPatrie Oct 4, 2023
5d04a96
chore: formatted whitespace for ci
AlexPatrie Oct 5, 2023
6d82941
chore: updated utils subdir docstrings
AlexPatrie Oct 5, 2023
150be1f
chore: reformatting
AlexPatrie Oct 5, 2023
ac2c686
temp archive scan
AlexPatrie Oct 5, 2023
3217351
feat: added spatial attributes to common config object and updated co…
AlexPatrie Oct 5, 2023
c006e79
feat: implemented simularium converter logic in combine exec method
AlexPatrie Oct 5, 2023
96f04ce
chore: removed unused comments
AlexPatrie Oct 5, 2023
ee726eb
feat: implemented exec file and method in spatial library
AlexPatrie Oct 5, 2023
487a5c2
minor reformat
AlexPatrie Oct 5, 2023
11b6099
chore: updated docstrings
AlexPatrie Oct 5, 2023
08862ce
feat: copied code from smoldyn.biosimulators methods
AlexPatrie Oct 5, 2023
7a02910
update
AlexPatrie Oct 5, 2023
9685e48
chore: updated docstrings
AlexPatrie Oct 6, 2023
0d620e4
chore: changed setter scope of default support spatial simulator
AlexPatrie Oct 6, 2023
14d9a29
chore: minor reformat
AlexPatrie Oct 6, 2023
e8d132c
fix: removed unused constructor param from factory
AlexPatrie Oct 6, 2023
c914a0e
chore: reformatted docstrings and code
AlexPatrie Oct 6, 2023
a0cef5d
updated nomenclature and reformatting
AlexPatrie Oct 6, 2023
e287e0e
chore: added test file to ignore to be deleted
AlexPatrie Oct 6, 2023
3ed7ec0
chore: updated doc signature
AlexPatrie Oct 6, 2023
4dc4471
rename nomenclature
AlexPatrie Oct 6, 2023
ae703fb
minor import dep adjustment
AlexPatrie Oct 6, 2023
696e363
chore: updated and reformatting
AlexPatrie Oct 6, 2023
3bf660f
updated implementation
AlexPatrie Oct 6, 2023
4a4c6a6
chore: updated exec
AlexPatrie Oct 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ docs/.buildinfo
docs/.doctrees/
docs/_raw_sources/
docs/_sources/

# test files (to be deleted)
test_spatial_exec.py
4 changes: 3 additions & 1 deletion biosimulators_utils/combine/data_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import abc
import datetime # noqa: F401
import enum
from typing import List


__all__ = [
'CombineArchiveBase',
Expand Down Expand Up @@ -40,7 +42,7 @@ def __init__(self, contents=None):
"""
self.contents = contents or []

def get_master_content(self):
def get_master_content(self) -> List:
""" Get the master content of an archive

Returns:
Expand Down
115 changes: 85 additions & 30 deletions biosimulators_utils/combine/exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,27 @@
import os
import tempfile
import shutil
import types # noqa: F401
from typing import Optional, Tuple
from types import FunctionType # noqa: F401


__all__ = [
'exec_sedml_docs_in_archive',
]


def exec_sedml_docs_in_archive(sed_doc_executer, archive_filename, out_dir, apply_xml_model_changes=False,
sed_doc_executer_supported_features=(Task, Report, DataSet, Plot2D, Curve, Plot3D, Surface),
sed_doc_executer_logged_features=(Task, Report, DataSet, Plot2D, Curve, Plot3D, Surface),
log_level=StandardOutputErrorCapturerLevel.c,
config=None):
""" Execute the SED-ML files in a COMBINE/OMEX archive (execute tasks and save outputs)
def exec_sedml_docs_in_archive(
sed_doc_executer,
archive_filename: str,
out_dir: str,
apply_xml_model_changes=False,
sed_doc_executer_supported_features=(Task, Report, DataSet, Plot2D, Curve, Plot3D, Surface),
sed_doc_executer_logged_features=(Task, Report, DataSet, Plot2D, Curve, Plot3D, Surface),
log_level=StandardOutputErrorCapturerLevel.c,
config: Optional[Config] = None
) -> Tuple[SedDocumentResults, CombineArchiveLog]:
""" Execute the SED-ML files in a COMBINE/OMEX archive (execute tasks and save outputs). If 'smoldyn' is detected
in the archive, a simularium file will automatically be generated.

Args:
sed_doc_executer (:obj:`types.FunctionType`): function to execute each SED document in the archive.
Expand All @@ -53,8 +61,10 @@ def sed_doc_executer(doc, working_dir, base_out_path, rel_out_path=None,
''' Execute the tasks specified in a SED document and generate the specified outputs

Args:
doc (:obj:`SedDocument` of :obj:`str`): SED document or 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)
doc (:obj:`SedDocument` of :obj:`str`): SED document or 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)

out_path (:obj:`str`): path to store the outputs

Expand All @@ -64,7 +74,8 @@ def sed_doc_executer(doc, working_dir, base_out_path, rel_out_path=None,
with reports at keys ``{rel_out_path}/{report.id}`` within the HDF5 file

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
apply_xml_model_changes (:obj:`bool`, optional): if :obj:`True`,
apply any model changes specified in the SED-ML file
log (:obj:`SedDocumentLog`, optional): execution status of document
log_level (:obj:`StandardOutputErrorCapturerLevel`, optional): level at which to log output
indent (:obj:`int`, optional): degree to indent status messages
Expand All @@ -77,14 +88,17 @@ def sed_doc_executer(doc, working_dir, base_out_path, rel_out_path=None,
* CSV: directory in which to save outputs to files
``{ out_dir }/{ relative-path-to-SED-ML-file-within-archive }/{ report.id }.csv``
* HDF5: directory in which to save a single HDF5 file (``{ out_dir }/reports.h5``),
with reports at keys ``{ relative-path-to-SED-ML-file-within-archive }/{ report.id }`` within the HDF5 file

apply_xml_model_changes (:obj:`bool`): if :obj:`True`, apply any model changes specified in the SED-ML files before
calling :obj:`task_executer`.
sed_doc_executer_supported_features (:obj:`list` of :obj:`type`, optional): list of the types of elements that the
SED document executer supports. Default: tasks, reports, plots, data sets, curves, and surfaces.
sed_doc_executer_logged_features (:obj:`list` of :obj:`type`, optional): list of the types fo elements which that
the SED document executer logs. Default: tasks, reports, plots, data sets, curves, and surfaces.
with reports at keys ``{ relative-path-to-SED-ML-file-within-archive }/{ report.id }``
within the HDF5 file

apply_xml_model_changes (:obj:`bool`): if :obj:`True`, apply any model changes specified in the
SED-ML files before calling :obj:`task_executer`.
sed_doc_executer_supported_features (:obj:`list` of :obj:`type`, optional): list of the types
of elements that the SED document executer supports. Default: tasks, reports, plots, data sets,
curves, and surfaces.
sed_doc_executer_logged_features (:obj:`list` of :obj:`type`, optional): list of the types of elements
which that the SED document executer logs. Default: tasks, reports,
plots, data sets, curves, and surfaces.
log_level (:obj:`StandardOutputErrorCapturerLevel`, optional): level at which to log output
config (:obj:`Config`): configuration

Expand Down Expand Up @@ -225,6 +239,34 @@ def sed_doc_executer(doc, working_dir, base_out_path, rel_out_path=None,
results[content.location] = doc_results
if config.LOG:
doc_log.status = Status.SUCCEEDED

# check the manifest for a smoldyn model
for file_contents in archive.contents:
if 'smoldyn' in file_contents.location:
config.SPATIAL = True
print('There is spatial!')

# generate simularium file if spatial
if config.SPATIAL:
import biosimulators_simularium as biosimularium
simularium_filename = os.path.join(out_dir, 'output')
spatial_archive = biosimularium.SmoldynCombineArchive(
rootpath=out_dir,
simularium_filename=simularium_filename
)
# check if modelout file exists
if not os.path.exists(spatial_archive.model_output_filename):
generate_model_output_file = True
else:
generate_model_output_file = False
# construct converter
converter = biosimularium.SmoldynDataConverter(
archive=spatial_archive,
generate_model_output=generate_model_output_file
)
# generate simularium file
converter.generate_simularium_file(io_format='json')

except Exception as exception:
if config.DEBUG:
raise
Expand All @@ -241,40 +283,47 @@ def sed_doc_executer(doc, working_dir, base_out_path, rel_out_path=None,

print('')

# handle smoldyn output/simularium conversion
# arch = SmoldynCombineArchive(rootpath=archive_tmp_dir)
# if arch.verify_smoldyn_in_manifest():
# converter = SmoldynDataConverter(arch)
# simularium_fp = os.path.join(arch.rootpath, 'simularium_output')
# arch.simularium_filename = simularium_fp
# converter.generate_simularium_file()

if config.BUNDLE_OUTPUTS:
print('Bundling outputs ...')

# bundle CSV files of reports into zip archive
report_formats = config.REPORT_FORMATS
archive_paths = [os.path.join(out_dir, '**', '*.' + format.value) for format in report_formats if format != ReportFormat.h5]
archive_paths = [
os.path.join(out_dir, '**', '*.' + f.value)
for f in report_formats if f != ReportFormat.h5
]
archive = build_archive_from_paths(archive_paths, out_dir)
if archive.files:
ArchiveWriter().run(archive, os.path.join(out_dir, config.REPORTS_PATH))

# bundle PDF files of plots into zip archive
viz_formats = config.VIZ_FORMATS
archive_paths = [os.path.join(out_dir, '**', '*.' + format.value) for format in viz_formats]
archive_paths = [os.path.join(out_dir, '**', '*.' + f.value) for f in viz_formats]
archive = build_archive_from_paths(archive_paths, out_dir)
if archive.files:
ArchiveWriter().run(archive, os.path.join(out_dir, config.PLOTS_PATH))

# bundle Simularium file into zip archive
if config.SPATIAL:
simularium_format = ['simularium']
archive_paths = [os.path.join(out_dir, '**', '*.' + f) for f in simularium_format]
archive = build_archive_from_paths(archive_paths, out_dir)
if archive.files:
ArchiveWriter().run(archive, os.path.join(out_dir, 'simularium.zip'))


# cleanup temporary files
print('Cleaning up ...')
if not config.KEEP_INDIVIDUAL_OUTPUTS:

report_formats = config.REPORT_FORMATS
viz_formats = config.VIZ_FORMATS
path_patterns = (
[os.path.join(out_dir, '**', '*.' + format.value) for format in report_formats if format != ReportFormat.h5]
+ [os.path.join(out_dir, '**', '*.' + format.value) for format in viz_formats]
[
os.path.join(out_dir, '**', '*.' + f.value)
for f in report_formats if format != ReportFormat.h5
]
+ [os.path.join(out_dir, '**', '*.' + f.value) for f in viz_formats]
)
for path_pattern in path_patterns:
for path in glob.glob(path_pattern, recursive=True):
Expand Down Expand Up @@ -330,3 +379,9 @@ def sed_doc_executer(doc, working_dir, base_out_path, rel_out_path=None,

# return results and log
return (results, log)






47 changes: 36 additions & 11 deletions biosimulators_utils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@
DEFAULT_BIOSIMULATIONS_API_ENDPOINT = 'https://api.biosimulations.org/'
DEFAULT_BIOSIMULATIONS_API_AUTH_ENDPOINT = 'https://auth.biosimulations.org/oauth/token'
DEFAULT_BIOSIMULATIONS_API_AUDIENCE = 'api.biosimulations.org'
DEFAULT_SUPPORTED_SPATIAL_SIMULATOR = 'smoldyn'


# noinspection PyPep8Naming,PyDefaultArgument
class Config(object):
SUPPORTED_SPATIAL_SIMULATOR: str

""" Configuration

Attributes:
Expand Down Expand Up @@ -65,6 +69,8 @@ class Config(object):
BIOSIMULATIONS_API_AUDIENCE (:obj:`str`): audience for the BioSimulations API
VERBOSE (:obj:`bool`): whether to display the detailed output of the execution of each task
DEBUG (:obj:`bool`): whether to raise exceptions rather than capturing them
SUPPORTED_SPATIAL_SIMULATOR (:obj:`strl`, optional): spatial simulator that this config supports. Currently
only `'smoldyn'` is supported.
"""

def __init__(self,
Expand Down Expand Up @@ -96,22 +102,26 @@ def __init__(self,
BIOSIMULATIONS_API_AUTH_ENDPOINT=DEFAULT_BIOSIMULATIONS_API_AUTH_ENDPOINT,
BIOSIMULATIONS_API_AUDIENCE=DEFAULT_BIOSIMULATIONS_API_AUDIENCE,
VERBOSE=False,
DEBUG=False):
DEBUG=False,
SPATIAL=False):
"""
Args:
OMEX_METADATA_INPUT_FORMAT (:obj:`OmexMetadataInputFormat`, optional): format to validate OMEX Metadata files against
OMEX_METADATA_INPUT_FORMAT (:obj:`OmexMetadataInputFormat`, optional): format to validate
OMEX Metadata files against
OMEX_METADATA_OUTPUT_FORMAT (:obj:`OmexMetadataOutputFormat`, optional): format to export OMEX Metadata files
OMEX_METADATA_SCHEMA (:obj:`OmexMetadataSchema`, optional): schema to validate OMEX Metadata files against
VALIDATE_OMEX_MANIFESTS (:obj:`bool`, optional): whether to validate OMEX manifests during the execution of COMBINE/OMEX archives
VALIDATE_SEDML (:obj:`bool`, optional): whether to validate SED-ML files during the execution of COMBINE/OMEX archives
VALIDATE_SEDML_MODELS (:obj:`bool`, optional): whether to validate models referenced by SED-ML files during the execution
VALIDATE_OMEX_MANIFESTS (:obj:`bool`, optional): whether to validate OMEX manifests during the execution
of COMBINE/OMEX archives
VALIDATE_SEDML (:obj:`bool`, optional): whether to validate SED-ML files during the execution of
COMBINE/OMEX archives
VALIDATE_SEDML_MODELS (:obj:`bool`, optional): whether to validate models referenced by SED-ML
files during the execution of COMBINE/OMEX archives
VALIDATE_IMPORTED_MODEL_FILES (:obj:`bool`, optional): whether to validate files imported from models
VALIDATE_OMEX_METADATA (:obj:`bool`, optional): whether to validate OMEX metadata (RDF files) during the execution of
COMBINE/OMEX archives
VALIDATE_IMAGES (:obj:`bool`, optional): whether to validate the images in COMBINE/OMEX archives during their execution
VALIDATE_RESULTS (:obj:`bool`, optional): whether to validate the results of simulations following their execution
ALGORITHM_SUBSTITUTION_POLICY (:obj:`str`, optional): algorithm substition policy
ALGORITHM_SUBSTITUTION_POLICY (:obj:`str`, optional): algorithm substitution policy
COLLECT_COMBINE_ARCHIVE_RESULTS (:obj:`bool`, optional): whether to assemble an in memory data structure with all of the
simulation results of COMBINE/OMEX archives
COLLECT_SED_DOCUMENT_RESULTS (:obj:`bool`, optional): whether to assemble an in memory data structure with all of the
Expand All @@ -132,6 +142,7 @@ def __init__(self,
BIOSIMULATIONS_API_AUDIENCE (:obj:`str`, optional): audience for the BioSimulations API
VERBOSE (:obj:`bool`, optional): whether to display the detailed output of the execution of each task
DEBUG (:obj:`bool`, optional): whether to raise exceptions rather than capturing them
SPATIAL (:obj:`bool`, optional): whether the simulation is spatial in nature and able to be simularium-ed
"""
self.OMEX_METADATA_INPUT_FORMAT = OMEX_METADATA_INPUT_FORMAT
self.OMEX_METADATA_OUTPUT_FORMAT = OMEX_METADATA_OUTPUT_FORMAT
Expand Down Expand Up @@ -162,23 +173,34 @@ def __init__(self,
self.BIOSIMULATIONS_API_AUDIENCE = BIOSIMULATIONS_API_AUDIENCE
self.VERBOSE = VERBOSE
self.DEBUG = DEBUG
self.SPATIAL = SPATIAL
self.SUPPORTED_SPATIAL_SIMULATOR = DEFAULT_SUPPORTED_SPATIAL_SIMULATOR
try:
assert self.SUPPORTED_SPATIAL_SIMULATOR == 'smoldyn'
except AssertionError:
raise ValueError(
"""
The only spatial simulator that is currently supported is 'smoldyn'. Please set the value of
SUPPORTED_SPATIAL_SIMULATOR to 'smoldyn' and try again.
"""
)


def get_config():
""" Get the configuration
""" Factory for generating a new instance of `Config`.

Returns:
:obj:`Config`: configuration
"""
report_formats = os.environ.get('REPORT_FORMATS', 'h5').strip()
if report_formats:
report_formats = [ReportFormat(format.strip().lower()) for format in report_formats.split(',')]
report_formats = [ReportFormat(f.strip().lower()) for f in report_formats.split(',')]
else:
report_formats = []

viz_formats = os.environ.get('VIZ_FORMATS', 'pdf').strip()
if viz_formats:
viz_formats = [VizFormat(format.strip().lower()) for format in viz_formats.split(',')]
viz_formats = [VizFormat(f.strip().lower()) for f in viz_formats.split(',')]
else:
viz_formats = []

Expand All @@ -198,7 +220,8 @@ def get_config():
VALIDATE_RESULTS=os.environ.get('VALIDATE_RESULTS', '1').lower() in ['1', 'true'],
ALGORITHM_SUBSTITUTION_POLICY=AlgorithmSubstitutionPolicy(os.environ.get(
'ALGORITHM_SUBSTITUTION_POLICY', DEFAULT_ALGORITHM_SUBSTITUTION_POLICY)),
COLLECT_COMBINE_ARCHIVE_RESULTS=os.environ.get('COLLECT_COMBINE_ARCHIVE_RESULTS', '0').lower() in ['1', 'true'],
COLLECT_COMBINE_ARCHIVE_RESULTS=os.environ.get('COLLECT_COMBINE_ARCHIVE_RESULTS',
'0').lower() in ['1', 'true'],
COLLECT_SED_DOCUMENT_RESULTS=os.environ.get('COLLECT_SED_DOCUMENT_RESULTS', '0').lower() in ['1', 'true'],
SAVE_PLOT_DATA=os.environ.get('SAVE_PLOT_DATA', '1').lower() in ['1', 'true'],
REPORT_FORMATS=report_formats,
Expand All @@ -212,10 +235,12 @@ def get_config():
LOG_PATH=os.environ.get('LOG_PATH', DEFAULT_LOG_PATH),
BIOSIMULATORS_API_ENDPOINT=os.environ.get('BIOSIMULATORS_API_ENDPOINT', DEFAULT_BIOSIMULATORS_API_ENDPOINT),
BIOSIMULATIONS_API_ENDPOINT=os.environ.get('BIOSIMULATIONS_API_ENDPOINT', DEFAULT_BIOSIMULATIONS_API_ENDPOINT),
BIOSIMULATIONS_API_AUTH_ENDPOINT=os.environ.get('BIOSIMULATIONS_API_AUTH_ENDPOINT', DEFAULT_BIOSIMULATIONS_API_AUTH_ENDPOINT),
BIOSIMULATIONS_API_AUTH_ENDPOINT=os.environ.get('BIOSIMULATIONS_API_AUTH_ENDPOINT',
DEFAULT_BIOSIMULATIONS_API_AUTH_ENDPOINT),
BIOSIMULATIONS_API_AUDIENCE=os.environ.get('BIOSIMULATIONS_API_AUDIENCE', DEFAULT_BIOSIMULATIONS_API_AUDIENCE),
VERBOSE=os.environ.get('VERBOSE', '1').lower() in ['1', 'true'],
DEBUG=os.environ.get('DEBUG', '0').lower() in ['1', 'true'],
SPATIAL=os.environ.get('SPATIAL', '0').lower() in ['1', 'true']
)


Expand Down
6 changes: 3 additions & 3 deletions requirements.optional.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ python_libsbml

[smoldyn]
smoldyn >= 2.66
# simulariumio

[simularium]
simulariumio
[spatial]
smoldyn >= 2.66
biosimulators_simularium

#################################
## Visualization formats
Expand Down
Loading