diff --git a/compose_worker/Dockerfile-compose_worker b/compose_worker/Dockerfile-compose_worker index f31f73012..e2c8de9fe 100644 --- a/compose_worker/Dockerfile-compose_worker +++ b/compose_worker/Dockerfile-compose_worker @@ -17,43 +17,16 @@ RUN apt-get update && apt-get install -y libatlas-base-dev \ liblapack-dev \ gcc \ gfortran \ - libgfortran5 - - -# PySCeS - -# SUNDIALS --> installation path is default cmake (/usr/local) with LD_LIBRARY_PATH as runtime location -# ignore certificate checking because certificate was expired as of 2021-11-10 -# ARG SUNDIALS_VERSION=2.6.2 -# RUN apt-get install -y --no-install-recommends \ -# wget \ -# cmake \ -# make \ -# g++ \ -# \ -# && cd /tmp \ -# && wget --no-check-certificate https://computing.llnl.gov/sites/default/files/inline-files/sundials-${SUNDIALS_VERSION}.tar.gz \ -# && tar xvvf sundials-${SUNDIALS_VERSION}.tar.gz \ -# && cd sundials-${SUNDIALS_VERSION} \ -# && mkdir build \ -# && cd build \ -# && CFLAGS="-fPIC" cmake .. \ -# && make \ -# && make install \ -# \ -# && cd /tmp \ -# && rm sundials-${SUNDIALS_VERSION}.tar.gz \ -# && rm -r sundials-${SUNDIALS_VERSION} -# ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH - - -############################################ -# App content + libgfortran5 \ + python3.10-venv + COPY . /app/worker ENV PATH="/root/.local/bin:$PATH" +ENV TEST_SBML_FP="test_fixtures/Elowitz-Nature-2000-Repressilator/BIOMD0000000012_url.xml" +ENV TEST_OMEX_FP="test_fixtures/Elowitz-Nature-2000-Repressilator.omex" # copy pysces config @@ -62,50 +35,26 @@ RUN mkdir -p /Pysces \ && mkdir -p /root/Pysces \ && mkdir -p /root/Pysces/psc \ && chmod ugo+rw -R /Pysces - COPY ./.pys_usercfg.ini /Pysces/.pys_usercfg.ini COPY ./.pys_usercfg.ini /root/Pysces/.pys_usercfg.ini # Install only worker deps TODO: include toml in base deps -RUN poetry install --only=worker,pysces --no-cache - - -# Install Assimulo from source for Pysces -# RUN apt-get update \ -# && apt-get install -y libblas-dev \ -# liblapack-dev \ -# libatlas-base-dev \ -# python3-distutils \ -# python3-dev \ -# && git clone https://github.com/modelon-community/Assimulo.git \ -# && cd Assimulo \ -# && poetry run pip install --upgrade setuptools pip wheel Cython numpy \ -# && poetry run python3 setup.py install --sundials-home=/usr/local --blas-home=/usr/lib/x86_64-linux-gnu - - -# install masspy TODO: implement this -# RUN apt-get install -y --no-install-recommends \ -# git \ -# gcc \ -# build-essential \ -# libfreetype6-dev \ -# libfreetype6 \ -# pkg-config \ -# \ -# && mkdir -p /.cache/cobrapy -# RUN git clone https://github.com/biosimulators/Biosimulators_MASSpy.git \ -# && cd Biosimulators_MASSpy \ -# && rm pyproject.toml +RUN python3 -m venv env \ + && env/bin/pip install -r /app/worker/requirements.worker.txt + + +# install amici +# RUN env/bin/pip install biosimulators-amici WORKDIR /app/worker -RUN python3 -c "import os;files=os.listdir();import shutil;[shutil.rmtree(f) if '__pycache__' in f else None for f in files]" +# RUN python3 -c "import os;files=os.listdir();import shutil;[shutil.rmtree(f) if '__pycache__' in f else None for f in files]" -ENTRYPOINT ["poetry", "run", "python3", "main.py"] +# ENTRYPOINT ["env/bin/python3", "main.py"] ############################# diff --git a/compose_worker/_Dockerfile-compose_worker b/compose_worker/_Dockerfile-compose_worker new file mode 100644 index 000000000..547ab9687 --- /dev/null +++ b/compose_worker/_Dockerfile-compose_worker @@ -0,0 +1,151 @@ +# Worker microservice ORIGINAL CONTENT + +FROM ghcr.io/biosimulators/bio-check-base:latest + + +# os deps +RUN apt-get update && apt-get install -y libatlas-base-dev \ + libhdf5-serial-dev \ + swig \ + libboost-all-dev \ + git \ + meson \ + build-essential \ + g++ \ + gfortran \ + libblas-dev \ + liblapack-dev \ + gcc \ + gfortran \ + libgfortran5 + + +# PySCeS + +# SUNDIALS --> installation path is default cmake (/usr/local) with LD_LIBRARY_PATH as runtime location +# ignore certificate checking because certificate was expired as of 2021-11-10 +ARG SUNDIALS_VERSION=2.6.2 +RUN apt-get install -y --no-install-recommends \ + wget \ + cmake \ + make \ + g++ \ + \ + && cd /tmp \ + && wget --no-check-certificate https://computing.llnl.gov/sites/default/files/inline-files/sundials-${SUNDIALS_VERSION}.tar.gz \ + && tar xvvf sundials-${SUNDIALS_VERSION}.tar.gz \ + && cd sundials-${SUNDIALS_VERSION} \ + && mkdir build \ + && cd build \ + && CFLAGS="-fPIC" cmake .. \ + && make \ + && make install \ + \ + && cd /tmp \ + && rm sundials-${SUNDIALS_VERSION}.tar.gz \ + && rm -r sundials-${SUNDIALS_VERSION} +ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH + + +############################################ +# App content + +COPY . /app/worker + + +ENV PATH="/root/.local/bin:$PATH" +ENV TEST_SBML_FP="test_fixtures/Elowitz-Nature-2000-Repressilator/BIOMD0000000012_url.xml" +ENV TEST_OMEX_FP="test_fixtures/Elowitz-Nature-2000-Repressilator.omex" + + +# copy pysces config +RUN mkdir -p /Pysces \ + && mkdir -p /Pysces/psc \ + && mkdir -p /root/Pysces \ + && mkdir -p /root/Pysces/psc \ + && chmod ugo+rw -R /Pysces + +COPY ./.pys_usercfg.ini /Pysces/.pys_usercfg.ini +COPY ./.pys_usercfg.ini /root/Pysces/.pys_usercfg.ini + + +# Install only worker deps TODO: include toml in base deps +RUN poetry install --only=worker,pysces --no-cache + + +# Install Assimulo from source for Pysces +# RUN apt-get update \ +# && apt-get install -y libblas-dev \ +# liblapack-dev \ +# libatlas-base-dev \ +# python3-distutils \ +# python3-dev \ +# && git clone https://github.com/modelon-community/Assimulo.git \ +# && cd Assimulo \ +# && poetry run pip install --upgrade setuptools pip wheel Cython numpy \ +# && poetry run python3 setup.py install --sundials-home=/usr/local --blas-home=/usr/lib/x86_64-linux-gnu + + +# install masspy TODO: implement this +# RUN apt-get install -y --no-install-recommends \ +# git \ +# gcc \ +# build-essential \ +# libfreetype6-dev \ +# libfreetype6 \ +# pkg-config \ +# \ +# && mkdir -p /.cache/cobrapy +# RUN git clone https://github.com/biosimulators/Biosimulators_MASSpy.git \ +# && cd Biosimulators_MASSpy \ +# && rm pyproject.toml + + +WORKDIR /app/worker + + +RUN python3 -c "import os;files=os.listdir();import shutil;[shutil.rmtree(f) if '__pycache__' in f else None for f in files]" + + +ENTRYPOINT ["poetry", "run", "python3", "main.py"] + + +############################# +# Fenics + +# TODO: start the fenics implementation +# RUN apt-get update && apt-get install -y petsc-dev \ +# libopenmpi-dev \ +# libspdlog-dev \ +# libpugixml-dev \ +# cmake \ +# gcc \ +# g++ \ +# gfortran \ +# && rm -rf /var/lib/apt/lists/* \ +# && add-apt-repository ppa:fenics-packages/fenics -y \ +# && apt update \ +# && apt install -y fenicsx \ +# && poetry run pip install meson-python meson ninja + +# RUN poetry run pip install \ +# biosimulators-utils[logging] \ +# biosimulators-amici \ +# biosimulators-copasi \ +# biosimulators-pysces \ +# biosimulators-tellurium + +# add deps with extras +# RUN yes | poetry cache clear PyPI --all \ +# && poetry add biosimulators-utils --extras=logging \ +# && poetry add pysces --extras=sbml \ +# && poetry add biosimulators-copasi --python="^3.10" + +# install requirements in poetry via pip prox +# RUN poetry run pip install -r /app/worker/requirements.worker.txt + +# install masspy TODO: do this +# RUN poetry run pip install biosimulators-masspy + +# install with poetry TODO: remove this eventually +# RUN /app/assets/install_deps.sh /app/worker/requirements.worker.txt \ No newline at end of file diff --git a/compose_worker/output_data.py b/compose_worker/output_data.py index 4a0cdfa46..44e181c99 100644 --- a/compose_worker/output_data.py +++ b/compose_worker/output_data.py @@ -1,34 +1,49 @@ +import os from tempfile import mkdtemp from typing import * from importlib import import_module import libsbml import numpy as np +from kisao import AlgorithmSubstitutionPolicy +from biosimulators_utils.config import Config + +from shared import handle_exception +from data_model import BiosimulationsRunOutputData +from compatible import COMPATIBLE_UTC_SIMULATORS +from io_worker import read_report_outputs, normalize_smoldyn_output_path_in_root, make_dir, read_h5_reports + +AMICI_ENABLED = True +COPASI_ENABLED = True +PYSCES_ENABLED = True +TELLURIUM_ENABLED = True +SMOLDYN_ENABLED = True try: from amici import SbmlImporter, import_model_module, Model, runAmiciSimulation except ImportError as e: print(e) + AMICI_ENABLED = False try: from basico import * except ImportError as e: print(e) + COPASI_ENABLED = False try: import tellurium as te except ImportError as e: print(e) + TELLURIUM_ENABLED = False try: from smoldyn import Simulation except ImportError as e: print(e) -from kisao import AlgorithmSubstitutionPolicy -from biosimulators_utils.config import Config -# from biosimulators_simularium import execute as execute_simularium - -from shared import handle_exception -from data_model import BiosimulationsRunOutputData -from compatible import COMPATIBLE_UTC_SIMULATORS -from io_worker import read_report_outputs, normalize_smoldyn_output_path_in_root, make_dir, read_h5_reports + SMOLDYN_ENABLED = False +try: + import pysces +except ImportError as e: + print(e) + PYSCES_ENABLED = False # def generate_smoldyn_simularium(smoldyn_configuration_file: str, output_dest_dir: str, use_json: bool = True, agent_params=None, box_size=None): @@ -148,11 +163,6 @@ def get_sbml_species_mapping(sbml_fp: str): return dict(zip(names, species_ids)) -# 1. add try/except to each sbml output generator: {error: msg} -# 2. in output_stack: return {simname: output} -# 3. In species comparison: for sim in stack.keys(): if isinstance(stack[sim], str): sims.remove(sim), stack.remove(..) - - def handle_sbml_exception() -> str: import traceback from pprint import pformat @@ -162,28 +172,50 @@ def handle_sbml_exception() -> str: return error_message -def run_sbml_pysces(sbml_fp: str, start, dur, steps): - import pysces - import os - import shutil +# def run_sbml_pysces(sbml_fp: str, start, dur, steps): +# import pysces +# import os +# import shutil +# # model compilation +# compilation_dir = '/Pysces/psc' +# # compilation_dir = mkdtemp() +# sbml_filename = sbml_fp.split('/')[-1] +# psc_filename = sbml_filename + '.psc' +# psc_fp = os.path.join(compilation_dir, psc_filename) +# try: +# # convert sbml to psc +# # pysces.model_dir = compilation_dir +# # pysces.interface.convertSBML2PSC(sbmlfile=sbml_fp, pscfile=psc_fp) # sbmldir=os.path.dirname(sbml_fp) +# # instantiate model from compilation contents +# # with open(psc_fp, 'r', encoding='utf-8', errors='replace') as F: +# # pscS = F.read() +# # model = pysces.model(psc_fp, loader='string', fString=pscS) +# model = pysces.loadSBML(sbmlfile=sbml_fp, pscfile=psc_fp) +# # run the simulation with specified time params +# model.sim_time = np.linspace(start, dur, steps + 1) +# model.Simulate(1) # specify userinit=1 to directly use model.sim_time (t) rather than the default +# # get output with mapping of internal species ids to external (shared) species names +# sbml_species_mapping = get_sbml_species_mapping(sbml_fp) +# obs_names = list(sbml_species_mapping.keys()) +# obs_ids = list(sbml_species_mapping.values()) +# data = { +# name: model.data_sim.getSimData(obs_id)[:, 1].tolist() +# for name, obs_id in sbml_species_mapping.items() +# } +# # clean up model dir +# shutil.rmtree(compilation_dir) +# return data +# except: +# error_message = handle_sbml_exception() +# return {"error": error_message} - # model compilation - compilation_dir = '/Pysces/psc' - # compilation_dir = mkdtemp() - sbml_filename = sbml_fp.split('/')[-1] - psc_filename = sbml_filename + '.psc' - psc_fp = os.path.join(compilation_dir, psc_filename) - - try: - # convert sbml to psc - pysces.model_dir = compilation_dir - - # pysces.interface.convertSBML2PSC(sbmlfile=sbml_fp, pscfile=psc_fp) # sbmldir=os.path.dirname(sbml_fp) - # instantiate model from compilation contents - # with open(psc_fp, 'r', encoding='utf-8', errors='replace') as F: - # pscS = F.read() - # model = pysces.model(psc_fp, loader='string', fString=pscS) +def run_sbml_pysces(sbml_fp: str, start, dur, steps): + if PYSCES_ENABLED: + # model compilation + sbml_filename = sbml_fp.split('/')[-1] + psc_filename = sbml_filename + '.psc' + psc_fp = os.path.join(pysces.model_dir, psc_filename) model = pysces.loadSBML(sbmlfile=sbml_fp, pscfile=psc_fp) # run the simulation with specified time params @@ -195,17 +227,13 @@ def run_sbml_pysces(sbml_fp: str, start, dur, steps): obs_names = list(sbml_species_mapping.keys()) obs_ids = list(sbml_species_mapping.values()) data = { - obs_names[i]: model.data_sim.getSimData(obs_id)[:, 1].tolist() - for i, obs_id in enumerate(obs_ids) + name: model.data_sim.getSimData(obs_id)[:, 1].tolist() + for name, obs_id in sbml_species_mapping.items() } - # clean up model dir - shutil.rmtree(compilation_dir) - return data - except: - error_message = handle_sbml_exception() - return {"error": error_message} + else: + return OSError('Pysces is not properly installed in your environment.') def run_sbml_tellurium(sbml_fp: str, start, dur, steps): diff --git a/compose_worker/requirements.worker.txt b/compose_worker/requirements.worker.txt index c2b489da0..c5aa9d026 100644 --- a/compose_worker/requirements.worker.txt +++ b/compose_worker/requirements.worker.txt @@ -1,8 +1,14 @@ -biosimulators-utils[sbml,logging] -biosimulators-amici +requests-toolbelt +python-dotenv +google-cloud-storage +pymongo[srv] +python-multipart +fastapi +toml biosimulators-copasi biosimulators-pysces biosimulators-tellurium -cython -scipy -matplotlib +smoldyn +process-bigraph +simulariumio +