diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..de109aff --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:latest +RUN apt update -y +RUN apt upgrade -y +RUN apt install build-essential python3 python3-pip git vim -y +RUN python3 -m pip install cmake +RUN git clone https://github.com/ScottishCovidResponse/Covid19_EERAModel.git /home/Covid19_EERAModel +RUN git clone https://github.com/ScottishCovidResponse/data_pipeline_api.git /home/Covid19_EERAModel/api +RUN python3 -m pip install -r /home/Covid19_EERAModel/api/bindings/cpp/requirements.txt +WORKDIR /home/Covid19_EERAModel +ENV DEBIAN_FRONTEND=noninteractive +RUN apt install -y libgsl-dev pkg-config +RUN cmake -H. -Bbuild -DDATA_PIPELINE=/home/Covid19_EERAModel/api -DPython3_EXECUTABLE=$(which python3) +RUN cmake --build build +ENV EERAMODEL_ROOT=/home/Covid19_EERAModel +ENTRYPOINT [ "/usr/bin/bash" ] \ No newline at end of file diff --git a/README.md b/README.md index 3b549c7a..ceb15dab 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,22 @@ At the present time, the `-d` and `-l` options are unused by the code and can be The command line options used on a given model run are logged in the output log file (see below) for traceability and future reference. +### Running with Docker + +The model can also be run via the included Dockerfile, firstly build the image by running: + +```bash +docker build --label eeramodel +``` + +you can then run an interactive terminal within a new container, with the additional option of mounting the repository to your local file system (important for having access to the model outputs): + +```bash +docker run -ti --label eeramodel_container -v :/home/Covid19_EERAModel eeramodel +``` + +note however that these outputs will be owned by `root` within the container, as such it is highly advised that this method not be used for development. If you do not care about having access to the files on your host file system the volume option can be dropped. + ### Inputs The model requires a number of input files to run, in addition to the command line arguments. Input files must be placed in the `data` directory, and must be named according to the table below. The required contents of each file are described in more detail underneath the table. diff --git a/src/IO.cpp b/src/IO.cpp index 4f42ab6f..4aa28355 100644 --- a/src/IO.cpp +++ b/src/IO.cpp @@ -430,16 +430,11 @@ void WriteOutputsToFiles(int smc, int herd_id, int Nparticle, int nPar, output_simu << "iterID" << "," << "day" << "," << "inc_case" << "," << "inc_death_hospital" << "," << "inc_death" << std::endl; //add the column names for each output list of the compartment values of the last day of the chosen simulations - output_ends << "iterID" << "," << "age_group" << "," << "comparts" << "," << "value" << std::endl; + WriteInferenceEndsHeader(output_ends); // outputs the list of particles (and corresponding predictions) that were accepted at each steps of ABC-smc for (int kk = 0; kk < Nparticle; ++kk) { - output_step << particleList[kk].iter << ", " << particleList[kk].nsse_cases << ", " << particleList[kk].nsse_deaths << ", " ; - - for (int var = 0; var < nPar; ++var) { - output_step << particleList[kk].parameter_set[var] << ", "; - } - output_step << particleList[kk].weight<< '\n'; + WriteInferenceParticlesRow(output_step, kk, particleList[kk]); for (unsigned int var = 0; var < particleList[kk].simu_outs.size(); ++var) { output_simu << particleList[kk].iter << ", " << var << ", " << particleList[kk].simu_outs[var] << ", " \ @@ -447,9 +442,7 @@ void WriteOutputsToFiles(int smc, int herd_id, int Nparticle, int nPar, } for (unsigned int age = 0; age < particleList[kk].end_comps.size(); ++age) { - for (unsigned int var = 0; var < particleList[kk].end_comps[0].size(); ++var) { - output_ends << particleList[kk].iter << ", " << age << ", " << var << ", " << particleList[kk].end_comps[age][var] << '\n'; - } + WriteInferenceEndsRow(output_ends, particleList[kk].iter, age, particleList[kk].end_comps[age]); } } @@ -499,6 +492,12 @@ void WritePredictionFullHeader(std::ostream& os) " I1, I2, I3, I4, I_s1, I_s2, I_s3, I_s4, H, R, D" << std::endl; } +void WriteInferenceEndsHeader(std::ostream& os) +{ + os << "iter, age_group, S, E, E_t, I_p, I_t," + " I1, I2, I3, I4, I_s1, I_s2, I_s3, I_s4, H, R, D" << std::endl; +} + void WritePredictionFullRow(std::ostream& os, int iter, int day, int age_group, const Compartments& comp) { os << iter << ", "; @@ -522,6 +521,44 @@ void WritePredictionFullRow(std::ostream& os, int iter, int day, int age_group, os << comp.D << std::endl; } +void WriteInferenceEndsRow(std::ostream& os, int iter, int age_group, const Compartments& comp) +{ + os << iter << ", "; + os << age_group << ", "; + os << comp.S << ", "; + os << comp.E << ", "; + os << comp.E_t << ", "; + os << comp.I_p << ", "; + os << comp.I_t << ", "; + os << comp.I1 << ", "; + os << comp.I2 << ", "; + os << comp.I3 << ", "; + os << comp.I4 << ", "; + os << comp.I_s1 << ", "; + os << comp.I_s2 << ", "; + os << comp.I_s3 << ", "; + os << comp.I_s4 << ", "; + os << comp.H << ", "; + os << comp.R << ", "; + os << comp.D << std::endl; +} + +void WriteInferenceParticlesRow(std::ostream& os, int iter, const particle particle) +{ + os << iter << ", "; + os << particle.nsse_cases << ", "; + os << particle.nsse_deaths << ", "; + os << particle.parameter_set[Model::ModelParameters::PINF] << ", "; + os << particle.parameter_set[Model::ModelParameters::PHCW] << ", "; + os << particle.parameter_set[Model::ModelParameters::CHCW] << ", "; + os << particle.parameter_set[Model::ModelParameters::D] << ", "; + os << particle.parameter_set[Model::ModelParameters::Q] << ", "; + os << particle.parameter_set[Model::ModelParameters::PS] << ", "; + os << particle.parameter_set[Model::ModelParameters::RRD] << ", "; + os << particle.parameter_set[Model::ModelParameters::LAMBDA] << ", "; + os << particle.weight << std::endl; +} + void WritePredictionSimuHeader(std::ostream& os) { os << "iter, day, " << "inc_case, " << "inc_death_hospital, " << "inc_death" << std::endl; diff --git a/src/IO.h b/src/IO.h index cdf32f9d..beea6853 100644 --- a/src/IO.h +++ b/src/IO.h @@ -1,6 +1,7 @@ #pragma once #include "ModelTypes.h" +#include "ModelCommon.h" #include "IniFile.h" #include "Utilities.h" #include @@ -185,10 +186,19 @@ void WritePredictionsToFiles(std::vector statuses, const std::string& ou */ void WritePredictionFullHeader(std::ostream& os); +/** + * @brief Write header row for inference end outputs + * + * Writes inference end state file header, followed by a newline + * + * @param os Stream to write the header to + */ +void WriteInferenceEndsHeader(std::ostream& os); + /** * @brief Write data row for prediction full outputs * - * Writes @p iter, @p daya, @p age_group, followed by the contents of @p comp, followed by a newline + * Writes @p iter, @p day, @p age_group, followed by the contents of @p comp, followed by a newline * * @param os Stream to write the row to * @param iter Iteration number @@ -198,6 +208,30 @@ void WritePredictionFullHeader(std::ostream& os); */ void WritePredictionFullRow(std::ostream& os, int iter, int day, int age_group, const Compartments& comp); +/** + * @brief Write data row for inference ends outputs + * + * Writes @p iter, @p age_group, followed by the contents of @p comp, followed by a newline + * + * @param os Stream to write the row to + * @param iter Iteration number + * @param day Day number + * @param age_group Age group number + * @param comp Epidemiological compartments for @p age_group + */ +void WriteInferenceEndsRow(std::ostream& os, int iter, int age_group, const Compartments& comp); + +/** + * @brief Write data row for inference ends outputs + * + * Writes @p iter, @p age_group, followed by the contents of @p comp, followed by a newline + * + * @param os Stream to write the row to + * @param iter Iteration number + * @param particle A particle representing a set of parameters + */ +void WriteInferenceParticlesRow(std::ostream& os, int iter, const particle particle); + /** * @brief Write header row for prediction simulation outputs * diff --git a/src/InferenceFramework.cpp b/src/InferenceFramework.cpp index 1f366b1b..f19e560a 100644 --- a/src/InferenceFramework.cpp +++ b/src/InferenceFramework.cpp @@ -218,7 +218,7 @@ void InferenceFramework::ModelSelect(EERAModel::particle& outvec, int n_sim_step outvec.simu_outs = status.simulation; outvec.hospital_death_outs = status.hospital_deaths; outvec.death_outs = status.deaths; - outvec.end_comps = Model::compartments_to_vector(status.ends); + outvec.end_comps = status.ends; } double InferenceFramework::ComputeParticleWeight(int smc, const std::vector& previousParticles, diff --git a/src/ModelCommon.cpp b/src/ModelCommon.cpp index 6bd2eac1..5e7697ca 100644 --- a/src/ModelCommon.cpp +++ b/src/ModelCommon.cpp @@ -60,20 +60,5 @@ int accumulate_compartments(const Compartments& comp) return _total; } -std::vector> compartments_to_vector(const std::vector& cmps_vec) -{ - std::vector> _temp; - - for(auto cmps : cmps_vec) - { - _temp.push_back({cmps.S, cmps.E, cmps.E_t, cmps.I_p, - cmps.I_t, cmps.I1, cmps.I2, cmps.I3, - cmps.I4, cmps.I_s1, cmps.I_s2, cmps.I_s3, - cmps.I_s4, cmps.H, cmps.R, cmps.D}); - } - - return _temp; -} - } // namespace Model } // namespace EERAModel \ No newline at end of file diff --git a/src/ModelCommon.h b/src/ModelCommon.h index c3315817..c996892e 100644 --- a/src/ModelCommon.h +++ b/src/ModelCommon.h @@ -164,17 +164,5 @@ std::vector ComputeAgeNums(int shb_id, int Npop, int N_hcw, const Observati */ std::vector BuildFixedParameters(unsigned int size, params parameters); -/** - * @brief Convert Vector of Compartments struct to a vector of integers - * - * NOTE: This is a temporary function to allow compatibility - * converts the Compartments struct to a vector of integers - * - * @param cmps_vec Vector of compartments struct containing population per category - * - * @return Vector of population counters - */ -std::vector> compartments_to_vector(const std::vector& cmps_vec); - } // namespace Model } // namespace EERAModel \ No newline at end of file diff --git a/src/ModelTypes.h b/src/ModelTypes.h index 39046893..35421e06 100644 --- a/src/ModelTypes.h +++ b/src/ModelTypes.h @@ -5,6 +5,31 @@ namespace EERAModel { +/** + * @brief Structure containing counters for different population categories + * + * Integers to count the number of people within the different compartments within the model + */ +struct Compartments +{ + int S = 0; /*!< Number of susceptible individuals (not infected). */ + int E = 0; /*!< Number of infected individuals but not yet infectious (exposed). */ + int E_t = 0; /*!< Number of exposed individuals and tested positive. */ + int I_p = 0; /*!< Number of infected and infectious symptomatic individuals but at pre-clinical stage (show yet no symptoms). */ + int I_t = 0; /*!< Number of tested positive individuals that infectious. */ + int I1 = 0; /*!< Number of infected and infectious asymptomatic individuals: first stage. */ + int I2 = 0; /*!< Number of infected and infectious asymptomatic individuals: second stage. */ + int I3 = 0; /*!< Number of infected and infectious asymptomatic individuals: third stage. */ + int I4 = 0; /*!< Number of infected and infectious asymptomatic individuals: last stage. */ + int I_s1 = 0; /*!< Number of infected and infectious symptomatic individuals: first stage. */ + int I_s2 = 0; /*!< Number of infected and infectious symptomatic individuals: second stage. */ + int I_s3 = 0; /*!< Number of infected and infectious symptomatic individuals: thrid stage. */ + int I_s4 = 0; /*!< Number of infected and infectious symptomatic individuals: last stage. */ + int H = 0; /*!< Number of infected individuals that are hospitalised. */ + int R = 0; /*!< Number of infected individuals that are recovered from infection. */ + int D = 0; /*!< Number of dead individuals due to disease. */ +}; + /** * @brief Structure for particles generated during inference */ @@ -17,7 +42,7 @@ struct particle { std::vector simu_outs; std::vector hospital_death_outs; std::vector death_outs; - std::vector< std::vector > end_comps; + std::vector< Compartments > end_comps; }; /** @@ -114,31 +139,6 @@ struct AgeGroupData std::vector pf_byage; /*!< Frailty Probability by age. */ }; -/** - * @brief Structure containing counters for different population categories - * - * Integers to count the number of people within the different compartments within the model - */ -struct Compartments -{ - int S = 0; /*!< Number of susceptible individuals (not infected). */ - int E = 0; /*!< Number of infected individuals but not yet infectious (exposed). */ - int E_t = 0; /*!< Number of exposed individuals and tested positive. */ - int I_p = 0; /*!< Number of infected and infectious symptomatic individuals but at pre-clinical stage (show yet no symptoms). */ - int I_t = 0; /*!< Number of tested positive individuals that infectious. */ - int I1 = 0; /*!< Number of infected and infectious asymptomatic individuals: first stage. */ - int I2 = 0; /*!< Number of infected and infectious asymptomatic individuals: second stage. */ - int I3 = 0; /*!< Number of infected and infectious asymptomatic individuals: third stage. */ - int I4 = 0; /*!< Number of infected and infectious asymptomatic individuals: last stage. */ - int I_s1 = 0; /*!< Number of infected and infectious symptomatic individuals: first stage. */ - int I_s2 = 0; /*!< Number of infected and infectious symptomatic individuals: second stage. */ - int I_s3 = 0; /*!< Number of infected and infectious symptomatic individuals: thrid stage. */ - int I_s4 = 0; /*!< Number of infected and infectious symptomatic individuals: last stage. */ - int H = 0; /*!< Number of infected individuals that are hospitalised. */ - int R = 0; /*!< Number of infected individuals that are recovered from infection. */ - int D = 0; /*!< Number of dead individuals due to disease. */ -}; - /** * @brief Structure to hold status objects *