Source code for emodpy_hiv.campaign.individual_intervention

import emod_api.schema_to_class as s2c

from emodpy.utils import validate_key_value_pair
from emodpy.campaign.individual_intervention import BroadcastEvent as BroadcastEvent
from emodpy.campaign.individual_intervention import BroadcastEventToOtherNodes as BroadcastEventToOtherNodes
from emodpy.campaign.individual_intervention import ControlledVaccine as ControlledVaccine
from emodpy.campaign.individual_intervention import DelayedIntervention as DelayedIntervention
from emodpy.campaign.individual_intervention import IndividualImmunityChanger as IndividualImmunityChanger
from emodpy.campaign.individual_intervention import IndividualNonDiseaseDeathRateModifier as IndividualNonDiseaseDeathRateModifier
from emodpy.campaign.individual_intervention import MigrateIndividuals as MigrateIndividuals
from emodpy.campaign.individual_intervention import MultiEffectBoosterVaccine as MultiEffectBoosterVaccine
from emodpy.campaign.individual_intervention import MultiEffectVaccine as MultiEffectVaccine
from emodpy.campaign.individual_intervention import MultiInterventionDistributor as MultiInterventionDistributor
from emodpy.campaign.individual_intervention import OutbreakIndividual as OutbreakIndividual
from emodpy.campaign.individual_intervention import PropertyValueChanger as PropertyValueChanger
from emodpy.campaign.individual_intervention import SimpleBoosterVaccine as SimpleBoosterVaccine
from emodpy.campaign.individual_intervention import SimpleVaccine as SimpleVaccine
from emodpy.campaign.individual_intervention import StandardDiagnostic as StandardDiagnostic
from emodpy.campaign.individual_intervention import IndividualIntervention
from emodpy.campaign.individual_intervention import IVCalendar as IVCalendar
from emodpy.utils import validate_value_range
from emodpy.campaign.utils import set_event
from emodpy_hiv.utils.emod_enum import (SensitivityType, SettingType, RelationshipType, EventOrConfig, PrioritizePartnersBy,
                                        CondomUsageParametersType)
from emodpy_hiv.utils.distributions import BaseDistribution
from emodpy_hiv.campaign.common import ValueMap, CommonInterventionParameters
from emodpy_hiv.campaign.waning_config import AbstractWaningConfig
from emod_api import campaign as api_campaign

from typing import Union

[docs]class Sigmoid: """ Defines a sigmoidal curve that can be used to define probabilities versus time. Args: min(float, optional): The left asymptote for the sigmoid trend over time. The **min** value must be smaller than the **max** value. Minimum value: -1 Maximum value: 1 Default value: 0 max(float, optional): The right asymptote for the sigmoid trend over time. The **max** value must be larger than the **min** value. Minimum value: -1 Maximum value: 1 Default value: 1 mid(float, optional): The time of the infection point in the sigmoid trend over time. Minimum value: 1900 Maximum value: 2200 Default value: 2000 rate(float, optional): The slope of the inflection point in the sigmoid trend over time. A Rate of 1 sets the slope to a 25% change in probability per year. Specify a negative Rate (e.g. -1) to achieve a negative sigmoid. Minimum value: -100 Maximum value: 100 Default value: 1 """ def __init__(self, min: float = 0, max: float = 1, mid: float = 2000, rate: float = 1): self.min = validate_value_range(min, 'min', -1, 1, float) self.max = validate_value_range(max, 'max', -1, 1, float) self.mid = validate_value_range(mid, 'mid', 1900, 2200, float) self.rate = validate_value_range(rate, 'rate', -100, 100, float) if self.min >= self.max: raise ValueError(f"The 'min'(={min}) value must be smaller than the 'max'(={max}) value.")
[docs] def check_value_ranges(self, class_name: str, min_low: float = -1, min_high: float = 1, max_low: float = -1, max_high: float = 1, mid_low: float = 0, mid_high: float = 3.40282e+38, rate_low: float = -100, rate_high: float = 100): if self.min < min_low or self.min > min_high: raise ValueError(f"For the {class_name} the Sigmoid's 'min'(={self.min}) value must be between {min_low} and {min_high}.") if self.max < max_low or self.max > max_high: raise ValueError(f"For the {class_name} the Sigmoid's 'max'(={self.max}) value must be between {max_low} and {max_high}.") if self.mid < mid_low or self.mid > mid_high: raise ValueError(f"For the {class_name} the Sigmoid's 'mid'(={self.mid}) value must be between {mid_low} and {mid_high}.") if self.rate < rate_low or self.rate > rate_high: raise ValueError(f"For the {class_name} the Sigmoid's 'rate'(={self.rate}) value must be between {rate_low} and {rate_high}.")
[docs] def to_schema_dict(self, campaign) -> s2c.ReadOnlyDict: """ A function that converts the Sigmoid object to a schema dictionary. """ sigmoid = s2c.get_class_with_defaults("idmType:Sigmoid", campaign.schema_path) sigmoid.Min = self.min sigmoid.Max = self.max sigmoid.Mid = self.mid sigmoid.Rate = self.rate sigmoid.finalize() return sigmoid
[docs]class RangeThreshold: """ An element of a look-up table where if a value (age in **AgeDiagnostic** or CD4 in **CD4Diagnostic**) is greater-than-or-equal-to the 'Low' value and less-than the 'High' value, the 'Event' will be broadcasted. Args: low(float, optional): The low end of the diagnostic level. For this 'Event' to be selected, the value must be greater-than-or-equal-to (>=) this threshold. Minimum value: 0 Maximum value: 2000 Default value: 0 high(float, optional): The high end of the diagnostic level. For this 'Event' to be selected, the value must be less-than this threshold. Minimum value: 0 Maximum value: 2000 Default value: 2000 event_to_broadcast(str, required): If 'low' <= value < 'high, then this event will be broadcast. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. """ def __init__(self, event_to_broadcast: str, low: float = 0, high: float = 2000): if event_to_broadcast is None or event_to_broadcast == '': raise ValueError(f"{event_to_broadcast} must be a string and cannot be None or empty.") self.event_to_broadcast = event_to_broadcast self.low = validate_value_range( low, 'low', 0, 2000, float) # Noqa: E241, E201, E221 self.high = validate_value_range(high, 'high', 0, 2000, float)
[docs] def to_schema_dict(self, campaign) -> s2c.ReadOnlyDict: """ A function that converts the Sigmoid object to a schema dictionary. """ rt = s2c.get_class_with_defaults("idmType:RangeThreshold", campaign.schema_path) rt.Low = self.low rt.High = self.high rt.Event = set_event(self.event_to_broadcast, 'event_to_broadcast', campaign, True) rt.finalize() return rt
[docs]class ARTDropout(IndividualIntervention): """ The **ARTDropout** intervention class removes an individual from antiretroviral therapy (ART) and interrupts their progress through the cascade of care. The individual's infectiousness will return to a non-suppressed level, and a new prognosis will be assigned. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'ARTDropout', common_intervention_parameters)
class ARTMortalityTable(IndividualIntervention): """ The **ARTMortalityTable** intervention class allows the user to modify an individual's life expectancy based on different levels of ART adherence; the user defines parameters for age, CD4 count, and time on ART in a multidimensional table which is then used to determine mortality rate. Note: If you have different adherence levels for each gender, then you will need to configure your campaign to distribute an ARTMortalityTable for each gender and adherence level. Additional considerations when using this intervention: - The model will not allow someone who is HIV negative to be put on ART. - A person who has not previously been on ART is considered to be 'starting ART' at the time this intervention is applied; the model will track this start time/duration. - If a person is already on ART from another intervention, receiving a second ART intervention will have no effect. - If a person is on already ART and receives the **ARTMortalityTable** intervention, the original ART start time will be used to calculate the duration from enrollment to ART AIDS Death. The duration since starting ART will not change; it will continue to increase. - If a person is on ART and receives the **ARTDropout** intervention, the person will go off ART and the duration will be reset; if receiving a new ART intervention, this new start time/duration will be used in any calculations. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. mortality_table(list[list[list[float]]], required): Three-dimensional array of mortality rates used to determine the number of days until AIDS death. Dimensioned by the values specified in **art_duration_days_bins**, **age_years_bins**, and **cd4_count_bins**. art_duration_days_bins(list[float], required): An array of bins representing the person's duration on ART, in days (greater than or equal to the value of the bin, but less than the value of the next bin). Each value represents the outer dimension of the **mortality_table**. Must be in ascending order. age_years_bins(list[float], required): An array of bins representing the age of the person, in years, at the time they received the intervention (greater than or equal to the value of the bin, but less than the value of the next bin). If they are new to ART, then it is the age that they started ART. If they are changing their adherence, then it is the age at that time. This bin is used to select the second dimension of the **mortality_table**. Must be in ascending order. cd4_count_bins(list[float], required): An array of bins representing a person's CD4 count at the time they received the intervention (started ART or changed adherence). For each value in the array, there will be one value in the associated row in the **mortality_table**. A mortality rate will be selected from the table as follows: * Person's CD4 is less than first value in array: Use first mortality rate * Person's CD4 is greater than the last value in the array: Use the last mortality rate * Person's CD4 is between two values: Use linear interpolation to find the mortality rate associated with the person's CD4 Must be in ascending order. days_to_achieve_viral_suppression(float, optional): The number of days after ART initiation over which infectiousness declines linearly until the **art_multiplier_on_transmission_prob_per_act** takes full effect. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 183 art_multiplier_on_transmission_prob_per_act(float, optional): Multiplier acting on Base_Infectivity to determine the per-act transmission probability of a virally suppressed HIV+ individual. Minimum value: 0 Maximum value: 1 Default value: 0.08 art_is_active_against_mortality_and_transmission(bool, optional): If set to true (1), ART will suppress viral load and extend prognosis. Default value: True common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None Example: Creating an ARTMortalityTable intervention with comprehensive mortality data: - 5 ART duration bins (0-6mo, 6-12mo, 12-24mo, 24-36mo, 36+mo) - 2 age groups (under 40, 40 and over) - 7 CD4 count bins reflecting different immune system states - Higher mortality rates for early ART duration and lower CD4 counts - Reduced mortality over time as patients stabilize on treatment >>> from emodpy_hiv.campaign.individual_intervention import ARTMortalityTable >>> from emodpy_hiv.campaign.common import CommonInterventionParameters >>> import emodpy_hiv.campaign as api_campaign >>> >>> art_duration_days_bins=[0, 183, 365, 730, 1095] # 0, 6mo, 1yr, 2yr, 3yr in days >>> age_years_bins=[0, 40] # Under 40, 40+ >>> cd4_count_bins=[0, 25, 74.5, 149.5, 274.5, 424.5, 624.5] # CD4 count thresholds >>> # Define mortality table: 5 duration bins x 2 age bins x 7 CD4 bins >>> mortality_table = [ >>> [ # Duration bin 0 (0-6 months) >>> [0.2015, 0.2015, 0.1128, 0.0625, 0.0312, 0.0206, 0.0162], # Age 0-40 >>> [0.0875, 0.0875, 0.0490, 0.0271, 0.0136, 0.0062, 0.0041] # Age 40+ >>> ], >>> [ # Duration bin 1 (6-12 months) >>> [0.0271, 0.0271, 0.0184, 0.0149, 0.0074, 0.0048, 0.0048], >>> [0.0171, 0.0171, 0.0116, 0.0094, 0.0047, 0.0030, 0.0030] >>> ], >>> [ # Duration bin 2 (12-24 months) >>> [0.0095, 0.0095, 0.0065, 0.0052, 0.0026, 0.0026, 0.0026], >>> [0.0095, 0.0095, 0.0065, 0.0052, 0.0026, 0.0026, 0.0026] >>> ], >>> [ # Duration bin 3 (24-36 months) >>> [0.0075, 0.0075, 0.0051, 0.0041, 0.0021, 0.0021, 0.0021], >>> [0.0075, 0.0075, 0.0051, 0.0041, 0.0021, 0.0021, 0.0021] >>> ], >>> [ # Duration bin 4 (36+ months) >>> [0.0060, 0.0060, 0.0041, 0.0033, 0.0017, 0.0017, 0.0017], >>> [0.0060, 0.0060, 0.0041, 0.0033, 0.0017, 0.0017, 0.0017] >>> ] >>> ] >>> >>> # Create the intervention >>> art_intervention = ARTMortalityTable(campaign=api_campaign, >>> mortality_table=mortality_table, >>> art_duration_days_bins=art_duration_days_bins, >>> age_years_bins=age_years_bins, >>> cd4_count_bins=cd4_count_bins, >>> days_to_achieve_viral_suppression=183.0, >>> art_multiplier_on_transmission_prob_per_act=0.08, >>> art_is_active_against_mortality_and_transmission=True, >>> common_intervention_parameters=CommonInterventionParameters(cost=1) >>> ) """ def __init__(self, campaign: api_campaign, mortality_table: list[list[list[float]]], art_duration_days_bins: list[float], age_years_bins: list[float], cd4_count_bins: list[float], days_to_achieve_viral_suppression: float = 183, art_multiplier_on_transmission_prob_per_act: float = 0.08, art_is_active_against_mortality_and_transmission: bool = True, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'ARTMortalityTable', common_intervention_parameters) self._validate_mortality_table_inputs(mortality_table, art_duration_days_bins, age_years_bins, cd4_count_bins) self._intervention.MortalityTable = mortality_table self._intervention.Days_To_Achieve_Viral_Suppression = validate_value_range(days_to_achieve_viral_suppression, 'days_to_achieve_viral_suppression', 0, 3.40282e+38, float) self._intervention.CD4_Count_Bins = cd4_count_bins self._intervention.Age_Years_Bins = age_years_bins self._intervention.ART_Multiplier_On_Transmission_Prob_Per_Act = validate_value_range(art_multiplier_on_transmission_prob_per_act, 'art_multiplier_on_transmission_prob_per_act', 0, 1, float) self._intervention.ART_Is_Active_Against_Mortality_And_Transmission = art_is_active_against_mortality_and_transmission self._intervention.ART_Duration_Days_Bins = art_duration_days_bins def _validate_mortality_table_inputs(self, mortality_table, art_duration_days_bins, age_years_bins, cd4_count_bins): """ Validate that mortality table and associated bins are consistent and properly formatted. Args: mortality_table: 3D list of mortality rates (required) art_duration_days_bins: List of ART duration bins (required) age_years_bins: List of age bins (required) cd4_count_bins: List of CD4 count bins (required) """ self._validate_bin_parameters(art_duration_days_bins, age_years_bins, cd4_count_bins) self._validate_mortality_table_structure_and_dimensions(mortality_table, art_duration_days_bins, age_years_bins, cd4_count_bins) def _validate_mortality_table_structure_and_dimensions(self, mortality_table, art_duration_days_bins, age_years_bins, cd4_count_bins): """ Validate the 3D structure, values, and dimensions of the mortality table in a single pass. Args: mortality_table: 3D list of mortality rates art_duration_days_bins: List of ART duration bins age_years_bins: List of age bins cd4_count_bins: List of CD4 count bins """ if not isinstance(mortality_table, list): raise TypeError("mortality_table must be a list") # Check first dimension (duration bins) if len(mortality_table) != len(art_duration_days_bins): raise ValueError(f"mortality_table first dimension ({len(mortality_table)}) must match art_duration_days_bins length ({len(art_duration_days_bins)})") # Validate each dimension and check dimensional consistency expected_age_bins = len(age_years_bins) expected_cd4_bins = len(cd4_count_bins) for i, outer_list in enumerate(mortality_table): if not isinstance(outer_list, list): raise TypeError(f"mortality_table[{i}] must be a list") # Check second dimension (age bins) if len(outer_list) != expected_age_bins: raise ValueError(f"mortality_table[{i}] length ({len(outer_list)}) must match age_years_bins length ({expected_age_bins})") for j, inner_list in enumerate(outer_list): if not isinstance(inner_list, list): raise TypeError(f"mortality_table[{i}][{j}] must be a list") # Check third dimension (CD4 bins) if len(inner_list) != expected_cd4_bins: raise ValueError(f"mortality_table[{i}][{j}] length ({len(inner_list)}) must match cd4_count_bins length ({expected_cd4_bins})") # Validate all values are numeric and within valid range for k, value in enumerate(inner_list): if not isinstance(value, (int, float)): raise TypeError(f"mortality_table[{i}][{j}][{k}] must be a number, got {type(value)}") if value < 0 or value > 1: raise ValueError(f"mortality_table[{i}][{j}][{k}] must between 0 and 1, got {value}") def _validate_bin_parameters(self, art_duration_days_bins, age_years_bins, cd4_count_bins): """ Validate the bin parameter arrays. Args: art_duration_days_bins: List of ART duration bins age_years_bins: List of age bins cd4_count_bins: List of CD4 count bins """ for bin_name, bin_values, max_value in [('art_duration_days_bins', art_duration_days_bins, None), ('age_years_bins', age_years_bins, 125), ('cd4_count_bins', cd4_count_bins, 1000)]: if not isinstance(bin_values, list): raise TypeError(f"{bin_name} must be a list") if len(bin_values) == 0: raise ValueError(f"{bin_name} cannot be empty") # Validate all values are numeric and non-negative for i, value in enumerate(bin_values): if not isinstance(value, (int, float)): raise TypeError(f"{bin_name}[{i}] must be a number, got {type(value)}") if value < 0: raise ValueError(f"{bin_name}[{i}] must be non-negative, got {value}") if max_value and value > max_value: raise ValueError(f"{bin_name}[{i}] must be less than or equal to {max_value}, got {value}") # Validate bins are in ascending order for i in range(1, len(bin_values)): if bin_values[i] <= bin_values[i-1]: raise ValueError(f"{bin_name} must be in ascending order: {bin_values[i-1]} >= {bin_values[i]} at positions {i-1}, {i}")
[docs]class AgeDiagnostic(IndividualIntervention): """ The **AgeDiagnostic** allows you to broadcast different events based on the individual's age. For example, you could distribute this intervention to people who are high risk and use the intervention to have different things happen (because of the broadcasted events) based on their age. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. age_thresholds(list[RangeThreshold], optional): Used to associate age ranges for individuals. Default value: None common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, age_thresholds: list[RangeThreshold] = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'AgeDiagnostic', common_intervention_parameters) for at in age_thresholds: self._intervention.Age_Thresholds.append(at.to_schema_dict(campaign))
[docs]class AntiretroviralTherapy(IndividualIntervention): """ The **AntiretroviralTherapy** intervention class begins antiretroviral therapy (ART) for specified individuals. To remove an individual from ART, use **ARTDropout**. Please refer to the documentation for **AntiretroviralTherapy** at the following link: :doc:`emod-hiv:emod/hiv-model-healthcare-systems`. Additional considerations when using this intervention: - The model will not allow someone who is HIV negative to be put on ART. - A person who has not previously been on ART is considered to be 'starting ART' at the time this intervention is applied; the model will track this start time/duration. - If a person is already on ART from another intervention, receiving a second ART intervention will have no effect. - If a person is on already ART and receives the ARTMortalityTable intervention, the original ART start time will be used to calculate the duration from enrollment to ART AIDS Death. The duration since starting ART will not change; it will continue to increase. - If a person is on ART and receives the **ARTDropout** intervention, the person will go off ART and the duration will be reset; if receiving a new ART intervention, this new start time/duration will be used in any calculations. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. days_to_achieve_viral_suppression(float, optional): The number of days after ART initiation over which infectiousness declines linearly until the **art_multiplier_on_transmission_prob_per_act** takes full effect. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 183 art_survival_who_stage_threshold_for_cox(float, optional): If the person receiving ART has a WHO Stage greater than or equal to this threshold, then use the hazard ratio determined by the parameter **art_survival_hazard_ratio_who_stage_3plus**. Minimum value: 0 Maximum value: 5 Default value: 3 art_survival_hazard_ratio_who_stage_3plus(float, optional): The hazard ratio comparing those starting ART in WHO stage >= 3 to those in WHO stage < 3. Minimum value: 1e-06 Maximum value: 1000000.0 Default value: 2.7142 art_survival_hazard_ratio_female(float, optional): The hazard ratio comparing survival female to male survival for those starting ART. Minimum value: 1e-06 Maximum value: 1000000.0 Default value: 0.6775 art_survival_hazard_ratio_cd4_slope(float, optional): The slope value to sue when calculating the hazard for for the person based on their CD4 count. multiplier = exp(cd4_slope * cd4 + cd4_intercept) Minimum value: -1000000.0 Maximum value: 1000000.0 Default value: -0.00758256 art_survival_hazard_ratio_cd4_intercept(float, optional): The Y-intercept to use when calculating the hazard ratio for the person based on their CD4 count. multiplier = exp(cd4_slope * cd4 + cd4_intercept) Minimum value: -1000000.0 Maximum value: 1000000.0 Default value: 0.282852 art_survival_hazard_ratio_body_weight_kg_slope(float, optional): The slope to use when calculating the hazard ratio for the person's body weight. The body weight is determined by WHO stage: * WHO Stage 0 = 65.0 kg * WHO Stage 1-2 = 62.1 kg * WHO Stage 2-3 = 57.0 kg * WHO Stage 3-4 = 50.0 kg * WHO Stage 4+ = 40.1 kg multiplier = exp(weight_slope * weight + weight_intercept) Minimum value: -1000000.0 Maximum value: 1000000.0 Default value: -0.073153 art_survival_hazard_ratio_body_weight_kg_intercept(float, optional): The Y-intercept to use when calculating the hazard ratio for the person's body weight. The body weight is determined by WHO stage: * WHO Stage 0 = 65.0 kg * WHO Stage 1-2 = 62.1 kg * WHO Stage 2-3 = 57.0 kg * WHO Stage 3-4 = 50.0 kg * WHO Stage 4+ = 40.1 kg multiplier = exp(weight_slope * weight + weight_intercept) Minimum value: -1000000.0 Maximum value: 1000000.0 Default value: 3.05043 art_survival_hazard_ratio_age_over_40yr(float, optional): The hazard ratio comparing the survival time of those starting ART over 40 years of age compared to those starting ART <40 years. Minimum value: 1e-06 Maximum value: 1000000.0 Default value: 1.4309 art_survival_baseline_hazard_weibull_shape(float, optional): Shape parameter for a Weibull distribution of survival time in years for a male < 40 with WHO stage of 1 or 2 starting ART (base case). Minimum value: 0 Maximum value: 10 Default value: 0.34 art_survival_baseline_hazard_weibull_scale(float, optional): Scale parameter for a Weibull distribution of survival time in years for a male < 40 with WHO stage of 1 or 2 starting ART (base case). Minimum value: 1e-06 Maximum value: 1000000.0 Default value: 123.83 art_multiplier_on_transmission_prob_per_act(float, optional): Multiplier acting on Base_Infectivity to determine the per-act transmission probability of a virally suppressed HIV+ individual. Minimum value: 0 Maximum value: 1 Default value: 0.08 art_is_active_against_mortality_and_transmission(bool, optional): If set to true (1), ART will suppress viral load and extend prognosis. Default value: True art_cd4_at_initiation_saturating_reduction_in_mortality(float, optional): The duration from ART enrollment to on-ART HIV-cause death increases with CD4 at ART initiation up to a threshold determined by this parameter value. This is the maximum value that CD4 is allowed to have in the hazard ratio calculation for CD4. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 350 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, days_to_achieve_viral_suppression: float = 183, art_survival_who_stage_threshold_for_cox: float = 3, art_survival_hazard_ratio_who_stage_3plus: float = 2.7142, art_survival_hazard_ratio_female: float = 0.6775, art_survival_hazard_ratio_cd4_slope: float = -0.00758256, art_survival_hazard_ratio_cd4_intercept: float = 0.282852, art_survival_hazard_ratio_body_weight_kg_slope: float = -0.073153, art_survival_hazard_ratio_body_weight_kg_intercept: float = 3.05043, art_survival_hazard_ratio_age_over_40yr: float = 1.4309, art_survival_baseline_hazard_weibull_shape: float = 0.34, art_survival_baseline_hazard_weibull_scale: float = 123.83, art_multiplier_on_transmission_prob_per_act: float = 0.08, art_is_active_against_mortality_and_transmission: bool = True, art_cd4_at_initiation_saturating_reduction_in_mortality: float = 350, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'AntiretroviralTherapy', common_intervention_parameters) self._intervention.Days_To_Achieve_Viral_Suppression = validate_value_range(days_to_achieve_viral_suppression, 'days_to_achieve_viral_suppression', 0, 3.40282e+38, float) self._intervention.ART_Survival_WHO_Stage_Threshold_For_Cox = validate_value_range(art_survival_who_stage_threshold_for_cox, 'art_survival_who_stage_threshold_for_cox', 0, 5, float) self._intervention.ART_Survival_Hazard_Ratio_WHO_Stage_3Plus = validate_value_range(art_survival_hazard_ratio_who_stage_3plus, 'art_survival_hazard_ratio_who_stage_3plus', 1e-06, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_Female = validate_value_range(art_survival_hazard_ratio_female, 'art_survival_hazard_ratio_female', 1e-06, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_CD4_Slope = validate_value_range(art_survival_hazard_ratio_cd4_slope, 'art_survival_hazard_ratio_cd4_slope', -1000000.0, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_CD4_Intercept = validate_value_range(art_survival_hazard_ratio_cd4_intercept, 'art_survival_hazard_ratio_cd4_intercept', -1000000.0, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_Body_Weight_Kg_Slope = validate_value_range(art_survival_hazard_ratio_body_weight_kg_slope, 'art_survival_hazard_ratio_body_weight_kg_slope', -1000000.0, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_Body_Weight_Kg_Intercept = validate_value_range(art_survival_hazard_ratio_body_weight_kg_intercept, 'art_survival_hazard_ratio_body_weight_kg_intercept', -1000000.0, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_Age_Over_40Yr = validate_value_range(art_survival_hazard_ratio_age_over_40yr, 'art_survival_hazard_ratio_age_over_40yr', 1e-06, 1000000.0, float) self._intervention.ART_Survival_Baseline_Hazard_Weibull_Shape = validate_value_range(art_survival_baseline_hazard_weibull_shape, 'art_survival_baseline_hazard_weibull_shape', 0, 10, float) self._intervention.ART_Survival_Baseline_Hazard_Weibull_Scale = validate_value_range(art_survival_baseline_hazard_weibull_scale, 'art_survival_baseline_hazard_weibull_scale', 1e-06, 1000000.0, float) self._intervention.ART_Multiplier_On_Transmission_Prob_Per_Act = validate_value_range(art_multiplier_on_transmission_prob_per_act, 'art_multiplier_on_transmission_prob_per_act', 0, 1, float) self._intervention.ART_Is_Active_Against_Mortality_And_Transmission = 1 if art_is_active_against_mortality_and_transmission else 0 self._intervention.ART_CD4_at_Initiation_Saturating_Reduction_in_Mortality = validate_value_range(art_cd4_at_initiation_saturating_reduction_in_mortality, 'art_cd4_at_initiation_saturating_reduction_in_mortality', 0, 3.40282e+38, float)
[docs]class AntiretroviralTherapyFull(IndividualIntervention): """ The **AntriretroviralTherapyFull** intervention class begins antiretroviral therapy (ART) on the person receiving the intervention. This class is similar to the standard AntiretroviralTherapy, but enhances it with two key features: 1) a built-in delay timer such that when the delay expires, the person will come off of ART (**ARTDropout** should NOT be used with this intervention), and 2) persistence with the individual so the user can track this intervention using ReferenceTrackingEventCoordinator. Additional considerations when using this intervention: - The model will not allow someone who is HIV negative to be put on ART. - A person who has not previously been on ART is considered to be 'starting ART' at the time this intervention is applied; the model will track this start time/duration. - If a person is already on ART from another intervention, receiving a second ART intervention will have no effect. - If a person is on already ART and receives the ARTMortalityTable intervention, the original ART start time will be used to calculate the duration from enrollment to ART AIDS Death. The duration since starting ART will not change; it will continue to increase. - If a person is on ART and receives the **ARTDropout** intervention, the person will go off ART and the duration will be reset; if receiving a new ART intervention, this new start time/duration will be used in any calculations. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. time_on_art_distribution(BaseDistribution, required): The type of distribution to use when determine how long a person will be on ART. Please use the following distribution classes from emodpy_hiv.utils.distributions to define the distribution: * ConstantDistribution * UniformDistribution * GaussianDistribution * ExponentialDistribution * PoissonDistribution * LogNormalDistribution * DualConstantDistribution * WeibullDistribution * DualExponentialDistribution stop_art_event(str, optional): This event is broadcast when the person drops off ART. This could happen either via the timer running out or the intervention detected a disqualifying property. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None days_to_achieve_viral_suppression(float, optional): The number of days after ART initiation over which infectiousness declines linearly until the **ART_Multiplier_On_Transmission_Prob_Per_Act** takes full effect. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 183 art_survival_who_stage_threshold_for_cox(float, optional): If the person receiving ART has a WHO Stage greater than or equal to this threshold, then use the hazard ratio determined by the parameter **ART_Survival_Hazard_Ratio_WHO_Stage_3Plus**. Minimum value: 0 Maximum value: 5 Default value: 3 art_survival_hazard_ratio_who_stage_3plus(float, optional): The hazard ratio comparing those starting ART in WHO stage >= 3 to those in WHO stage < 3. Minimum value: 1e-06 Maximum value: 1000000.0 Default value: 2.7142 art_survival_hazard_ratio_female(float, optional): The hazard ratio comparing survival female to male survival for those starting ART. Minimum value: 1e-06 Maximum value: 1000000.0 Default value: 0.6775 art_survival_hazard_ratio_cd4_slope(float, optional): The slope value to sue when calculating the hazard for for the person based on their CD4 count. multiplier = exp(cd4_slope * cd4 + cd4_intercept) Minimum value: -1000000.0 Maximum value: 1000000.0 Default value: -0.00758256 art_survival_hazard_ratio_cd4_intercept(float, optional): The Y-intercept to use when calculating the hazard ratio for the person based on their CD4 count. multiplier = exp(cd4_slope * cd4 + cd4_intercept) Minimum value: -1000000.0 Maximum value: 1000000.0 Default value: 0.282852 art_survival_hazard_ratio_body_weight_kg_slope(float, optional): The slope to use when calculating the hazard ratio for the person's body weight. The body weight is determined by WHO stage: * WHO Stage 0 = 65.0 kg * WHO Stage 1-2 = 62.1 kg * WHO Stage 2-3 = 57.0 kg * WHO Stage 3-4 = 50.0 kg * WHO Stage 4+ = 40.1 kg multiplier = exp(weight_slope * weight + weight_intercept) Minimum value: -1000000.0 Maximum value: 1000000.0 Default value: -0.073153 art_survival_hazard_ratio_body_weight_kg_intercept(float, optional): The Y-intercept to use when calculating the hazard ratio for the person's body weight. The body weight is determined by WHO stage: * WHO Stage 0 = 65.0 kg * WHO Stage 1-2 = 62.1 kg * WHO Stage 2-3 = 57.0 kg * WHO Stage 3-4 = 50.0 kg * WHO Stage 4+ = 40.1 kg multiplier = exp(weight_slope * weight + weight_intercept) Minimum value: -1000000.0 Maximum value: 1000000.0 Default value: 3.05043 art_survival_hazard_ratio_age_over_40yr(float, optional): The hazard ratio comparing the survival time of those starting ART over 40 years of age compared to those starting ART <40 years. Minimum value: 1e-06 Maximum value: 1000000.0 Default value: 1.4309 art_survival_baseline_hazard_weibull_shape(float, optional): Shape parameter for a Weibull distribution of survival time in years for a male < 40 with WHO stage of 1 or 2 starting ART (base case). Minimum value: 0 Maximum value: 10 Default value: 0.34 art_survival_baseline_hazard_weibull_scale(float, optional): Scale parameter for a Weibull distribution of survival time in years for a male < 40 with WHO stage of 1 or 2 starting ART (base case). Minimum value: 1e-06 Maximum value: 1000000.0 Default value: 123.83 art_multiplier_on_transmission_prob_per_act(float, optional): Multiplier acting on Base_Infectivity to determine the per-act transmission probability of a virally suppressed HIV+ individual. Minimum value: 0 Maximum value: 1 Default value: 0.08 art_is_active_against_mortality_and_transmission(bool, optional): If set to true (1), ART will suppress viral load and extend prognosis. Default value: True art_cd4_at_initiation_saturating_reduction_in_mortality(float, optional): The duration from ART enrollment to on-ART HIV-cause death increases with CD4 at ART initiation up to a threshold determined by this parameter value. This is the maximum value that CD4 is allowed to have in the hazard ratio calculation for CD4. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 350 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, time_on_art_distribution: BaseDistribution, stop_art_event: str = None, days_to_achieve_viral_suppression: float = 183, art_survival_who_stage_threshold_for_cox: float = 3, art_survival_hazard_ratio_who_stage_3plus: float = 2.7142, art_survival_hazard_ratio_female: float = 0.6775, art_survival_hazard_ratio_cd4_slope: float = -0.00758256, art_survival_hazard_ratio_cd4_intercept: float = 0.282852, art_survival_hazard_ratio_body_weight_kg_slope: float = -0.073153, art_survival_hazard_ratio_body_weight_kg_intercept: float = 3.05043, art_survival_hazard_ratio_age_over_40yr: float = 1.4309, art_survival_baseline_hazard_weibull_shape: float = 0.34, art_survival_baseline_hazard_weibull_scale: float = 123.83, art_multiplier_on_transmission_prob_per_act: float = 0.08, art_is_active_against_mortality_and_transmission: bool = True, art_cd4_at_initiation_saturating_reduction_in_mortality: float = 350, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'AntiretroviralTherapyFull', common_intervention_parameters) if not isinstance(time_on_art_distribution, BaseDistribution): raise ValueError(f"time_on_art_distribution must be an instance of BaseDistribution, not {type(time_on_art_distribution)}.") self.set_distribution(time_on_art_distribution, 'Time_On_ART') self._intervention.Stop_ART_Event = set_event(stop_art_event, 'stop_art_event', campaign, True) self._intervention.Days_To_Achieve_Viral_Suppression = validate_value_range(days_to_achieve_viral_suppression, 'days_to_achieve_viral_suppression', 0, 3.40282e+38, float) self._intervention.ART_Survival_WHO_Stage_Threshold_For_Cox = validate_value_range(art_survival_who_stage_threshold_for_cox, 'art_survival_who_stage_threshold_for_cox', 0, 5, float) self._intervention.ART_Survival_Hazard_Ratio_WHO_Stage_3Plus = validate_value_range(art_survival_hazard_ratio_who_stage_3plus, 'art_survival_hazard_ratio_who_stage_3plus', 1e-06, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_Female = validate_value_range(art_survival_hazard_ratio_female, 'art_survival_hazard_ratio_female', 1e-06, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_CD4_Slope = validate_value_range(art_survival_hazard_ratio_cd4_slope, 'art_survival_hazard_ratio_cd4_slope', -1000000.0, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_CD4_Intercept = validate_value_range(art_survival_hazard_ratio_cd4_intercept, 'art_survival_hazard_ratio_cd4_intercept', -1000000.0, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_Body_Weight_Kg_Slope = validate_value_range(art_survival_hazard_ratio_body_weight_kg_slope, 'art_survival_hazard_ratio_body_weight_kg_slope', -1000000.0, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_Body_Weight_Kg_Intercept = validate_value_range(art_survival_hazard_ratio_body_weight_kg_intercept, 'art_survival_hazard_ratio_body_weight_kg_intercept', -1000000.0, 1000000.0, float) self._intervention.ART_Survival_Hazard_Ratio_Age_Over_40Yr = validate_value_range(art_survival_hazard_ratio_age_over_40yr, 'art_survival_hazard_ratio_age_over_40yr', 1e-06, 1000000.0, float) self._intervention.ART_Survival_Baseline_Hazard_Weibull_Shape = validate_value_range(art_survival_baseline_hazard_weibull_shape, 'art_survival_baseline_hazard_weibull_shape', 0, 10, float) self._intervention.ART_Survival_Baseline_Hazard_Weibull_Scale = validate_value_range(art_survival_baseline_hazard_weibull_scale, 'art_survival_baseline_hazard_weibull_scale', 1e-06, 1000000.0, float) self._intervention.ART_Multiplier_On_Transmission_Prob_Per_Act = validate_value_range(art_multiplier_on_transmission_prob_per_act, 'art_multiplier_on_transmission_prob_per_act', 0, 1, float) self._intervention.ART_Is_Active_Against_Mortality_And_Transmission = 1 if art_is_active_against_mortality_and_transmission else 0 self._intervention.ART_CD4_at_Initiation_Saturating_Reduction_in_Mortality = validate_value_range(art_cd4_at_initiation_saturating_reduction_in_mortality, 'art_cd4_at_initiation_saturating_reduction_in_mortality', 0, 3.40282e+38, float)
[docs]class CD4Diagnostic(IndividualIntervention): """ The **CD4Diagnostic** allows you to have different things happen to a person based on their actual CD4 count. For example, if a person was given an HIVRapidDiagnostic and tested positive, you could give that person the **CD4Diagnositic**. The diagnostic would broadcast different events based on their current CD4 count. If the CD4 count was high, you could broadcast an event that would give the person a delay that would have the person re-test in three months. If the CD4 count was low, you could broadcast an event that would cause them to go on ART immediately. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. cd4_thresholds(list[RangeThreshold], optional): This parameter associates ranges of CD4 counts with events that should occur for individuals whose CD4 counts fall into those ranges. Default value: None common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, cd4_thresholds: list[RangeThreshold] = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'CD4Diagnostic', common_intervention_parameters) for ct in cd4_thresholds: self._intervention.CD4_Thresholds.append(ct.to_schema_dict(campaign))
[docs]class CoitalActRiskFactors(IndividualIntervention): """ The **CoitalActRiskFactors** intervention class provides a method of modifying an individual's risk/probability of acquiring or transmitting an STI. If other risk multipliers are active (across other interventions), the values will be multiplied together; the resulting value will be multiplied with any active STI co-infection factors. When the intervention expires, the individual's risk factor multiplier returns to one. Since this intervention persists, it can be used with Distributors.add_intervention_tracker(). NOTE: An individual can have multiple of these interventions with each one being multiplied times the other. The risk multiplier for a coital act has three contributions: 1. *Coital Act Risk Factors* - The factors from the use of this intervention. 2. *Co-Infection* - A person can get a co-infection by using the **ModifyStiCoInfectionStatus** intervention. If the person has a co-infection, then the configuration paameters **STI_Coinfection_Transmission_Multiplier** or **STI_Coinfection_Acquisition_Multiplier** depending on whether the person has HIV (transmitter) or not (aquirer). The maximum value of the multiplier between the transmitter and acquirer is used. 3. *Condom Transmission Blocking* - If condoms were used in this coital act, then the configuration parameter **Condom_Transmission_Blocking_Probability** is included. The value of the multiplier is calculated as follows: >>> co_inf_transmission = infected_individual.STI_Coinfection_Transmission_Multiplier if co-infected else 1 >>> co_inf_acquisition = uninfected_individual.STI_Coinfection_Acquisition_Multiplier if co-infected else 1 >>> risk_multiplier = max( co_inf_transmission, co_inf_acquisition ) >>> >>> risk_factor_transmission = infected_individual.CoitalActsRiskFactors.Transmission_Multiplier >>> risk_factor_acquisition = uninfected_individual.CoitalActsRiskFactors.Acquisition_Multiplier >>> risk_multiplier *= risk_factor_transmission * risk_factor_acquisition; >>> >>> risk_multiplier *= (1 - Condom_Transmission_Blocking_Probability) if using_condom else 1 This risk multiplier is then used to determine if the uninfected person becomes infected: >>> probability_infected = risk_multiplier >>> * transmission_probability >>> * acquisition_probability **Acquisition Probability** There are three things that contribute to the probability that an uninfected person can acquire HIV from a coital act with an infected person. They are: 1. *Male Circumcision* - If the uninfected person is male and has been circumcised, their probability of acquisition is reduced. The male individual will have the **MaleCircumcision** intervention and its **Circumcision_Reduced_Acquire** parameter will be used. 2. *Female Susceptibility By Age* - If the uninfected person is female, then their current age is used to determine the a factor from the configuration parameters **Male_To_Female_Relative_Infectivity_Ages** and **Male_To_Female_Relative_Infectivity_Multipliers**. Their age is used with linear interpolation to calculate a multiplier. 3. *PrEP / Vaccine* - If the uninfected person has a vaccine or PrEP, their probability of acquisition is also reduced. >>> probability_acquire = 1.0 >>> probability_acquire *= MaleCircumcision.Circumcision_Reduced_Acquire if male and circumcised else 1 >>> probability_acquire *= get_female_susceptibility( person.age ) if female else 1 >>> probability_acquire *= vaccine_reduced_acquire if person has vaccine else 1 **Transmission Probability** In EMOD, the probability of a person transmitting HIV comes down to whether nor not the person has been vaccinated and how infectious they are. 1. *Vaccine* - If the infected person has a vaccine that reduces transmission, its probability of transmission reduction is used. 2. *Infectiousness* - The infectiousness of a person depends on the following four factors: 2a. *Base Infectivity* - The configuration parameter **Base_Infectivity** determines the starting amount of infectiousness. It is the starting point of the calculation and is assumed to be female-to-male transmission. 2b. *Heterogeneity* - To represent the heterogeneity in people, the **Base_Infectivity** is multiplied by a value from a Log Normal distribution based on the configuration parameter **Heterogeneous_Infectiousness_LogNormal_Scale**. >>> median = -0.5 * Heterogeneous_Infectiousness_LogNormal_Scale**2 >>> heterogeneity_factor = median + eGauss() * Heterogeneous_Infectiousness_LogNormal_Scale where eGauss() is a gaussian distributed random number between 0 and 1. 2c. *Stage of Infection* - The mount the infection has progressed also impacts the amount of infectiousness. If the person is in the 'acute' stage, then we multiply the **Base_Infectivity** times the configuration parameter **Acute_Stage_Infectivity_Multiplier**. If the person is in the 'AIDS' stage, we multiply by the configuration parameter **AIDS_Stage_Infectivity_Multiplier**. If they are in the 'latent' stage, we do not adjust the **Base_Infectivity**. 2d. *ART Suppression* - If a person has been given an ART intervention (**AntiretroviralTherapy**, **AntiretroviralTherapyFull**, or **ARTMortalityTable**) and has not dropped off of art (**ARTDropout**), then ART can suppress the person's infectiousness. This amount of suppression is determined by the intervention parameters **ART_Multiplier_On_Transmission_Prob_Per_Act** and **Days_To_Achieve_Viral_Suppression**. If the person has been on ART less than **Days_To_Achieve_Viral_Suppression**, the **ART_Multiplier_On_Transmission_Prob_Per_Act** will be reduced proportionally. These different factors are combined as follows: >>> infectiousness = Base_Infectivity >>> infectiousness *= heterogeneity_factor >>> >>> if hiv_stage == ACUTE: >>> infectiousness *= Acute_Stage_Infectivity_Multiplier >>> elif hiv_stage == AIDS: >>> infectiousness *= AIDS_Stage_Infectivity_Multiplier >>> >>> suppression = ART_Multiplier_On_Transmission_Prob_Per_Act >>> if Days_To_Achieve_Viral_Suppression > 0: >>> art_mult = ART_Multiplier_On_Transmission_Prob_Per_Act >>> days_to_achieve = Days_To_Achieve_Viral_Suppression >>> suppression = 1 - ((1 - art_mult) / days_to_achieve) * time_since_starting_ART >>> infectiousness *= suppression The transmission probability is then calculated as: >>> probability_transmission = infectiousness * vaccine_reduced_transmission Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. transmission_multiplier(float, optional): Multiplier for STI transmission probability per coital act. Minimum value: 0 Maximum value: 100 Default value: 1 expiration_period_distribution(BaseDistribution, required): The distribution type to use for setting the expiration of the intervention. Each intervention gets an expiration duration by doing a random draw from the distribution. Please use the following distribution classes from emodpy_hiv.utils.distributions to define the distribution: * ConstantDistribution * UniformDistribution * GaussianDistribution * ExponentialDistribution * PoissonDistribution * LogNormalDistribution * DualConstantDistribution * WeibullDistribution * DualExponentialDistribution expiration_event_trigger(str, optional): When the intervention expires, this individual-level event will be broadcast. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None acquisition_multiplier(float, optional): Multiplier for STI acquisition probability per coital act. Minimum value: 0 Maximum value: 100 Default value: 1 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, expiration_period_distribution: BaseDistribution, transmission_multiplier: float = 1, expiration_event_trigger: str = None, acquisition_multiplier: float = 1, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'CoitalActRiskFactors', common_intervention_parameters) self._intervention.Transmission_Multiplier = validate_value_range(transmission_multiplier, 'transmission_multiplier', 0, 100, float) self._intervention.Expiration_Event_Trigger = set_event(expiration_event_trigger, 'expiration_event_trigger', campaign, True) self._intervention.Acquisition_Multiplier = validate_value_range(acquisition_multiplier, 'acquisition_multiplier', 0, 100, float) if not isinstance(expiration_period_distribution, BaseDistribution): raise ValueError(f"expiration_period_distribution must be an instance of BaseDistribution, not {type(expiration_period_distribution)}.") self.set_distribution(expiration_period_distribution, 'Expiration_Period')
[docs]class FemaleContraceptive(IndividualIntervention): """ The **FemaleContraceptive** intervention is used to reduce the fertility rate of females of reproductive age (14 to 45 years old), based on a distribution set by the user. This intervention can only be distributed to females, and ignores the waning condition expiration (as women could still use a contraceptive, even if it is ineffective). Note: the Birth_Rate_Dependence configuration parameter must be set to INDIVIDUAL_PREGNANCIES or INDIVIDUAL_PREGNANCIES_BY_AGE_AND_YEAR or an error will result. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. waning_config(AbstractWaningConfig, required): A WaningConfig object used to control the efficacy of the contraceptive, typically over time. Specify how this effect decays over time using one of the Waning Config classes in emodpy_hiv.campaign.waning_config. usage_expiration_event(str, optional): When the woman stops using the contraceptive, this event will be broadcast. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None usage_duration_distribution(BaseDistribution, required): For the distribution of each contraceptive, a randomly selected duration from this distribution will determine when the woman stops using the contraceptive. This is independent of how long the contraceptive is effective. Please use the following distribution classes from emodpy_hiv.utils.distributions to define the distribution: * ConstantDistribution * UniformDistribution * GaussianDistribution * ExponentialDistribution * PoissonDistribution * LogNormalDistribution * DualConstantDistribution * WeibullDistribution * DualExponentialDistribution common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, waning_config: AbstractWaningConfig, usage_expiration_event: str, usage_duration_distribution: BaseDistribution, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'FemaleContraceptive', common_intervention_parameters) if not isinstance(waning_config, AbstractWaningConfig): raise ValueError(f"waning_config must be an instance of AbstractWaningConfig, not {type(waning_config)}.") self._intervention.Waning_Config = waning_config.to_schema_dict(campaign) self._intervention.Usage_Expiration_Event = set_event(usage_expiration_event, 'usage_expiration_event', campaign, True) if not isinstance(usage_duration_distribution, BaseDistribution): raise ValueError(f"usage_duration_distribution must be an instance of BaseDistribution, not {type(usage_duration_distribution)}.") self.set_distribution(usage_duration_distribution, 'Usage_Duration')
[docs]class HIVARTStagingByCD4Diagnostic(IndividualIntervention): """ The **HIVARTStagingByCD4Diagnostic** intervention class checks for treatment eligibility based on CD4 count. It uses the lowest-ever recorded CD4 count for that individual, based on the history of past CD4 counts conducted using the **HIVDrawBlood** intervention. To specify the outcome based on age bins instead of CD4 testing, use **HIVARTStagingCD4AgnosticDiagnostic**. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. cd4_threshold(ValueMap, required): It is a piecewise table of years to CD4 and the individual's CD4 count must be below this threshold in order to get a positive 'diagnosis'. if_pregnant(ValueMap, required): If the individual does not pass the diagnostic from the **cd4_threshold** or if_active_TB, and the individual is pregnant, then the individual's CD4 is compared to the value found in the **ValueMap matrix**. if_active_tb(ValueMap, required): If the individual's CD4 is not below the threshold in the **cd4_threshold** table and the individual has TB, then the individual's CD4 will be compared to the CD4 value retrieved from the **ValueMap** matrix based on the current year. Whether a person has TB is determined by the value of an Individual Property as determined by the parameters individual_property_active_tb_key(typically 'HasActiveTB') and individual_property_active_tb_value(typically 'Yes'). positive_diagnosis_event(str, required): If the test is positive, this specifies an event that will be broadcast. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. negative_diagnosis_event(str, optional): If the test is negative, this specifies an event that will be broadcast. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None individual_property_active_tb_value(str, optional): The **IndividualProperty** value ('Yes') used to determine whether the individual has TB. If you want to use this feature, you will need to define the property in the demographics Default value: None individual_property_active_tb_key(str, optional): The **IndividualProperty** key ('HasActiveTB') used to determine whether the individual has TB. If you want to use this feature, you will need to define the property in the demographics Default value: None common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, cd4_threshold: ValueMap, if_pregnant: ValueMap, if_active_tb: ValueMap, positive_diagnosis_event: str, negative_diagnosis_event: str = None, individual_property_active_tb_value: str = None, individual_property_active_tb_key: str = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVARTStagingByCD4Diagnostic', common_intervention_parameters) self._intervention.Threshold = cd4_threshold.to_schema_dict(campaign) self._intervention.If_Pregnant = if_pregnant.to_schema_dict(campaign) self._intervention.If_Active_TB = if_active_tb.to_schema_dict(campaign) self._intervention.Positive_Diagnosis_Event = set_event(positive_diagnosis_event, 'positive_diagnosis_event', campaign, False) self._intervention.Negative_Diagnosis_Event = set_event(negative_diagnosis_event, 'negative_diagnosis_event', campaign, True) # individual_property_active_tb_value and individual_property_active_tb_key are optional, but if one is set, both must be set if individual_property_active_tb_value is not None and individual_property_active_tb_key is not None: self._intervention.Individual_Property_Active_TB_Value = individual_property_active_tb_value self._intervention.Individual_Property_Active_TB_Key = individual_property_active_tb_key elif individual_property_active_tb_value is not None or individual_property_active_tb_key is not None: raise ValueError("If individual_property_active_tb_value is set, individual_property_active_tb_key must also be set, and vice versa.")
[docs]class HIVARTStagingCD4AgnosticDiagnostic(IndividualIntervention): """ The **HIVARTStagingCD4AgnosticDiagnostic** intervention class checks for treatment eligibility based on age. It uses the individual's age and the **adult_treatment_age** argument to determine if the person should be usin the adult or child requirements. To specify the outcome based on CD4 testing, use **HIVARTStagingByCD4Diagnostic**. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. child_treat_under_age_in_years_threshold(ValueMap, required): Determines the age at which children are eligible for ART regardless of CD4, WHO stage, or other factors. This parameter uses **ValueMap** to define **Times** (by year) and **Values** for the history and expected treatment guidelines for future years. child_by_who_stage(ValueMap, required): Determines the WHO stage at or above which children are eligible for ART. This parameter uses **ValueMap** to define **Times** (by year) and **Values** for the history and expected treatment guidelines for future years. child_by_tb(ValueMap, required): Determines the WHO stage at or above which children having active TB are eligible for ART. This parameter uses **ValueMap** to define **Times** (by year) and **Values** for the history and expected treatment guidelines for future years. Whether a child has TB is determined by the value of an Individual Property as determined by the parameters individual_property_active_tb_key(typically 'HasActiveTB') and individual_property_active_tb_value(typically 'Yes'). adult_by_who_stage(ValueMap, required): Determines the WHO stage at or above which adults are eligible for ART. This parameter uses ValueMap to define **Times** (by year) and **Values** for the history and expected treatment guidelines for future years. adult_by_tb(ValueMap, required): Determines the WHO stage at or above which adults having active TB are eligible for ART. This parameter uses ValueMap to define **Times** (by year) and **Values** for the history and expected treatment guidelines for future years. Whether an adult has TB is determined by the value of an Individual Property as determined by the parameters individual_property_active_tb_key(typically 'HasActiveTB') and individual_property_active_tb_value(typically 'Yes'). adult_by_pregnant(ValueMap, required): Determines the WHO stage at or above which pregnant adults are eligible for ART. This parameter uses ValueMap to define **Times** (by year) and **Values** for the history and expected treatment guidelines for future years. positive_diagnosis_event(str, required): If an individual tests positive, this specifies an event that may trigger another intervention when the event occurs. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. negative_diagnosis_event(str, optional): If an individual tests negative, this specifies an event that will be broadcast and may trigger another intervention. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None individual_property_active_tb_value(str, optional): The **IndividualProperty** value ('Yes') used to determine whether the individual has TB. Default value: None individual_property_active_tb_key(str, optional): The **IndividualProperty** key ('HasActiveTB') used to determine whether the individual has TB. Default value: None adult_treatment_age(float, optional): The age (in years) that delineates adult patients from pediatric patients for the purpose of treatment eligibility. Patients younger than this age may be eligible on the basis of their pediatric patient status. Minimum value: -1 Maximum value: 3.40282e+38 Default value: 5 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, child_treat_under_age_in_years_threshold: ValueMap, child_by_who_stage: ValueMap, child_by_tb: ValueMap, adult_by_who_stage: ValueMap, adult_by_tb: ValueMap, adult_by_pregnant: ValueMap, positive_diagnosis_event: str, negative_diagnosis_event: str = None, individual_property_active_tb_value: str = None, individual_property_active_tb_key: str = None, adult_treatment_age: float = 5, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVARTStagingCD4AgnosticDiagnostic', common_intervention_parameters) self._intervention.Child_Treat_Under_Age_In_Years_Threshold = child_treat_under_age_in_years_threshold.to_schema_dict(campaign) self._intervention.Child_By_WHO_Stage = child_by_who_stage.to_schema_dict(campaign) self._intervention.Child_By_TB = child_by_tb.to_schema_dict(campaign) self._intervention.Adult_By_WHO_Stage = adult_by_who_stage.to_schema_dict(campaign) self._intervention.Adult_By_TB = adult_by_tb.to_schema_dict(campaign) self._intervention.Adult_By_Pregnant = adult_by_pregnant.to_schema_dict(campaign) self._intervention.Positive_Diagnosis_Event = set_event(positive_diagnosis_event, 'positive_diagnosis_event', campaign, False) self._intervention.Negative_Diagnosis_Event = set_event(negative_diagnosis_event, 'negative_diagnosis_event', campaign, True) # individual_property_active_tb_value and individual_property_active_tb_key are optional, but if one is set, both must be set if individual_property_active_tb_value is not None and individual_property_active_tb_key is not None: self._intervention.Individual_Property_Active_TB_Value = individual_property_active_tb_value self._intervention.Individual_Property_Active_TB_Key = individual_property_active_tb_key elif individual_property_active_tb_value is not None or individual_property_active_tb_key is not None: raise ValueError( "If individual_property_active_tb_value is set, individual_property_active_tb_key must also be set, and vice versa.") self._intervention.Adult_Treatment_Age = validate_value_range(adult_treatment_age, 'adult_treatment_age', -1, 3.40282e+38, float)
# DanB - After seaching the campaign files for known country models, I did not find an HIVDelayedIntervention that used # the special "expiration_period" parameter. I'm going to leave this private just in case someone needs it, but they # should be able to use DelayedIntervention instead. class _HIVDelayedIntervention(IndividualIntervention): # make this class private until we have time to review and test it. """ **HIVDelayedIntervention** is an intermediate intervention class based on **DelayedIntervention**, but adds several features that are specific to the HIV model. This intervention enables event broadcasting after the delay period expires. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. broadcast_event(str, required): The event that should occur at the end of the delay period. expiration_period(float, optional): A fixed time period, in days, after which the **Broadcast_On_Expiration_Event** occurs instead of the **Broadcast_Event**. Only applied if the **Expiration_Period** occurs earlier than the end of the delay period. For example, if loss to follow-up (LTFU) occurs at a high rate for the first 6 months of care, and then later transitions to a lower rate, then the **Expiration_Period** should be set to 183 days and **Broadcast_On_Expiration_Event** can link to another delay intervention with a longer average delay time until LTFU. If LTFU does not occur in the first 6 months, then the expiration will allow the first rate to give way to the post-6-month rate. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 3.40282e+38 delay_period_distribution(BaseDistribution, required): The distribution type to use for assigning the delay period for distributing interventions. Each assigned value is a random draw from the distribution. Please use the following distribution classes from emodpy_hiv.utils.distributions to define the distribution: * ConstantDistribution * UniformDistribution * GaussianDistribution * ExponentialDistribution * PoissonDistribution * LogNormalDistribution * DualConstantDistribution * WeibullDistribution * DualExponentialDistribution broadcast_on_expiration_event(str, optional): If the delay intervention expires before arriving at the end of the delay period, this specifies the event that should occur. For example, if loss to follow-up occurs at a high rate for the first 6 months of care, and then later transitions to a lower rate, then the **Expiration_Period** should be set to 183 days and **Broadcast_On_Expiration_Event** can link to another delay intervention with a longer average delay time until loss to follow up (LTFU). If LTFU does not occur in the first 6 months, then the expiration will allow the first rate to give way to the post-6-month rate. See the list of available events for possible values .See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 4 common parameters: intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. The following parameters are not valid for this intervention: cost Default value: None """ def __init__(self, campaign: api_campaign, broadcast_event: str, delay_period_distribution: BaseDistribution, expiration_period: float = 3.40282e+38, broadcast_on_expiration_event: str = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVDelayedIntervention', common_intervention_parameters) self._intervention.Broadcast_Event = set_event(broadcast_event, 'broadcast_event', campaign, False) self._intervention.Expiration_Period = validate_value_range(expiration_period, 'expiration_period', 0, 3.40282e+38, float) self._intervention.Coverage = 1 # do not make option for user self._intervention.Broadcast_On_Expiration_Event = set_event(broadcast_on_expiration_event, 'broadcast_on_expiration_event', campaign, True) if not isinstance(delay_period_distribution, BaseDistribution): raise ValueError(f"delay_period_distribution must be an instance of BaseDistribution, not {type(delay_period_distribution)}.") self.set_distribution(delay_period_distribution, 'Delay_Period') def _set_cost(self, cost: float) -> None: raise ValueError('Cost_To_Consumer is not a valid parameter for the HIVDelayedIntervention intervention.')
[docs]class HIVDrawBlood(IndividualIntervention): """ The **HIVDrawBlood** intervention class represents a test where blood is drawn and the person's CD4 or viral load are determined. It allows for a test result to be recorded and used for future health care decisions, but does not intrinsically lead to a health care event. A future health care decision will use this recorded CD4 count or viral load, even if the actual CD4/viral load has changed since last phlebotomy. The result can be updated by distributing another **HIVDrawBlood** intervention. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. positive_diagnosis_event(str, required): If an individual tests positive, this specifies an event that may trigger another intervention when the event occurs. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, positive_diagnosis_event: str, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVDrawBlood', common_intervention_parameters) self._intervention.Positive_Diagnosis_Event = set_event(positive_diagnosis_event, 'positive_diagnosis_event', campaign, False)
[docs]class HIVMuxer(IndividualIntervention): """ The **HIVMuxer** intervention class is a method of placing groups of individuals into a waiting pattern for the next event, and is based on DelayedIntervention. **HIVMuxer** adds the ability to limit the number of times an individual can be registered with the delay, which ensures that an individual is only provided with the delay one time. For example, without **HIVMuxer**, an individual could be given an exponential delay twice, effectively doubling the rate of leaving the delay. Please refer to the documentation for **HIVMuxer** at the following link: :doc:`emod-hiv:emod/parameter-campaign-individual-hivmuxer` Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. muxer_name(str, required): A name used to identify the delay and check whether individuals have entered it multiple times. If the same name is used at multiple points in the health care process, then the number of entries is combined when **max_entries** is applied. delay_period_distribution(BaseDistribution, required): The distribution type to use for assigning the delay period for distributing interventions. Each assigned value is a random draw from the distribution. Please use the following distribution classes from emodpy_hiv.utils.distributions to define the distribution: * ConstantDistribution * UniformDistribution * GaussianDistribution * ExponentialDistribution * PoissonDistribution * LogNormalDistribution * DualConstantDistribution * WeibullDistribution * DualExponentialDistribution max_entries(int, optional): The maximum number of times the individual can be registered with the HIVMuxer delay. Determines what should happen if an individual reaches the HIVMuxer stage of health care multiple times. For example, registering for an exponential delay two times effectively doubles the rate of leaving the delay. Setting **max_entries** to 1 prevents the rate from doubling. Minimum value: 0 Maximum value: 2147480000.0 Default value: 1 expiration_period(float, optional): A fixed time period, in days, after which the **broadcast_on_expiration_event** occurs instead of the **broadcast_delay_complete_event**. Only applied if the **expiration_period** occurs earlier than the end of the delay period. For example, if loss to follow-up (LTFU) occurs at a high rate for the first 6 months of care, and then later transitions to a lower rate, then the **Expiration_Period** should be set to 183 days and **Broadcast_On_Expiration_Event** can link to another delay intervention with a longer average delay time until LTFU. If LTFU does not occur in the first 6 months, then the expiration will allow the first rate to give way to the post-6-month rate. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 3.40282e+38 broadcast_on_expiration_event(str, optional): If the delay intervention expires before arriving at the end of the delay period, this specifies the event that should occur. For example, if loss to follow-up occurs at a high rate for the first 6 months of care, and then later transitions to a lower rate, then the **Expiration_Period** should be set to 183 days and **Broadcast_On_Expiration_Event** can link to another delay intervention with a longer average delay time until loss to follow up (LTFU). If LTFU does not occur in the first 6 months, then the expiration will allow the first rate to give way to the post-6-month rate. See the list of available events for possible values. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None broadcast_delay_complete_event(str, optional): The event that should occur at the end of the delay period. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. custom event. Default value: None common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 4 common parameters: intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. The following parameters are not valid for this intervention: cost Default value: None """ def __init__(self, campaign: api_campaign, muxer_name: str, delay_period_distribution: BaseDistribution, max_entries: int = 1, expiration_period: float = 3.40282e+38, broadcast_on_expiration_event: str = None, broadcast_delay_complete_event: str = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVMuxer', common_intervention_parameters) self._intervention.Muxer_Name = muxer_name if not isinstance(delay_period_distribution, BaseDistribution): raise ValueError(f"delay_period_distribution must be an instance of BaseDistribution, not {type(delay_period_distribution)}.") self.set_distribution(delay_period_distribution, 'Delay_Period') self._intervention.Max_Entries = validate_value_range(max_entries, 'max_entries', 0, 2147480000.0, int) self._intervention.Expiration_Period = validate_value_range(expiration_period, 'expiration_period', 0, 3.40282e+38, float) self._intervention.Broadcast_On_Expiration_Event = set_event(broadcast_on_expiration_event, 'broadcast_on_expiration_event', campaign, True) self._intervention.Broadcast_Event = set_event(broadcast_delay_complete_event, 'broadcast_event', campaign, True) def _set_cost(self, cost: float) -> None: raise ValueError('Cost_To_Consumer is not a valid parameter for the HIVMuxer intervention.')
[docs]class HIVPiecewiseByYearAndSexDiagnostic(IndividualIntervention): """ The **HIVPiecewiseByYearAndSexDiagnostic** intervention class is used to model the roll-out of an intervention over time. Unlike **HIVSigmoidByYearAndSexDiagnostic**, which requires the time trend to have a sigmoid shape, this intervention allows for any trend of time to be configured using piecewise or linear interpolation. The trends over time can be configured differently for males and females. Note that the term "diagnosis" is used, but this intervention is typically used more like a trend in behavior or coverage over time. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. time_value_map(ValueMap, required): Please use the ValueMap class from emodpy_hiv.campaign.common to define the **time_value_map**. The years (times) and matching probabilities for test results. This parameter uses ValueMap to define **Times** (by year) and **Values** for the history and expected treatment guidelines for future years. This creates a JSON structure containing one array of **Times** and one for **Values**, which allows for a time-variable probability that can take on any shape over time. When queried at a simulation year corresponding to one of the listed **Times**, it returns the corresponding **Value**. When queried earlier than the first listed **Time**, it returns the default **Value**. When queried in between listed **Times**, it either returns the **Value** for the most recent past time (when **linear_interpolation** is False) or linearly interpolates Values between **Times** (when **linear_interpolation** is True). When queried after the last **Time** in the list, it returns the last **Value**. The **Times** and **Values** must be of equal length, and can consist of a single value. **Times** must monotonically increase. positive_diagnosis_event(str, required): If an individual tests positive, this specifies an event that may trigger another intervention when the event occurs. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. negative_diagnosis_event(str, optional): If an individual tests negative, this specifies an event that may trigger another intervention when the event occurs. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None linear_interpolation(bool, optional): When set to False, interpolation between values in the **time_value_map** is zero-order ('staircase'). When set to True, interpolation between values in the **time_value_map** is linear. The final value is held constant for all times after the last time specified in the **time_value_map**. Default value: False female_multiplier(float, optional): Allows for the probabilities in the **time_value_map** to be different for males and females, by multiplying the female probabilities by a constant value. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 1 default_value(float, optional): The probability of positive diagnosis if the intervention is used before the earliest specified time in the **time_value_map**. Minimum value: 0 Maximum value: 1 Default value: 0 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, time_value_map: ValueMap, positive_diagnosis_event: str, negative_diagnosis_event: str = None, linear_interpolation: bool = False, female_multiplier: float = 1, default_value: float = 0, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVPiecewiseByYearAndSexDiagnostic', common_intervention_parameters) self._intervention.Time_Value_Map = time_value_map.to_schema_dict(campaign) self._intervention.Positive_Diagnosis_Event = set_event(positive_diagnosis_event, 'positive_diagnosis_event', campaign, False) self._intervention.Negative_Diagnosis_Event = set_event(negative_diagnosis_event, 'negative_diagnosis_event', campaign, True) self._intervention.Interpolation_Order = 1 if linear_interpolation else 0 self._intervention.Female_Multiplier = validate_value_range(female_multiplier, 'female_multiplier', 0, 3.40282e+38, float) self._intervention.Default_Value = validate_value_range(default_value, 'default_value', 0, 1, float)
[docs]class HIVRandomChoice(IndividualIntervention): """ The **HIVRandomChoice** intervention class is used to change the logic in how and where treatment is applied to individuals based on specified probabilities. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. choice_probabilities(list[float], required): An array of probabilities that the event will be selected, used with **choice_names**. Values in map must be normalized to sum to one. choice_names(list[str], required): An array of event names to be broadcast if randomly selected, used with **choice_probabilities**. common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, choice_probabilities: list[float] = None, choice_names: list[str] = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVRandomChoice', common_intervention_parameters) # check if the choice_probabilities and choice_names are the same length if len(choice_probabilities) != len(choice_names): raise ValueError('The length of choice_probabilities and choice_names must be the same.') # check if the sum of the choice_probabilities is equal to 1 if sum(choice_probabilities) != 1: raise ValueError('The sum of choice_probabilities must be equal to 1.') choice_names = [set_event(choice_name, 'choice_name', campaign, False) for choice_name in choice_names] self._intervention.Choice_Probabilities = choice_probabilities self._intervention.Choice_Names = choice_names
[docs]class HIVRapidHIVDiagnostic(IndividualIntervention): """ The **HIVRapidHIVDiagnostic** intervention class builds on **StandardDiagnostic** by also updating the individual's knowledge of their HIV status. This can affect their access to ART in the future as well as other behaviors. This intervention should be used only if the individual's knowledge of their status should impact a voluntary male circumcision campaign. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. positive_diagnosis_event(str, required): If the test is positive, this specifies an event that will be broadcast. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. base_sensitivity(float, optional): Use this parameter to set a constant value for sensitivity of the diagnostic. If you want to set the sensitivity over time, use the **sensitivity_versus_time** parameter instead. You need to set either **base_sensitivity** or **sensitivity_versus_time**. This sets the proportion of the time that individuals with the condition being tested receive a positive diagnostic test. When set to 1, the diagnostic always accurately reflects the condition. When set to zero, then individuals who have the condition always receive a false-negative diagnostic test. Minimum value: 0 Maximum value: 1 Default value: None sensitivity_versus_time(ValueMap, Optional): Use this parameter to set the sensitivity of the diagnostic test over time. If you want to set a constant value for sensitivity, use the **base_sensitivity** parameter instead. You need to set either **base_sensitivity** or **sensitivity_versus_time**. This expects a ValueMap object (from emodpy_hiv.campaign.common) that contains two arrays: The 'Times' values are the duration from when the person became infected. 'Values' is the sensitivity of the diagnostic for the given age of the infection. Default value: None base_specificity(float, optional): The specificity of the diagnostic. This sets the proportion of the time that individuals without the condition being tested receive a negative diagnostic test. When set to 1, the diagnostic always accurately reflects the lack of having the condition. When set to zero, then individuals who do not have the condition always receive a false-positive diagnostic test. Minimum value: 0 Maximum value: 1 Default value: 1 probability_received_result(float, optional): The probability that an individual received the results of a diagnostic test. Minimum value: 0 Maximum value: 1 Default value: 1 negative_diagnosis_event(str, optional): If the test is negative, this event will be broadcast. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None enable_is_symptomatic(bool, optional): If true, requires an infection to be symptomatic to return a positive test. Default value: True days_to_diagnosis(float, optional): The number of days from diagnosis (which is done when the intervention is distributed) until a positive response is performed. The response to a negative diagnosis is done immediately when the diagnosis is made (at distribution of the intervention). Minimum value: 0 Maximum value: 3.40282e+38 Default value: 0 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, positive_diagnosis_event: str, base_sensitivity: float = None, base_specificity: float = 1, sensitivity_versus_time: ValueMap = None, probability_received_result: float = 1, negative_diagnosis_event: str = None, enable_is_symptomatic: bool = False, days_to_diagnosis: float = 0, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVRapidHIVDiagnostic', common_intervention_parameters) if base_sensitivity is None and sensitivity_versus_time is None: raise ValueError('Either base_sensitivity or sensitivity_versus_time must be provided.') elif base_sensitivity is not None and sensitivity_versus_time is not None: raise ValueError('Only one of base_sensitivity or sensitivity_versus_time can be provided.') elif base_sensitivity is not None: self._intervention.Base_Sensitivity = validate_value_range(base_sensitivity, 'base_sensitivity', 0, 1, float) self._intervention.Sensitivity_Type = SensitivityType.SINGLE_VALUE else: self._intervention.Sensitivity_Versus_Time = sensitivity_versus_time.to_schema_dict(campaign) self._intervention.Sensitivity_Type = SensitivityType.VERSUS_TIME self._intervention.Positive_Diagnosis_Event = set_event(positive_diagnosis_event, 'positive_diagnosis_event', campaign, False) self._intervention.Probability_Received_Result = validate_value_range(probability_received_result, 'probability_received_result', 0, 1, float) self._intervention.Negative_Diagnosis_Event = set_event(negative_diagnosis_event, 'negative_diagnosis_event', campaign, True) self._intervention.Enable_Is_Symptomatic = enable_is_symptomatic self._intervention.Days_To_Diagnosis = validate_value_range(days_to_diagnosis, 'days_to_diagnosis', 0, 3.40282e+38, float) self._intervention.Base_Specificity = validate_value_range(base_specificity, 'base_specificity', 0, 1, float)
[docs]class HIVSigmoidByYearAndSexDiagnostic(IndividualIntervention): """ The **HIVSigmoidByYearAndSexDiagnostic** intervention class broadcasts a positive 'diagnosis' event by selecting a probability of that event from a sigmoidal curve versus time. For a linear approach, use **HIVPiecewiseByYearandSexDiagnostic**. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. positive_diagnosis_event(str, required): If an individual tests positive, this specifies an event that may trigger another intervention when the event occurs. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. year_sigmoid(Sigmoid, required): Defines a sigmoidal curve for the probability of a positive diagnosis versus time (year). female_multiplier(float, optional): Allows for the sigmoid time-varying probability to be different for males and females, by multiplying the female probability by a constant value. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 1 negative_diagnosis_event(str, optional): If an individual tests negative, this specifies an event that may trigger another intervention when the event occurs. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, positive_diagnosis_event: str, year_sigmoid: Sigmoid, female_multiplier: float = 1, negative_diagnosis_event: str = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVSigmoidByYearAndSexDiagnostic', common_intervention_parameters) if year_sigmoid is None: raise ValueError("'year_sigmoid' must be defined.") # Don't need to check values because these values are the same as the ranges in the Sigmoid class. self._intervention.Ramp_Min = year_sigmoid.min self._intervention.Ramp_Max = year_sigmoid.max self._intervention.Ramp_MidYear = year_sigmoid.mid self._intervention.Ramp_Rate = year_sigmoid.rate self._intervention.Female_Multiplier = validate_value_range(female_multiplier, 'female_multiplier', 0, 3.40282e+38, float) self._intervention.Positive_Diagnosis_Event = set_event(positive_diagnosis_event, 'positive_diagnosis_event', campaign, False) self._intervention.Negative_Diagnosis_Event = set_event(negative_diagnosis_event, 'negative_diagnosis_event', campaign, True)
# DanB - After searching the campaign files for known country models, I did not see any one using HIVSimpleDiagnostic. # People pretty much use HIVRapidHIVDiagnostic instead. I'm going to leave this private just in case someone needs it. class _HIVSimpleDiagnostic(IndividualIntervention): # make this class private until we have time to review and test it. """ The **HIVSimpleDiagnostic** intervention class is based on the **SimpleDiagnostic** intervention, but adds the ability to specify outcomes upon both positive and negative diagnosis (whereas **SimpleDiagnostic** only allows for an outcome resulting from a positive diagnosis). **HIVSimpleDiagnostic** tests for HIV status without logging the HIV test to the individual's medical history. To log the HIV test to the medical history, use **HIVRapidHIVDiagnostic** instead. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. positive_diagnosis_event(str, required): If the test is positive, this specifies an event that can trigger another intervention when the event occurs. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. negative_diagnosis_event(str, optional): This parameter defines the event to be broadcasted on a negative test result. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None enable_is_symptomatic(bool, optional): If true, requires an infection to be symptomatic to return a positive test. Default value: True days_to_diagnosis(float, optional): The number of days from diagnosis (which is done when the intervention is distributed) until a positive response is performed. The response to a negative diagnosis is done immediately when the diagnosis is made (at distribution of the intervention). Minimum value: 0 Maximum value: 3.40282e+38 Default value: 0 base_specificity(float, optional): The specificity of the diagnostic. This sets the proportion of the time that individuals without the condition being tested receive a negative diagnostic test. When set to 1, the diagnostic always accurately reflects the lack of having the condition. When set to zero, then individuals who do not have the condition always receive a false-positive diagnostic test. Minimum value: 0 Maximum value: 1 Default value: 1 base_sensitivity(float, optional): The sensitivity of the diagnostic. This sets the proportion of the time that individuals with the condition being tested receive a positive diagnostic test. When set to 1, the diagnostic always accurately reflects the condition. When set to zero, then individuals who have the condition always receive a false-negative diagnostic test. Minimum value: 0 Maximum value: 1 Default value: 1 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, positive_diagnosis_event: str, negative_diagnosis_event: str = None, enable_is_symptomatic: bool = False, days_to_diagnosis: float = 0, base_specificity: float = 1, base_sensitivity: float = 1, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'HIVSimpleDiagnostic', common_intervention_parameters) self._intervention.Positive_Diagnosis_Event = set_event(positive_diagnosis_event, 'positive_diagnosis_event', campaign, False) self._intervention.Negative_Diagnosis_Event = set_event(negative_diagnosis_event, 'negative_diagnosis_event', campaign, True) self._intervention.Enable_Is_Symptomatic = enable_is_symptomatic self._intervention.Days_To_Diagnosis = validate_value_range(days_to_diagnosis, 'days_to_diagnosis', 0, 3.40282e+38, float) self._intervention.Base_Specificity = validate_value_range(base_specificity, 'base_specificity', 0, 1, float) self._intervention.Base_Sensitivity = validate_value_range(base_sensitivity, 'base_sensitivity', 0, 1, float)
[docs]class InterventionForCurrentPartners(IndividualIntervention): """ The **InterventionForCurrentPartners** intervention class provides a mechanism for the partners of individuals in the care system to also seek care. Partners do not need to seek testing at the same time; a delay may occur between the initial test and the partner's test. If a relationship has been paused, such as when a partner migrates to a different node, the partner will not be contacted. Either the **intervention_config** or **broadcast_event** parameter must be set, but not both. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. intervention_config(IndividualIntervention, optional): The intervention definition that is immediately distributed to the partner. This parameter is required if **broadcast_event** is not set. Default value: None broadcast_event(str, optional): The event that is immediately broadcast to the partner. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for possible built-in values, or use your own custom event. This parameter is required if **intervention_config** is not set. Default value: None prioritize_partners_by(PrioritizePartnersBy, optional): How to prioritize partners for the intervention, as long as they have been in a relationship longer than **minimum_duration_years**. Expect PrioritizePartnersBy enum from emodpy_hiv.utils.emod_enum. Possible values are: * NO_PRIORTIZATION - All partners are contacted. * CHOSEN_AT_RANDOM - Partners are randomly selected until **maximum_partners** have received the intervention. * LONGER_TIME_IN_RELATIONSHIP - Partners are sorted in descending order of the duration of the relationship. Partners are contacted from the beginning of this list until **maximum_partners** have received the intervention. * SHORTER_TIME_IN RELATIONSHIP - Partners are sorted in ascending order of the duration of the relationship. Partners are contacted from the beginning of the list until **maximum_partners** have received the intervention. * OLDER_AGE - Partners are sorted in descending order of their age. Partners are contacted from the beginning of this list until **maximum_partners** have received the intervention. * YOUNGER_AGE - Partners sorted in ascending order of the duration of the relationship. Partners are contacted from the beginning of this list until **maximum_partners** have received the intervention. * RELATIONSHIP_TYPE - Partners are sorted based on the order of relationship types defined in the **relationship_types** array. For example, 'relationship_types' : ['MARITAL', 'INFORMAL', 'TRANSITORY', 'COMMERCIAL'], will prioritize marital first, then informal, then transitory, then commercial, with random selection between mulitple partners of the same type. Default value: PrioritizePartnersBy.NO_PRIORITIZATION relationship_types(list[RelationshipTypes], optional): An array listing all possible relationship types for which partners can qualify for the intervention. Expect RelationshipTypes enum emodpy_hiv.utils.emod_enum. Possible values are: TRANSITORY, INFORMAL, MARITAL, and COMMERCIAL. If **prioritize_partners_by** is set to PrioritizePartnersBy.RELATIONSHIP_TYPE, then the order of these types is used. The array may not contain duplicates, and cannot be empty. Default value: None minimum_duration_years(float, optional): The minimum amount of time, in years, between relationship formation and the current time for the partner to qualify for the intervention. Minimum value: 0 Maximum value: 200 Default value: 0 maximum_partners(float, optional): The maximum number of partners that will receive the intervention. Required when **Prioritize_Partners_By** is not set to NO_PRIORITIZATION. Minimum value: 0 Maximum value: 100 Default value: 100 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 4 common parameters: intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. The following parameters are not valid for this intervention: cost Default value: None """ def __init__(self, campaign: api_campaign, intervention_config: IndividualIntervention = None, broadcast_event: str = None, prioritize_partners_by: 'PrioritizePartnersBy' = PrioritizePartnersBy.NO_PRIORITIZATION, relationship_types: list[str] = None, minimum_duration_years: float = 0, maximum_partners: float = 100, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'InterventionForCurrentPartners', common_intervention_parameters) self._intervention.Prioritize_Partners_By = prioritize_partners_by if prioritize_partners_by == PrioritizePartnersBy.RELATIONSHIP_TYPE: if relationship_types is None or len(relationship_types) == 0: raise ValueError('The relationship_types parameter must be set when prioritize_partners_by is set to RELATIONSHIP_TYPE.') self._intervention.Relationship_Types = relationship_types if prioritize_partners_by != PrioritizePartnersBy.NO_PRIORITIZATION: self._intervention.Maximum_Partners = validate_value_range(maximum_partners, 'maximum_partners', 0, 100, float) self._intervention.Minimum_Duration_Years = validate_value_range(minimum_duration_years, 'minimum_duration_years', 0, 200, float) if intervention_config is not None and broadcast_event is not None: raise ValueError('You can only set either intervention_config or broadcast_event, but not both.') elif intervention_config is not None: self._intervention.Intervention_Config = intervention_config.to_schema_dict() self._intervention.Event_Or_Config = EventOrConfig.Config elif broadcast_event is not None: self._intervention.Broadcast_Event = set_event(broadcast_event, 'broadcast_event', campaign, False) self._intervention.Event_Or_Config = EventOrConfig.Event else: raise ValueError('You must set either intervention_config or broadcast_event.') def _set_cost(self, cost: float) -> None: raise ValueError('Cost_To_Consumer is not a valid parameter for the InterventionForCurrentPartners intervention.')
[docs]class MaleCircumcision(IndividualIntervention): """ The **MaleCircumcision** intervention class introduces male circumcision as a method to control HIV transmission. Voluntary medical male circumcision (VMMC) permanently reduces a male's likelihood of acquiring HIV; successful distribution results in a reduction in the probability of transmission. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. distributed_event_trigger(str, optional): The name of the event to be broadcast when the intervention is distributed to an individual. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None circumcision_reduced_acquire(float, optional): The reduction of susceptibility to STI by voluntary male medical circumcision (VMMC). Minimum value: 0 Maximum value: 1 Default value: 0.6 apply_if_higher_reduced_acquire(bool, optional): If set to False, the **MaleCircumcision** intervention can never be applied to someone who already has a **MaleCircumcision** intervention. If set to True, a male who already has a **MaleCircumcision** intervention, but whose pre-existing **MaleCircumcision** intervention has a lower efficacy parameter (**circumcision_reduced_acquire**) than the one about to be applied, will receive the higher-efficacy **MaleCircumcision**. Default value: False common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, distributed_event_trigger: str = None, circumcision_reduced_acquire: float = 0.6, apply_if_higher_reduced_acquire: bool = False, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'MaleCircumcision', common_intervention_parameters) self._intervention.Distributed_Event_Trigger = set_event(distributed_event_trigger, 'distributed_event_trigger', campaign, True) self._intervention.Circumcision_Reduced_Acquire = validate_value_range(circumcision_reduced_acquire, 'circumcision_reduced_acquire', 0, 1, float) self._intervention.Apply_If_Higher_Reduced_Acquire = 1 if apply_if_higher_reduced_acquire else 0
[docs]class ModifyStiCoInfectionStatus(IndividualIntervention): """ The **ModifyStiCoInfectionStatus** intervention class creates or removes STI co-infections (which influence the rate of HIV transmission). This intervention can be used to represent things like STI treatment programs or STI outbreaks. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. new_sti_coinfection_status(bool, required): Determines whether to apply STI co-infection, or cure/remove STI co-infection. Set to True to include co-infection; set to False to remove co-infection. """ def __init__(self, campaign: api_campaign, new_sti_coinfection_status: bool): super().__init__(campaign, 'ModifyStiCoInfectionStatus') self._intervention.New_STI_CoInfection_Status = 1 if new_sti_coinfection_status else 0 def _set_intervention_name(self, intervention_name: str) -> None: raise ValueError('Intervention_Name is not a valid parameter for the ModifyStiCoInfectionStatus intervention.') def _set_dont_allow_duplicates(self, dont_allow_duplicates: bool) -> None: raise ValueError('Dont_Allow_Duplicates is not a valid parameter for the ModifyStiCoInfectionStatus intervention.') def _set_new_property_value(self, new_property_value: str) -> None: raise ValueError('New_Property_Value is not a valid parameter for the ModifyStiCoInfectionStatus intervention.') def _set_disqualifying_properties(self, disqualifying_properties: Union[dict[str, str], list[str]]) -> None: raise ValueError('Disqualifying_Properties is not a valid parameter for the ModifyStiCoInfectionStatus intervention.') def _set_cost(self, cost: float) -> None: raise ValueError('Cost_To_Consumer is not a valid parameter for the ModifyStiCoInfectionStatus intervention.')
[docs]class PMTCT(IndividualIntervention): """ The **PMTCT** (Prevention of Mother-to-Child Transmission) intervention class is used to define the efficacy of PMTCT treatment at time of birth. This can only be used for mothers who are not on suppressive ART and will automatically expire 40 weeks after distribution. Efficacy will be reset to 0 once it expires. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. efficacy(float, optional): Represents the efficacy of a Prevention of Mother to Child Transmission (PMTCT) intervention, defined as the rate ratio of mother to child transmission (MTCT) between women receiving the intervention and women not receiving the intervention. A setting of 1 is equivalent to 100% blocking efficacy, and 0 reverts to the default probability of transmission, configured through the config.json parameter **Maternal_Transmission_Probability**. Minimum value: 0 Maximum value: 1 Default value: 0.5 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 4 common parameters: intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. The following parameters are not valid for this intervention: cost Default value: None """ def __init__(self, campaign: api_campaign, efficacy: float = 0.5, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'PMTCT', common_intervention_parameters) self._intervention.Efficacy = validate_value_range(efficacy, 'efficacy', 0, 1, float) def _set_cost(self, cost: float) -> None: raise ValueError('Cost_To_Consumer is not a valid parameter for the PMTCT intervention.')
[docs]class STIBarrier(IndividualIntervention): """ The **STIBarrier** intervention is used to reduce the probability of STI or HIV transmission by applying a time-variable probability of condom usage. Each **STIBarrier** intervention is directed at a specific relationship type, and must be configured as a sigmoid trend over time. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. usage_expiration_event(str, optional): When the person stops using the STIBarrier, this event will be broadcasted. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None usage_duration_distribution(BaseDistribution, required): For the distribution of each **STIBarrier**, a randomly selected duration from this distribution will determine when the man stops using the intervention and revert back to condom usage based on the relationship type. Please use the following distribution classes from emodpy_hiv.utils.distributions to define the distribution: * ConstantDistribution * UniformDistribution * GaussianDistribution * ExponentialDistribution * PoissonDistribution * LogNormalDistribution * DualConstantDistribution * WeibullDistribution * DualExponentialDistribution relationship_type('RelationshipType', optional): The relationship type to which the condom usage probability is applied. Possible values are: * TRANSITORY * INFORMAL * MARITAL * COMMERCIAL Default value: TRANSITORY condom_usage_sigmoid(Sigmoid, required): The new sigmoid to use when determining the probability that a condom is used during a coital act within the specified relationship. This overrides the **Condom_Usage_Probablility** for the relationship type as defined in the Demographics file. If None (default), the **Condom_Usage_Probablility** is not overridden. - **WARNING:** For **STIBarrier**, the 'min' and 'max' values of the sigmoid must be between 0 and 1. common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, usage_expiration_event: str, usage_duration_distribution: BaseDistribution, relationship_type: 'RelationshipType' = RelationshipType.TRANSITORY, condom_usage_sigmoid: Sigmoid = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'STIBarrier', common_intervention_parameters) if condom_usage_sigmoid is None: raise ValueError("'condom_usage_sigmoid' must be defined.") else: condom_usage_sigmoid.check_value_ranges( class_name="STIBarrier", min_low= 0, min_high=1, max_low= 0, max_high=1, mid_low=1900, mid_high=2200, rate_low=-100, rate_high=100) if not isinstance(usage_duration_distribution, BaseDistribution): raise ValueError(f"usage_duration_distribution must be an instance of BaseDistribution, not {type(usage_duration_distribution)}.") self.set_distribution(usage_duration_distribution, 'Usage_Duration') self._intervention.Usage_Expiration_Event = set_event(usage_expiration_event, 'usage_expiration_event', campaign, True) self._intervention.Relationship_Type = relationship_type self._intervention.Rate = condom_usage_sigmoid.rate self._intervention.MidYear = condom_usage_sigmoid.mid self._intervention.Late = condom_usage_sigmoid.max self._intervention.Early = condom_usage_sigmoid.min
[docs]class STIIsPostDebut(IndividualIntervention): """ The **STIIsPostDebut** intervention class checks to see if the individual is post-STI debut. Note that this is not connected to IndividualProperties in the demographics file. User can either set the diagnosis_config parameters: - `positive_diagnosis_config` (required) - `negative_diagnosis_config` (optional) or set the diagnosis_event parameters: - `positive_diagnosis_event` (required) - `negative_diagnosis_event` (optional) but not both. Args: campaign (api_campaign, optional): An instance of the emod_api.campaign module. positive_diagnosis_config(IndividualIntervention, optional): The intervention distributed to individuals if they test positive. Default value: None negative_diagnosis_config(IndividualIntervention, optional): The intervention distributed to individuals if they test negative. Default value: None positive_diagnosis_event(str, optional): The event to be broadcast on a positive test result. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None negative_diagnosis_event(str, optional): The event to be broadcast on a negative test result. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, positive_diagnosis_config: IndividualIntervention = None, negative_diagnosis_config: IndividualIntervention = None, positive_diagnosis_event: str = None, negative_diagnosis_event: str = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'STIIsPostDebut', common_intervention_parameters) # Make sure that user only set either config or event, but not both if any([positive_diagnosis_config, negative_diagnosis_config]) and any([positive_diagnosis_event, negative_diagnosis_event]): raise ValueError('You can only set either diagnosis_config(s) or diagnosis_event(s), but not both.') # Make sure that user set either config or event if not any([positive_diagnosis_config, negative_diagnosis_config, positive_diagnosis_event, negative_diagnosis_event]): raise ValueError('You must set either diagnosis_config(s) or diagnosis_event(s).') # Set the intervention based on the provided config if positive_diagnosis_config or negative_diagnosis_config: if not positive_diagnosis_config: raise ValueError('positive_diagnosis_config must be set if you set negative_diagnosis_config.') self._intervention.Positive_Diagnosis_Config = positive_diagnosis_config.to_schema_dict() if negative_diagnosis_config: self._intervention.Negative_Diagnosis_Config = negative_diagnosis_config.to_schema_dict() self._intervention.Event_Or_Config = EventOrConfig.Config self._intervention.pop("Positive_Diagnosis_Event") self._intervention.pop("Negative_Diagnosis_Event") # Set the event based on the provided event if positive_diagnosis_event or negative_diagnosis_event: if not positive_diagnosis_event: raise ValueError('positive_diagnosis_event must be set if you set negative_diagnosis_event.') self._intervention.Positive_Diagnosis_Event = set_event(positive_diagnosis_event, 'positive_diagnosis_event', campaign, False) self._intervention.Negative_Diagnosis_Event = set_event(negative_diagnosis_event, 'negative_diagnosis_event', campaign, True) self._intervention.Event_Or_Config = EventOrConfig.Event self._intervention.pop("Positive_Diagnosis_Config") self._intervention.pop("Negative_Diagnosis_Config")
[docs]class SetSexualDebutAge(IndividualIntervention): """ The **SetSexualDebutAge** intervention class is used to set the age of the individual when they start seeking sexual relationships. If the individual's current age is greater than the age being set, they will immediately debut. This intervention is typically used when setting the configuration parameter **Sexual_Debut_Age_Setting_Type** to **FROM_INTERVENTION**. This setting causes all individuals to be initialized with a very large sexual debut age (max float) so that they never debut. The intervention is used to target specific individuals and set their debut age. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. setting_type('SettingType', optional): Use Weibull distribution to initialize sexual debut age or an intervention. Default value: CURRENT_AGE distributed_event_trigger(str, optional): The name of the event to be broadcast when the intervention is distributed to an individual. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None age_years(float, optional): The age (in years) at which the person receiving the intervention will start seeking sexual relationships. If the person is already order than this age, they will start seeking relationships immediately. You must set **Setting_Type** to **USER_SPECIFIED** for the parameter to become activated. Minimum value: 0 Maximum value: 3.40282e+38 Default value: 125 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 4 common parameters: intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. The following parameters are not valid for this intervention: cost Default value: None """ def __init__(self, campaign: api_campaign, setting_type: 'SettingType' = SettingType.CURRENT_AGE, distributed_event_trigger: str = None, age_years: float = 125, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'SetSexualDebutAge', common_intervention_parameters) self._intervention.Setting_Type = setting_type self._intervention.Distributed_Event_Trigger = set_event(distributed_event_trigger, 'distributed_event_trigger', campaign, True) if setting_type == SettingType.USER_SPECIFIED: self._intervention.Age_Years = validate_value_range(age_years, 'age_years', 0, 3.40282e+38, float) def _set_cost(self, cost: float) -> None: raise ValueError('Cost_To_Consumer is not a valid parameter for the SetSexualDebutAge intervention.')
[docs]class StartNewRelationship(IndividualIntervention): """ The **StartNewRelationship** intervention class provides a method of triggering the formation of a relationship following a user-specified event. The parameters of the relationship that is formed can also be customized by the user, such as individual properties required of the partner, or modified condom usage probability within the relationship. Note: These new relationships can be made by people of any age (the intervention disregards **IsPostDebut** and **Sexual_Debut_Age_Min**). Additionally, these relationships are considered outside of the Pair Formation Algorithm (PFA), and do not impact/are not impacted by concurrency or pair formation parameters. Coital act and condom usage rate are as per the corresponding relationship type, unless modified by the user. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. relationship_type('RelationshipType', optional): The type of the relationship to start for this person. Possible values are: * TRANSITORY * INFORMAL * MARITAL * COMMERCIAL Default value: TRANSITORY partner_has_ip(str, optional): The **IndividualProperty** key:value pair that the potential partner must have. Empty string implies no filtering. See :ref:`demo-properties` parameters for more information. Default value: None relationship_created_event(str, optional): The event trigger to broadcast when a new relationship is created due to the intervention. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None condom_usage_sigmoid(Sigmoid, required): The new sigmoid to use when determining the probability that a condom is used during a coital act within the specified relationship. This overrides the **Condom_Usage_Probablility** for the relationship type as defined in the Demographics file. If None (default), the **Condom_Usage_Probablility** is not overridden. - **WARNING:** For **StartNewRelationship**, the 'min' and 'max' values of the sigmoid must be between 0 and 1. common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 4 common parameters: intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. The following parameters are not valid for this intervention: cost Default value: None """ def __init__(self, campaign: api_campaign, relationship_type: 'RelationshipType' = RelationshipType.TRANSITORY, partner_has_ip: str = "", relationship_created_event: str = "", condom_usage_sigmoid: Sigmoid = None, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'StartNewRelationship', common_intervention_parameters) self._intervention.Relationship_Type = relationship_type self._intervention.Relationship_Created_Event = set_event(relationship_created_event, 'relationship_created_event', campaign, True) if partner_has_ip: self._intervention.Partner_Has_IP = validate_key_value_pair(partner_has_ip) if condom_usage_sigmoid is not None: condom_usage_sigmoid.check_value_ranges( class_name="StartNewRelationship", min_low= 0, min_high=1, max_low= 0, max_high=1, mid_low=1900, mid_high=2200, rate_low=-100, rate_high=100) self._intervention.Condom_Usage_Parameters_Type = CondomUsageParametersType.SPECIFY_USAGE self._intervention.Condom_Usage_Sigmoid = condom_usage_sigmoid.to_schema_dict(campaign) else: self._intervention.Condom_Usage_Parameters_Type = CondomUsageParametersType.USE_DEFAULT def _set_cost(self, cost: float) -> None: raise ValueError('Cost_To_Consumer is not a valid parameter for the StartNewRelationship intervention.')
class _StiCoInfectionDiagnostic(IndividualIntervention): # make this class private until we have time to review and test it. """ The **StiCoInfectionDiagnostic** intervention class is based on **SimpleDiagnostic** and allows for diagnosis of STI co-infection. It includes **SimpleDiagnostic** features and works in conjunction with the **ModifyCoInfectionStatus** flag. Args: campaign (api_campaign, required): An instance of the emod_api.campaign module. positive_diagnosis_config(IndividualIntervention, required): The intervention distributed to individuals if they test positive. treatment_fraction(float, optional): The fraction of positive diagnoses that are given the positive_diagnosis_config or positive_diagnosis_event, whichever is defined. diagnosis. Minimum value: 0 Maximum value: 1 Default value: 1 positive_diagnosis_event(str, optional): If the test is positive, this specifies an event that can trigger another intervention when the event occurs. See :doc:`emod-hiv:emod/parameter-campaign-event-list` for events already used in EMOD or use your own custom event. Default value: None enable_is_symptomatic(bool, optional): If true, requires an infection to be symptomatic to return a positive test. Default value: True days_to_diagnosis(float, optional): The number of days from diagnosis (which is done when the intervention is distributed) until a positive response is performed. The response to a negative diagnosis is done immediately when the diagnosis is made (at distribution of the intervention). Minimum value: 0 Maximum value: 3.40282e+38 Default value: 0 base_specificity(float, optional): The specificity of the diagnostic. This sets the proportion of the time that individuals without the condition being tested receive a negative diagnostic test. When set to 1, the diagnostic always accurately reflects the lack of having the condition. When set to zero, then individuals who do not have the condition always receive a false-positive diagnostic test. Minimum value: 0 Maximum value: 1 Default value: 1 base_sensitivity(float, optional): The sensitivity of the diagnostic. This sets the proportion of the time that individuals with the condition being tested receive a positive diagnostic test. When set to 1, the diagnostic always accurately reflects the condition. When set to zero, then individuals who have the condition always receive a false-negative diagnostic test. Minimum value: 0 Maximum value: 1 Default value: 1 common_intervention_parameters (CommonInterventionParameters, optional): The CommonInterventionParameters object that contains the 5 common parameters: cost, intervention_name, new_property_value, disqualifying_properties, dont_allow_duplicates. Default value: None """ def __init__(self, campaign: api_campaign, positive_diagnosis_config: IndividualIntervention, treatment_fraction: float = 1, positive_diagnosis_event: str = None, enable_is_symptomatic: bool = False, days_to_diagnosis: float = 0, base_specificity: float = 1, base_sensitivity: float = 1, common_intervention_parameters: CommonInterventionParameters = None): super().__init__(campaign, 'StiCoInfectionDiagnostic', common_intervention_parameters) if bool(positive_diagnosis_event) == bool(positive_diagnosis_config): raise ValueError("Either 'positive_diagnosis_config' or 'positive_diagnosis_event' must be defined, " "but not both.") if positive_diagnosis_config: if not isinstance(positive_diagnosis_config, IndividualIntervention): raise ValueError('positive_diagnosis_config must be a Intervention instance.') self._intervention.Positive_Diagnosis_Config = positive_diagnosis_config.to_schema_dict() self._intervention.Event_Or_Config = EventOrConfig.Config self._intervention.pop("Positive_Diagnosis_Event") else: self._intervention.Positive_Diagnosis_Event = set_event(positive_diagnosis_event, 'positive_diagnosis_event', campaign, False) self._intervention.pop("Positive_Diagnosis_Config") self._intervention.Event_Or_Config = EventOrConfig.Event self._intervention.Treatment_Fraction = validate_value_range(treatment_fraction, 'treatment_fraction', 0, 1, float) self._intervention.Enable_Is_Symptomatic = enable_is_symptomatic self._intervention.Days_To_Diagnosis = validate_value_range(days_to_diagnosis, 'days_to_diagnosis', 0, 3.40282e+38, float) self._intervention.Base_Specificity = validate_value_range(base_specificity, 'base_specificity', 0, 1, float) self._intervention.Base_Sensitivity = validate_value_range(base_sensitivity, 'base_sensitivity', 0, 1, float) # __all_exports: A list of classes that are intended to be exported from this module. # the private classes are commented out until we have time to review and test them. __all_exports = [ ARTDropout, # _ARTMortalityTable, AgeDiagnostic, AntiretroviralTherapy, AntiretroviralTherapyFull, CD4Diagnostic, CoitalActRiskFactors, FemaleContraceptive, HIVARTStagingByCD4Diagnostic, HIVARTStagingCD4AgnosticDiagnostic, # _HIVDelayedIntervention, HIVDrawBlood, HIVMuxer, HIVPiecewiseByYearAndSexDiagnostic, HIVRandomChoice, HIVRapidHIVDiagnostic, HIVSigmoidByYearAndSexDiagnostic, # _HIVSimpleDiagnostic, IVCalendar, # _ImmunityBloodTest, InterventionForCurrentPartners, MaleCircumcision, ModifyStiCoInfectionStatus, PMTCT, RangeThreshold, STIBarrier, STIIsPostDebut, SetSexualDebutAge, Sigmoid, StartNewRelationship, # _StiCoInfectionDiagnostic, BroadcastEvent, BroadcastEventToOtherNodes, ControlledVaccine, DelayedIntervention, IndividualImmunityChanger, IndividualNonDiseaseDeathRateModifier, MigrateIndividuals, MultiEffectBoosterVaccine, MultiEffectVaccine, MultiInterventionDistributor, OutbreakIndividual, PropertyValueChanger, SimpleBoosterVaccine, SimpleVaccine, StandardDiagnostic, ] # The following loop sets the __module__ attribute of each class in __all_exports to the name of the current module. # This is done to ensure that when these classes are imported from this module, their __module__ attribute correctly # reflects their source module. for _ in __all_exports: _.__module__ = __name__ # __all__: A list that defines the public interface of this module. # This is essential to ensure that Sphinx builds documentation for these classes, including those that are imported # from emodpy. # It contains the names of all the classes that should be accessible when this module is imported using the syntax # 'from module import *'. # Here, it is set to the names of all classes in __all_exports. __all__ = [_.__name__ for _ in __all_exports]