"""
This module contains functionality for malaria intervention distribution
via a cascade of care that may contain diagnostics and drug treatments.
"""
from copy import deepcopy, copy
import random
from emod_api.interventions.common import *
from emodpy_malaria.interventions.drug import _antimalarial_drug
from emodpy_malaria.interventions.diag_survey import add_diagnostic_survey
from emodpy_malaria.interventions.common import add_campaign_event, add_triggered_campaign_delay_event
# Different configurations of regimens and drugs
drug_cfg = {
"ALP": ["Artemether", "Lumefantrine", "Primaquine"],
"AL": ["Artemether", "Lumefantrine"],
"ASA": ["Artesunate", "Amodiaquine"],
"DP": ["DHA", "Piperaquine"],
"DPP": ["DHA", "Piperaquine", "Primaquine"],
"PPQ": ["Piperaquine"],
"DHA_PQ": ["DHA", "Primaquine"],
"DHA": ["DHA"],
"PMQ": ["Primaquine"],
"DA": ["DHA", "Abstract"],
"CQ": ["Chloroquine"],
"SP": ["Sulfadoxine", "Pyrimethamine"],
"SPP": ["Sulfadoxine", "Pyrimethamine", 'Primaquine'],
"SPA": ["Sulfadoxine", "Pyrimethamine", 'Amodiaquine'],
"Vehicle": ["Vehicle"]
}
[docs]
def drug_configs_from_code(campaign, drug_code: str = None):
"""
Add a single or multiple drug regimen to the configuration file based
on its code and add the corresponding
:doc:`emod/parameter-campaign-individual-antimalarialdrug`
intervention to the return dictionary. For example, passing the ``ALP`` drug
code will add the drug configuration for artemether, lumefantrine, and
primaquine to the configuration file and will return a dictionary containing a
full treatment course for those three drugs. For more information, see
**Malaria_Drug_Params** in :doc:`emod/parameter-configuration-drugs`.
Args:
campaign: The :py:obj:`emod_api:emod_api.campaign` object to which the intervention
will be added.
drug_code: The code of the drug regimen. This must be listed in the ``drug_cfg``
dictionary.
Returns:
A dictionary containing the intervention for the given drug regimen.
"""
if not drug_code or drug_code not in drug_cfg:
raise Exception("Please pass in a (valid) drug_code.\n"
"Available drug codes:\n"
"\"ALP\": Artemether, Lumefantrine, Primaquine.\n"
"\"AL\": Artemether, Lumefantrine. \n"
"\"ASAQ\": Artesunate, Amodiaquine.\n"
"\"DP\": DHA, Piperaquine.\n"
"\"DPP\": DHA, Piperaquine, Primaquine.\n"
"\"PPQ\": Piperaquine.\n"
"\"DHA_PQ\": DHA, Primaquine.\n"
"\"DHA\": DHA.\n"
"\"PMQ\": Primaquine.\n"
"\"DA\": DHA, Abstract.\n"
"\"CQ\": Chloroquine.\n"
"\"SP\": Sulfadoxine, Pyrimethamine.\n"
"\"SPP\": Sulfadoxine, Pyrimethamine, Primaquine.\n"
"\"SPA\": Sulfadoxine, Pyrimethamine, Amodiaquine.\n"
"\"Vehicle\": Vehicle.\n")
drug_array = drug_cfg[drug_code]
drug_configs = []
for drug in drug_array:
drug_intervention = _antimalarial_drug(campaign, drug_type=drug, cost_to_consumer=1.5)
drug_configs.append(drug_intervention)
return drug_configs
[docs]
def add_drug_campaign(campaign,
campaign_type: str = 'MDA',
drug_code: str = None,
start_days: list = None,
coverage: float = 1.0,
repetitions: int = 1,
tsteps_btwn_repetitions: int = 60,
diagnostic_type: str = 'BLOOD_SMEAR_PARASITES',
diagnostic_threshold: float = 40,
measurement_sensitivity: float = 0.1,
fmda_radius: int = 0,
node_selection_type: str = 'DISTANCE_ONLY',
trigger_coverage: float = 1.0,
trigger_name: str = None,
snowballs: int = 0,
treatment_delay: int = 0,
triggered_campaign_delay: int = 0,
delay_distribution: dict = None,
node_ids: list = None,
target_group: any = 'Everyone',
drug_ineligibility_duration: int = 0,
ind_property_restrictions: list = None,
ind_prop_restr_birthtrigger_event: list = None,
disqualifying_properties: list = None,
trigger_condition_list: list = None,
listening_duration: int = -1,
adherent_drug_configs: list = None,
target_residents_only: int = 1,
check_eligibility_at_trigger: bool = False,
receiving_drugs_event_name='Received_Campaign_Drugs'):
"""
Add a drug intervention campaign from a list of malaria campaign types.
This intervention uses the
:doc:`emod/parameter-campaign-individual-malariadiagnostic` class
to create either a scheduled or a triggered event to the campaign and the
:doc:`emod/parameter-campaign-individual-antimalarialdrug` class
to configure drug interventions. You can also specify a delay period for a
triggered event that broadcasts afterwards. If the campaign is repeated
or triggered, separate
:doc:`emod/parameter-campaign-node-nodelevelhealthtriggerediv`
interventions are created with a delay that sends an event to distribute
drugs.
Args:
campaign: The :py:obj:`emod_api:emod_api.campaign` object to which the intervention will
be added.
campaign_type: The type of drug campaign. Available options are:
MDA - Add a mass drug administration intervention.
MSAT - Add a mass screening and treatment intervention.
SMC - Add a seasonal malaria chemoprevention intervention.
fMDA- Add a focal mass drug administration intervention based on
results from a diagnostic survey, which is either scheduled or
triggered (when **trigger_condition_list** is present).
MTAT- Add a mass testing and treatment intervention.
rfMSAT -Add a reactive focal mass screening and treatment intervention.
Detecting malaria triggers diagnostic surveys to run on
neighboring nodes and so on, up to the number of triggered interventions
defined in the **snowballs** parameter.
rfMDA - Add a reactive focal mass drug administration intervention. This triggers
to broadcast a "Give_Drugs_rfMDA" event, which triggers
to distribute drugs and a "Received_Treatment" event followed by
a delayed "Give_Drugs_rfMDA" event to neighboring nodes, which
will trigger another drug distribution.
PMC -
drug_code: The code of the drug regimen to distribute. This must be
listed in the ``drug_cfg`` dictionary.
start_days: List of start days (integers) when the drug regimen will
be distributed. Due to diagnostic/treatment configuration,
the earliest start day is 1. When **trigger_condition_list** is used,
the first entry of **start_days** is the day to start listening
for the trigger(s).
coverage: The demographic coverage of the distribution (the fraction of
people at home during the campaign).
repetitions: The number of repetitions.
tsteps_btwn_repetitions: The timesteps between the repetitions.
diagnostic_type: The setting for **Diagnostic_Type** in
:doc:`emod/parameter-campaign-individual-malariadiagnostic`.
In addition to the accepted values listed there, you may also set
TRUE_INFECTION_STATUS, which calls
:doc:`emod/parameter-campaign-individual-standarddiagnostic`
instead.
diagnostic_threshold: The setting for **Diagnostic_Threshold** in
:doc:`emod/parameter-campaign-individual-malariadiagnostic`.
measurement_sensitivity: The setting for **Measurement_Sensitivity**
in :doc:`emod/parameter-campaign-individual-malariadiagnostic`.
fmda_radius: Radius (in km) of focal response upon finding infection.
Used in simulations with many small nodes to simulate
community health workers distributing drugs to surrounding houses.
Used when **campaign_type** is set to fMDA.
node_selection_type: The setting for **Node_Selection_Type** in
:doc:`emod/parameter-campaign-individual-broadcasteventtoothernodes`.
trigger_coverage: The fraction of trigger events that will trigger reactive
case detection (RCD). Used when **campaign_type** is set to rfMSAT or rfMDA.
To set the fraction of individuals reached during RCD response, use **coverage**.
trigger_name: Name of broadcast event sent out after trigger event.
Also used as in drug campaign with default "Received_{trigger_name}"
Example:
"IPTi_{x}" with x = number of IPTi dose
snowballs: The number of times each triggered intervention will be distributed
to surrounding nodes. For example, one snowball gives drugs to nodes
neighboring the first node and two snowballs gives drugs to the nodes
neighboring those nodes. Used when **campaign_type** is set to rfMSAT.
treatment_delay: For **campaign_type** set to MSAT or fMDA, the length of time
between administering a diagnostic and giving drugs; for values of rfMSAT
or rfMDA, the length of time between treating the index case and triggering
an RCD response.
triggered_campaign_delay: When using **trigger_condition_list**, this
indicates the delay period between receiving the trigger event
and running the triggered campaign intervention.
delay_distribution: For triggered_campaign_delay_event used in IPTi campaign,
dictionary of parameters that define the distribution for duration at node, including the distribution
Default: None
Durations are in days.
Examples::
{"Delay_Period_Distribution":"GAUSSIAN_DISTRIBUTION",
"Delay_Period_Gaussian_Mean": triggered_campaign_delay, "Delay_Period_Gaussian_Std_Dev" 3}
node_ids: The setting for **Node_List** in :ref:`campaign-nodeset-config`.
target_group: A dictionary of ``{'agemin': x, 'agemax': y}`` to
target MDA, SMC, MSAT, fMDA to individuals between x and y years
of age. Default is Everyone.
drug_ineligibility_duration: The number of days to set the **DrugStatus**
individual property to **RecentDrug**, after which the property value
is reverted. This property value prevents people from receiving drugs too
frequently, but they can still receive diagnostics during this period.
For more information, see :doc:`emod/model-targeted-interventions`.
ind_property_restrictions: The setting for **Property_Restrictions_Within_Node**
in :doc:`emod/parameter-campaign-event-triggeredeventcoordinator`
that individuals must have to receive the diagnostic intervention.
ind_prop_restr_birthtrigger_event: List of IndividualProperty key:value pairs that
individuals must have to create trigger event for the intervention.
For example, ``[{"IndividualProperty1":"PropertyValue1"},
{"IndividualProperty2":"PropertyValue2"}]``. Default is no restrictions.
Used in triggered_campaign_delay_event that creates BroadcastEvent to trigger vaccine campaign.
disqualifying_properties: The setting for **Disqualifying_Properties**
in :doc:`emod/parameter-campaign-individual-antimalarialdrug` or
in :doc:`emod/parameter-campaign-individual-malariadiagnostic`.
trigger_condition_list: The setting for **Start_Trigger_Condition_List** in
:doc:`emod/parameter-campaign-event-triggeredeventcoordinator`.
listening_duration: The setting for **Duration** in
:doc:`emod/parameter-campaign-event-triggeredeventcoordinator`.
adherent_drug_configs: List of adherent drug configurations, which are
dictionaries from configure_adherent_drug.
target_residents_only: The setting for **Target_Residents_Only** in
:doc:`emod/parameter-campaign-event-triggeredeventcoordinator`.
check_eligibility_at_trigger: Set to True to check the individual or node's
eligibility at the initial trigger; set to False to check eligibility
when the event is actually distributed after a delay.
receiving_drugs_event_name: The event to broadcast when a person receives drugs.
Returns:
A dictionary with drug campaign parameters.
"""
if not drug_code and not adherent_drug_configs:
raise Exception("You have to pass in drug_code(AL, DP, etc; allowable types defined in malaria_drugs.py) or"
"a list of adherent_drug_configs, which can be generated with adherent_drug.py/configure_"
"adherent_drug.\n")
elif drug_code and adherent_drug_configs:
raise Exception("You passed in a drug_code AND a list of adherent_drug_configs. Please pick one.\n")
if adherent_drug_configs:
drug_configs = adherent_drug_configs
else:
drug_configs = drug_configs_from_code(campaign, drug_code=drug_code)
if not ind_property_restrictions:
ind_property_restrictions = []
if not disqualifying_properties:
disqualifying_properties = []
# set up events to broadcast when receiving campaign drug
receiving_drugs_event = BroadcastEvent(campaign, Event_Trigger=receiving_drugs_event_name)
if campaign_type[0] == 'r': # if reactive campaign
receiving_drugs_event.Broadcast_Event = 'Received_RCD_Drugs'
if drug_code and 'Vehicle' in drug_code: # if distributing Vehicle drug
receiving_drugs_event.Broadcast_Event = "Received_Vehicle"
expire_recent_drugs = None
if drug_ineligibility_duration > 0:
expire_recent_drugs = PropertyValueChanger(camp=campaign,
Target_Property_Key="DrugStatus",
Target_Property_Value="RecentDrug",
Revert=drug_ineligibility_duration)
if start_days is None:
start_days = [1]
# set up drug campaign
if campaign_type == 'MDA' or campaign_type == 'SMC':
if treatment_delay:
raise ValueError('"treatment_delay" parameter is not used in MDA or SMC')
add_MDA(campaign, start_days=start_days, coverage=coverage, drug_configs=drug_configs,
receiving_drugs_event=receiving_drugs_event, repetitions=repetitions,
tsteps_btwn_repetitions=tsteps_btwn_repetitions, node_ids=node_ids,
expire_recent_drugs=expire_recent_drugs,
ind_property_restrictions=ind_property_restrictions, disqualifying_properties=disqualifying_properties,
target_group=target_group, trigger_condition_list=trigger_condition_list,
listening_duration=listening_duration, triggered_campaign_delay=triggered_campaign_delay,
target_residents_only=target_residents_only, check_eligibility_at_trigger=check_eligibility_at_trigger)
elif campaign_type == 'MSAT' or campaign_type == 'MTAT':
add_MSAT(campaign, start_days=start_days, coverage=coverage, drug_configs=drug_configs,
receiving_drugs_event=receiving_drugs_event, repetitions=repetitions,
tsteps_btwn_repetitions=tsteps_btwn_repetitions, treatment_delay=treatment_delay,
diagnostic_type=diagnostic_type, diagnostic_threshold=diagnostic_threshold,
measurement_sensitivity=measurement_sensitivity,
node_ids=node_ids,
expire_recent_drugs=expire_recent_drugs,
ind_property_restrictions=ind_property_restrictions, disqualifying_properties=disqualifying_properties,
target_group=target_group, trigger_condition_list=trigger_condition_list,
triggered_campaign_delay=triggered_campaign_delay, listening_duration=listening_duration,
check_eligibility_at_trigger=check_eligibility_at_trigger)
elif campaign_type == 'fMDA':
add_fMDA(campaign, start_days=start_days, trigger_coverage=trigger_coverage, coverage=coverage,
drug_configs=drug_configs, receiving_drugs_event=receiving_drugs_event, repetitions=repetitions,
tsteps_btwn_repetitions=tsteps_btwn_repetitions, treatment_delay=treatment_delay,
diagnostic_type=diagnostic_type, diagnostic_threshold=diagnostic_threshold,
measurement_sensitivity=measurement_sensitivity,
fmda_radius=fmda_radius,
node_selection_type=node_selection_type, node_ids=node_ids, expire_recent_drugs=expire_recent_drugs,
ind_property_restrictions=ind_property_restrictions,
disqualifying_properties=disqualifying_properties, target_group=target_group,
trigger_condition_list=trigger_condition_list, listening_duration=listening_duration,
triggered_campaign_delay=triggered_campaign_delay,
check_eligibility_at_trigger=check_eligibility_at_trigger)
# not a triggerable campaign
elif campaign_type == 'rfMSAT':
add_rfMSAT(campaign, start_day=start_days[0], coverage=coverage, drug_configs=drug_configs,
receiving_drugs_event=receiving_drugs_event, listening_duration=listening_duration,
treatment_delay=treatment_delay, trigger_coverage=trigger_coverage, diagnostic_type=diagnostic_type,
diagnostic_threshold=diagnostic_threshold,
measurement_sensitivity=measurement_sensitivity,
fmda_radius=fmda_radius,
node_selection_type=node_selection_type, snowballs=snowballs, node_ids=node_ids,
expire_recent_drugs=expire_recent_drugs,
ind_property_restrictions=ind_property_restrictions,
disqualifying_properties=disqualifying_properties)
# not a triggerable campaign
elif campaign_type == 'rfMDA':
add_rfMDA(campaign, start_day=start_days[0], coverage=coverage, drug_configs=drug_configs,
receiving_drugs_event=receiving_drugs_event, listening_duration=listening_duration,
treatment_delay=treatment_delay, trigger_coverage=trigger_coverage, fmda_radius=fmda_radius,
node_selection_type=node_selection_type, node_ids=node_ids, expire_recent_drugs=expire_recent_drugs,
ind_property_restrictions=ind_property_restrictions,
disqualifying_properties=disqualifying_properties)
# birthtriggered drug campaign
elif campaign_type == 'PMC':
if treatment_delay:
raise ValueError('"treatment_delay" parameter is not used in IPTi')
add_IPTi(campaign, start_day=start_days[0],
triggered_campaign_delay=triggered_campaign_delay, trigger_name=trigger_name,
coverage=coverage, delay_distribution=delay_distribution,
drug_configs=drug_configs, listening_duration=listening_duration,
node_ids=node_ids,
ind_prop_restr_birthtrigger_event=ind_prop_restr_birthtrigger_event,
ind_property_restrictions=ind_property_restrictions)
else:
raise Exception('Warning: unrecognized campaign type\n')
pass
return {'drug_campaign.type': campaign_type,
'drug_campaign.drugs': drug_code,
'drug_campaign.trigger_coverage': trigger_coverage,
'drug_campaign.coverage': coverage
}
[docs]
def add_MDA(campaign, start_days: list = None, coverage: float = 1.0, drug_configs: list = None,
receiving_drugs_event: BroadcastEvent = None, repetitions: int = 1, tsteps_btwn_repetitions: int = 60,
node_ids: list = None, expire_recent_drugs: PropertyValueChanger = None,
ind_property_restrictions: list = None, disqualifying_properties: list = None,
target_group: any = 'Everyone',
trigger_condition_list: list = None, listening_duration: int = -1, triggered_campaign_delay: int = 0,
target_residents_only: int = 1, check_eligibility_at_trigger: bool = False):
"""
Add an MDA (mass drug administration) drug intervention to your campaign.
See :py:func:`add_drug_campaign` for more information about each
argument.
Returns:
None
"""
if start_days is None:
start_days = [1]
if drug_configs is None:
raise Exception("You have to pass in drug_configs (list of drug configurations) that can be generated with "
"malaria.interventions.malaria_drugs import drug_configs_from_code.\n")
if disqualifying_properties is None:
disqualifying_properties = []
interventions = drug_configs
if receiving_drugs_event:
interventions.append(receiving_drugs_event)
if expire_recent_drugs:
interventions.append(expire_recent_drugs)
target_sex = "All"
target_age_min = 0
target_age_max = 9.3228e+35
if "agemin" in target_group:
target_age_min = target_group["agemin"]
if "agemax" in target_group:
target_age_max = target_group["agemax"]
if "gender" in target_group:
target_sex = target_group["gender"]
"""
raise KeyError("Unknown target_group parameter. Please pass in 'Everyone' or a dictionary of "
"{'agemin' : x, 'agemax' : y, 'gender': 'Female'} to target to individuals between x and "
"y years of age, and (optional) gender.\n")
"""
if trigger_condition_list:
# if once triggered, you want the diagnostic survey to repeat or if there is a delay (or both)
# this creates a series of broadcast events that once triggered send out broadcast_event
# at pre-determined intervals
if repetitions > 1 or triggered_campaign_delay > 0:
# create a trigger for each of the delays.
broadcast_event = "MDA_Now_{}".format(random.randint(1, 10000))
trigger_ind_property_restrictions = []
if check_eligibility_at_trigger:
trigger_ind_property_restrictions = ind_property_restrictions
ind_property_restrictions = []
for x in range(repetitions):
tcde = TriggeredCampaignEvent(
campaign,
Start_Day=start_days[0] + 1,
Event_Name="MDA_Delayed",
Node_Ids=node_ids,
Triggers=trigger_condition_list,
Duration=listening_duration,
Intervention_List=[BroadcastEvent(campaign, broadcast_event)],
Property_Restrictions=trigger_ind_property_restrictions,
Delay=triggered_campaign_delay + (x * tsteps_btwn_repetitions))
campaign.add(tcde)
trigger_condition_list = [broadcast_event]
drug_event = TriggeredCampaignEvent(
campaign,
Start_Day=start_days[0],
Event_Name="MDA_Now",
Node_Ids=node_ids,
Target_Age_Min=target_age_min,
Target_Age_Max=target_age_max,
Target_Gender=target_sex,
Property_Restrictions=ind_property_restrictions,
Demographic_Coverage=coverage,
Disqualifying_Properties=disqualifying_properties,
Triggers=trigger_condition_list,
Duration=listening_duration,
Target_Residents_Only=target_residents_only,
Intervention_List=interventions)
campaign.add(drug_event)
else:
for start_day in start_days:
add_campaign_event(
campaign=campaign,
start_day=start_day,
node_ids=node_ids,
target_age_min=target_age_min,
target_age_max=target_age_max,
target_gender=target_sex,
ind_property_restrictions=ind_property_restrictions,
demographic_coverage=coverage,
individual_intervention=interventions,
repetitions=repetitions,
timesteps_between_repetitions=tsteps_btwn_repetitions)
[docs]
def add_MSAT(campaign, start_days: list = None, coverage: float = 1.0, drug_configs: list = None,
receiving_drugs_event: BroadcastEvent = None, repetitions: int = 1, tsteps_btwn_repetitions: int = 60,
treatment_delay: int = 0, diagnostic_type: str = 'BLOOD_SMEAR_PARASITES',
diagnostic_threshold: float = 40, measurement_sensitivity: float = 0.1, node_ids: list = None,
expire_recent_drugs: PropertyValueChanger = None, ind_property_restrictions: list = None,
disqualifying_properties: list = None, target_group: any = 'Everyone', trigger_condition_list: list = None,
triggered_campaign_delay: int = 0, listening_duration: int = -1,
check_eligibility_at_trigger: bool = False):
"""
Add an MSAT (mass screening and treatment) drug intervention to your
campaign. See :py:func:`add_drug_campaign` for more information about each
argument.
Returns:
None
"""
if not start_days:
start_days = [1]
if drug_configs is None:
raise Exception("You have to pass in drug_configs (list of drug configurations) that can be generated with "
"malaria.interventions.malaria_drugs import drug_configs_from_code.\n")
if disqualifying_properties is None:
disqualifying_properties = []
event_config = drug_configs
if receiving_drugs_event:
event_config.append(receiving_drugs_event)
if expire_recent_drugs:
event_config.append(expire_recent_drugs)
if treatment_delay == 0:
msat_cfg = event_config
else:
msat_cfg = [DelayedIntervention(
campaign,
Delay_Dict={"Delay_Period_Constant": treatment_delay},
Configs=event_config)]
# MSAT controlled by MalariaDiagnostic campaign event rather than New_Diagnostic_Sensitivity
if trigger_condition_list:
add_diagnostic_survey(campaign, coverage=coverage, repetitions=repetitions,
tsteps_btwn_repetitions=tsteps_btwn_repetitions,
target=target_group, start_day=start_days[0],
diagnostic_type=diagnostic_type, diagnostic_threshold=diagnostic_threshold,
measurement_sensitivity=measurement_sensitivity,
node_ids=node_ids, positive_diagnosis_configs=msat_cfg,
ind_property_restrictions=ind_property_restrictions,
disqualifying_properties=disqualifying_properties,
trigger_condition_list=trigger_condition_list,
listening_duration=listening_duration, triggered_campaign_delay=triggered_campaign_delay,
check_eligibility_at_trigger=check_eligibility_at_trigger,
expire_recent_drugs=expire_recent_drugs)
else:
for start_day in start_days:
add_diagnostic_survey(campaign, coverage=coverage, repetitions=repetitions,
tsteps_btwn_repetitions=tsteps_btwn_repetitions,
target=target_group, start_day=start_day,
diagnostic_type=diagnostic_type, diagnostic_threshold=diagnostic_threshold,
measurement_sensitivity=measurement_sensitivity,
node_ids=node_ids, positive_diagnosis_configs=msat_cfg,
listening_duration=listening_duration,
ind_property_restrictions=ind_property_restrictions,
disqualifying_properties=disqualifying_properties,
expire_recent_drugs=expire_recent_drugs)
[docs]
def add_fMDA(
campaign,
start_days: list = None,
trigger_coverage: float = 1,
coverage: float = 1,
drug_configs: list = None,
receiving_drugs_event: BroadcastEvent = None,
repetitions: int = 1,
tsteps_btwn_repetitions: int = 365,
treatment_delay: int = 0,
diagnostic_type: str = 'BLOOD_SMEAR_PARASITES',
diagnostic_threshold: float = 40,
measurement_sensitivity: float = 0.1,
fmda_radius: int = 0, node_selection_type: str = 'DISTANCE_ONLY', node_ids: list = None,
expire_recent_drugs: PropertyValueChanger = None,
ind_property_restrictions: list = None,
disqualifying_properties: list = None, target_group: any = 'Everyone', trigger_condition_list: list = None,
listening_duration: int = -1, triggered_campaign_delay: int = 0,
check_eligibility_at_trigger: bool = False):
"""
Add an fMDA (focal mass drug administration) drug intervention to your
campaign. See :py:func:`add_drug_campaign` for more information about each
argument.
Returns:
None
"""
if not start_days:
start_days = [1]
if drug_configs is None:
raise Exception("You have to pass in drug_configs (list of drug configurations) that can be generated with \n"
"malaria.interventions.malaria_drugs import drug_configs_from_code.\n")
# rewritten to give out a unique trigger for the fmda
fmda_trigger_tether = "Give_Drugs_fMDA_{}".format(random.randint(1, 10000))
fmda_trigger_event = BroadcastEvent(campaign, Event_Trigger="Give_Drugs_fMDA")
fmda_setup = [fmda_cfg(campaign, fmda_radius, node_selection_type, event_trigger=fmda_trigger_tether),
fmda_trigger_event]
interventions = drug_configs
if receiving_drugs_event:
interventions.append(receiving_drugs_event)
if expire_recent_drugs:
interventions.append(expire_recent_drugs)
if treatment_delay > 0:
fmda_setup = [DelayedIntervention(
campaign,
Delay_Dict={"Delay_Period_Constant": treatment_delay},
Configs=fmda_setup)]
if trigger_condition_list:
add_diagnostic_survey(campaign, coverage=trigger_coverage, repetitions=repetitions,
tsteps_btwn_repetitions=tsteps_btwn_repetitions,
target=target_group, start_day=start_days[0] + 1,
diagnostic_type=diagnostic_type, diagnostic_threshold=diagnostic_threshold,
measurement_sensitivity=measurement_sensitivity,
node_ids=node_ids, positive_diagnosis_configs=fmda_setup,
ind_property_restrictions=ind_property_restrictions,
trigger_condition_list=trigger_condition_list,
listening_duration=listening_duration, triggered_campaign_delay=triggered_campaign_delay,
check_eligibility_at_trigger=check_eligibility_at_trigger,
expire_recent_drugs=expire_recent_drugs)
fmda_distribute_drugs = TriggeredCampaignEvent(
campaign,
Event_Name="Distribute fMDA",
Start_Day=start_days[0],
Node_Ids=node_ids,
Demographic_Coverage=coverage,
Blackout_Event_Trigger="fMDA_Blackout_Event_Trigger",
Blackout_Period=1,
Blackout_On_First_Occurrence=1,
Target_Residents_Only=1,
Property_Restrictions=ind_property_restrictions,
Disqualifying_Properties=disqualifying_properties,
Duration=listening_duration,
Triggers=[fmda_trigger_tether],
Intervention_List=interventions)
campaign.add(fmda_distribute_drugs)
else:
for start_day in start_days:
# separate event for each repetition, otherwise RCD and fMDA can get entangled.
for rep in range(repetitions):
add_diagnostic_survey(campaign, coverage=trigger_coverage, repetitions=1,
tsteps_btwn_repetitions=tsteps_btwn_repetitions,
target=target_group, start_day=start_day + 1 + tsteps_btwn_repetitions * rep,
diagnostic_type=diagnostic_type, diagnostic_threshold=diagnostic_threshold,
measurement_sensitivity=measurement_sensitivity,
node_ids=node_ids, positive_diagnosis_configs=fmda_setup,
ind_property_restrictions=ind_property_restrictions,
disqualifying_properties=disqualifying_properties,
expire_recent_drugs=expire_recent_drugs)
fmda_distribute_drugs = TriggeredCampaignEvent(
campaign,
Event_Name="Distribute fMDA (2)",
Start_Day=start_days[0],
Node_Ids=node_ids,
Demographic_Coverage=coverage,
Blackout_Event_Trigger="fMDA_Blackout_Event_Trigger",
Blackout_Period=1,
Blackout_On_First_Occurrence=1,
Target_Residents_Only=1,
Property_Restrictions=ind_property_restrictions,
Disqualifying_Properties=disqualifying_properties,
Triggers=[fmda_trigger_tether],
Intervention_List=interventions)
campaign.add(fmda_distribute_drugs)
[docs]
def add_rfMSAT(campaign, start_day: int = 0, coverage: float = 1, drug_configs: list = None,
receiving_drugs_event: BroadcastEvent = None, listening_duration: int = -1, treatment_delay: int = 0,
trigger_coverage: float = 1, diagnostic_type: str = 'BLOOD_SMEAR_PARASITES',
diagnostic_threshold: float = 40,
measurement_sensitivity: float = 0.1,
fmda_radius: int = 0, node_selection_type: str = 'DISTANCE_ONLY', snowballs: int = 0,
node_ids: list = None,
expire_recent_drugs: PropertyValueChanger = None,
ind_property_restrictions: list = None, disqualifying_properties: list = None):
"""
Add a rfMSAT (reactive focal mass screening and treatment) drug intervention to your
campaign. See :py:func:`add_drug_campaign` for more information about each
argument.
Returns:
None
"""
if drug_configs is None:
raise Exception("You have to pass in drug_configs (list of drug configurations) that can be generated with "
"malaria.interventions.malaria_drugs import drug_configs_from_code.\n")
if disqualifying_properties is None:
disqualifying_properties = []
fmda_setup = fmda_cfg(campaign, fmda_radius, node_selection_type) # default trigger used
snowball_setup = [deepcopy(fmda_setup) for x in range(snowballs + 1)]
snowball_trigger = 'Diagnostic_Survey_'
snowball_setup[0].Event_Trigger = snowball_trigger + "0"
rcd_event = TriggeredCampaignEvent(
campaign,
Event_Name="Trigger RCD MSAT",
Start_Day=start_day,
Node_Ids=node_ids,
Demographic_Coverage=trigger_coverage,
Duration=listening_duration,
Triggers=["Received_Treatment"],
Intervention_List=[DelayedIntervention(
campaign,
Delay_Dict={"Delay_Period_Constant": treatment_delay},
Configs=[snowball_setup[0]])]
)
campaign.add(rcd_event)
event_config = drug_configs
if receiving_drugs_event:
event_config.append(receiving_drugs_event)
if expire_recent_drugs:
event_config.append(expire_recent_drugs)
add_diagnostic_survey(campaign, coverage=coverage, start_day=start_day,
diagnostic_type=diagnostic_type, diagnostic_threshold=diagnostic_threshold,
measurement_sensitivity=measurement_sensitivity,
node_ids=node_ids,
trigger_condition_list=[snowball_setup[0].Event_Trigger],
event_name='Reactive MSAT level 0',
positive_diagnosis_configs=event_config,
listening_duration=listening_duration,
ind_property_restrictions=ind_property_restrictions,
disqualifying_properties=disqualifying_properties, expire_recent_drugs=expire_recent_drugs)
for snowball in range(snowballs):
snowball_setup[snowball + 1].Event_Trigger = snowball_trigger + str(snowball + 1)
event_config = [snowball_setup[snowball + 1], receiving_drugs_event] + drug_configs
curr_trigger = snowball_trigger + str(snowball)
add_diagnostic_survey(campaign, coverage=coverage, start_day=start_day,
diagnostic_type=diagnostic_type, diagnostic_threshold=diagnostic_threshold,
measurement_sensitivity=measurement_sensitivity,
node_ids=node_ids,
trigger_condition_list=[curr_trigger],
event_name='Snowball level ' + str(snowball),
positive_diagnosis_configs=event_config,
listening_duration=listening_duration,
ind_property_restrictions=ind_property_restrictions,
disqualifying_properties=disqualifying_properties,
expire_recent_drugs=expire_recent_drugs)
[docs]
def add_rfMDA(campaign, start_day: int = 0, coverage: float = 1, drug_configs: list = None,
receiving_drugs_event: BroadcastEvent = None, listening_duration: int = -1, treatment_delay: int = 0,
trigger_coverage: float = 1, fmda_radius: int = 0, node_selection_type: str = 'DISTANCE_ONLY',
node_ids: list = None, expire_recent_drugs: PropertyValueChanger = None,
ind_property_restrictions: list = None, disqualifying_properties: list = None):
"""
Add an rfMDA (reactive focal mass drug administration) drug intervention
to your campaign. See :py:func:`add_drug_campaign` for more information
about each argument.
Returns:
None
"""
if drug_configs is None:
raise Exception("You have to pass in drug_configs (list of drug configurations) that can be generated with "
"malaria.interventions.malaria_drugs import drug_configs_from_code.\n")
interventions = drug_configs
if receiving_drugs_event:
interventions.append(receiving_drugs_event)
if disqualifying_properties is None:
disqualifying_properties = []
rfmda_trigger = "Give_Drugs_rfMDA"
fmda_setup = fmda_cfg(campaign, fmda_radius, node_selection_type, event_trigger=rfmda_trigger)
rcd_event = TriggeredCampaignEvent(
campaign,
Event_Name="Trigger RCD MDA",
Start_Day=start_day,
Node_Ids=node_ids,
Demographic_Coverage=trigger_coverage,
Property_Restrictions=ind_property_restrictions,
Triggers=["Received_Treatment"],
Duration=listening_duration,
Intervention_List=[
DelayedIntervention(
campaign,
Delay_Dict={"Delay_Period_Constant": treatment_delay},
Configs=[fmda_setup])
]
)
if expire_recent_drugs:
interventions = interventions + [expire_recent_drugs]
# distributes drugs to individuals broadcasting "Give_Drugs_rfMDA"
# who is broadcasting is determined by other events
# if campaign drugs change (less effective, different cocktail), then this event should have an expiration date.
fmda_distribute_drugs = TriggeredCampaignEvent(
campaign,
Event_Name="Distribute fMDA",
Start_Day=start_day,
Node_Ids=node_ids,
Demographic_Coverage=coverage,
Property_Restrictions=ind_property_restrictions,
Disqualifying_Properties=disqualifying_properties,
Duration=listening_duration,
Triggers=[rfmda_trigger],
Intervention_List=interventions)
campaign.add(rcd_event)
campaign.add(fmda_distribute_drugs)
[docs]
def fmda_cfg(campaign, fmda_type: any = 0, node_selection_type: str = 'DISTANCE_ONLY',
event_trigger: str = 'Give_Drugs'):
"""
Create an fMDA (focal mass drug administration) configuration.
Args:
fmda_type: The setting for **Max_Distance_To_Other_Nodes_Km** in
:doc:`emod/parameter-campaign-individual-broadcasteventtoothernodes`.
node_selection_type: The setting for **Node_Selection_Type** in
:doc:`emod/parameter-campaign-individual-broadcasteventtoothernodes`.
event_trigger: The setting for **Event_Trigger** in
:doc:`emod/parameter-campaign-individual-broadcasteventtoothernodes`.
Returns:
Configured :doc:`emod/parameter-campaign-individual-broadcasteventtoothernodes`
intervention.
"""
if isinstance(fmda_type, str):
fmda_type = 0
return BroadcastEventToOtherNodes(
campaign,
Event_Trigger=event_trigger,
Include_My_Node=1,
Node_Selection_Type=node_selection_type,
Max_Distance_To_Other_Nodes_Km=fmda_type)
[docs]
def add_IPTi(campaign, start_day: int = 1, triggered_campaign_delay: int = None, trigger_name: str = None,
coverage: float = 1, trigger_coverage: float = 1,
drug_configs: list = None, listening_duration: int = -1,
delay_distribution: dict = None,
node_ids: list = None, ind_prop_restr_birthtrigger_event: list = None,
ind_property_restrictions: list = None):
"""
This function adds two intervention types and multiple deployments to your campaign file:
1) "IPTi" (IPTi eligible) - triggered campaign_delay_event of
"Births" event with a "triggered_campaign_delay" option, with "demographic_coverage".
2) "Received_IPTi" event-triggered MultiIntervention event
distributing "drug_configs" drugs, with "coverage"
to specify custom coverages at the triggered campaign_delay_event.
Upon "Births" event a delayed "IPTi" is sent out,
which triggers giving drugs in a separate event "Received_IPTi".
Args:
campaign: The :py:obj:`emod_api:emod_api.campaign` object to which the intervention will
be added.
start_day: The day the intervention is distributed. Default is 0.
trigger_coverage: Used to create BroadcastEvent to trigger IPTi campaign after Births. Default is 1
(i.e. all infants are captured by health system to reach an age eligible for IPTi).
coverage: The proportion of the population covered by the intervention (fraction of infants receiving IPTi)
drug_configs: List of dictionaries of drug configurations to be
distributed, created in add_drug_campaign.
listening_duration: Duration of the existence of the intervention.
Default is ongoing.
delay_distribution: Dictionary of parameters that define the distribution for duration at node, including
the distribution
Default: None
Durations are in days.
Examples::
{"Delay_Period_Distribution":"GAUSSIAN_DISTRIBUTION",
"Delay_Period_Gaussian_Mean": 14, "Delay_Period_Gaussian_Std_Dev" 3}
{"Delay_Period_Distribution":"POISSON_DISTRIBUTION",
"Delay_Period_Poisson_Mean" 30}
If None automatically uses:
{"Delay_Period_Distribution": "CONSTANT_DISTRIBUTION",
"Delay_Period_Constant": triggered_campaign_delay}
triggered_campaign_delay: When using trigger_condition_list, this indicates the delay period
between receiving the trigger event and running the triggered campaign intervention
(days after Births at which infant is eligible for IPTi).
This is ignored if delay_distribution is not None.
trigger_name: Name of broadcast event sent out after trigger event.
Also used as in drug campaign with default "Received_{trigger_name}"
Example:
"IPTi_{x}" with x = number of IPTi dose
node_ids: The list of nodes to apply this intervention to (**Node_List**
parameter). If not provided, set value of NodeSetAll.
ind_property_restrictions: List of IndividualProperty key:value pairs that
individuals must have to receive the diagnostic intervention.
For example, ``[{"IndividualProperty1":"PropertyValue1"},
{"IndividualProperty2":"PropertyValue2"}]``. Default is no restrictions.
Returns:
None
"""
if drug_configs is None:
raise Exception("You have to pass in drug_configs (list of drug configurations) that can be generated with "
"malaria.interventions.malaria_drugs import drug_configs_from_code.\n")
if triggered_campaign_delay and delay_distribution:
raise Exception("You passed in a triggered_campaign_delay AND a delay_distribution. Please pick one.\n")
if triggered_campaign_delay:
delay_distribution = {"Delay_Period_Distribution": "CONSTANT_DISTRIBUTION",
"Delay_Period_Constant": triggered_campaign_delay}
if ind_property_restrictions is None:
ind_property_restrictions = []
broadcast_event = BroadcastEvent(campaign, trigger_name)
if delay_distribution:
broadcast_event = DelayedIntervention(campaign, Configs=[broadcast_event],
Delay_Dict=delay_distribution)
add_triggered_campaign_delay_event(campaign, start_day=start_day,
trigger_condition_list=['Births'],
demographic_coverage=trigger_coverage,
listening_duration=listening_duration,
ind_property_restrictions=ind_prop_restr_birthtrigger_event,
node_ids=node_ids,
individual_intervention=broadcast_event)
interventions = drug_configs + [BroadcastEvent(campaign, f"Received_{trigger_name}")]
add_triggered_campaign_delay_event(campaign=campaign,
start_day=start_day,
trigger_condition_list=[trigger_name],
listening_duration=listening_duration,
demographic_coverage=coverage,
node_ids=node_ids,
ind_property_restrictions=ind_property_restrictions,
individual_intervention=interventions)