package uk.ac.ed.inf.biopepa.core.sba;
import java.util.LinkedList;
import java.util.List;
import uk.ac.ed.inf.biopepa.core.compiler.CompartmentData;
import uk.ac.ed.inf.biopepa.core.compiler.ComponentNode;
import uk.ac.ed.inf.biopepa.core.sba.SBAComponentBehaviour.Type;
public class OutlineAnalyser {
public SimpleTree[] createOutlineTree(SBAModel sbaModel){
if(sbaModel == null) {
SimpleTree[] treearray = new SimpleTree[1];
treearray[0] = new SimpleTree();
treearray[0].name = "Non-parseable Bio-PEPA model";
return treearray;
} else {
CompartmentData[] compartments = sbaModel.getCompartments();
ComponentNode[] species = sbaModel.getComponents();
SBAReaction[] reactions = sbaModel.getReactions();
boolean needCompartmentTree = compartments.length != 0;
/* We now set up a list of sources and sinks*/
boolean[] speciesSources = new boolean[species.length];
boolean[] speciesSinks = new boolean[species.length];
int numberSources = 0;
int numberSinks = 0;
/* A species is a source if it a reactant is never
* anything but a reactant.
*/
for (int sIndex = 0; sIndex < species.length; sIndex++) {
boolean isReactant = false;
boolean isProduct = false;
ComponentNode potentialReactant = species[sIndex];
String sourceName = potentialReactant.getName();
for (SBAReaction reaction : reactions) {
for (SBAComponentBehaviour cb : reaction.getReactants()) {
if (cb.getName().equals(sourceName) && cb.getType().equals(Type.REACTANT)) {
isReactant = true;
}
}
for (SBAComponentBehaviour cb : reaction.getProducts()) {
if (cb.getName().equals(sourceName)) {
isProduct = true;
}
}
speciesSources[sIndex] = isReactant && !isProduct;
speciesSinks[sIndex] = !isReactant && isProduct;
}
}
/* Now we just wish to count the number of sources and sinks */
for (boolean sourceBool : speciesSources){
if (sourceBool) { numberSources++ ; }
}
for (boolean sinkBool : speciesSinks){
if (sinkBool){ numberSinks++ ; }
}
/*
* Now the sources and sinks we do the same but for actions
* so that we obtain action sources and actions sinks
* an action source is one that produces something
* "out of the ether" that is it has no reactant but some
* product
*/
LinkedList<SBAReaction> sourceActions = new LinkedList<SBAReaction>();
LinkedList<SBAReaction> sinkActions = new LinkedList<SBAReaction>();
for(SBAReaction reaction : reactions){
List<SBAComponentBehaviour> reactants = reaction.getReactants();
List<SBAComponentBehaviour> products = reaction.getProducts();
/* So if there are no products then the reaction is said to be
* a sink
*/
boolean isSink = false;
boolean isSource = true;
for (SBAComponentBehaviour cb : reactants){
if (cb.getType().equals(Type.REACTANT)) {
// to be source it must have no reactants
isSource = false;
// to be a sink it must have at least one
// reactant.
isSink = true;
break;
}
}
// To be a sink action it must have at least one
// reactant which we have checked above and the products
// must be empty.
if (isSink && products.isEmpty()){
sinkActions.add(reaction);
}
// To be a source there must be no reactants which we
// have checked above and there must be at least one
// product.
if (isSource && !products.isEmpty()){
sourceActions.add(reaction);
}
}
// We build up a list of simple trees and then simply turn
// that into an array of simple trees.
LinkedList<SimpleTree> treelist = new LinkedList<SimpleTree>();
if (needCompartmentTree) {
String name = compartments.length + " Location" +
(compartments.length > 1 ? "s" : "");
SimpleTree cTree = new SimpleTree(name);
treelist.addLast(cTree);
cTree.id = "Locations";
//for (int i = 0; i < compartments.length; i++) {
for (CompartmentData cd : compartments){
// cd = compartments[i];
SimpleTree tree = new SimpleTree(cd.getName());
cTree.addChild(tree);
String infoName = cd.getType().toString();
SimpleTree infoTree = new SimpleTree(infoName);
tree.addChild(infoTree);
String volname = "Volume = " + cd.getVolume();
SimpleTree volTree = new SimpleTree(volname);
tree.addChild(volTree);
if(!Double.isNaN(cd.getStepSize())) {
String stepName = "Step-size = " + cd.getStepSize();
SimpleTree stepTree = new SimpleTree(stepName);
tree.addChild(stepTree);
}
}
}
String speciesName = species.length + " Species";
SimpleTree speciesTree = new SimpleTree(speciesName);
speciesTree.id = "Species";
treelist.addLast(speciesTree);
String lastname = null;
// This initialisation is redundant and is only here
// to avoid errors about a possibly uninitialised variable.
// However because on the first iteration of the for loop
// lastname is null, we know that the
// if (componentName.equals(lastname))
// will be false and hence this will be 'reinitialised' on the
// first iteration of the for loop.
SimpleTree compTree = new SimpleTree();
for (int i = 0; i < species.length; i++) {
ComponentNode component = species[i];
String componentName = component.getComponent();
/*
* We only want one tree for each species, but there
* will be more than one component node if the species
* exists in more than one compartment. Hence we only
* create a new componentTree if we are not just adding
* to the previous one.
*/
if(!componentName.equals(lastname)) {
compTree = new SimpleTree(componentName);
speciesTree.addChild(compTree);
lastname = componentName;
}
StringBuilder sb = new StringBuilder();
if(needCompartmentTree) {
sb.append("in ");
sb.append(component.getCompartment().getName());
sb.append(" ");
}
sb.append("with initial #molecules = ");
sb.append(component.getCount());
if (speciesSources[i]){
sb.append(" (is-source)");
}
if (speciesSinks[i]){
sb.append(" (is-sink)");
}
SimpleTree initTree = new SimpleTree(sb.toString());
compTree.addChild(initTree);
// Underneath the tree of the component we add a
// leaf for ever reaction in which it is involved.
// Originally I had a single tree which you could
// expand to show all the reactions but I think expanding
// the component node is enough, generally each component
// in only involved in a few reactions.
for (SBAReaction reaction : reactions){
String involvedName = component.getName();
if (AnalysisUtils.compInvolvedInReaction(involvedName,
reaction)){
SimpleTree rTree = new SimpleTree(reaction.toString());
compTree.addChild(rTree);
}
}
}
/*
* At this point we used to have a for loop which would look
* through all the comptrees and see which had more than one
* child. This would mean that there were several species in
* different locations had the same name and were put under the
* same tree. We can't do that now because we have the reactions
* as children as well. I'm not sure how worthwhile it is anyway.
* If we really want to we can keep a count of how many species
* are under each component name and update the titles here
* accordinly, but I'm not convinced it is worth it.
*/
/* Reactions Tree */
String rTreeName = reactions.length + " Reaction" +
(reactions.length > 1 ? "s" : "");
SimpleTree reactionsTree = new SimpleTree (rTreeName);
reactionsTree.id = "Reactions";
treelist.addLast(reactionsTree);
for (SBAReaction reaction : reactions) {
String enabled ;
if (reaction.isEnabled()){
enabled = "";
} else { enabled = " disabled"; }
String name = reaction.toString() + enabled;
SimpleTree rTree = new SimpleTree (name);
reactionsTree.addChild(rTree);
}
/* Source and Sinks Tree, first Sources */
if (numberSources > 0) {
String name = numberSources + " Sources";
SimpleTree sourcesTree = new SimpleTree (name);
sourcesTree.id = "Sources";
treelist.addLast(sourcesTree);
for (int sIndex = 0; sIndex < species.length; sIndex++) {
if (speciesSources[sIndex]) {
ComponentNode comp = species[sIndex];
String sourceName = comp.getName();
sourcesTree.addNamedChild(sourceName);
}
}
}
/* Second sinks */
if (numberSinks > 0) {
String name = numberSinks + " Sinks";
SimpleTree sinksTree = new SimpleTree(name);
sinksTree.id = "Sinks";
treelist.addLast(sinksTree);
for (int sIndex = 0; sIndex < species.length; sIndex++) {
if (speciesSinks[sIndex]) {
ComponentNode comp = species[sIndex];
sinksTree.addNamedChild(comp.getName());
}
}
}
/*
* The same again for source actions and for sink actions.
*/
if (sourceActions.size() > 0){
String sourceName = sourceActions.size() + " source actions";
SimpleTree sourcesTree = new SimpleTree (sourceName);
sourcesTree.id = "source actions";
treelist.addLast(sourcesTree);
for (SBAReaction reaction : sourceActions){
String name = reaction.toString();
sourcesTree.addNamedChild(name);
}
}
// Same again for the sink actions
if (sinkActions.size() > 0){
String sinksName = sinkActions.size() + " sink actions";
SimpleTree sinksTree = new SimpleTree(sinksName);
treelist.addLast(sinksTree);
sinksTree.id = "sink actions";
for (SBAReaction reaction : sinkActions){
String name = reaction.toString();
sinksTree.addNamedChild(name);
}
}
// Finally (within the 'else') return the array of trees.
return treelist.toArray(new SimpleTree[treelist.size()]);
}
}
}