/** * @file Gillespie.hh * * Gillespie simulator * * Copyright (c) 2016 - 2018, Peter Helfer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef GILLESPIE #define GILLESPIE #include <limits.h> #include <float.h> #include "Trace.hh" class Gillespie { public: /** * Constructor */ Gillespie( const char *gilFileName, void (*preIterFunc)(double time) = NULL); /** * Print molecule info */ void printMolecules(); /** * Print reaction info */ void printReactions(); double calcReactProbs(); /** * Run the Gillespie algorithm until (a) stopTime is reached, or (b) no * more reactions are possible, or (c) the count of a specified molecule * passes through a specified threshold (from either direction.) * * @param plotInterval Time interval between molecule count outputs * @param stopTime Simulated time at which to stop unconditionally * @param monitorId Id of molecule to be monitored * @param threshold Stop after monitored molecule count reaches this * value * @param monitorDelay Continue for this time interval after threshold * reached * @param runIdle Keep running even if no reaction can run * @param idleTick Length of time step while idling */ void run( double plotInterval, double stopTime, const char *monitorId = NULL, double threshold = -DBL_MAX, double monitorDelay = 0.0); /** * Member accessors */ void setMwidth(uint w) { mwidth = w; } void setTwidth(uint w) { twidth = w; } void setRwidth(uint w) { rwidth = w; } void setMoleculeCount(uint id, uint count) { ABORT_IF(id > molecules.size(), "Invalid molecule id"); molecules[id].setCount(count); } void setReactionInhibition(uint id, double inhibition) { ABORT_IF(id > reactions.size(), "Invalid reaction id"); reactions[id].inhibition = inhibition; } private: class Reaction; struct Molecule { string id; string description; // Reactions in which this molecule is a reactant // std::vector<uint> downstreamReactions; // Constructor // Molecule(Gillespie &g, string id, uint count, string description) : id(id), description(description), g(g), count(count) {} // Assignment operator // const Molecule &operator=(const Molecule &other) { return other; } // Copy constructor // Molecule(const Molecule &other) : id(other.id), description(other.description), g(other.g), count(other.count) {} void setCount(uint value) { count = value; for (auto r : downstreamReactions) { g.reactions[r].isDirty = true; } } uint getCount() { return count; } private: Gillespie &g; uint count; }; class Reaction { public: string id; string formula; double k; // reaction rate (as used in // deterministic rate reaction) string description; double inhibition; // (1.0 - inhibition) multiplies c to // yield effective reaction constant; std::vector<uint> left; // number of each molecule 0..n // on left side std::vector<uint> right; // number of each molecule 0..n // on right side uint h; // number of available reactant // combinations double a; // a*dt=prob that this reaction // happens in dt double c; // reaction constant bool isDirty; // h and a need to be recalculated bool recalc; // h and a were recalculated in last iteration // - used for debug printout only. // Constructor // Reaction( Gillespie &g, string id, string formula, double k, string description) : id(id), formula(formula), k(k), description(description), inhibition(0.0), isDirty(true), recalc(true), g(g) {} // Assignment operator // const Reaction &operator=(const Reaction &other) { return other; } // Copy constructor // Reaction(const Reaction &other) : id (other.id), formula(other.formula), k(other.k), description(other.description), inhibition(other.inhibition), left(other.left), right(other.right), h(other.h), a(other.a), c(other.c), isDirty(other.isDirty), recalc(other.recalc), g(other.g) {} /** * Parse the chemical formula into vectors of molecule * counts on the and right side of the reaction, and * calculate the stochastic reaction constant c. */ void parseFormula(string fname, uint lineNum); private: Gillespie &g; }; /* * Read system from .gil file * @param fp FILE pointer * @return Number of lines read */ uint readGilFile(const char *fname); /** * Verify and post-process data read from .gil file(s) */ void verify(const char *fname, uint numLines); /** * Expand a wildcard (*) in a reaction ID */ void expandReactionWildcard(string &id); /** * Check if there are enough molecules for reaction r to happen * @param r Reaction */ bool isPossible(Reaction &r); /** * Make a header line for the output * @param molecules Array of molecules */ string makeHeader(const std::vector<Molecule> &molecules); double volume; // containment volume bool runIdle; // whether to keep running when no reactions are possible double idleTick; // time step size while idling; std::vector<Molecule> molecules; std::vector<Reaction> reactions; void (*preIterFunc)(double time); uint twidth; // width of time field in output uint mwidth; // minimum width of molecule count field in output uint rwidth; // width of reaction name field in output std::vector<uint> fwidths; // field widths in output /** * Retrieve molecule index by id */ uint moleculeIndex(string id); /** * Retrieve reaction index by id */ uint reactionIndex(string id); }; #endif