Exemplo n.º 1
0
/**************************************************************************
 emergency_output_hook:
    This is an atexit hook to flush reaction output to disk in case an error is
    occurred.  Set emergency_output_hook_enabled to 0 to prevent it from being
    called (say, on successful exit).

  In: No arguments.
  Out: None.

**************************************************************************/
static void emergency_output_hook(void) {
  if (emergency_output_hook_enabled) {
    /* Disable the emergency output hook in case a signal is received while
     * producing emergency output. */
    emergency_output_hook_enabled = 0;

    int n_errors = emergency_output(global_state);
    if (n_errors == 0)
      mcell_warn("Reaction output was successfully flushed to disk.");
    else if (n_errors == 1)
      mcell_warn("An error occurred while flushing reaction output to disk.");
    else
      mcell_warn("%d errors occurred while flushing reaction output to disk.",
                 n_errors);
  }
}
Exemplo n.º 2
0
/**************************************************************************
 install_emergency_output_hooks:
    Installs all relevant hooks for catching invalid program termination and
    flushing output to disk, where possible.

  In: No arguments.
  Out: None.
**************************************************************************/
void install_emergency_output_hooks(struct volume *world) {
  global_state = world;

  if (atexit(&emergency_output_hook) != 0)
    mcell_warn("Failed to install emergency output hook.");

  install_emergency_output_signal_handler(
      SIGILL); /* not generated on Windows but can be raised manually */
  install_emergency_output_signal_handler(SIGABRT);
  install_emergency_output_signal_handler(SIGFPE);
  install_emergency_output_signal_handler(SIGSEGV);
#ifdef SIGBUS
  install_emergency_output_signal_handler(SIGBUS);
#endif
}
Exemplo n.º 3
0
/**************************************************************************
 install_emergency_output_signal_handler:
    This installs a handler for a single signal which will print out a sensible
    message, then try to flush as much output data to disk as possible before
    dying.

  In: No arguments.
  Out: None.
**************************************************************************/
static void install_emergency_output_signal_handler(int signo) {
#ifdef _WIN32 /* fixme: for Windows do a better job than just signal(), need   \
                 to find out what other things the *nix version is doing */
  signal(signo, &emergency_output_signal_handler);
#else
  struct sigaction sa, saPrev;
  sa.sa_sigaction = NULL;
  sa.sa_handler = &emergency_output_signal_handler;
  sa.sa_flags = SA_RESTART | SA_RESETHAND | SA_NODEFER;
  sigfillset(&sa.sa_mask);

  if (sigaction(signo, &sa, &saPrev) != 0)
    mcell_warn("Failed to install emergency output signal handler.");
#endif
}
Exemplo n.º 4
0
/*************************************************************************
trigger_trimolecular:
   In: hash values of the three colliding molecules
       pointers to the species of three colliding molecules
       (reacA is the moving molecule and reacB and reacC are the targets)
       orientations of the three molecules
       array of pointers to the possible reactions
   Out: number of possible reactions for species reacA, reacB, and reacC
        Also the first "number" slots in the "matching_rxns"
        array are filled with pointers to the possible reactions objects.
   Note: The target molecules are already scheduled and can be destroyed
         but not rescheduled.  Assume we have or will check separately that
         the moving molecule is not inert!
   PostNote1: If one of the targets is a surface_molecule - it is reacC,
              if two of the targets are surface molecules - they are
                    reacB and reacC.
*************************************************************************/
int trigger_trimolecular(struct rxn **reaction_hash, int rx_hashsize,
                         u_int hashA, u_int hashB, u_int hashC,
                         struct species *reacA, struct species *reacB,
                         struct species *reacC, int orientA, int orientB,
                         int orientC, struct rxn **matching_rxns) {
  u_int rawhash = 0;
  u_int hash = 0;            /* index in the reaction hash table */
  int num_matching_rxns = 0; /* number of matching reactions */
  short geomA = SHRT_MIN, geomB = SHRT_MIN, geomC = SHRT_MIN;
  struct rxn *inter;
  int correct_players_flag;
  int correct_orientation_flag;

  if (strcmp(reacA->sym->name, reacB->sym->name) < 0) {
    if (strcmp(reacB->sym->name, reacC->sym->name) < 0)
      rawhash = (hashA + hashB);
    else
      rawhash = (hashA + hashC);
  } else if (strcmp(reacA->sym->name, reacC->sym->name) < 0)
    rawhash = (hashB + hashA);
  else
    rawhash = (hashB + hashC);
  hash = rawhash & (rx_hashsize - 1);

  inter = reaction_hash[hash];

  while (inter != NULL) {
    if (inter->n_reactants == 3) /* Enough reactants?  */
    {
      correct_players_flag = 0;
      correct_orientation_flag = 0;

      /* Check that we have the right players */

      if (reacA == inter->players[0]) {
        if ((reacB == inter->players[1] && reacC == inter->players[2])) {
          geomA = inter->geometries[0];
          geomB = inter->geometries[1];
          geomC = inter->geometries[2];
          correct_players_flag = 1;
        } else if ((reacB == inter->players[2] && reacC == inter->players[1])) {
          geomA = inter->geometries[0];
          geomB = inter->geometries[2];
          geomC = inter->geometries[1];
          correct_players_flag = 1;
        }
      } else if (reacA == inter->players[1]) {
        if ((reacB == inter->players[0]) && (reacC == inter->players[2])) {
          geomA = inter->geometries[1];
          geomB = inter->geometries[0];
          geomC = inter->geometries[2];
          correct_players_flag = 1;
        } else if ((reacB == inter->players[2]) &&
                   (reacC == inter->players[0])) {
          geomA = inter->geometries[1];
          geomB = inter->geometries[2];
          geomC = inter->geometries[0];
          correct_players_flag = 1;
        }
      } else if (reacA == inter->players[2]) {
        if ((reacB == inter->players[0]) && (reacC == inter->players[1])) {
          geomA = inter->geometries[2];
          geomB = inter->geometries[0];
          geomC = inter->geometries[1];
          correct_players_flag = 1;
        } else if ((reacB == inter->players[1]) &&
                   (reacC == inter->players[0])) {
          geomA = inter->geometries[2];
          geomB = inter->geometries[1];
          geomC = inter->geometries[0];
          correct_players_flag = 1;
        }
      }

      /* Check to see if orientation classes are zero or different.
         In such case we do not care about relative orientations of the
         volume and surface reactants.
      */
      if ((geomA == 0) && (geomB == 0) && (geomC == 0)) {
        /* all volume molecules */
        correct_orientation_flag = 1;
      }
      /* two volume and one surface molecule */
      /* since geomA = geomB we will test only for geomA */
      else if (((reacA->flags & NOT_FREE) == 0) &&
               ((reacB->flags & NOT_FREE) == 0) &&
               ((reacC->flags & ON_GRID) != 0)) {
        /* different orientation classes */
        if ((geomA + geomC) * (geomA - geomC) != 0) {
          correct_orientation_flag = 1;
        }

        /* Same class, is the orientation correct? */
        else if (orientA != 0 && orientA * orientC * geomA * geomC > 0) {
          correct_orientation_flag = 1;
        }
      }
      /* (one volume molecule and two surface molecules) or
         (three surface molecules) */
      else {
        /* different orientation classes for all 3 reactants */
        if (((geomA + geomC) * (geomA - geomC) != 0) &&
            ((geomA + geomB) * (geomA - geomB) != 0) &&
            ((geomB + geomC) * (geomB - geomC))) {
          correct_orientation_flag = 1;
        }
        /*  two reactants in the zero orientation class */
        else if ((geomB == 0) && (geomC == 0) && (orientA != 0) &&
                 (geomA != 0)) {
          correct_orientation_flag = 1;
        } else if ((geomA == 0) && (geomC == 0) && (orientB != 0) &&
                   (geomB != 0)) {
          correct_orientation_flag = 1;
        } else if ((geomA == 0) && (geomB == 0) && (orientC != 0) &&
                   (geomC != 0)) {
          correct_orientation_flag = 1;
        }
        /* one reactant in the zero orientation class */
        else if (geomA == 0) {
          /* different orientation classes */
          if ((geomB + geomC) * (geomB - geomC) != 0) {
            correct_orientation_flag = 1;
          }

          /* Same class, is the orientation correct? */
          else if (orientB != 0 && orientB * orientC * geomB * geomC > 0) {
            correct_orientation_flag = 1;
          }
        } else if (geomB == 0) {
          /* different orientation classes */
          if ((geomA + geomC) * (geomA - geomC) != 0) {
            correct_orientation_flag = 1;
          }

          /* Same class, is the orientation correct? */
          else if (orientA != 0 && orientA * orientC * geomA * geomC > 0) {
            correct_orientation_flag = 1;
          }
        } else if (geomC == 0) {
          /* different orientation classes */
          if ((geomA + geomB) * (geomA - geomB) != 0) {
            correct_orientation_flag = 1;
          }

          /* Same class, is the orientation correct? */
          else if (orientA != 0 && orientA * orientB * geomA * geomB > 0) {
            correct_orientation_flag = 1;
          }
          /* two geometries are the same  */
        } else if (geomB == geomC) {

          /* different orientation classes */
          if (((geomA + geomB) * (geomA - geomB) != 0) &&
              (orientB == orientC)) {
            correct_orientation_flag = 1;
          }

          /* Same class, is the orientation correct? */
          else if ((orientA != 0 && orientA * orientB * geomA * geomB > 0) &&
                   (orientB == orientC)) {
            correct_orientation_flag = 1;
          }
        } else if (geomA == geomC) {
          /* different orientation classes */
          if (((geomA + geomB) * (geomA - geomB) != 0) &&
              (orientA == orientC)) {
            correct_orientation_flag = 1;
          }

          /* Same class, is the orientation correct? */
          else if ((orientA != 0 && orientA * orientB * geomA * geomB > 0) &&
                   (orientA == orientC)) {
            correct_orientation_flag = 1;
          }
        } else if (geomA == geomB) {
          /* different orientation classes */
          if (((geomA + geomC) * (geomA - geomC) != 0) &&
              (orientA == orientB)) {
            correct_orientation_flag = 1;
          }

          /* Same class, is the orientation correct? */
          else if ((orientA != 0 && orientA * orientC * geomA * geomC > 0) &&
                   (orientA == orientB)) {
            correct_orientation_flag = 1;
          }
          /* all three geometries are non-zero but the same */
        } else if ((geomA == geomB) && (geomA == geomC)) {
          if ((orientA == orientB) && (orientA == orientC)) {
            /* Same class, is the orientation correct? */
            if (orientA != 0 && orientA * orientC * geomA * geomC > 0 &&
                orientA * orientB * geomA * geomB > 0) {
              correct_orientation_flag = 1;
            }
          }
        }
      }

      if (correct_players_flag && correct_orientation_flag) {
        if (num_matching_rxns >= MAX_MATCHING_RXNS)
          break;
        matching_rxns[num_matching_rxns] = inter;
        num_matching_rxns++;
      }
    }
    inter = inter->next;
  }

  if (num_matching_rxns > MAX_MATCHING_RXNS) {
    mcell_warn("Number of matching reactions exceeds the maximum allowed "
               "number MAX_MATCHING_RXNS.");
  }

  return num_matching_rxns;
}
Exemplo n.º 5
0
/*************************************************************************
trigger_bimolecular:
   In: hash values of the two colliding molecules
       pointers to the two colliding molecules
       orientations of the two colliding molecules
         both zero away from a surface
         both nonzero (+-1) at a surface
       A is the moving molecule and B is the target
       array of pointers to the possible reactions
   Out: number of possible reactions for molecules reacA and reacB
        Also the first 'number' slots in the 'matching_rxns'
        array are filled with pointers to the possible reactions objects.
   Note: The target molecule is already scheduled and can be destroyed
         but not rescheduled.  Assume we have or will check separately that
         the moving molecule is not inert!
*************************************************************************/
int trigger_bimolecular(struct rxn **reaction_hash, int rx_hashsize,
                        u_int hashA, u_int hashB,
                        struct abstract_molecule *reacA,
                        struct abstract_molecule *reacB, short orientA,
                        short orientB, struct rxn **matching_rxns) {
  u_int hash;                /* index in the reaction hash table */
  int test_wall;             /* flag */
  int num_matching_rxns = 0; /* number of matching reactions */
  short geomA, geomB;
  struct rxn *inter;
  struct surf_class_list *scl, *scl2;
  int need_complex = 0;
  int right_walls_surf_classes; /* flag to check whether SURFACE_CLASSES
                                   of the walls for one or both reactants
                                   match the SURFACE_CLASS of the reaction
                                   (if needed) */

  hash = (hashA + hashB) & (rx_hashsize - 1);

  /* Check if either reactant belongs to a complex */
  if ((reacA->flags | reacB->flags) & COMPLEX_MEMBER) {
    need_complex = 1;

    /* If both reactants are subunits, this reaction cannot occur */
    if (((reacA->flags ^ reacB->flags) & COMPLEX_MEMBER) == 0)
      return 0;
  }

  for (inter = reaction_hash[hash]; inter != NULL; inter = inter->next) {
    right_walls_surf_classes = 0;

    /* Right number of reactants? */
    if (inter->n_reactants < 2)
      continue;
    else if (inter->n_reactants > 2 && !(inter->players[2]->flags & IS_SURFACE))
      continue;

    /* If it's a complex rxn, make sure one of the molecules is part of a
     * complex
     */
    if (inter->is_complex) {
      if (!need_complex)
        continue;
    } else {
      if (need_complex)
        continue;
    }

    /* Do we have the right players? */
    if (reacA->properties == reacB->properties) {
      if ((reacA->properties != inter->players[0] ||
           reacA->properties != inter->players[1]))
        continue;
    } else if ((reacA->properties == inter->players[0] &&
                reacB->properties == inter->players[1])) {
      if (inter->is_complex != NULL) {
        if (inter->is_complex[0] != ((reacA->flags & COMPLEX_MEMBER) ? 1 : 0))
          continue;
        /* Don't need to check other reactant -- we know we have the right
         * number of subunits
         */
      }
    } else if ((reacB->properties == inter->players[0] &&
                reacA->properties == inter->players[1])) {
      if (inter->is_complex != NULL) {
        if (inter->is_complex[0] != ((reacB->flags & COMPLEX_MEMBER) ? 1 : 0))
          continue;
        /* Don't need to check other reactant -- we know we have the right
         * number of subunits
         */
      }
    } else
      continue;

    test_wall = 0;
    geomA = inter->geometries[0];
    geomB = inter->geometries[1];

    /* Check to see if orientation classes are zero/different */
    if (geomA == 0 || geomB == 0 || (geomA + geomB) * (geomA - geomB) != 0) {
      if (inter->n_reactants == 2) {
        if (num_matching_rxns >= MAX_MATCHING_RXNS)
          break;
        matching_rxns[num_matching_rxns] = inter;
        num_matching_rxns++;
        continue;
      } else {
        test_wall = 1;
      }
    }

    /* Same class, is the orientation correct? */
    else if (orientA != 0 && orientA * orientB * geomA * geomB > 0) {
      if (inter->n_reactants == 2) {
        if (num_matching_rxns >= MAX_MATCHING_RXNS)
          break;
        matching_rxns[num_matching_rxns] = inter;
        num_matching_rxns++;
        continue;
      } else {
        test_wall = 1;
      }
    }

    /* See if we need to check a wall (fails if we're in free space) */
    if (test_wall && orientA != 0) {
      struct wall *w_A = NULL, *w_B = NULL;
      short geomW;
      /* short orientW = 1;  Walls always have orientation 1 */

      /* If we are oriented, one of us is a surface mol. */
      /* For volume molecule wall that matters is the target's wall */
      if (((reacA->properties->flags & NOT_FREE) == 0) &&
          (reacB->properties->flags & ON_GRID) != 0) {
        w_B = (((struct surface_molecule *)reacB)->grid)->surface;
      } else if (((reacA->properties->flags & ON_GRID) != 0) &&
                 (reacB->properties->flags & ON_GRID) != 0) {
        w_A = (((struct surface_molecule *)reacA)->grid)->surface;
        w_B = (((struct surface_molecule *)reacB)->grid)->surface;
      }

      /* If a wall was found, we keep going to check....
         This is a case for reaction between volume and surface molecules */
      if ((w_A == NULL) && (w_B != NULL)) {
        /* Right wall type--either this type or generic type? */
        for (scl = w_B->surf_class_head; scl != NULL; scl = scl->next) {
          if (inter->players[2] == scl->surf_class) {
            right_walls_surf_classes = 1;
            break;
          }
        }
      }

      /* if both reactants are surface molecules they should be on
         the walls with the same SURFACE_CLASS */
      if ((w_A != NULL) && (w_B != NULL)) {
        for (scl = w_A->surf_class_head; scl != NULL; scl = scl->next) {
          for (scl2 = w_B->surf_class_head; scl2 != NULL; scl2 = scl->next) {
            if (scl->surf_class == scl2->surf_class) {
              if (inter->players[2] == scl->surf_class) {
                right_walls_surf_classes = 1;
                break;
              }
            }
          }
        }
      }

      if (right_walls_surf_classes) {
        geomW = inter->geometries[2];

        if (geomW == 0) {
          if (num_matching_rxns >= MAX_MATCHING_RXNS)
            break;
          matching_rxns[num_matching_rxns] = inter;
          num_matching_rxns++;
          continue;
        }

        /* We now care whether A and B correspond to player [0] and [1] or */
        /* vice versa, so make sure A==[0] and B==[1] so W can */
        /* match with the right one! */
        if (reacA->properties != inter->players[0]) {
          short temp = geomB;
          geomB = geomA;
          geomA = temp;
        }

        if (geomA == 0 ||
            (geomA + geomW) * (geomA - geomW) != 0) /* W not in A's class */
        {
          if (geomB == 0 || (geomB + geomW) * (geomB - geomW) != 0) {
            if (num_matching_rxns >= MAX_MATCHING_RXNS)
              break;
            matching_rxns[num_matching_rxns] = inter;
            num_matching_rxns++;
            continue;
          }
          if (orientB * geomB * geomW > 0) {
            if (num_matching_rxns >= MAX_MATCHING_RXNS)
              break;
            matching_rxns[num_matching_rxns] = inter;
            num_matching_rxns++;
            continue;
          }
        } else /* W & A in same class */
        {
          if (orientA * geomA * geomW > 0) {
            if (num_matching_rxns >= MAX_MATCHING_RXNS)
              break;
            matching_rxns[num_matching_rxns] = inter;
            num_matching_rxns++;
            continue;
          }
        }
      } /* if (right_walls_surf_classes) ... */

    } /* end if (test_wall && orientA != NULL) */
  }   /* end for (inter = reaction_hash[hash]; ...) */

  if (num_matching_rxns > MAX_MATCHING_RXNS) {
    mcell_warn("Number of matching reactions exceeds the maximum allowed "
               "number MAX_MATCHING_RXNS.");
  }

  return num_matching_rxns;
}
Exemplo n.º 6
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;
}