guts-base 2.0.0b0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- guts_base/__init__.py +15 -0
- guts_base/data/__init__.py +35 -0
- guts_base/data/expydb.py +248 -0
- guts_base/data/generator.py +191 -0
- guts_base/data/openguts.py +296 -0
- guts_base/data/preprocessing.py +55 -0
- guts_base/data/survival.py +148 -0
- guts_base/data/time_of_death.py +595 -0
- guts_base/data/utils.py +8 -0
- guts_base/mod.py +332 -0
- guts_base/plot.py +201 -0
- guts_base/prob/__init__.py +13 -0
- guts_base/prob/binom.py +18 -0
- guts_base/prob/conditional_binom.py +118 -0
- guts_base/prob/conditional_binom_mv.py +233 -0
- guts_base/prob/predictions.py +164 -0
- guts_base/sim/__init__.py +28 -0
- guts_base/sim/base.py +1286 -0
- guts_base/sim/config.py +170 -0
- guts_base/sim/constructors.py +31 -0
- guts_base/sim/ecx.py +585 -0
- guts_base/sim/mempy.py +290 -0
- guts_base/sim/report.py +405 -0
- guts_base/sim/transformer.py +548 -0
- guts_base/sim/units.py +313 -0
- guts_base/sim/utils.py +10 -0
- guts_base-2.0.0b0.dist-info/METADATA +853 -0
- guts_base-2.0.0b0.dist-info/RECORD +32 -0
- guts_base-2.0.0b0.dist-info/WHEEL +5 -0
- guts_base-2.0.0b0.dist-info/entry_points.txt +3 -0
- guts_base-2.0.0b0.dist-info/licenses/LICENSE +674 -0
- guts_base-2.0.0b0.dist-info/top_level.txt +1 -0
guts_base/sim/config.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
import numpy as np
|
|
3
|
+
from pydantic import BeforeValidator, ConfigDict, PlainSerializer
|
|
4
|
+
from typing import Literal, Optional, List, Dict, Tuple, Annotated, Mapping
|
|
5
|
+
from pymob.sim.config import (
|
|
6
|
+
PymobModel,
|
|
7
|
+
string_to_list,
|
|
8
|
+
serialize_list_to_string,
|
|
9
|
+
nested_dict_to_string,
|
|
10
|
+
to_nested_dict,
|
|
11
|
+
string_to_dict,
|
|
12
|
+
serialize_dict_to_string,
|
|
13
|
+
OptionListStr,
|
|
14
|
+
)
|
|
15
|
+
from pymob.sim.config.casestudy_registry import register_case_study_config
|
|
16
|
+
|
|
17
|
+
OptionListMix = Annotated[
|
|
18
|
+
Optional[Tuple[float,float,int]],
|
|
19
|
+
BeforeValidator(string_to_list),
|
|
20
|
+
serialize_list_to_string
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
OptionListFloat = Annotated[
|
|
24
|
+
List[float],
|
|
25
|
+
BeforeValidator(string_to_list),
|
|
26
|
+
serialize_list_to_string
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
class ExposureDict(PymobModel):
|
|
30
|
+
start: float = 0.0
|
|
31
|
+
end: Optional[float] = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
serialize_datavar_to_string = PlainSerializer(
|
|
35
|
+
partial(nested_dict_to_string, dict_model=ExposureDict),
|
|
36
|
+
return_type=str,
|
|
37
|
+
when_used="json"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
NestedDict = Annotated[
|
|
41
|
+
Dict[str,Dict[str,float|None]],
|
|
42
|
+
BeforeValidator(partial(to_nested_dict, dict_model=ExposureDict)),
|
|
43
|
+
serialize_datavar_to_string
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
DictStr = Annotated[
|
|
48
|
+
Mapping[str, str],
|
|
49
|
+
BeforeValidator(partial(string_to_dict, split_str=" ", sep_str="=")),
|
|
50
|
+
serialize_dict_to_string
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
AllowedTimeUnits = Literal["second", "hour", "day", "minute",]
|
|
55
|
+
|
|
56
|
+
class GutsBaseConfig(PymobModel):
|
|
57
|
+
# extra arguments can be passed to the settings file, but they won't be validated
|
|
58
|
+
model_config = ConfigDict(validate_assignment=True, extra="allow", validate_default=True)
|
|
59
|
+
|
|
60
|
+
# the time unit of the simulation
|
|
61
|
+
unit_time: AllowedTimeUnits = "day"
|
|
62
|
+
|
|
63
|
+
# the input unit of the simulation, by default no unit is given
|
|
64
|
+
# It is however, highly recommended to priovide a unit for each exposure path/substance
|
|
65
|
+
# this would be done by specifiying, e.g. unit_input={"A": "mg", "B": "ng/kg"}
|
|
66
|
+
# if the openguts file consists of two exposure sheets (A and B)
|
|
67
|
+
# In future versions, the unit of exposure might be read directly from the metadata,
|
|
68
|
+
# at the moment it must be provided explicitly
|
|
69
|
+
unit_input: DictStr = {"default": ""}
|
|
70
|
+
|
|
71
|
+
# if the units should be converted to a target this will be specified here.
|
|
72
|
+
# The syntax is input->output and {x} is a placeholder for the input unit.
|
|
73
|
+
# This means, if the unit input of exposure is 'mg', then '{x}->{x}' applies no
|
|
74
|
+
# transformation. The target unit will also be 'mg'.
|
|
75
|
+
# To change the target unit, you could apply '{x}->mg'. Provided {x} is a mass quantity,
|
|
76
|
+
# the conversion will work. If however {x} is a concentration (mg/ml), then a more
|
|
77
|
+
# elaborate transformation is necessary: {x}/(1.12g/ml)->mg/mg
|
|
78
|
+
# this will successfully bring the output unit to a mass concentration.
|
|
79
|
+
# Generally, the string accepts any arithmetic operations that can be handled with pint
|
|
80
|
+
# https://pint.readthedocs.io/en/stable/getting/tutorial.html
|
|
81
|
+
# TODO: Write a validation method for the string. I could use pint for this already
|
|
82
|
+
unit_target: DictStr = {"default": "{x}->{x}"}
|
|
83
|
+
|
|
84
|
+
# If the dataset provided to GutsBase contains additional DataArrays with substance
|
|
85
|
+
# names, that should be used for exposure AND an exposure DataArray does not exist.
|
|
86
|
+
# Use this instead. A copy of that data array <substance> will be placed in
|
|
87
|
+
# observations["exposure"]. By default GutsBase assumes that the exposure data is
|
|
88
|
+
# contained in observations["exposure"]
|
|
89
|
+
substance: Optional[str] = None
|
|
90
|
+
|
|
91
|
+
# start, end and the number fo timepoints to interpolate the results for plotting
|
|
92
|
+
# this will be inserted into numpy.linspace
|
|
93
|
+
results_interpolation: OptionListMix = (np.nan, np.nan, 100)
|
|
94
|
+
|
|
95
|
+
# whether GutsBase should make sure that the exposure profiles are forward
|
|
96
|
+
# interpolated. This means, if a rectangular profile is not explicitly given,
|
|
97
|
+
# by providing the same exposure (time, value) combination at the moment before the
|
|
98
|
+
# next recorded change in the exposure profile, the default behavior is to interpolate
|
|
99
|
+
# linearly over the profile. E.g. a profile like (time=0,value=10), (time=2,value=0)
|
|
100
|
+
# would implicitly yield the points, e.g.: (time=1,value=5), (time=1.99, value=~0).
|
|
101
|
+
# If forward_interpolate_exposure_data = True, then the interpolated point would be
|
|
102
|
+
# (time=1,value=10), (time=1.99,value=10)
|
|
103
|
+
forward_interpolate_exposure_data: bool = False
|
|
104
|
+
|
|
105
|
+
# if the IT model is used, the x-dim (time) resolution needs to be increased
|
|
106
|
+
# (reindexed), because the solution requires numeric integration of the hazard
|
|
107
|
+
# function in each solve. The default is to increase the temporal resolution to
|
|
108
|
+
# 100 datapoints. If the simulated time period is very long, 100 points may not be
|
|
109
|
+
# enough to capture the dynamics of the hazard function
|
|
110
|
+
n_reindexed_x: int = 100
|
|
111
|
+
|
|
112
|
+
# this is if case_study.observations is an .xlsx file. In this case you are allowed
|
|
113
|
+
# to pass a preprocessing script by the full module path. e.g.
|
|
114
|
+
# 'guts_base.data.preprocessing.ringtest' where the last element is the function
|
|
115
|
+
# name in a regular python file. The function must have the arguments path and new_path
|
|
116
|
+
# because it will read the file and save a processed file.
|
|
117
|
+
# create_database_and_import_data_main will try to import this function with
|
|
118
|
+
# import_module and execute the preprocessing
|
|
119
|
+
# The default behavior is not to pass a string and preprocess the file
|
|
120
|
+
data_preprocessing: Optional[str] = None
|
|
121
|
+
|
|
122
|
+
# private option (should only in case of errors be modified by the user)
|
|
123
|
+
# this will skip the data_processing section of GutsBase.initialize
|
|
124
|
+
# >>> if not _skip_data_processing: self.process_data()
|
|
125
|
+
# This option is set to true when simulations are exported with .nc files,
|
|
126
|
+
# which already are processed and do not need (and can't be) processed again
|
|
127
|
+
skip_data_processing: bool = False
|
|
128
|
+
|
|
129
|
+
# this parameter is not for user interaction. It is simply set when parsing the model
|
|
130
|
+
background_mortality_parameters: OptionListStr = []
|
|
131
|
+
|
|
132
|
+
# GUTS-REPORT Settings
|
|
133
|
+
# ====================
|
|
134
|
+
|
|
135
|
+
# Guts base uses pint to parse units. To see which other options are available to
|
|
136
|
+
# format the resulting strings see:
|
|
137
|
+
# https://pint.readthedocs.io/en/stable/user/formatting.html
|
|
138
|
+
unit_format_pint: str = "~P"
|
|
139
|
+
|
|
140
|
+
# Define the exposure scenarios that should be used for ecx computations
|
|
141
|
+
ecx_exposure_scenarios: NestedDict = {
|
|
142
|
+
"acute_1day": {"start": 0.0, "end": 1.0},
|
|
143
|
+
"chronic": {"start": 0.0, "end": None},
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# whether to assess the uncertainty of the ECx estimate (draws) or not (mean)
|
|
147
|
+
ecx_mode: Literal["mean", "draws"] = "draws"
|
|
148
|
+
|
|
149
|
+
# number of draws from the posterior for assessing the uncertainty of the estimate
|
|
150
|
+
ecx_draws: int = 250
|
|
151
|
+
|
|
152
|
+
# if the number of draws is below 100, an error is raised. If ecx_force_draws,
|
|
153
|
+
# this error is supressed
|
|
154
|
+
ecx_force_draws: bool = False
|
|
155
|
+
|
|
156
|
+
# times after being of the exposure to estimate the ECx for
|
|
157
|
+
ecx_estimates_times: OptionListFloat = [1, 2, 4, 10]
|
|
158
|
+
|
|
159
|
+
# effect levels to estimate the ecx for
|
|
160
|
+
ecx_estimates_x: OptionListFloat = [0.1, 0.25, 0.5, 0.75, 0.9]
|
|
161
|
+
|
|
162
|
+
# whether the background mortality should be set to zero when estimating the ECx
|
|
163
|
+
ecx_set_background_mortality_to_zero: bool = True
|
|
164
|
+
|
|
165
|
+
# whether the posterior should be summarized with the mean or the median of the
|
|
166
|
+
# distribution. Median is more robust
|
|
167
|
+
table_parameter_stat_focus: Literal["mean", "median"] = "median"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
register_case_study_config("guts_base", model_cls=GutsBaseConfig)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import arviz as az
|
|
3
|
+
from guts_base.sim import GutsBase
|
|
4
|
+
|
|
5
|
+
def construct_sim_from_config(
|
|
6
|
+
scenario: str,
|
|
7
|
+
simulation_class: type,
|
|
8
|
+
output_path=None
|
|
9
|
+
) -> GutsBase:
|
|
10
|
+
"""Helper function to construct simulations for debugging"""
|
|
11
|
+
sim = simulation_class(f"scenarios/{scenario}/settings.cfg")
|
|
12
|
+
|
|
13
|
+
# this sets a different output directory
|
|
14
|
+
if output_path is not None:
|
|
15
|
+
p = output_path / sim.config.case_study.name / "results" / sim.config.case_study.scenario
|
|
16
|
+
sim.config.case_study.output_path = str(p)
|
|
17
|
+
else:
|
|
18
|
+
sim.config.case_study.scenario = "debug_test"
|
|
19
|
+
sim.setup()
|
|
20
|
+
return sim
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def load_idata(sim: GutsBase, idata_file: str) -> GutsBase:
|
|
24
|
+
sim.set_inferer("numpyro")
|
|
25
|
+
|
|
26
|
+
if os.path.exists(idata_file):
|
|
27
|
+
sim.inferer.idata = az.from_netcdf(idata_file)
|
|
28
|
+
else:
|
|
29
|
+
sim.inferer.idata = None
|
|
30
|
+
|
|
31
|
+
return sim
|