package reaction;
import java.util.List;
import java.util.Vector;
import recorders.Recorder;
import miscellaneous.CSVList;
import miscellaneous.LSVList;
/**
*
* @author akpinar
*
* @questions How do you change k?
*/
public class Reaction {
public List<Reactant> reactants = new Vector<Reactant>();
public List<Product> products = new Vector<Product>();
private double k = 0.0;
private double rate = 0.0;
/**
* This method will automatically calculate the forward reaction rate based on stoichiometry and elementary reactions. This is usually overwritten by the classes who extend Reaction.
*
* @param cell
* This is where the reaction will find information about reactant concentrations
* @param attenuation
* ?????
*/
/**
* calculates rate
*/
public void calculateBaseRate()
{
// uses amounts, orders, and k to calculate a base rate based on mass action (stoichiometry is handled later)
// rules
double baseRate = 1.0;
double c = 0;
for (Reactant r : this.reactants)
{
c = r.pool.getCount(r.name);
// if(c < 0)
// {
// c = 0;
// Recorder.log(r.name + " is below 0!!!", this);
// }
baseRate = baseRate * Math.pow(r.pool.getCount(r.name), r.order);
}
baseRate = baseRate * this.k;
this.rate = baseRate;
}
/**
* sets reaction rate constant k
*
* @param k
*/
public void setk(double k)
{
this.k = k;
}
/**
*
* @return rate constant k
*/
public double getk()
{
return this.k;
}
/**
* This is what you can call if you want to override that calculated dA/dt (i.e. the base rate of the reaction) with your own calculated rate. This allows you to do things like add if statements and set things to 0 if need be in certain
* situations.
*
* @param rate
*
*/
public void setRate(double rate)
{
this.rate = rate;
}
/**
*
* @return rate
*/
public double getRate()
{
return this.rate;
}
/**
* add reactants from a pool at a certain stoichiometry and order
*
* @param pool
* @param name
* @param stoich
* @param order
*/
public void addReactant(Pool pool, String name, double stoich, double order)
{
this.addReactant(pool, name, name, stoich, order);
}
public void addReactant(Pool pool, String name, String nickname, double stoich, double order)
{
this.reactants.add(new Reactant(pool, name, nickname, stoich, order));
}
/**
* add products from a pool at a certain stoichiometry and delay
*
* @param pool
* @param name
* @param stoich
* @param delay
*/
public void addProduct(Pool pool, String name, double stoich, double delay)
{
this.addProduct(pool, name, name, stoich, delay);
}
public void addProduct(Pool pool, String name, String nickname, double stoich, double delay)
{
if(stoich != 0)
{
Product newProd = new Product(pool, name, nickname, stoich, delay);
for (Product p : this.products)
{
if((p.name == name) && (p.pool == pool))
{
p.setRepeated(true);
newProd.setRepeated(true);
}
}
this.products.add(newProd);
}
}
/**
* multiplies with stoiciometric ratio
*
* @param cell
*/
public void applyStoichAndRate()
{
// add all rates of change to 'rates' portion of pool
if(this.getRate() == 0.0)
{
// Recorder.log("Caution: reaction rate is 0.0", this);
}
for (Reactant reactant : this.reactants)
{
reactant.pool.rates.put(new Item(reactant.name, -1 * reactant.adjustRate(this.getRate()), 0.0)); // substract the reactant based on stoichiometric constant
}
for (Product product : this.products)
{
product.pool.rates.put(new Item(product.name, product.adjustRate(this.getRate()), product.delay));// add the product based on stoichiometric constant
}
}
/**
* The polKineticFactorPerTemplate is equal to the following for each type of polymerase reaction... Translation -> [Rib], Transcription -> [Pol], Replication -> [Pol][N], (i.e., it is all the reactants 'concentrations' multiplied together except
* for the template).
*
* @param ntPerSec
* [nt/sec] polymerase rate [nt/sec]
* @param polSpacing
* [nt] polymerase spacing on the template [nt]
* @param polKineticFactorPerTemplate
* polymerase number for transcription
*
* @param kOn
* , promoter strength [various units depending on number of reactants]
* @return
*
* @questions polKineticFactorPerTemplate??? why does promoter strength depend on number of reactants? Why not type of reactant?
*/
public static Double polymeraseOnRatePerTemplate(Double ntPerSec, Double polSpacing, Double polKineticFactorPerTemplate, Double promoterStrength)
{
double tSpacing = polSpacing / ntPerSec;
if(polKineticFactorPerTemplate <= 0)
{
return 0.0;
}
return 1 / (tSpacing + (1 / (promoterStrength * polKineticFactorPerTemplate)));
}
/**
* @return the reaction in the form of A + B --> C(delay) + D(delay), kRxn = ###
*
* @questions What will be the output????
*/
@Override
public String toString()
{
// return the reaction in the form
// A + B -> C(delay) + D(delay), kRxn = ###
String reactantString = new String();
String productString = new String();
String kString = new String();
for (Reactant reactant : this.reactants)
{
reactantString += reactant.toString() + " +";
}
// reactantString=reactantString.substring(0,
// reactantString.length()-1);
reactantString += " --> ";
CSVList repeatedProduct = new CSVList();
String repeatedProductString = new String();
for (Product product : this.products)
{
// if we have not added the product, add it normally
if(product.isRepeated)
{
repeatedProduct.add(product.toStringRepeated());
repeatedProductString = product.name + "(" + product.pool.name + ")";
}
else
{
productString += product.toString() + " +";
}
}
if(!repeatedProduct.isEmpty())
{
repeatedProductString = "[" + repeatedProduct.toString() + "]*" + repeatedProductString;
}
if(productString.length() < 1)
{
productString = "0";
}
// productString=productString.substring(0, productString.length()-1);
kString = " , kRxn = " + Double.toString(this.getk());
return reactantString + productString + repeatedProductString + kString;
}
public String checkReactionBalance()
{
LSVList cnsrvdRctnts = new LSVList();
cnsrvdRctnts.add("Check balance for conserved reactants");
String outString = new String();
// Generate a list of conserved reactants/products
for (Reactant r : this.reactants)
{
double rStoich = r.stoich;
double pStoich = 0.0;
boolean conserved = false;
for (Product p : this.products)
{
// if the names are the same and the pools are the same they are
// the same entity and conserved
if(r.name == p.name && r.pool == p.pool)
{
conserved = true;
// add up all the products (they are different because of
// delays)
pStoich += p.stoich;
}
}
if(conserved)
{
// add to the list, and display the reactant product stoich
outString = r.name + ": " + rStoich + " , " + pStoich;
cnsrvdRctnts.add(outString);
}
}
return cnsrvdRctnts.toString();
}
// ***********************************************************************
// OLD METHODS
// ***********************************************************************
/*
* public static void multiplyIntoMap(double multiplicationFactor, TreeMap<String,Double> map) { for(Entry<String,Double> e : map.entrySet()) { Double temp = e.getValue(); double newTemp = temp*multiplicationFactor; if(Double.isInfinite(newTemp))
* { newTemp = Math.signum(newTemp)*Double.MIN_VALUE; Recorder.log("Infinite Value Reached! " + e.getKey() + " : " + e.getValue() + " * " + multiplicationFactor, Reaction.class.getSimpleName()); } e.setValue(newTemp); } }
*/
/*
* public static void addIntoMap(double amountToAdd, TreeMap<String,Double> map) { for(Entry<String,Double> e : map.entrySet()) { Double temp = e.getValue(); double newTemp = temp + amountToAdd; if(Double.isInfinite(newTemp)) { newTemp =
* Math.signum(newTemp)*Double.MIN_VALUE; Recorder.log("Infinite Value Reached! " + e.getKey() + " : " + e.getValue() + " + " + amountToAdd, Reaction.class.getSimpleName()); } e.setValue(newTemp); } }
*
* public static void addMap1ToMap2(TreeMap<String,Double> map1, TreeMap<String,Double> map2) { for(Entry<String,Double> e : map2.entrySet()) { double temp = 0.0; if(map1.containsKey(e.getKey())) { temp = temp + map1.get(e.getKey()); } temp =
* temp + e.getValue(); if(Double.isInfinite(temp)) { temp = Math.signum(temp)*Double.MAX_VALUE; Recorder.log("Limit value reached during addition. Map1: " + e.getKey() + ", " + map1.get(e.getKey()) + " + Map2: " + e.getKey() + ", " +
* e.getValue(), Reaction.class.getSimpleName()); } e.setValue(temp); } }
*//**
* multiplies the doubles in two TreeMap<String,Double> objects. However, if one map is null for a particular value, the value is assumed to be 1.0 instead of 0.0
*
* @param map1
* @param map2
* @return new map with multiplied values
*/
/*
* public static TreeMap<String,Double> multiplyMaps(TreeMap<String,Double> map1, TreeMap<String,Double> map2) { TreeMap<String,Double> ret = new TreeMap<String,Double>(); for(Entry<String,Double> e : map2.entrySet()) { double temp = 1.0;
* if(map1.containsKey(e.getKey())) { temp = temp * map1.get(e.getKey()); } temp = temp * e.getValue(); if(Double.isInfinite(temp)) { temp = Math.signum(temp)*Double.MAX_VALUE; Recorder.log("Limit value reached during multiplication. Map1: " +
* e.getKey() + ", " + map1.get(e.getKey()) + " * Map2: " + e.getKey() + ", " + e.getValue(), Reaction.class.getSimpleName()); } ret.put(e.getKey(),temp); } return ret; }
*
* public static TreeMap<String,Double> copyMap(TreeMap<String,Double> map) { TreeMap<String,Double> ret = new TreeMap<String,Double>(); for(Entry<String,Double> e : map.entrySet()) { ret.put(e.getKey(), e.getValue().doubleValue()); } return ret;
* }
*/
/**
* polKineticFactorPerTemplate is something like pol*N*Genome/Genome (replication), pol*Genome/Genome (transcription) or rib*N_transcript/N_transcript (translation)
*
* @param polRate
* @param polSpacing
* @param polKineticFactorPerTemplate
* @param kOn
* @return
*/
// @Override
// public Reaction copy()
// {
// Reaction ret = new Reaction();
// for (Reactant r : this.reactants)
// {
// ret.reactants.add(r);
// }
// for (Product p : this.products)
// {
// ret.products.add(p);
// }
// ret.k = this.k;
// ret.rate = this.rate;
//
// return ret;
// }
}