/*---------------------------- Ingeneue source code ©Copyright 2000 by George von Dassow, Eli Meir, Edwin Munro, and Garrett Odell. Permission is granted for use by private individuals and by individuals and groups at all non-profit institutions, as long as those using the software or examining the code do not intend to make a profit from its use, and subject to all other conditions given on the website www.ingenenue.org. www.ingeneue.org contact@ingeneue.org ----------------------------*/ package main; import java.util.*; import java.awt.*; import affectors.Affector; import java.io.PrintWriter; import integrators.NodeValues; /** A node is one of the state variables in the model: an mRNA, protein, protein complex, protein at a membrane, etc. Each node contains a set of Affectors which specify how that node changes over time. A copy of each type of node is put into each cell.

Note - you can't use a freshly made node. You must use a copy of the node, because copying the node fixes the array of affectors (the original uses affectorVector so that it is easy to build). */ public class Node extends Object implements Cloneable { static float FPStabilizer = 0.3f; // sets alpha value in fixed point iteration: // x(t+1) = alpha*F(x(t)) + (1 - alpha)*x(t) // INSTANCE MEMBERS int itsNodeNum; // An index into the names array float [] values; float [] integrationValues; int numAffectorsPerSide; // The number of different affectors for this node public int numSides; // The number of sides that this node has. 1 for non-membrane nodes, otherwise number of sides per cell public Affector [] affectors; // The array of affectors for this node. This is the final array for a particular // instance of an affector in a particular node in a particular cell (ie. after copy() ) Vector affectorVector = new Vector(); // This is used while building the net, then thrown out // Note that affectorVector contains one copy of each affector // per side of this node, if this is a membrane node. // So the number of affectors in affectorVector = numAffectorsPerSide * numSides // Also note that, for sided nodes, the order in which the affectors are // stored here matters, because the integrator needs to figure out // which affector goes with which side. // These next variables are for adding in affectors after the model is already set up int numExpAffectorsPerSide = 0; Affector [] expAffectors = null; // These are for noise added to nodes NoiseGenerator [] noiseGenerator = null; final static int ABSOLUTE_NOISE = 1, PROPORTIONAL_VALUE_NOISE = 2, PROPORTIONAL_DERIV_NOISE = 3; int noiseType = PROPORTIONAL_VALUE_NOISE; // To distinguish nodes when debugging - take back out when stuff works static int debug_num = 0; public int this_debug_num = debug_num++; // CONSTRUCTORS Node() {} Node(int node_num, int num_sides) { itsNodeNum = node_num; setNumSides(num_sides); } public void setAffectors(Vector affector_templates, Cell cell) throws Exception { numAffectorsPerSide = affector_templates.size(); affectors = new Affector[numAffectorsPerSide * numSides]; for(int i = 0; i < numAffectorsPerSide; i++) { for(int j = 0; j < numSides; j++) { affectors[i*numSides + j] = ((AffectorTemplate)(affector_templates.elementAt(i))).makeAffector(cell, j); } } } protected void init(int node_num) { itsNodeNum = node_num; numAffectorsPerSide = 0; // Just a default - this gets set for real in copy() setNumSides(1); // Assume its cytoplasmic } public void setNumSides(int num_sides) { numSides = num_sides; values = new float[numSides]; integrationValues = new float[numSides]; } private float addNoise(float value, int side, float time, float deriv) { if(noiseGenerator == null) return value; float noise = noiseGenerator[side].getNoise(time); switch(noiseType) { case ABSOLUTE_NOISE: return value + noise; case PROPORTIONAL_VALUE_NOISE: return value * noise; case PROPORTIONAL_DERIV_NOISE: return value + deriv * noise; default: return value; } } // This duplicates the core code in ckIntegrate below. Maybe we should call this // from there to avoid retyping the same code over and over public final float getAffectorsValue(int side) { float val = 0; int i; for(i = 0; i < numAffectorsPerSide; i++) { val += affectors[i * numSides + side].getValue(this); } if(numExpAffectorsPerSide > 0) { for(i = 0; i < numExpAffectorsPerSide; i++) { val += expAffectors[i * numSides + side].getValue(this); } } return val; } public final void getAffectorsValue(float [] vals) { for(int side = 0; side < numSides; side++) { vals[side] = 0f; for(int i = 0; i < numAffectorsPerSide; i++) { vals[side] += affectors[i * numSides + side].getValue(this); } if(numExpAffectorsPerSide > 0) { for(int i = 0; i < numExpAffectorsPerSide; i++) { vals[side] += expAffectors[i * numSides + side].getValue(this); } } } } public final void getSeparatedDeriv(float [] fhat_vals, float [] dfdyi_vals) { for(int side = 0; side < numSides; side++) { fhat_vals[side] = 0f; dfdyi_vals[side] = 0f; for(int i = 0; i < numAffectorsPerSide; i++) { if(affectors[i * numSides + side].isLinearInTarget()) { float temp = affectors[i * numSides + side].getNCValue(this); /*if(temp <= 0f)*/dfdyi_vals[side] += temp; // try this to see if neg. values are causing integrator jams } else { fhat_vals[side] += affectors[i * numSides + side].getValue(this); } } if(numExpAffectorsPerSide > 0) { for(int i = 0; i < numExpAffectorsPerSide; i++) { if(expAffectors[i * numSides + side].isLinearInTarget()) { float temp = expAffectors[i * numSides + side].getNCValue(this); /*if(temp <= 0f)*/dfdyi_vals[side] += temp; } else { fhat_vals[side] += expAffectors[i * numSides + side].getValue(this); } } } } } public float getIntegrationValue() { float value = 0f; for(int side = 0; side < numSides; side++) value += integrationValues[side]; return value; } public float getIntegrationValue(int side) { return integrationValues[side]; } public void setIntegrationValues(float [] vals) { for(int side = 0; side < numSides; side++) integrationValues[side] = Math.max(0f,vals[side]); } public void setFinalValues(float [] vals) { for(int side = 0; side < numSides; side++) values[side] = Math.max(0f,vals[side]); } // GET/SET METHODS public float getValue(int side) { if(numSides == 1) side = 0; return(values[side]); } public void getValue(float [] vals) { for(int side = 0; side < numSides; side++) { vals[side] = values[side]; } } public float getSum() { float v = 0; for(int i = 0; i < numSides; i++) { v += values[i]; } return(v); } public void setValue(float val) { for(int i = 0; i < numSides; i++) values[i]= val/numSides; } public void setValue(int side, float val) { values[side] = val; } public void setValue(NodeValues newvalues) { for(int i = 0; i < numSides; i++) values[i] = newvalues.values[i]; } public float getNoise() { if(noiseGenerator == null) return 0f; else return noiseGenerator[0].getMaxAmplitude(); } public void setNoise(float amplitude) { if(amplitude == 0) noiseGenerator = null; else { if(noiseGenerator == null) { noiseGenerator = new NoiseGenerator[numSides]; for(int i = 0; i < numSides; i++) noiseGenerator[i] = new NoiseGenerator(); } for(int i = 0; i < numSides; i++) noiseGenerator[i].setMaxAmplitude(amplitude); } } public int getNodeNum() { return itsNodeNum; } public int getNumAffectors() { return numSides * numAffectorsPerSide; } public Node copy() { Node c = null; try { c = (Node)this.clone(); } catch(CloneNotSupportedException e) {} c.values = new float[numSides]; System.arraycopy(values, 0, c.values, 0, values.length); c.integrationValues = new float[numSides]; System.arraycopy(integrationValues, 0, c.integrationValues, 0, integrationValues.length); c.numAffectorsPerSide = affectorVector.size() / numSides; c.affectors = new Affector[affectorVector.size()]; for(int i = 0; i < affectorVector.size(); i++) { c.affectors[i] = ((Affector)(affectorVector.elementAt(i))).copy(); } c.this_debug_num = debug_num++; return(c); } // AFFECTOR-HANDLING METHODS public void addExpAffector(Affector aff, Cell cell) throws Exception { int i; if(numExpAffectorsPerSide > 0) { Affector [] newaff = new Affector[(numExpAffectorsPerSide + 1) * numSides]; for(i = 0; i < numExpAffectorsPerSide; i++) newaff[i] = expAffectors[i]; expAffectors = newaff; } else expAffectors = new Affector[numSides]; for(i = numExpAffectorsPerSide * numSides; i < numExpAffectorsPerSide * numSides + numSides; i++) { expAffectors[i] = aff.copy(); expAffectors[i].fixNodes(cell, new String[0]); } numExpAffectorsPerSide++; } public void removeExpAffectors() { for(int i = 0; i < numExpAffectorsPerSide * numSides; i++) { expAffectors[i] = null; } expAffectors = null; numExpAffectorsPerSide = 0; } }