/**
 * Responds to a trace result by ordering quarantine.
 *
 * @param self the model.
 * @param units the list of units.
 * @param event a trace result event.
 */
void
handle_trace_result_event (struct adsm_module_t_ *self, UNT_unit_list_t * units,
                           EVT_trace_result_event_t * event,
                           EVT_event_queue_t * queue)
{
  local_data_t *local_data;
  UNT_unit_t *unit;

#if DEBUG
  g_debug ("----- ENTER handle_trace_result_event (%s)", MODEL_NAME);
#endif

  local_data = (local_data_t *) (self->model_data);

  if (event->traced)
    {
      if (event->direction == ADSM_TraceForwardOrOut)
        unit = event->exposed_unit;
      else
        unit = event->exposing_unit;

      #if DEBUG
        g_debug ("requesting quarantine of unit \"%s\"", unit->official_id);
      #endif

      UNT_quarantine (unit);
      EVT_event_enqueue (queue, EVT_new_quarantine_event (unit, event->day));
    }

#if DEBUG
  g_debug ("----- EXIT handle_trace_result_event (%s)", MODEL_NAME);
#endif
  return;
}
/**
 * Responds to a trace result by ordering a zone focus to be established.
 *
 * @param self the model.
 * @param event a trace result event.
 * @param queue for any new events the model creates.
 */
void
handle_trace_result_event (struct naadsm_model_t_ *self,
                           EVT_trace_result_event_t * event, EVT_event_queue_t * queue)
{
  local_data_t *local_data;
  HRD_herd_t *herd;

#if DEBUG
  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- ENTER trace_result_event (%s)", MODEL_NAME);
#endif

  local_data = (local_data_t *) (self->model_data);
  herd = event->exposed_herd;

  /* Check whether the herd is a production type we're interested in. */
  if (local_data->production_type[herd->production_type] == FALSE)
    goto end;

  /* Check whether the trace is for a contact type we're interested in. */
  if (event->contact_type != local_data->contact_type)
    goto end;

#if DEBUG
  g_debug ("ordering a zone focus around unit \"%s\"", herd->official_id);
#endif
  EVT_event_enqueue (queue, EVT_new_request_for_zone_focus_event (herd, event->day, "trace out"));

end:
#if DEBUG
  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- EXIT handle_trace_result_event (%s)", MODEL_NAME);
#endif
  return;
}
Example #3
0
/**
 * Responds to a detection by requesting traces.
 *
 * @param self the model.
 * @param herds the list of herds.
 * @param event a detection event.
 * @param rng a random number generator.
 * @param queue for any new events the model creates.
 */
void
handle_detection_event (struct naadsm_model_t_ *self, HRD_herd_list_t * herds,
                        EVT_detection_event_t * event, RAN_gen_t * rng, EVT_event_queue_t * queue)
{
  local_data_t *local_data;
  HRD_herd_t *herd;

#if DEBUG
  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- ENTER handle_detection_event (%s)", MODEL_NAME);
#endif

  local_data = (local_data_t *) (self->model_data);
  herd = event->herd;
  if (local_data->production_type[herd->production_type] == TRUE)
    {
#if DEBUG
      g_debug ("unit \"%s\" request to %s %ss", 
               herd->official_id,
               NAADSM_trace_direction_name[local_data->direction],
               NAADSM_contact_type_name[local_data->contact_type]);
#endif
      EVT_event_enqueue (queue,
                         EVT_new_attempt_to_trace_event (herd,
                                                         event->day,
                                                         local_data->contact_type,
                                                         local_data->direction,
                                                         local_data->trace_period));
    }

#if DEBUG
  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- EXIT handle_detection_event (%s)", MODEL_NAME);
#endif
}
/**
 * Before any simulations, this module announces the output variables it is
 * recording.
 *
 * @param self this module.
 * @param queue for any new events this function creates.
 */
void
handle_before_any_simulations_event (struct naadsm_model_t_ *self,
                                     EVT_event_queue_t *queue)
{
  unsigned int n, i;
  RPT_reporting_t *output;
  GPtrArray *outputs = NULL;

  n = self->outputs->len;
  for (i = 0; i < n; i++)
    {
      output = (RPT_reporting_t *) g_ptr_array_index (self->outputs, i);
      if (output->frequency != RPT_never)
        {
          if (outputs == NULL)
            outputs = g_ptr_array_new();
          g_ptr_array_add (outputs, output);
        }
    }

  if (outputs != NULL)
    EVT_event_enqueue (queue, EVT_new_declaration_of_outputs_event (outputs));
  /* We don't free the pointer array, that will be done when the event is freed
   * after all interested modules have processed it. */

  return;
}
/**
 * Responds to a detection by ordering destruction actions.
 *
 * @param self the model.
 * @param herds the list of herds.
 * @param event a report event.
 * @param queue for any new events the model creates.
 */
void
handle_detection_event (struct naadsm_model_t_ *self, HRD_herd_list_t * herds,
                        EVT_detection_event_t * event, EVT_event_queue_t * queue)
{
  local_data_t *local_data;
  HRD_herd_t *herd;

#if DEBUG
  g_debug ("----- ENTER handle_detection_event (%s)", MODEL_NAME);
#endif

  local_data = (local_data_t *) (self->model_data);
  herd = event->herd;

  /* Check whether the herd is a production type we're interested in, and that
   * it is not already destroyed.  We can "detect" a destroyed herd because of
   * test result delays -- if a test comes back positive and the herd has been
   * pre-emptively destroyed in the meantime, that is still a "detection".
   *
   * In the experimental version 'Riverton', "naturally immune" units have
   * died out and no longer exist, so they don't need to be destroyed. */
  if (
      local_data->production_type[herd->production_type] == TRUE
      && herd->status != Destroyed
      #ifdef RIVERTON
      && herd->status != NaturallyImmune
      #endif
  )
    {
#if DEBUG
      g_debug ("ordering unit \"%s\" destroyed", event->herd->official_id);
#endif
      EVT_event_enqueue (queue,
                         EVT_new_request_for_destruction_event (event->herd,
                                                                event->day,
                                                                "Det",
                                                                local_data->priority));
    }

#if DEBUG
  g_debug ("----- EXIT handle_detection_event (%s)", MODEL_NAME);
#endif
  return;
}
/**
 * Before any simulations, this module declares all the reasons for which it
 * may request a destruction.
 *
 * @param queue for any new events the model creates.
 */
void
handle_before_any_simulations_event (EVT_event_queue_t * queue)
{
  GPtrArray *reasons;

#if DEBUG
  g_debug ("----- ENTER handle_before_any_simulations_event (%s)", MODEL_NAME);
#endif

  reasons = g_ptr_array_sized_new (1);
  g_ptr_array_add (reasons, "Det");
  EVT_event_enqueue (queue, EVT_new_declaration_of_destruction_reasons_event (reasons));

  /* Note that we don't clean up the GPtrArray.  It will be freed along with
   * the declaration event after all interested sub-models have processed the
   * event. */

#if DEBUG
  g_debug ("----- EXIT handle_before_any_simulations_event (%s)", MODEL_NAME);
#endif
  return;
}
Example #7
0
/**
 * Responds to a request for infection causes by declaring all the causes which
 * this model may state for an infection.
 *
 * @param self the model.
 * @param queue for any new events the model creates.
 */
void
handle_request_for_infection_causes_event (struct ergadm_model_t_ *self, EVT_event_queue_t * queue)
{
  GPtrArray *causes;

#if DEBUG
  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
         "----- ENTER handle_request_for_infection_causes_event (%s)", MODEL_NAME);
#endif

  causes = g_ptr_array_sized_new (1);
  g_ptr_array_add (causes, "airborne spread");
  EVT_event_enqueue (queue, EVT_new_declaration_of_infection_causes_event (causes));

  /* Note that we don't clean up the GPtrArray.  It will be freed along with
   * the declaration event after all interested sub-models have processed the
   * event. */

#if DEBUG
  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
         "----- EXIT handle_request_for_infection_causes_event (%s)", MODEL_NAME);
#endif
  return;
}
Example #8
0
/**
 * Responds to a new day event by releasing any pending infections and
 * stochastically generating infections.
 *
 * @param self the model.
 * @param herds a list of herds.
 * @param event a new day event.
 * @param rng a random number generator.
 * @param queue for any new events the model creates.
 */
void
handle_new_day_event (struct ergadm_model_t_ *self, HRD_herd_list_t * herds,
                      EVT_new_day_event_t * event, RAN_gen_t * rng, EVT_event_queue_t * queue)
{
  local_data_t *local_data;
  HRD_herd_t *herd1;
  unsigned int nherds;          /* number of herds */
  unsigned int herd1_index, herd2_index;
  gboolean herd1_can_be_source;
  double distance;
  GQueue *q;
  EVT_event_t *pending_event;
  struct Rect search_rect;      /* for narrowing down radius searches using the
                                   R-tree (spatial index) */
  double mult;                  /* to account for latitude */
  callback_t callback_data;
#if DEBUG
  GString *s;
#endif

#if DEBUG
  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- ENTER handle_new_day_event (%s)", MODEL_NAME);
#endif

  local_data = (local_data_t *) (self->model_data);

  /* Release any pending (due to airborne transport delays) events. */
  local_data->rotating_index =
    (local_data->rotating_index + 1) % local_data->pending_infections->len;
  q = (GQueue *) g_ptr_array_index (local_data->pending_infections, local_data->rotating_index);
  while (!g_queue_is_empty (q))
    {
      /* Remove the event from this model's internal queue and place it in the
       * simulation's event queue. */
      pending_event = (EVT_event_t *) g_queue_pop_head (q);
      EVT_event_enqueue (queue, pending_event);
      local_data->npending_infections--;
    }

  if (
#if defined(USE_RTREE) && USE_RTREE == 1
       /* For debugging purposes, you can #define USE_RTREE to 0 to never use
        * the spatial index, or 1 to always use it. */
       TRUE ||
#endif
       local_data->use_rtree_index)
    {
      /* Initialize a data structure used by the callback function. */
      callback_data.self = self;
      callback_data.herds = herds;
      callback_data.event = event;
      callback_data.rng = rng;
      callback_data.queue = queue;
    }

  nherds = HRD_herd_list_length (herds);
  for (herd1_index = 0; herd1_index < nherds; herd1_index++)
    {
      herd1 = HRD_herd_list_get (herds, herd1_index);

      /* Can this herd be the source of an exposure? */
#if DEBUG
      s = g_string_new (NULL);
      g_string_sprintf (s, "unit \"%s\" is %s, state is %s: ",
                        herd1->official_id, herd1->production_type_name,
                        HRD_status_name[herd1->status]);
#endif
      herd1_can_be_source =
        local_data->param_block[herd1->production_type] != NULL
        && (herd1->status == InfectiousSubclinical || herd1->status == InfectiousClinical);
#if DEBUG
      g_string_sprintfa (s, "%s be source", herd1_can_be_source ? "can" : "cannot");
      g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s", s->str);
      g_string_free (s, TRUE);
#endif
      if (!herd1_can_be_source)
        continue;

      if (local_data->use_rtree_index[herd1->production_type])
        {
          distance = local_data->max_spread[herd1->production_type] / GIS_DEGREE_DISTANCE;
          mult = 1.0 / MIN (cos (DEG2RAD * (herd1->lat + distance)), cos(DEG2RAD * (herd1->lat - distance))); 
          search_rect.boundary[0] = herd1->lon - (distance * mult) - EPSILON;
          search_rect.boundary[1] = herd1->lat - distance - EPSILON;
          search_rect.boundary[2] = herd1->lon + (distance * mult) + EPSILON;
          search_rect.boundary[3] = herd1->lat + distance + EPSILON;
          callback_data.herd1 = herd1;
          RTreeSearch (herds->spatial_index, &search_rect, callback, &callback_data);
        }
      else
        for (herd2_index = 0; herd2_index < nherds; herd2_index++)
          check_and_infect (self, herds, herd1,
                            HRD_herd_list_get (herds, herd2_index), event, rng, queue);
    }

#if DEBUG
  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "----- EXIT handle_new_day_event (%s)", MODEL_NAME);
#endif

  return;
}
Example #9
0
/**
 * 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;
}