Source code for metawards._disease


from dataclasses import dataclass as _dataclass
from typing import List as _List
import pathlib as _pathlib
import os as _os

__all__ = ["Disease"]

_default_disease_path = _os.path.join(_pathlib.Path.home(),
                                      "GitHub", "MetaWardsData")

_default_folder_name = "diseases"


def _safe_eval_float(s):
    """Convert 's' to a float. This supports normal floats,
       but also simple maths expressions like 1/1.2
    """
    try:
        return float(s)
    except Exception:
        pass

    try:
        # this is about as save as eval gets in python
        return float(eval(s, {"__builtins__":None},{}))
    except Exception:
        pass

    raise ValueError(f"Cannot interpret '{s}' as a float")


[docs]@_dataclass class Disease: """This class holds the parameters about a single disease A disease is characterised as a serious of stages, each with their own values of the beta, progress, too_ill_to_move and contrib_foi parameters. To load a disease use the Disease.load function, e.g. Examples -------- >>> disease = Disease.load("ncov") >>> print(disease) Disease ncov repository: https://github.com/metawards/MetaWardsData repository_branch: master repository_version: 0.2.0 beta = [0.0, 0.0, 0.95, 0.95, 0.0] progress = [1.0, 0.1923, 0.909091, 0.909091, 0.0] too_ill_to_move = [0.0, 0.0, 0.0, 0.0, 0.0] contrib_foi = [1.0, 1.0, 1.0, 1.0, 0.0] """ #: Beta parameter for each stage of the disease beta: _List[float] = None #: Progress parameter for each stage of the disease progress: _List[float] = None #: TooIllToMove parameter for each stage of the disease too_ill_to_move: _List[float] = None #: Contribution to the Force of Infection (FOI) parameter for each #: stage of the disease contrib_foi: _List[float] = None #: Index of the first symptomatic stage start_symptom: int = None _name: str = None _version: str = None _authors: str = None _contacts: str = None _references: str = None _filename: str = None _repository: str = None _repository_version: str = None _repository_branch: str = None def __str__(self): return f"Disease {self._name}\n" \ f"loaded from {self._filename}\n" \ f"version: {self._version}\n" \ f"author(s): {self._authors}\n" \ f"contact(s): {self._contacts}\n" \ f"references(s): {self._references}\n" \ f"repository: {self._repository}\n" \ f"repository_branch: {self._repository_branch}\n" \ f"repository_version: {self._repository_version}\n\n" \ f"beta = {self.beta}\n" \ f"progress = {self.progress}\n" \ f"too_ill_to_move = {self.too_ill_to_move}\n" \ f"contrib_foi = {self.contrib_foi}\n" \ f"start_symptom = {self.start_symptom}\n\n" def __eq__(self, other): return self.beta == other.beta and \ self.progress == other.progress and \ self.too_ill_to_move == other.too_ill_to_move and \ self.contrib_foi == other.contrib_foi and \ self.start_symptom == other.start_symptom def __len__(self): if self.beta: return len(self.beta) else: return 0
[docs] def N_INF_CLASSES(self): """Return the number of stages of the disease""" return len(self.beta)
def _validate(self): """Check that the loaded parameters make sense""" try: n = len(self.beta) assert len(self.progress) == n assert len(self.too_ill_to_move) == n assert len(self.contrib_foi) == n except Exception as e: raise AssertionError(f"Data read for disease {self._name} " f"is corrupted! {e.__class__}: {e}") if self.start_symptom is None or self.start_symptom < 0 or \ self.start_symptom >= n: raise AssertionError(f"start_symptom {self.start_symptom} is " f"invalid for a disease with {n} stages") self.start_symptom = int(self.start_symptom) for i in range(0, n): try: self.progress[i] = _safe_eval_float(self.progress[i]) self.too_ill_to_move[i] = _safe_eval_float( self.too_ill_to_move[i]) self.beta[i] = _safe_eval_float(self.beta[i]) self.contrib_foi[i] = _safe_eval_float(self.contrib_foi[i]) except Exception as e: raise AssertionError( f"Invalid disease parameter at index {i}: " f"{e.__class__} {e}")
[docs] @staticmethod def load(disease: str = "ncov", repository: str = None, folder: str = _default_folder_name, filename: str = None): """Load the disease parameters for the specified disease. This will look for a file called f"{disease}.json" in the directory f"{repository}/{disease}/{disease}.ncon" By default this will load the ncov (SARS-Cov-2) parameters from $HOME/GitHub/model_data/2011Data/diseases/ncov.json Alternatively you can provide the full path to the json file via the "filename" argument Parameters ---------- disease: str The name of the disease to load. This is the name that will be searched for in the METAWARDSDATA diseases directory repository: str The location of the cloned METAWARDSDATA repository folder: str The name of the folder within the METAWARDSDATA repository that contains the diseases filename: str The name of the file to load the disease from - this directly loads this file without searching through the METAWARDSDATA repository Returns ------- disease: Disease The constructed and validated disease """ repository_version = None repository_branch = None if filename is None: import os if os.path.exists(disease): filename = disease elif os.path.exists(f"{disease}.json"): filename = f"{disease}.json" if filename is None: if repository is None: repository = _os.getenv("METAWARDSDATA") if repository is None: repository = _default_disease_path filename = _os.path.join(repository, folder, f"{disease}.json") from ._parameters import get_repository_version v = get_repository_version(repository) repository = v["repository"] repository_version = v["version"] repository_branch = v["branch"] json_file = filename try: with open(json_file, "r") as FILE: import json data = json.load(FILE) except Exception as e: print(f"Could not find the disease file {json_file}") print(f"Either it does not exist of was corrupted.") print(f"Error was {e.__class__} {e}") print(f"To download the disease data type the command:") print(f" git clone https://github.com/metawards/MetaWardsData") print(f"and then re-run this function passing in the full") print(f"path to where you downloaded this directory") raise FileNotFoundError(f"Could not find or read {json_file}: " f"{e.__class__} {e}") disease = Disease(beta=data.get("beta", []), progress=data.get("progress", []), too_ill_to_move=data.get("too_ill_to_move", []), contrib_foi=data.get("contrib_foi", []), start_symptom=data.get("start_symptom", 3), _name=disease, _authors=data["author(s)"], _contacts=data["contact(s)"], _references=data["reference(s)"], _filename=json_file, _repository=repository, _repository_branch=repository_branch, _repository_version=repository_version) disease._validate() return disease