/** * Responds to an infection event by changing the herd's state from susceptible * to infected. * * @param self the model. * @param event an infection event. * @param rng a random number generator. */ void handle_infection_event (struct naadsm_model_t_ *self, EVT_infection_event_t * event, RAN_gen_t * rng) { local_data_t *local_data; HRD_herd_t *herd; int latent_period, infectious_subclinical_period, infectious_clinical_period, immunity_period; unsigned int day_in_disease_cycle; #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- ENTER handle_infection_event (%s)", MODEL_NAME); #endif local_data = (local_data_t *) (self->model_data); herd = event->infected_herd; if (local_data->production_type[herd->production_type] == FALSE) { #if DEBUG g_debug ("unit is %s, sub-model does not apply", herd->production_type_name); #endif goto end; } day_in_disease_cycle = 0; /* Latent period. */ latent_period = (int) round (PDF_random (local_data->latent_period, rng)); if (latent_period < 0) { #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s distribution returned %i for latent period, using 0 instead", PDF_dist_type_name[local_data->latent_period->type], latent_period); #endif latent_period = 0; } if (event->override_initial_state == Latent) { if (event->override_days_in_state > 0 && event->override_days_left_in_state > 0) { /* Override both the days elapsed and the days left in the latent * period. */ latent_period = event->override_days_in_state + event->override_days_left_in_state; day_in_disease_cycle = event->override_days_in_state; } else if (event->override_days_in_state > 0) { /* Override just the days elapsed in the latent period. If the given * value is greater than the sampled length of the latent period, * extend the latent period. */ latent_period = MAX(latent_period, event->override_days_in_state); day_in_disease_cycle = event->override_days_in_state; } else if (event->override_days_left_in_state > 0) { /* Override just the days left in the latent period. If the given * value is greater than the sampled length of the latent period, * extend the latent period. */ latent_period = MAX(latent_period, event->override_days_left_in_state); day_in_disease_cycle = latent_period - event->override_days_left_in_state; } } #if DEBUG g_debug ("latent period will last %i days", latent_period); #endif /* Infectious subclinical period. */ infectious_subclinical_period = (int) round (PDF_random (local_data->infectious_subclinical_period, rng)); if (infectious_subclinical_period < 0) { #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s distribution returned %i for infectious subclinical period, using 0 instead", PDF_dist_type_name[local_data->infectious_subclinical_period->type], infectious_subclinical_period); #endif infectious_subclinical_period = 0; } if (event->override_initial_state == InfectiousSubclinical) { day_in_disease_cycle = latent_period; if (event->override_days_in_state > 0 && event->override_days_left_in_state > 0) { /* Override both the days elapsed and the days left in the infectious * subclinical period. */ infectious_subclinical_period = event->override_days_in_state + event->override_days_left_in_state; day_in_disease_cycle += event->override_days_in_state; } else if (event->override_days_in_state > 0) { /* Override just the days elapsed in the infectious subclinical * period. If the given value is greater than the sampled length of * the infectious subclinical period, extend the infectious * subclinical period. */ infectious_subclinical_period = MAX(infectious_subclinical_period, event->override_days_in_state); day_in_disease_cycle += event->override_days_in_state; } else if (event->override_days_left_in_state > 0) { /* Override just the days left in the infectious subclinical period. * If the given value is greater than the sampled length of the * infectious subclinical period, extend the infectious subclinical * period. */ infectious_subclinical_period = MAX(infectious_subclinical_period, event->override_days_left_in_state); day_in_disease_cycle += (infectious_subclinical_period - event->override_days_left_in_state); } } #if DEBUG g_debug ("infectiousness (with no visible signs) will last %i days", infectious_subclinical_period); #endif /* Infectious clinical period. */ infectious_clinical_period = (int) round (PDF_random (local_data->infectious_clinical_period, rng)); if (infectious_clinical_period < 0) { #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s distribution returned %i for infectious clinical period, using 0 instead", PDF_dist_type_name[local_data->infectious_clinical_period->type], infectious_clinical_period); #endif infectious_clinical_period = 0; } if (event->override_initial_state == InfectiousClinical) { day_in_disease_cycle = latent_period + infectious_subclinical_period; if (event->override_days_in_state > 0 && event->override_days_left_in_state > 0) { /* Override both the days elapsed and the days left in the infectious * clinical period. */ infectious_clinical_period = event->override_days_in_state + event->override_days_left_in_state; day_in_disease_cycle += event->override_days_in_state; } else if (event->override_days_in_state > 0) { /* Override just the days elapsed in the infectious clinical period. * If the given value is greater than the sampled length of the * infectious clinical period, extend the infectious clinical period. */ infectious_clinical_period = MAX(infectious_clinical_period, event->override_days_in_state); day_in_disease_cycle += event->override_days_in_state; } else if (event->override_days_left_in_state > 0) { /* Override just the days left in the infectious clinical period. If * the given value is greater than the sampled length of the * infectious clinical period, extend the infectious clinical period. */ infectious_clinical_period = MAX(infectious_clinical_period, event->override_days_left_in_state); day_in_disease_cycle += (infectious_clinical_period - event->override_days_left_in_state); } } #if DEBUG g_debug ("infectiousness (with visible signs) will last %i days", infectious_clinical_period); #endif /* Natural immunity period. */ immunity_period = (int) round (PDF_random (local_data->immunity_period, rng)); if (immunity_period < 0) { #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s distribution returned %i for immunity period, using 0 instead", PDF_dist_type_name[local_data->immunity_period->type], immunity_period); #endif immunity_period = 0; } if (event->override_initial_state == NaturallyImmune) { day_in_disease_cycle = latent_period + infectious_subclinical_period + infectious_clinical_period; if (event->override_days_in_state > 0 && event->override_days_left_in_state > 0) { /* Override both the days elapsed and the days left in the immunity * period. */ immunity_period = event->override_days_in_state + event->override_days_left_in_state; day_in_disease_cycle += event->override_days_in_state; } else if (event->override_days_in_state > 0) { /* Override just the days elapsed in the immunity period. If the * given value is greater than the sampled length of the immunity * period, extend the immunity period. */ immunity_period = MAX(immunity_period, event->override_days_in_state); day_in_disease_cycle += event->override_days_in_state; } else if (event->override_days_left_in_state > 0) { /* Override just the days left in the immunity period. If the given * value is greater than the sampled length of the immunity period, * extend the immunity period. */ immunity_period = MAX(immunity_period, event->override_days_left_in_state); day_in_disease_cycle += (immunity_period - event->override_days_left_in_state); } } #if DEBUG g_debug ("natural immunity will last %i days", immunity_period); #endif HRD_infect (event->infected_herd, latent_period, infectious_subclinical_period, infectious_clinical_period, immunity_period, day_in_disease_cycle); end: #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- EXIT handle_infection_event (%s)", MODEL_NAME); #endif return; }
/** * Check whether herd 1 can infect herd 2 and if so, attempt to infect herd 2. * This function is used by both the naive search and the R-tree (spatial * index) search. */ void check_and_infect (struct ergadm_model_t_ *self, HRD_herd_list_t * herds, HRD_herd_t * herd1, HRD_herd_t * herd2, EVT_new_day_event_t * event, RAN_gen_t * rng, EVT_event_queue_t * queue) { local_data_t *local_data; gboolean herd2_can_be_target; param_block_t *param_block; double max_spread, distance, heading; double distance_factor, herd1_size_factor, herd2_size_factor; EVT_event_t *attempt_to_infect; double r, P; int delay; int delay_index; GQueue *q; HRD_expose_t exposure_update; #if DEBUG GString *s; #endif #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- ENTER check_and_infect (%s)", MODEL_NAME); #endif /* Are herd 1 and herd 2 the same? */ if (herd1 == herd2) goto end; local_data = (local_data_t *) (self->model_data); /* Can herd 2 be the target of an exposure? */ #if DEBUG s = g_string_new (NULL); g_string_sprintf (s, "unit \"%s\" is %s, state is %s: ", herd2->official_id, herd2->production_type_name, HRD_status_name[herd2->status]); #endif param_block = local_data->param_block[herd1->production_type][herd2->production_type]; herd2_can_be_target = (param_block != NULL && herd2->status != Destroyed); #if DEBUG g_string_sprintfa (s, "%s be target", herd2_can_be_target ? "can" : "cannot"); g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s", s->str); g_string_free (s, TRUE); #endif if (!herd2_can_be_target) goto end; /* Is herd 2 close enough to herd 1? */ distance = GIS_local_distance (herd1->lat, herd1->lon, herd2->lat, herd2->lon); max_spread = param_block->max_spread; if (distance - max_spread > EPSILON) { #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, " unit \"%s\" too far (%g > %g)", herd2->official_id, distance, max_spread); #endif goto end; } #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, " unit \"%s\" within range (%g <= %g)", herd2->official_id, distance, max_spread); #endif /* Is herd 2 within the wind direction range? */ heading = GIS_local_heading (herd1->lat, herd1->lon, herd2->lat, herd2->lon); if (param_block->wind_range_crosses_0 ? (param_block->wind_dir_start - heading > EPSILON && heading - param_block->wind_dir_end >= EPSILON) : (param_block->wind_dir_start - heading > EPSILON || heading - param_block->wind_dir_end >= EPSILON)) { #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, " unit \"%s\" outside wind angles (%g)", herd2->official_id, heading); #endif goto end; } #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, " unit \"%s\" within wind angles (%g)", herd2->official_id, heading); #endif distance_factor = (max_spread - distance) / (max_spread - 1); herd1_size_factor = local_data->herd_size_factor[herd1->index]; herd2_size_factor = local_data->herd_size_factor[herd2->index]; #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, " P = %g * %g * %g * %g * %g", herd1_size_factor, herd1->prevalence, distance_factor, param_block->prob_spread_1km, herd2_size_factor); #endif P = herd1_size_factor * herd1->prevalence * distance_factor * param_block->prob_spread_1km * herd2_size_factor; r = RAN_num (rng); if (r < P && herd2->status == Susceptible) { if (NULL != guilib_record_exposure) { exposure_update.dest_index = herd2->index; exposure_update.dest_status = herd2->status; exposure_update.src_index = herd1->index; exposure_update.src_status = herd1->status; exposure_update.exposure_method = "A"; exposure_update.success = -1; guilib_record_exposure (exposure_update); } attempt_to_infect = EVT_new_attempt_to_infect_event (herd1, herd2, event->day, "airborne spread"); delay = (int) round (PDF_random (param_block->delay, rng)); if (delay <= 0) { EVT_event_enqueue (queue, attempt_to_infect); #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, " r (%g) < P (%g), target herd infected", r, P); #endif } else { attempt_to_infect->u.attempt_to_infect.day = event->day + delay; if (delay > local_data->pending_infections->len) ergadm_extend_rotating_array (local_data->pending_infections, delay, local_data->rotating_index); delay_index = (local_data->rotating_index + delay) % local_data->pending_infections->len; q = (GQueue *) g_ptr_array_index (local_data->pending_infections, delay_index); g_queue_push_tail (q, attempt_to_infect); local_data->npending_infections++; #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, " r (%g) < P (%g), target unit will be infected on day %i", r, P, event->day + delay); #endif } } else { if (NULL != guilib_record_exposure) { exposure_update.dest_index = herd2->index; exposure_update.dest_status = herd2->status; exposure_update.src_index = herd1->index; exposure_update.src_status = herd1->status; exposure_update.exposure_method = "A"; exposure_update.success = 0; guilib_record_exposure (exposure_update); } #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, " r (%g) >= P (%g), target unit not infected", r, P); #endif ; } end: #if DEBUG g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- EXIT check_and_infect (%s)", MODEL_NAME); #endif return; }