Skip to content

Commit

Permalink
adding ability to save data for plots to HDF5
Browse files Browse the repository at this point in the history
  • Loading branch information
jonrkarr committed Apr 14, 2021
1 parent e8a276c commit abdd602
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 10 deletions.
46 changes: 41 additions & 5 deletions biosimulators_tellurium/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from biosimulators_utils.report.data_model import DataSetResults, ReportResults, ReportFormat # noqa: F401
from biosimulators_utils.report.io import ReportWriter
from biosimulators_utils.sedml.data_model import Task, Report, DataSet, Plot2D, Curve, Plot3D, Surface
from biosimulators_utils.sedml.io import SedmlSimulationReader
from biosimulators_utils.sedml.io import SedmlSimulationReader, SedmlSimulationWriter
from tellurium.sedml.tesedml import SEDMLCodeFactory
import glob
import os
Expand Down Expand Up @@ -94,9 +94,43 @@ def exec_sed_doc(filename, working_dir, base_out_path, rel_out_path=None,
# - Plots: PDF
tmp_out_dir = tempfile.mkdtemp()

# add a report for each plot to make tellurium output the data for each plot
doc = SedmlSimulationReader().run(filename)
for output in doc.outputs:
if isinstance(output, (Plot2D, Plot3D)):
report = Report(
id='__plot__' + output.id,
name=output.name)

data_generators = {}
if isinstance(output, Plot2D):
for curve in output.curves:
data_generators[curve.x_data_generator.id] = curve.x_data_generator
data_generators[curve.y_data_generator.id] = curve.y_data_generator

elif isinstance(output, Plot3D):
for surface in output.surfaces:
data_generators[surface.x_data_generator.id] = surface.x_data_generator
data_generators[surface.y_data_generator.id] = surface.y_data_generator
data_generators[surface.z_data_generator.id] = surface.z_data_generator

for data_generator in data_generators.values():
report.data_sets.append(DataSet(
id='__data_set__{}_{}'.format(output.id, data_generator.id),
name=data_generator.name,
label=data_generator.id,
data_generator=data_generator,
))

report.data_sets.sort(key=lambda data_set: data_set.id)
doc.outputs.append(report)

filename_with_reports_for_plots = os.path.join(tmp_out_dir, 'simulation.sedml')
SedmlSimulationWriter().run(doc, filename_with_reports_for_plots)

# Use tellurium to execute the SED document and generate the specified outputs
try:
factory = SEDMLCodeFactory(filename,
factory = SEDMLCodeFactory(filename_with_reports_for_plots,
workingDir=working_dir,
createOutputs=True,
saveOutputs=True,
Expand All @@ -113,7 +147,6 @@ def exec_sed_doc(filename, working_dir, base_out_path, rel_out_path=None,
# Convert tellurium's CSV reports to the desired BioSimulators format(s)
# - Transpose rows/columns
# - Encode into BioSimulators format(s)
doc = SedmlSimulationReader().run(filename)
report_results = ReportResults()
for report_filename in glob.glob(os.path.join(tmp_out_dir, '*.csv')):
report_id = os.path.splitext(os.path.basename(report_filename))[0]
Expand All @@ -128,14 +161,17 @@ def exec_sed_doc(filename, working_dir, base_out_path, rel_out_path=None,
data_set_results[data_set.id] = data_set_df.loc[data_set.label, :].to_numpy()

# append to data structure of report results
report_results[report_id] = data_set_results
if '__plot__' not in report_id:
report_results[report_id] = data_set_results

# save file in desired BioSimulators format(s)
export_id = report_id.replace('__plot__', '')
report.id = export_id
for report_format in report_formats:
ReportWriter().run(report,
data_set_results,
base_out_path,
os.path.join(rel_out_path, report_id) if rel_out_path else report_id,
os.path.join(rel_out_path, export_id) if rel_out_path else export_id,
format=report_format)

# Move the plot outputs to the permanent output directory
Expand Down
31 changes: 26 additions & 5 deletions tests/test_core_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def _get_combine_archive_exec_env(self):
def _assert_combine_archive_outputs(self, dirname, reports=True, plots=True):
expected_files = set()

if reports:
if reports or plots:
expected_files.add('reports.h5')
else:
self.assertNotIn('reports.h5', os.listdir(dirname))
Expand All @@ -104,10 +104,16 @@ def _assert_combine_archive_outputs(self, dirname, reports=True, plots=True):

# check that the expected reports where created at the expected locations with the expected values
if reports:
self.assertEqual(set(ReportReader().get_ids(dirname)), set([
'ex1/BIOMD0000000297.sedml/report_1_task1',
'ex2/BIOMD0000000297.sedml/report_1_task1',
]))
if not plots:
self.assertEqual(set(ReportReader().get_ids(dirname)), set([
'ex1/BIOMD0000000297.sedml/report_1_task1',
'ex2/BIOMD0000000297.sedml/report_1_task1',
]))
else:
self.assertEqual(set([
'ex1/BIOMD0000000297.sedml/report_1_task1',
'ex2/BIOMD0000000297.sedml/report_1_task1',
]).difference(set(ReportReader().get_ids(dirname))), set([]))

report = Report(
data_sets=[
Expand All @@ -125,6 +131,21 @@ def _assert_combine_archive_outputs(self, dirname, reports=True, plots=True):

# check that expected plots where created at the expected locations
if plots:
if not reports:
self.assertEqual(set(ReportReader().get_ids(dirname)), set([
'ex1/BIOMD0000000297.sedml/plot_1_task1',
'ex1/BIOMD0000000297.sedml/plot_3_task1',
'ex2/BIOMD0000000297.sedml/plot_1_task1',
'ex2/BIOMD0000000297.sedml/plot_3_task1',
]))
else:
self.assertEqual(set([
'ex1/BIOMD0000000297.sedml/plot_1_task1',
'ex1/BIOMD0000000297.sedml/plot_3_task1',
'ex2/BIOMD0000000297.sedml/plot_1_task1',
'ex2/BIOMD0000000297.sedml/plot_3_task1',
]).difference(set(ReportReader().get_ids(dirname))), set([]))

plots_dir = os.path.join(self.dirname, 'plots')
archive = ArchiveReader().run(os.path.join(dirname, 'plots.zip'), plots_dir)
self.assertEqual(set(file.archive_path for file in archive.files), set([
Expand Down

0 comments on commit abdd602

Please sign in to comment.