I haven't implemented any of these changes, they are purely observations.
Message Classes
There are several classes of message:
Assignment
tb_assignment : A message declaring that a person has active TB. Only emitted by people with TB, only holds their id.
Membership
Primary: This links a personid, houseid, church id/freq/duration
household_membership: A message declaring that a person is a member of a household
Secondary: These all link personId, eventId (and duration)
church_membership: A message declaring that a person is a member of a household
transport_membership:A message declaring that a person uses a transport`
workplace_membership:A message declaring that a person is employed at a workplace
school_membership:A message declaring that a person studies at a school
Location
location: A message declaring that a person is in a given location at a given time
Infection
These messages are all:
A message containing the lambda value for a given location at a given time'
With a lambda value and location index.
household_infection
church_infection
transport_infection
clinic_infection
workplace_infection
bar_infection
school_infection
Improvements
Membership
I haven't looked at household membership, but presumably it's the same, just more properties.
Msg Output
Each iteration <location>_membership agent has a <abbreviated location>init() which outputs these messages.
Msg Input
Person has a membership function person<abbreviated location>init() for each location type, which iterates all messages, to decide whether that person is a member of the location. From this it stores the location's id under the corresponding agent variable e.g. person->school = school_membership_message->school_id
Solution
I can't really tell the purpose of these agents/messages. The agents are created in the init function, and they never change, similarly the message's mirror the agent's directly and our output continuously.
Unless I'm missing something, this looks alot like a hack for their initialisation:
- They create the people
- They create the associations
- They create association agents to represent the associations
- Each iteration:
- associations output message
- person reads messages to set their internal associations
Restructuring init, to create people, but not commit them to device until associations have been decided should allow all of these messages/agents to be removed.
Benefit
- Removal of ~7 spurious agents/messages
- Removal of 14 redundant device functions (7x message input and output)
Assignment
Msg Output
TBAssignment agent tbinit() fn
Msg Input
Person agent persontbinit() fn
Solution
This looks like another init hack, membership by another name.
TBAssignment are created in the init function, hold a person Id, and they only output a message with that id.
People then iterate messages, to find if they have TB and perform some maths to set some other values.
Similar fix to membership, probably some arguments in favour of moving init where possible to GPU however (e.g. one time Person agent function that slurps up all this data to properly init people).
Benefit
~
Location
Msg Output
Each iteration, person all run update() which updates their location and TB status. Those with TB output a location message.
Msg Input
For each location type, there is an agent function which counts how many location messages have the required location ID and applys it to some formula to calculate the locations infection level, which is then output as an infection message.
Each location type has it's own formula.
Solution
- Bin all of the location messages
- Allocate an array of
int where we can atomically build a histogram of infection count at each location. (An alternative would be to output to an array/agent variable and use cub:histogram)
- Locations can then directly access the count, rather than having to iterate loads of messages.
- In combination with Infection message fix, move all of the existing message input functions into a single layer (Can't combine kernel launches (without major rewrite) due to different agents/infection formulae)
Benefits:
- Saves redundant iteration to count.
- Attempts to use some concurrency
Infection
All of these messages are simply set to identify the delta of a location, and are output by that location in the schupdate hhupdate style functions.
Msg Output
All <location> output a message saying <my infection level is> (e.g. schupdate())
Msg Input
Person iterates all infection messages, looking for the one which corresponds with their current location, and takes the 'lambda' value from it. (e.g. updatelambdasch())
Solution
- Bin all of the infection messages.
- Allocate an array of
float, where location's instead write their lambda value (It appears location id is globally imposed, rather than per event type).
- Rewrite message output functions to instead write to this array.
- Merge all of the infection message input functions, where a person simply calls
me->lambda = location_lambdas[me->locationId]
Benefits
- Reduces 7(?) kernel launches to 1 (possibly 0, if logic allows that single line to go elsewhere).
- Allows persons to directly access their message, rather than having to iterate several thousand, across multiple kernel launches.
- Probably removes a few hundred LoC from
functions.c and XMLModelFile.xml
I haven't implemented any of these changes, they are purely observations.
Message Classes
There are several classes of message:
Assignment
tb_assignment: A message declaring that a person has active TB. Only emitted by people with TB, only holds their id.Membership
Primary: This links a personid, houseid, church id/freq/duration
household_membership: A message declaring that a person is a member of a householdSecondary: These all link personId, eventId (and duration)
church_membership: A message declaring that a person is a member of a householdtransport_membership:A message declaring that a person uses a transport`workplace_membership:A message declaring that a person is employed at a workplaceschool_membership:A message declaring that a person studies at a schoolLocation
location: A message declaring that a person is in a given location at a given timeInfection
These messages are all:
With a lambda value and location index.
household_infectionchurch_infectiontransport_infectionclinic_infectionworkplace_infectionbar_infectionschool_infectionImprovements
Membership
I haven't looked at household membership, but presumably it's the same, just more properties.
Msg Output
Each iteration
<location>_membershipagent has a<abbreviated location>init()which outputs these messages.Msg Input
Person has a membership function
person<abbreviated location>init()for each location type, which iterates all messages, to decide whether that person is a member of the location. From this it stores the location's id under the corresponding agent variable e.g.person->school = school_membership_message->school_idSolution
I can't really tell the purpose of these agents/messages. The agents are created in the init function, and they never change, similarly the message's mirror the agent's directly and our output continuously.
Unless I'm missing something, this looks alot like a hack for their initialisation:
Restructuring init, to create people, but not commit them to device until associations have been decided should allow all of these messages/agents to be removed.
Benefit
Assignment
Msg Output
TBAssignmentagenttbinit()fnMsg Input
Personagentpersontbinit()fnSolution
This looks like another init hack, membership by another name.
TBAssignmentare created in the init function, hold a person Id, and they only output a message with that id.People then iterate messages, to find if they have TB and perform some maths to set some other values.
Similar fix to membership, probably some arguments in favour of moving init where possible to GPU however (e.g. one time
Personagent function that slurps up all this data to properly init people).Benefit
~
Location
Msg Output
Each iteration,
personall runupdate()which updates their location and TB status. Those with TB output a location message.Msg Input
For each location type, there is an agent function which counts how many location messages have the required location ID and applys it to some formula to calculate the locations infection level, which is then output as an infection message.
Each location type has it's own formula.
Solution
intwhere we can atomically build a histogram of infection count at each location. (An alternative would be to output to an array/agent variable and use cub:histogram)Benefits:
Infection
All of these messages are simply set to identify the delta of a location, and are output by that location in the
schupdatehhupdatestyle functions.Msg Output
All <location> output a message saying <my infection level is> (e.g.
schupdate())Msg Input
Person iterates all infection messages, looking for the one which corresponds with their current location, and takes the 'lambda' value from it. (e.g.
updatelambdasch())Solution
float, where location's instead write their lambda value (It appears location id is globally imposed, rather than per event type).me->lambda = location_lambdas[me->locationId]Benefits
functions.candXMLModelFile.xml