package parameterrules; import java.io.*; import main.BetterTokenizer; import main.GeneralInput; import main.MoreMath; import parameters.ParameterSet; import parameters.Parameter; /** Because of the way things are scaled, dimers can have concentrations more than 1. Specifically, a dimer's value can reach HalfLifeDimer / HalfLifeScalingMonomer where the scaling monomer is the monomer that the dimer is scaled with respect to. This means that to get the same half-maximal activation and repression ranges for a transcription factor dimer as for undimerized transcription factors, the absolute ranges have to be adjusted upwards by the ration above. The clumsy way we do that now is to make the range of those K parameters in the files large enough to cover all possible ratios of half lives, and then use this parameter rule to keep the actual values used in a simulation run within the range we want. This rule implements the following calculation:

LowerBound * ratio <= DimerKParam <= UpperBound * ratio
where ratio = DimerHalfLife / ScalingHalfLife */ public class DimerHalfMaxRule extends ParameterRule { /** These store the lower and upper bounds that the product of the parameters have to be between (inclusive of edges) */ private float lowerBound, upperBound; private int dimerHalfLifePos = -1, scalingHalfLifePos = -1, dimerKParamPos = -1; DimerHalfMaxRule() {} public float getFuzzyScore(float [] params) { float ratio = params[paramNums[dimerHalfLifePos]] / params[paramNums[scalingHalfLifePos]]; if(lowerBound * ratio > params[paramNums[dimerKParamPos]]) return lowerBound * ratio - params[paramNums[dimerKParamPos]]; else if(upperBound * ratio < params[paramNums[dimerKParamPos]]) return params[paramNums[dimerKParamPos]] - upperBound * ratio; else return 0f; } public boolean changeParameters(float [] params, int mode, ParameterSet set) { float ratio = params[paramNums[dimerHalfLifePos]] / params[paramNums[scalingHalfLifePos]]; if(lowerBound * ratio <= params[paramNums[dimerKParamPos]] && upperBound * ratio >= params[paramNums[dimerKParamPos]]) return true; // Figure out the new bounds float min = lowerBound * ratio; float max = upperBound * ratio; // Pick the value pickNewParameterValue(params, paramNums[dimerKParamPos], min, max, mode, set); return false; } /** Overridden to do error checking, making sure that all parameters are specified. */ public void loadParameters(BetterTokenizer tokenizer) throws Exception { super.loadParameters(tokenizer); if(dimerHalfLifePos < 0) throw new Exception("DimerHalfLife not specified in DimerHalfMaxRule"); if(scalingHalfLifePos < 0) throw new Exception("ScalingHalfLife not specified in DimerHalfMaxRule"); if(dimerKParamPos < 0) throw new Exception("DimerKParam not specified in DimerHalfMaxRule"); } protected void loadParameter(String info, BetterTokenizer tokenizer) throws Exception { if(info.equals("LowerBound")) { GeneralInput.nextToken(tokenizer); lowerBound = (float)tokenizer.nval; } else if(info.equals("UpperBound")) { GeneralInput.nextToken(tokenizer); upperBound = (float)tokenizer.nval; } else if(info.equals("DimerHalfLife")) { super.loadParameter("Param", tokenizer); // Just use code already there and then keep track of positions of each dimerHalfLifePos = numParams - 1; } else if(info.equals("ScalingHalfLife")) { super.loadParameter("Param", tokenizer); // Just use code already there and then keep track of positions of each scalingHalfLifePos = numParams - 1; } else if(info.equals("DimerKParam")) { super.loadParameter("Param", tokenizer); // Just use code already there and then keep track of positions of each dimerKParamPos = numParams - 1; } else super.loadParameter(info, tokenizer); } }