/*******************************************************************************
* Copyright (c) 2009 University of Edinburgh.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the BSD Licence, which accompanies this feature
* and can be downloaded from http://groups.inf.ed.ac.uk/pepa/update/licence.txt
******************************************************************************/
package uk.ac.ed.inf.biopepa.ui;
import java.io.*;
import java.util.*;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.*;
import uk.ac.ed.inf.biopepa.core.BioPEPA;
import uk.ac.ed.inf.biopepa.core.BioPEPAException;
import uk.ac.ed.inf.biopepa.core.compiler.ModelCompiler;
import uk.ac.ed.inf.biopepa.core.compiler.ProblemInfo;
import uk.ac.ed.inf.biopepa.core.compiler.ProblemInfo.Severity;
import uk.ac.ed.inf.biopepa.core.dom.Model;
import uk.ac.ed.inf.biopepa.core.dom.internal.ParserException;
import uk.ac.ed.inf.biopepa.core.interfaces.*;
import uk.ac.ed.inf.biopepa.core.sba.Parameters;
import uk.ac.ed.inf.biopepa.core.sba.Parameters.Parameter;
import uk.ac.ed.inf.biopepa.core.sba.PhaseLine;
import uk.ac.ed.inf.biopepa.core.sba.SBAModel;
import uk.ac.ed.inf.biopepa.core.sba.ExperimentLine;
import uk.ac.ed.inf.biopepa.ui.interfaces.BioPEPAListener;
import uk.ac.ed.inf.biopepa.ui.interfaces.BioPEPAModel;
public class BioPEPAModelImpl implements BioPEPAModel {
Model astModel = null;
ModelCompiler compiledModel = null;
private List<BioPEPAListener> listeners = new ArrayList<BioPEPAListener>();
Map<QualifiedName, String> metaData = new HashMap<QualifiedName, String>();
ProblemInfo[] problems;
IResource resource = null;
List<IMarker> markers = new ArrayList<IMarker>();
Runnable bringProblemsToView = new Runnable() {
public void run() {
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().showView(IPageLayout.ID_PROBLEM_VIEW);
} catch (Exception e) {
}
}
};
SBAModel sbaModel = null;
BioPEPAModelImpl(IResource resource) {
this.resource = resource;
}
public void addListener(BioPEPAListener listener) {
if (!listeners.contains(listener))
listeners.add(listener);
}
public void dispose() {
for (Map.Entry<QualifiedName, String> me : metaData.entrySet()) {
try {
resource.setPersistentProperty(me.getKey(), me.getValue());
} catch (CoreException e) {
}
}
try {
for (IMarker marker : markers)
marker.delete();
} catch (CoreException e) {
}
}
public String[] getComponentNames() {
if (sbaModel != null)
return sbaModel.getComponentNames();
return null;
}
public String[] getDynamicVariableNames() {
if (sbaModel != null)
return sbaModel.getDynamicVariableNames();
return new String[0];
}
public String getProperty(String name) {
QualifiedName key = new QualifiedName(BioPEPAPlugin.PLUGIN_ID, name);
if (metaData.containsKey(key))
return metaData.get(key);
String s = null;
try {
s = resource.getPersistentProperty(key);
metaData.put(key, s);
} catch (CoreException e) {
s = null;
}
return s;
}
public IResource getUnderlyingResource() {
return resource;
}
private String source = null;
public void parse() throws CoreException {
long start = System.currentTimeMillis();
for (IMarker marker : markers)
marker.delete();
markers.clear();
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
((IFile) resource).getContents()));
StringBuffer buf = new StringBuffer();
char[] cbuf = new char[4096];
int c;
while ((c = in.read(cbuf)) != -1) {
buf.append(cbuf, 0, c);
}
source = buf.toString();
} catch (IOException e) {
IStatus status = new Status(IStatus.ERROR, BioPEPAPlugin.PLUGIN_ID,
"Input/Output problem", e);
BioPEPAPlugin.getDefault().log(status);
Display.getDefault().asyncExec(bringProblemsToView);
throw new CoreException(status);
}
if (source != null) {
try {
astModel = BioPEPA.parse(source);
} catch (Throwable e) {
IStatus status = new Status(IStatus.ERROR,
BioPEPAPlugin.PLUGIN_ID, "Parsing problem", e);
if (e instanceof ParserException) {
ParserException pe = (ParserException) e;
IMarker marker = resource.createMarker(IMarker.PROBLEM);
marker.setAttribute(IMarker.MESSAGE, pe.getMessage());
marker.setAttribute(IMarker.LINE_NUMBER, pe.getLine());
marker.setAttribute(IMarker.CHAR_START, pe.getChar());
marker.setAttribute(IMarker.CHAR_END, pe.getChar()
+ pe.getLength());
marker.setAttribute(IMarker.SEVERITY,
IMarker.SEVERITY_ERROR);
marker.setAttribute(IMarker.TRANSIENT, true);
markers.add(marker);
} else
BioPEPAPlugin.getDefault().log(status);
Display.getDefault().asyncExec(bringProblemsToView);
throw new CoreException(status);
}
}
compiledModel = BioPEPA.compile(astModel);
problems = compiledModel.compile();
int c = 0;
for (ProblemInfo p : problems)
if (p.severity.equals(Severity.ERROR))
c++;
if (c == 0)
sbaModel = BioPEPA.generateSBA(compiledModel);
else {
Display.getDefault().asyncExec(bringProblemsToView);
sbaModel = null;
}
IMarker marker;
for (ProblemInfo pi : problems) {
marker = resource.createMarker(IMarker.PROBLEM);
marker.setAttribute(IMarker.MESSAGE, pi.message);
marker.setAttribute(IMarker.SEVERITY, eclipseSeverity(pi.severity));
marker.setAttribute(IMarker.TRANSIENT, true);
if (pi.sourceRange != null) {
marker.setAttribute(IMarker.LINE_NUMBER, pi.sourceRange
.getLine());
marker.setAttribute(IMarker.CHAR_START, pi.sourceRange
.getChar());
marker.setAttribute(IMarker.CHAR_END, pi.sourceRange.getChar()
+ pi.sourceRange.getLength());
}
markers.add(marker);
}
notify(new BioPEPAEvent(this, BioPEPAEvent.Event.PARSED, System
.currentTimeMillis()
- start));
}
/*
* Used for overriding during experimentation, we assume that
* the problems introduced by the experimentation are not interesting
* for the user, so for example when we knock out a reaction this will
* give the reaction a rate of zero which in turn means that it will
* not be dependent on the concentrations of the reactants. But this
* warning would be uninteresting.
*
* A further concern is that the model may have already been overridden,
* we wish to avoid the problem of accumulating overrides. For this reason
* we hold a copy of the original model's source code and
* we unfortunately need to re-parse the source code to produce a copy of
* the astModel which we are free to modify.
* Alternatively we could implement cloning for ASTModels.
*
*/
public void overrideAndRecompile (ExperimentLine experimentLine)
throws BioPEPAException{
if (astModel != null && this.source != null){
try {
astModel = BioPEPA.parse(source);
} catch (ParserException e) {
throw new BioPEPAException ("Original source not-reparsable, fatal error");
} catch (Exception e) {
throw new BioPEPAException ("Original source not-reparsable, fatal error");
}
experimentLine.applyToAst(astModel);
compiledModel = BioPEPA.compile(astModel);
problems = compiledModel.compile();
sbaModel = BioPEPA.generateSBA(compiledModel);
}
}
public void notify(BioPEPAEvent event) {
for (BioPEPAListener l : listeners)
l.modelChanged(event);
}
private static final int eclipseSeverity(Severity severity) {
switch (severity) {
case ERROR:
return IMarker.SEVERITY_ERROR;
case WARNING:
return IMarker.SEVERITY_WARNING;
case INFO:
return IMarker.SEVERITY_INFO;
default:
throw new UnsupportedOperationException();
}
}
public void removeListener(BioPEPAListener listener) {
listeners.remove(listener);
}
public void setProperty(String name, String value) {
QualifiedName key = new QualifiedName(BioPEPAPlugin.PLUGIN_ID, name);
metaData.put(key, value);
}
/*
* (non-Javadoc)
* @see uk.ac.ed.inf.biopepa.ui.interfaces.BioPEPAModel#runPhasesTimeSeries(uk.ac.ed.inf.biopepa.core.interfaces.Solver, uk.ac.ed.inf.biopepa.core.sba.Parameters, org.eclipse.core.runtime.IProgressMonitor, uk.ac.ed.inf.biopepa.core.sba.ExperimentSet.ExperimentLine[], double[])
* TODO: There is a slight problem here, we need to ensure that every
* single component is in the results, otherwise it won't get added to
* the phase line in order to override its initial population.
* So we need someway of adding all the components and then triming
* the results at the end.
*/
public Result runPhasesTimeSeries(Solver solver,
Parameters parameters,
IProgressMonitor monitor,
PhaseLine[] phaseLines) throws BioPEPAException, CoreException {
double endTime = (Double) parameters.getValue(Parameter.Stop_Time);
Result result = null;
double processedTime = 0.0;
int phaseIndex = 0;
while (processedTime < endTime){
PhaseLine phaseLine = phaseLines[phaseIndex];
ExperimentLine experLine = phaseLine.getExperimentLine();
// If there is already a result then we should
// override the initial populations with the current
// populations.
if (result != null){
String [] componentNames = result.getComponentNames();
for (int index = 0; index < componentNames.length; index++){
String name = componentNames[index];
double midwayPopulation = result.getPopulation(index);
experLine.addInitialConcentration(name, midwayPopulation);
}
}
this.overrideAndRecompile(experLine);
double thisDelay = phaseLine.getDuration();
parameters.setValue(Parameter.Stop_Time, thisDelay);
Result thisResult = timeSeriesAnalysis(solver, parameters, monitor);
if (result == null){
result = thisResult;
} else {
result.concatenateResults(thisResult);
}
phaseIndex++;
if (phaseIndex >= phaseLines.length){
phaseIndex = 0;
}
processedTime += thisDelay;
}
return result;
}
public Result timeSeriesAnalysis(Solver solver,
Parameters parameters,
IProgressMonitor monitor) throws CoreException {
if (solver == null || parameters == null)
throw new NullPointerException();
try {
ProgressMonitor progressMonitor =
(monitor == null ? null :
new ProgressMonitorImpl("", monitor));
// Take the time now and then we'll do the same when it returns,
// this might not be incredibly accurate but should at least provide
// some means of comparison.
// Get current time
long startingTime = System.currentTimeMillis();
Result results = solver.startTimeSeriesAnalysis(sbaModel,
parameters,
progressMonitor);
// Get elapsed time in milliseconds
long elapsedTimeMillis = System.currentTimeMillis()-startingTime;
// Get elapsed time in seconds
float elapsedTimeSec = elapsedTimeMillis/1000F;
// Get elapsed time in minutes
// float elapsedTimeMin = elapsedTimeMillis/(60*1000F);
results.setSimulationRunTime(elapsedTimeSec);
return results;
} catch (BioPEPAException e) {
IStatus status = new Status(IStatus.ERROR, BioPEPAPlugin.PLUGIN_ID,
e.getMessage());
// Used to log error here, but current code extends Job which logs
// non-OK status responses itself.
// BioPEPAPlugin.getDefault().log(status);
throw new CoreException(status);
}
}
public boolean errorsPresent() {
try {
for (IMarker marker : markers)
if (((Integer) marker.getAttribute(IMarker.SEVERITY))
.intValue() == IMarker.SEVERITY_ERROR)
return true;
} catch (CoreException e) {
return true;
}
return false;
}
public SBAModel getSBAModel() {
return sbaModel;
}
public ModelCompiler getCompiledModel() {
return compiledModel;
}
}