예제 #1
0
파일: react_cond.c 프로젝트: tgbugs/mcell
/*************************************************************************
test_many_bimolecular:
  In: an array of reactions we're testing
      scaling coefficients depending on how many timesteps we've moved
        at once (1.0 means one timestep) and/or missing interaction areas
      local probability factor for the corresponding reactions
      the number of elements in the array of reactions
      placeholder for the chosen pathway in the reaction (works as return
          value)
      a flag to indicate if
  Out: RX_NO_RX if no reaction occurs
       index in the reaction array corresponding to which reaction occurs
          if one does occur
  Note: If this reaction does not return RX_NO_RX, then we update
        counters appropriately assuming that the reaction does take place.
  Note: this uses only one call to get a random double, so you can't
        effectively sample events that happen less than 10^-9 of the
        time (for 32 bit random number).
  NOTE: This function was merged with test_many_bimolecular_all_neighbors.
        These two functions were almost identical, and the behavior of the
        "all_neighbors" version is preserved with a flag that can be passed in.
        For reactions between two surface molecules, set this flag to 1. For
        such reactions (local_prob_factor > 0)
*************************************************************************/
int test_many_bimolecular(struct rxn **rx, double *scaling,
                          double local_prob_factor, int n, int *chosen_pathway,
                          struct abstract_molecule **complexes,
                          int *complex_limits, struct rng_state *rng,
                          int all_neighbors_flag) {
  double rxp[2 * n]; /* array of cumulative rxn probabilities */
  struct rxn *my_rx;
  int i; /* index in the array of reactions - return value */
  int m, M;
  double p, f;
  int has_coop_rate = 0;
  int nmax;

  if (all_neighbors_flag && local_prob_factor <= 0)
    mcell_internal_error("Local probability factor = %g in the function "
                         "'test_many_bimolecular_all_neighbors().",
                         local_prob_factor);

  if (n == 1) {
    if (all_neighbors_flag)
      return test_bimolecular(rx[0], scaling[0], local_prob_factor,
                              complexes[0], NULL, rng);
    else
      return test_bimolecular(rx[0], 0, scaling[0], complexes[0], NULL, rng);
  }

  /* Note: lots of division here, if we're CPU-bound,could invert the
     definition of scaling_coefficients */
  if (rx[0]->rates)
    has_coop_rate = 1;
  if (all_neighbors_flag && local_prob_factor > 0) {
    rxp[0] = (rx[0]->max_fixed_p) * local_prob_factor / scaling[0];
  } else {
    rxp[0] = rx[0]->max_fixed_p / scaling[0];
  }
  for (i = 1; i < n; i++) {
    if (all_neighbors_flag && local_prob_factor > 0) {
      rxp[i] =
          rxp[i - 1] + (rx[i]->max_fixed_p) * local_prob_factor / scaling[i];
    } else {
      rxp[i] = rxp[i - 1] + rx[i]->max_fixed_p / scaling[i];
    }
    if (rx[i]->rates)
      has_coop_rate = 1;
  }
  if (has_coop_rate) {
    for (; i < 2 * n; ++i) {
      if (all_neighbors_flag && local_prob_factor > 0) {
        rxp[i] = rxp[i - 1] +
                 (rx[i - n]->min_noreaction_p - rx[i - n]->max_fixed_p) *
                     local_prob_factor / scaling[i];
      } else {
        rxp[i] =
            rxp[i - 1] +
            (rx[i - n]->min_noreaction_p - rx[i - n]->max_fixed_p) / scaling[i];
      }
    }
  }
  nmax = i;

  if (has_coop_rate) {
    p = rng_dbl(rng);

    /* Easy out - definitely no reaction */
    if (p > rxp[nmax - 1])
      return RX_NO_RX;

    /* Might we have missed any? */
    if (rxp[nmax - 1] > 1.0) {
      double deficit = 0.0;
      int cxNo = 0;
      for (i = n; i < 2 * n; ++i) {
        if (i - n >= complex_limits[cxNo])
          ++cxNo;

        for (int n_path = 0; n_path < rx[i]->n_pathways; ++n_path) {
          if (rx[i]->rates[n_path] == NULL)
            continue;

          deficit += macro_lookup_rate(rx[i]->rates[n_path], complexes[cxNo],
                                       scaling[i - n] * rx[i]->pb_factor);
        }
        rxp[n] -= deficit;
      }

      /* Ok, did we REALLY miss any? */
      if (rxp[nmax - 1] > 1.0) {
        f = rxp[nmax - 1] - 1.0; /* Number of failed reactions */
        for (i = 0; i < n; i++)  /* Distribute failures */
        {
          if (all_neighbors_flag && local_prob_factor > 0) {
            rx[i]->n_skipped += f * ((rx[i]->max_fixed_p) * local_prob_factor +
                                     rxp[n + i] - rxp[n + i - 1]) /
                                rxp[n - 1];
          } else {
            rx[i]->n_skipped +=
                f * (rx[i]->max_fixed_p + rxp[n + i] - rxp[n + i - 1]) /
                rxp[n - 1];
          }
        }

        p *= rxp[nmax - 1];
      }

      /* Was there any reaction? */
      if (p > rxp[nmax - 1])
        return RX_NO_RX;

      /* Pick the reaction that happens.  Note that the binary search is over
       * 2*n items, not n.  The first n are the fixed rate pathways of each of
       * the n reactions, and the next n are the cooperative pathways. */
      i = binary_search_double(rxp, p, nmax - 1, 1);
      if (i > 0)
        p = (p - rxp[i - 1]);

      /* If it was a varying rate... */
      if (i >= n) {
        i -= n;
        p = p * scaling[i];

        cxNo = 0;
        while (i >= complex_limits[cxNo])
          ++cxNo;

        for (int n_path = 0; n_path < rx[i]->n_pathways; ++n_path) {
          if (rx[i]->rates[n_path] == NULL)
            continue;

          double prob = macro_lookup_rate(rx[i]->rates[n_path], complexes[cxNo],
                                          scaling[i] * rx[i]->pb_factor);
          if (p > prob)
            p -= prob;
          else {
            *chosen_pathway = n_path;
            return i;
          }
        }

        return RX_NO_RX;
      }

      /* else it was a fixed rate... */
      else {
        p = p * scaling[i];

        /* Now pick the pathway within that reaction */
        my_rx = rx[i];
        M = my_rx->n_pathways - 1;

        if (all_neighbors_flag && local_prob_factor > 0)
          m = binary_search_double(my_rx->cum_probs, p, M, local_prob_factor);
        else
          m = binary_search_double(my_rx->cum_probs, p, M, 1);

        *chosen_pathway = m;

        return i;
      }
    }

    /* We didn't miss any reactions and also don't need to consult the varying
     * probabilities */
    else if (p <= rxp[n - 1]) {
      /* Pick the reaction that happens */
      i = binary_search_double(rxp, p, n - 1, 1);

      my_rx = rx[i];
      if (i > 0)
        p = (p - rxp[i - 1]);
      p = p * scaling[i];

      /* Now pick the pathway within that reaction */
      M = my_rx->n_pathways - 1;

      if (all_neighbors_flag && local_prob_factor > 0)
        m = binary_search_double(my_rx->cum_probs, p, M, local_prob_factor);
      else
        m = binary_search_double(my_rx->cum_probs, p, M, 1);

      *chosen_pathway = m;

      return i;
    }

    /* The hard way.  We're in the cooperativity region of probability space
     * and will need to examine the varying probabilities. */
    else {
      p -= rxp[n - 1];
      int cxNo = 0;
      for (i = n; i < 2 * n; ++i) {
        if (i - n >= complex_limits[cxNo])
          ++cxNo;

        for (int n_path = 0; n_path < rx[i]->n_pathways; ++n_path) {
          if (rx[i]->rates[n_path] == NULL)
            continue;

          double prob = macro_lookup_rate(rx[i]->rates[n_path], complexes[cxNo],
                                          scaling[i - n] * rx[i]->pb_factor);
          if (p > prob)
            p -= prob;
          else {
            *chosen_pathway = n_path;
            return i - n;
          }
        }
      }

      return RX_NO_RX;
    }

    mcell_internal_error("Should never reach this point in the code.");
    return RX_NO_RX;
  } else {
    if (rxp[n - 1] > 1.0) {
      f = rxp[n - 1] - 1.0;   /* Number of failed reactions */
      for (i = 0; i < n; i++) /* Distribute failures */
      {
        if (all_neighbors_flag && local_prob_factor > 0) {
          rx[i]->n_skipped += f * ((rx[i]->cum_probs[rx[i]->n_pathways - 1]) *
                                   local_prob_factor) /
                              rxp[n - 1];
        } else {
          rx[i]->n_skipped +=
              f * (rx[i]->cum_probs[rx[i]->n_pathways - 1]) / rxp[n - 1];
        }
      }
      p = rng_dbl(rng) * rxp[n - 1];
    } else {
      p = rng_dbl(rng);
      if (p > rxp[n - 1])
        return RX_NO_RX;
    }

    /* Pick the reaction that happens */
    i = binary_search_double(rxp, p, n - 1, 1);

    my_rx = rx[i];
    if (i > 0)
      p = (p - rxp[i - 1]);
    p = p * scaling[i];

    /* Now pick the pathway within that reaction */
    M = my_rx->n_pathways - 1;

    if (all_neighbors_flag && local_prob_factor > 0)
      m = binary_search_double(my_rx->cum_probs, p, M, local_prob_factor);
    else
      m = binary_search_double(my_rx->cum_probs, p, M, 1);

    *chosen_pathway = m;

    return i;
  }
}
예제 #2
0
파일: react_cond.c 프로젝트: tgbugs/mcell
/*************************************************************************
test_many_reactions_all_neighbors:
  In: an array of reactions we're testing
      an array of scaling coefficients depending on how many timesteps
      we've moved  at once (1.0 means one timestep) and/or missing
         interaction areas
      an array of local probability factors for the corresponding reactions
      the number of elements in the array of reactions
      placeholder for the chosen pathway in the reaction (works as return
          value)
  Out: RX_NO_RX if no reaction occurs
       index in the reaction array corresponding to which reaction occurs
          if one does occur
  Note: If this reaction does not return RX_NO_RX, then we update
        counters appropriately assuming that the reaction does take place.
  Note: this uses only one call to get a random double, so you can't
        effectively sample events that happen less than 10^-9 of the
        time (for 32 bit random number).
  NOTE: This function should be used for now only for the reactions
        between three surface molecules.
*************************************************************************/
int test_many_reactions_all_neighbors(struct rxn **rx, double *scaling,
                                      double *local_prob_factor, int n,
                                      int *chosen_pathway,
                                      struct rng_state *rng) {

  if (local_prob_factor == NULL)
    mcell_internal_error("There is no local probability factor information in "
                         "the function 'test_many_reactions_all_neighbors().");

  if (n == 1)
    return test_bimolecular(rx[0], scaling[0], local_prob_factor[0], NULL, NULL,
                            rng);

  double rxp[n]; /* array of cumulative rxn probabilities */
  if (local_prob_factor[0] > 0) {
    rxp[0] = (rx[0]->max_fixed_p) * local_prob_factor[0] / scaling[0];
  } else {
    rxp[0] = rx[0]->max_fixed_p / scaling[0];
  }

  // i: index in the array of reactions - return value
  for (int i = 1; i < n; i++) {
    if (local_prob_factor[i] > 0) {
      rxp[i] =
          rxp[i - 1] + (rx[i]->max_fixed_p) * local_prob_factor[i] / scaling[i];
    } else {
      rxp[i] = rxp[i - 1] + rx[i]->max_fixed_p / scaling[i];
    }
  }

  double p;
  if (rxp[n - 1] > 1.0) {
    double f = rxp[n - 1] - 1.0; /* Number of failed reactions */
    for (int i = 0; i < n; i++)  /* Distribute failures */
    {
      if (local_prob_factor[i] > 0) {
        rx[i]->n_skipped += f * ((rx[i]->cum_probs[rx[i]->n_pathways - 1]) *
                                 local_prob_factor[i]) /
                            rxp[n - 1];
      } else {
        rx[i]->n_skipped +=
            f * (rx[i]->cum_probs[rx[i]->n_pathways - 1]) / rxp[n - 1];
      }
    }
    p = rng_dbl(rng) * rxp[n - 1];
  } else {
    p = rng_dbl(rng);
    if (p > rxp[n - 1])
      return RX_NO_RX;
  }

  /* Pick the reaction that happens */
  int i = binary_search_double(rxp, p, n - 1, 1);

  struct rxn *my_rx = rx[i];

  double my_local_prob_factor = local_prob_factor[i];
  if (i > 0)
    p = (p - rxp[i - 1]);
  p = p * scaling[i];

  /* Now pick the pathway within that reaction */
  int M = my_rx->n_pathways - 1;
  if (my_local_prob_factor > 0) {
    *chosen_pathway =
        binary_search_double(my_rx->cum_probs, p, M, my_local_prob_factor);
  } else {
    *chosen_pathway = binary_search_double(my_rx->cum_probs, p, M, 1);
  }

  return i;
}
예제 #3
0
/*************************************************************************
test_many_bimolecular:
  In: an array of reactions we're testing
      scaling coefficients depending on how many timesteps we've moved
        at once (1.0 means one timestep) and/or missing interaction areas
      local probability factor for the corresponding reactions
      the number of elements in the array of reactions
      placeholder for the chosen pathway in the reaction (works as return
          value)
      a flag to indicate if
  Out: RX_NO_RX if no reaction occurs
       index in the reaction array corresponding to which reaction occurs
          if one does occur
  Note: If this reaction does not return RX_NO_RX, then we update
        counters appropriately assuming that the reaction does take place.
  Note: this uses only one call to get a random double, so you can't
        effectively sample events that happen less than 10^-9 of the
        time (for 32 bit random number).
  NOTE: This function was merged with test_many_bimolecular_all_neighbors.
        These two functions were almost identical, and the behavior of the
        "all_neighbors" version is preserved with a flag that can be passed in.
        For reactions between two surface molecules, set this flag to 1. For
        such reactions local_prob_factor > 0.
*************************************************************************/
int test_many_bimolecular(struct rxn **rx, double *scaling,
                          double local_prob_factor, int n, int *chosen_pathway,
                          struct rng_state *rng,
                          int all_neighbors_flag) {
  double rxp[2 * n]; /* array of cumulative rxn probabilities */
  struct rxn *my_rx;
  int i; /* index in the array of reactions - return value */
  int m, M;
  double p, f;

  if (all_neighbors_flag && local_prob_factor <= 0)
    mcell_internal_error("Local probability factor = %g in the function "
                         "'test_many_bimolecular_all_neighbors().",
                         local_prob_factor);

  if (n == 1) {
    if (all_neighbors_flag)
      return test_bimolecular(rx[0], scaling[0], local_prob_factor, NULL, NULL, rng);
    else
      return test_bimolecular(rx[0], 0, scaling[0], NULL, NULL, rng);
  }

  /* Note: lots of division here, if we're CPU-bound,could invert the
     definition of scaling_coefficients */
  if (all_neighbors_flag && local_prob_factor > 0) {
    rxp[0] = (rx[0]->max_fixed_p) * local_prob_factor / scaling[0];
  } else {
    rxp[0] = rx[0]->max_fixed_p / scaling[0];
  }
  for (i = 1; i < n; i++) {
    if (all_neighbors_flag && local_prob_factor > 0) {
      rxp[i] =
          rxp[i - 1] + (rx[i]->max_fixed_p) * local_prob_factor / scaling[i];
    } else {
      rxp[i] = rxp[i - 1] + rx[i]->max_fixed_p / scaling[i];
    }
  }

  if (rxp[n - 1] > 1.0) {
    f = rxp[n - 1] - 1.0;   /* Number of failed reactions */
    for (i = 0; i < n; i++) /* Distribute failures */
    {
      if (all_neighbors_flag && local_prob_factor > 0) {
        rx[i]->n_skipped += f * ((rx[i]->cum_probs[rx[i]->n_pathways - 1]) *
                                 local_prob_factor) /
                            rxp[n - 1];
      } else {
        rx[i]->n_skipped +=
            f * (rx[i]->cum_probs[rx[i]->n_pathways - 1]) / rxp[n - 1];
      }
    }
    p = rng_dbl(rng) * rxp[n - 1];
  } else {
    p = rng_dbl(rng);
    if (p > rxp[n - 1])
      return RX_NO_RX;
  }

  /* Pick the reaction that happens */
  i = binary_search_double(rxp, p, n - 1, 1);

  my_rx = rx[i];
  if (i > 0)
    p = (p - rxp[i - 1]);
  p = p * scaling[i];

  /* Now pick the pathway within that reaction */
  M = my_rx->n_pathways - 1;

  if (all_neighbors_flag && local_prob_factor > 0)
    m = binary_search_double(my_rx->cum_probs, p, M, local_prob_factor);
  else
    m = binary_search_double(my_rx->cum_probs, p, M, 1);

  *chosen_pathway = m;

  return i;
}