Skip to content

High Risk

Bases: BaseFeature

Source code in titan/features/high_risk.py
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
class HighRisk(base_feature.BaseFeature):
    name = "high_risk"
    stats = [
        "high_risk_new",
        "high_risk_new_hiv",
        "high_risk_new_aids",
        "high_risk_new_dx",
        "high_risk_new_haart",
        "hiv_new_high_risk",
        "hiv_new_high_risk_ever",
    ]
    """
        High Risk collects the following stats:

        * high_risk_new - number of agents that became active high risk this time step
        * high_risk_new_hiv - number of agents that became active high risk this time step with HIV
        * high_risk_new_aids - number of agents that became active high risk this time step with AIDS
        * high_risk_new_dx - number of agents that became active high risk this time step with diagnosed HIV
        * high_risk_new_haart - number of agents that became active high risk this time step with active HAART
        * hiv_new_high_risk - number of agents that became active with HIV this time step who are high risk
        * hiv_new_high_risk_ever - number of agents that became active with HIV this time step were ever high risk
    """

    def __init__(self, agent: "agent.Agent"):
        super().__init__(agent)

        self.active = False
        self.time: Optional[int] = None
        self.duration = 0
        self.ever = False

    def init_agent(self, pop: "population.Population", time: int):
        """
        Initialize the agent for this feature during population initialization (`Population.create_agent`).  Called on only features that are enabled per the params.

        Based on agent demographic params, randomly initialize agent as high risk.

        args:
            pop: the population this agent is a part of
            time: the current time step
        """
        if (
            pop.pop_random.random()
            < self.agent.location.params.demographics[self.agent.race]
            .sex_type[self.agent.sex_type]
            .high_risk.init
        ):
            self.become_high_risk(pop, time)

    def update_agent(self, model: "model.TITAN"):
        """
        Update the agent for this feature for a time step.  Called once per time step in `TITAN.update_all_agents`. Agent level updates are done after population level updates.   Called on only features that are enabled per the params.

        Update high risk agents or remove them from high risk pool.  An agent becomes high_risk through the incarceration feature

        args:
            model: the instance of TITAN currently being run
        """
        if not self.active:
            # released last step, evaluate agent for high risk
            if self.agent.incar.release_time == model.time - 1:  # type: ignore[attr-defined]
                self.become_high_risk(model.pop, model.time)

            # incarcerated last step, evaluate agent's partners for high risk
            elif self.agent.incar.time == model.time - 1:  # type: ignore[attr-defined]
                # put partners in high risk
                for partner in self.agent.get_partners(
                    self.agent.location.params.high_risk.partnership_types
                ):
                    if (
                        not partner.high_risk.active  # type: ignore[attr-defined]
                        and model.run_random.random()
                        < partner.location.params.high_risk.prob
                    ):
                        partner.high_risk.become_high_risk(model.pop, model.time)  # type: ignore[attr-defined]
        elif self.duration > 0:
            self.duration -= 1
        else:
            self.active = False

            self.update_partner_numbers(
                model.pop, -1 * self.agent.location.params.high_risk.partner_scale
            )

            for bond in self.agent.location.params.high_risk.partnership_types:
                num_ended = 0
                while (
                    len(self.agent.partners[bond]) - num_ended
                ) > self.agent.target_partners[bond]:
                    rel = utils.safe_random_choice(
                        self.agent.relationships, model.run_random
                    )
                    if rel is not None:
                        num_ended += 1
                        rel.duration = 0  # will end on next step

    def set_stats(self, stats: Dict[str, int], time: int):
        if self.time == time:
            stats["high_risk_new"] += 1
            if self.agent.hiv.active:  # type: ignore[attr-defined]
                stats["high_risk_new_hiv"] += 1
                if self.agent.hiv.aids:  # type: ignore[attr-defined]
                    stats["high_risk_new_aids"] += 1
                if self.agent.hiv.dx:  # type: ignore[attr-defined]
                    stats["high_risk_new_dx"] += 1
                    if self.agent.haart.active:  # type: ignore[attr-defined]
                        stats["high_risk_new_haart"] += 1

        # newly hiv
        if self.agent.hiv.time == time:  # type: ignore[attr-defined]
            if self.active:
                stats["hiv_new_high_risk"] += 1
            if self.ever:
                stats["hiv_new_high_risk_ever"] += 1

    # ============== HELPER METHODS ================

    def become_high_risk(
        self, pop: "population.Population", time: int, duration: Optional[int] = None
    ):
        """
        Mark an agent as high risk and assign a duration to their high risk period

        args:
            pop: the model poopulation
            time: the time step the agent is becoming high risk
            duration: duration of the high risk period, defaults to param value if not passed [params.high_risk.sex_based]
        """

        if not self.agent.location.params.features.high_risk:
            return None

        if not self.ever:
            self.time = time

        self.active = True
        self.ever = True

        if duration is not None:
            self.duration = duration
        else:
            self.duration = self.agent.location.params.high_risk.sex_based[
                self.agent.sex_type
            ].duration

        self.update_partner_numbers(
            pop, self.agent.location.params.high_risk.partner_scale
        )

    def update_partner_numbers(self, pop: "population.Population", amount: int):
        """
        Update the agent's mean and target partner numbers by the amount passed.  Update partnerability for the population.

        args:
            pop: the model population
            amount: the positive or negatative amount to adjust the mean by
        """
        for bond in self.agent.location.params.high_risk.partnership_types:
            self.agent.mean_num_partners[bond] += amount  # could be negative
            self.agent.target_partners[bond] = poisson(
                pop.np_random, self.agent.mean_num_partners[bond]
            )
            pop.update_partnerability(self.agent)

stats = ['high_risk_new', 'high_risk_new_hiv', 'high_risk_new_aids', 'high_risk_new_dx', 'high_risk_new_haart', 'hiv_new_high_risk', 'hiv_new_high_risk_ever'] class-attribute instance-attribute

High Risk collects the following stats:

  • high_risk_new - number of agents that became active high risk this time step
  • high_risk_new_hiv - number of agents that became active high risk this time step with HIV
  • high_risk_new_aids - number of agents that became active high risk this time step with AIDS
  • high_risk_new_dx - number of agents that became active high risk this time step with diagnosed HIV
  • high_risk_new_haart - number of agents that became active high risk this time step with active HAART
  • hiv_new_high_risk - number of agents that became active with HIV this time step who are high risk
  • hiv_new_high_risk_ever - number of agents that became active with HIV this time step were ever high risk

become_high_risk(pop, time, duration=None)

Mark an agent as high risk and assign a duration to their high risk period

Parameters:

Name Type Description Default
pop Population

the model poopulation

required
time int

the time step the agent is becoming high risk

required
duration Optional[int]

duration of the high risk period, defaults to param value if not passed [params.high_risk.sex_based]

None
Source code in titan/features/high_risk.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
def become_high_risk(
    self, pop: "population.Population", time: int, duration: Optional[int] = None
):
    """
    Mark an agent as high risk and assign a duration to their high risk period

    args:
        pop: the model poopulation
        time: the time step the agent is becoming high risk
        duration: duration of the high risk period, defaults to param value if not passed [params.high_risk.sex_based]
    """

    if not self.agent.location.params.features.high_risk:
        return None

    if not self.ever:
        self.time = time

    self.active = True
    self.ever = True

    if duration is not None:
        self.duration = duration
    else:
        self.duration = self.agent.location.params.high_risk.sex_based[
            self.agent.sex_type
        ].duration

    self.update_partner_numbers(
        pop, self.agent.location.params.high_risk.partner_scale
    )

init_agent(pop, time)

Initialize the agent for this feature during population initialization (Population.create_agent). Called on only features that are enabled per the params.

Based on agent demographic params, randomly initialize agent as high risk.

Parameters:

Name Type Description Default
pop Population

the population this agent is a part of

required
time int

the current time step

required
Source code in titan/features/high_risk.py
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def init_agent(self, pop: "population.Population", time: int):
    """
    Initialize the agent for this feature during population initialization (`Population.create_agent`).  Called on only features that are enabled per the params.

    Based on agent demographic params, randomly initialize agent as high risk.

    args:
        pop: the population this agent is a part of
        time: the current time step
    """
    if (
        pop.pop_random.random()
        < self.agent.location.params.demographics[self.agent.race]
        .sex_type[self.agent.sex_type]
        .high_risk.init
    ):
        self.become_high_risk(pop, time)

update_agent(model)

Update the agent for this feature for a time step. Called once per time step in TITAN.update_all_agents. Agent level updates are done after population level updates. Called on only features that are enabled per the params.

Update high risk agents or remove them from high risk pool. An agent becomes high_risk through the incarceration feature

Parameters:

Name Type Description Default
model TITAN

the instance of TITAN currently being run

required
Source code in titan/features/high_risk.py
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def update_agent(self, model: "model.TITAN"):
    """
    Update the agent for this feature for a time step.  Called once per time step in `TITAN.update_all_agents`. Agent level updates are done after population level updates.   Called on only features that are enabled per the params.

    Update high risk agents or remove them from high risk pool.  An agent becomes high_risk through the incarceration feature

    args:
        model: the instance of TITAN currently being run
    """
    if not self.active:
        # released last step, evaluate agent for high risk
        if self.agent.incar.release_time == model.time - 1:  # type: ignore[attr-defined]
            self.become_high_risk(model.pop, model.time)

        # incarcerated last step, evaluate agent's partners for high risk
        elif self.agent.incar.time == model.time - 1:  # type: ignore[attr-defined]
            # put partners in high risk
            for partner in self.agent.get_partners(
                self.agent.location.params.high_risk.partnership_types
            ):
                if (
                    not partner.high_risk.active  # type: ignore[attr-defined]
                    and model.run_random.random()
                    < partner.location.params.high_risk.prob
                ):
                    partner.high_risk.become_high_risk(model.pop, model.time)  # type: ignore[attr-defined]
    elif self.duration > 0:
        self.duration -= 1
    else:
        self.active = False

        self.update_partner_numbers(
            model.pop, -1 * self.agent.location.params.high_risk.partner_scale
        )

        for bond in self.agent.location.params.high_risk.partnership_types:
            num_ended = 0
            while (
                len(self.agent.partners[bond]) - num_ended
            ) > self.agent.target_partners[bond]:
                rel = utils.safe_random_choice(
                    self.agent.relationships, model.run_random
                )
                if rel is not None:
                    num_ended += 1
                    rel.duration = 0  # will end on next step

update_partner_numbers(pop, amount)

Update the agent's mean and target partner numbers by the amount passed. Update partnerability for the population.

Parameters:

Name Type Description Default
pop Population

the model population

required
amount int

the positive or negatative amount to adjust the mean by

required
Source code in titan/features/high_risk.py
162
163
164
165
166
167
168
169
170
171
172
173
174
175
def update_partner_numbers(self, pop: "population.Population", amount: int):
    """
    Update the agent's mean and target partner numbers by the amount passed.  Update partnerability for the population.

    args:
        pop: the model population
        amount: the positive or negatative amount to adjust the mean by
    """
    for bond in self.agent.location.params.high_risk.partnership_types:
        self.agent.mean_num_partners[bond] += amount  # could be negative
        self.agent.target_partners[bond] = poisson(
            pop.np_random, self.agent.mean_num_partners[bond]
        )
        pop.update_partnerability(self.agent)