Ejemplo n.º 1
0
/*
 * Reschedule a volume output item, if necessary.
 */
static int reschedule_volume_output_item(struct volume *wrld,
                                         struct volume_output_item *vo) {
  /* Find the next time */
  if (vo->timer_type == OUTPUT_BY_STEP)
    vo->t += (vo->step_time / wrld->time_unit);
  else {
    double time_scale = 0.0;

    /* Check if we're done */
    if (vo->next_time == vo->times + vo->num_times) {
      free(vo->filename_prefix);
      free(vo->molecules);
      free(vo->times);
      free(vo);
      return 0;
    }

    /* Compute the next time and advance the next_time ptr */
    if (vo->timer_type == OUTPUT_BY_ITERATION_LIST)
      time_scale = 1.0;
    else
      time_scale = 1.0 / wrld->time_unit;
    vo->t = (*vo->next_time++) * time_scale;
  }

  switch (wrld->notify->volume_output_report) {
  case NOTIFY_NONE:
  case NOTIFY_BRIEF:
    break;

  case NOTIFY_FULL:
    mcell_log("  Next output scheduled for time %.15g.",
              vo->t * wrld->time_unit);
    break;

  default:
    UNHANDLED_CASE(wrld->notify->volume_output_report);
  }

  /* Add to the schedule */
  if (schedule_add(wrld->volume_output_scheduler, vo))
    mcell_allocfailed("Failed to add volume output request to scheduler.");

  return 0;
}
Ejemplo n.º 2
0
/*
 * Output a block of volume data as requested by the 'vo' object.
 */
int update_volume_output(struct volume *wrld, struct volume_output_item *vo) {
  int failure = 0;
  char *filename;

  switch (wrld->notify->volume_output_report) {
  case NOTIFY_NONE:
    break;

  case NOTIFY_BRIEF:
  case NOTIFY_FULL:
    mcell_log("Updating volume output '%s' scheduled at time %.15g on "
              "iteration %lld.",
              vo->filename_prefix, vo->t, wrld->current_iterations);
    break;

  default:
    UNHANDLED_CASE(wrld->notify->volume_output_report);
  }

  /* build the filename */
  filename = CHECKED_SPRINTF("%s.%lld.dat", vo->filename_prefix, wrld->current_iterations);

  /* Try to make the directory if it doesn't exist */
  if (make_parent_dir(filename)) {
    free(filename);
    return 1;
  }

  /* Output the volume item */
  failure = output_volume_output_item(wrld, filename, vo);
  free(filename);

  /* Reschedule this volume item, if appropriate */
  if (!failure)
    failure = reschedule_volume_output_item(wrld, vo);

  /* Should we return failure if we can't create the file?  Doing so will bring
   * down the entire sim...
   */
  return failure;
}
Ejemplo n.º 3
0
/************************************************************************
 *
 * function for printing a string
 *
 * XXX: This is a temporary hack to be able to print in mcell.c
 *      since mcell disables regular printf
 *
 ************************************************************************/
void mcell_print(const char *message) { mcell_log("%s", message); }
Ejemplo n.º 4
0
/**************************************************************************
write_reaction_output:
  In: the output_set we want to write to disk
      the flag that signals an end to the scheduled reaction outputs
  Out: 0 on success, 1 on failure.
       The reaction output buffer is flushed and written to disk.
       Indices are not reset; that's the job of the calling function.
**************************************************************************/
int write_reaction_output(struct volume *world, struct output_set *set) {

  FILE *fp;
  struct output_column *column;
  char *mode;
  u_int n_output;
  u_int i;

  switch (set->file_flags) {
  case FILE_OVERWRITE:
  case FILE_CREATE:
    if (set->chunk_count == 0)
      mode = "w";
    else
      mode = "a";
    break;
  case FILE_SUBSTITUTE:
    if (world->chkpt_seq_num == 1 && set->chunk_count == 0)
      mode = "w";
    else
      mode = "a";
    break;
  case FILE_APPEND:
  case FILE_APPEND_HEADER:
    mode = "a";
    break;
  default:
    mcell_internal_error(
        "Bad file output code %d for reaction data output file '%s'.",
        set->file_flags, set->outfile_name);
  }

  fp = open_file(set->outfile_name, mode);
  if (fp == NULL)
    return 1;

  /*int idx = set->block->buf_index;*/
  if (set->column_head->buffer[0].data_type != COUNT_TRIG_STRUCT) {
    n_output = set->block->buffersize;
    if (set->block->buf_index < set->block->buffersize)
      n_output = set->block->buf_index;

    if (world->notify->file_writes == NOTIFY_FULL)
      mcell_log("Writing %d lines to output file %s.", n_output,
                set->outfile_name);

    /* Write headers */
    if (set->chunk_count == 0 && set->header_comment != NULL &&
        set->file_flags != FILE_APPEND &&
        (world->chkpt_seq_num == 1 || set->file_flags == FILE_APPEND_HEADER ||
         set->file_flags == FILE_CREATE || set->file_flags == FILE_OVERWRITE)) {
      if (set->block->timer_type == OUTPUT_BY_ITERATION_LIST)
        fprintf(fp, "%sIteration_#", set->header_comment);
      else
        fprintf(fp, "%sSeconds", set->header_comment);

      for (column = set->column_head; column != NULL; column = column->next) {
        if (column->expr->title == NULL)
          fprintf(fp, " untitled");
        else
          fprintf(fp, " %s", column->expr->title);
      }
      fprintf(fp, "\n");
    }

    /* Write data */
    for (i = 0; i < n_output; i++) {
      fprintf(fp, "%.15g", set->block->time_array[i]);

      for (column = set->column_head; column != NULL; column = column->next) {
        switch (column->buffer[i].data_type) {
        case COUNT_INT:
          fprintf(fp, " %d", (column->buffer[i].val.ival));
          break;

        case COUNT_DBL:
          fprintf(fp, " %.9g", (column->buffer[i].val.dval));
          break;

        case COUNT_UNSET:
          fprintf(fp, " X");
          break;

        case COUNT_TRIG_STRUCT:
        default:
          if (column->expr->title != NULL)
            mcell_warn(
                "Unexpected data type in column titled '%s' -- skipping.",
                column->expr->title);
          else
            mcell_warn("Unexpected data type in untitled column -- skipping.");
          break;
        }
      }
      fprintf(fp, "\n");
    }
  } else /* Write accumulated trigger data */
  {
    struct output_trigger_data *trig;
    char event_time_string[1024]; /* Wouldn't run out of space even if we
                                     printed out DBL_MAX in non-exponential
                                     notation! */

    n_output = (u_int)set->column_head->initial_value;
    for (i = 0; i < n_output; i++) {
      trig = set->column_head->buffer[i].val.tval;

      if (set->exact_time_flag)
        sprintf(event_time_string, "%.12g ", trig->event_time);
      else
        strcpy(event_time_string, "");

      if (trig->flags & TRIG_IS_RXN) /* Just need time, pos, name */
      {
        fprintf(fp, "%.15g %s%.9g %.9g %.9g %s\n",
                trig->t_iteration,
                event_time_string,
                trig->loc.x,
                trig->loc.y,
                trig->loc.z,
                (trig->name == NULL) ? "" : trig->name);
      } else if (trig->flags & TRIG_IS_HIT) /* Need orientation also */
      {
        fprintf(fp, "%.15g %s%.9g %.9g %.9g %d %s\n",
                trig->t_iteration,
                event_time_string,
                trig->loc.x,
                trig->loc.y,
                trig->loc.z,
                trig->orient,
                (trig->name == NULL) ? "" : trig->name);
      } else /* Molecule count -- need both number and orientation */
      {
        fprintf(fp, "%.15g %s%.9g %.9g %.9g %d %d %s %lu\n",
                trig->t_iteration,
                event_time_string,
                trig->loc.x,
                trig->loc.y,
                trig->loc.z,
                trig->orient,
                trig->how_many,
                (trig->name == NULL) ? "" : trig->name,
                trig->id);
      }
    }
  }

  set->chunk_count++;

  fclose(fp);
  return 0;
}
Ejemplo n.º 5
0
/**************************************************************************
update_reaction_output:
  In: the output_block we want to update
  Out: 0 on success, 1 on failure.
       The counters in this block are updated, and the block is
       rescheduled for the next output time.  The counters are saved
       to an internal buffer, and written out when full.
**************************************************************************/
int update_reaction_output(struct volume *world, struct output_block *block) {
  int report_as_non_trigger = 1;
  int i = block->buf_index;
  if (block->data_set_head != NULL &&
      block->data_set_head->column_head != NULL &&
      block->data_set_head->column_head->buffer[i].data_type == COUNT_TRIG_STRUCT)
    report_as_non_trigger = 0;

  if (report_as_non_trigger) {
    switch (world->notify->reaction_output_report) {
    case NOTIFY_NONE:
      break;

    case NOTIFY_BRIEF:
      mcell_log(
          "Updating reaction output scheduled at time %.15g on iteration %lld.",
          block->t, world->current_iterations);
      break;

    case NOTIFY_FULL:
      mcell_log("Updating reaction output scheduled at time %.15g on iteration"
                " %lld.\n  Buffer fill level is at %u/%u.",
                block->t, world->current_iterations, block->buf_index,
                block->buffersize);
      break;

    default:
      UNHANDLED_CASE(world->notify->reaction_output_report);
    }
  }

  /* update all counters */

  block->t /= (1. + EPS_C);
  if (world->chkpt_seq_num == 1) {
    if (block->timer_type == OUTPUT_BY_ITERATION_LIST)
      block->time_array[i] = block->t;
    else
      block->time_array[i] = block->t * world->time_unit;
  } else {
    if (block->timer_type == OUTPUT_BY_ITERATION_LIST) {
      block->time_array[i] = block->t;
    } else if (block->timer_type == OUTPUT_BY_TIME_LIST) {
      if (block->time_now == NULL) {
        return 0;
      } else {
        block->time_array[i] = block->time_now->value;
      }
    } else {
      /* OUTPUT_BY_STEP */
      block->time_array[i] = convert_iterations_to_seconds(
          world->start_iterations, world->time_unit,
          world->simulation_start_seconds, block->t);
    }
  }

  struct output_set *set;
  struct output_column *column;
  // Each file
  for (set = block->data_set_head; set != NULL; set = set->next) 
  {
    if (report_as_non_trigger) {
      if (world->notify->reaction_output_report == NOTIFY_FULL)
        mcell_log("  Processing reaction output file '%s'.", set->outfile_name);
    }
    // Each column
    for (column = set->column_head; column != NULL; column = column->next) 
    {
      if (column->buffer[i].data_type != COUNT_TRIG_STRUCT) {
        eval_oexpr_tree(column->expr, 1);
        switch (column->buffer[i].data_type) {
        case COUNT_INT:
          column->buffer[i].val.ival = (int)column->expr->value;
          break;

        case COUNT_DBL:
          column->buffer[i].val.dval = (double)column->expr->value;
          break;

        case COUNT_UNSET:
          column->buffer[i].val.cval = 'X';
          break;

        case COUNT_TRIG_STRUCT:
        default:
          UNHANDLED_CASE(column->buffer[i].data_type);
        }
      }
    }
  }
  block->buf_index++;

  int final_chunk_flag = 0; // flag signaling an end to the scheduled
                            // reaction outputs. Takes values {0,1}.
                            // 0 - end not reached yet,
                            // 1 - end reached.
  /* Pick time of next output, if any */
  if (block->timer_type == OUTPUT_BY_STEP)
    block->t += block->step_time / world->time_unit;
  else if (block->time_now != NULL) {
    block->time_now = block->time_now->next;
    if (block->time_now == NULL)
      final_chunk_flag = 1;
    else {
      if (block->timer_type == OUTPUT_BY_ITERATION_LIST)
        block->t = block->time_now->value;
      else {
        /* OUTPUT_BY_TIME_LIST */
        if (world->chkpt_seq_num == 1) {
          block->t = block->time_now->value / world->time_unit;
        } else {
          block->t = world->start_iterations +
                     (block->time_now->value - world->simulation_start_seconds) /
                         world->time_unit;
        }
      }
    }
  } else
    final_chunk_flag = 1;

  /* Schedule next output event--even if we're at the end, since triggers may
   * not yet be written */
  double actual_t;
  if (final_chunk_flag == 1) {
    actual_t = block->t;
    block->t = FOREVER;
  } else
    actual_t = -1;
  block->t *= (1. + EPS_C);
  if (schedule_add(world->count_scheduler, block)) {
    mcell_allocfailed_nodie("Failed to add count to scheduler.");
    return 1;
  }

  if (distinguishable(actual_t, -1, EPS_C))
    block->t = actual_t; /* Fix time for output */

  if (report_as_non_trigger &&
      world->notify->reaction_output_report == NOTIFY_FULL) {
    mcell_log("  Next output for this block scheduled at time %.15g.",
              block->t);
  }

  if (block->t >= world->iterations + 1)
    final_chunk_flag = 1;

  /* write data to outfile */
  if (block->buf_index == block->buffersize || final_chunk_flag) {
    for (set = block->data_set_head; set != NULL; set = set->next) {
      if (set->column_head->buffer[i].data_type == COUNT_TRIG_STRUCT)
        continue;
      if (write_reaction_output(world, set)) {
        mcell_error_nodie("Failed to write reaction output to file '%s'.",
                          set->outfile_name);
        return 1;
      }
    }
    block->buf_index = 0;
    no_printf("Done updating reaction output\n");
  }

  if (distinguishable(actual_t, -1, EPS_C))
    block->t = FOREVER; /* Back to infinity if we're done */

  return 0;
}