blob: ae6d1a7d913ee30a07921c55ea87e5ee844d6bd3 [file] [log] [blame]
package org.eclipse.stem.solvers.fd.impl;
/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
import java.util.Iterator;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.stem.core.graph.DynamicLabel;
import org.eclipse.stem.core.graph.IntegrationLabel;
import org.eclipse.stem.core.graph.IntegrationLabelValue;
import org.eclipse.stem.core.graph.LabelValue;
import org.eclipse.stem.core.model.Decorator;
import org.eclipse.stem.core.model.IntegrationDecorator;
import org.eclipse.stem.core.model.STEMTime;
import org.eclipse.stem.core.solver.impl.SolverImpl;
import org.eclipse.stem.core.trigger.Trigger;
import org.eclipse.stem.solvers.fd.FdPackage;
import org.eclipse.stem.solvers.fd.FiniteDifference;
import org.eclipse.stem.ui.Activator;
/**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Finite Difference</b></em>'.
* <!-- end-user-doc -->
* <p>
* </p>
*
* @generated
*/
public class FiniteDifferenceImpl extends SolverImpl implements FiniteDifference {
// The worker jobs
private FdJob [] jobs;
// Number of threads
private short num_threads;
private final static int MAX_PROGRESS_REPORTS = 5;
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public FiniteDifferenceImpl() {
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
@Override
public boolean step(STEMTime time, long timeDelta, int cycle) {
Activator act = org.eclipse.stem.ui.Activator.getDefault();
if(act != null) {
final Preferences preferences = act.getPluginPreferences();
num_threads = (short)preferences.getInt(org.eclipse.stem.ui.preferences.PreferenceConstants.SIMULATION_THREADS);
} else num_threads = 2; // Just so we can run inside junit test
partitioner.setNumProcesses(num_threads);
// Find triggers and make sure they are invoked
for(Decorator decorator:this.getDecorators()) {
if(decorator instanceof Trigger) {
decorator.updateLabels(time, timeDelta, cycle);
}
}
// First initialize the Y and temp label values from the current
// label values.
for(Decorator decorator:this.getDecorators()) {
EList<DynamicLabel>allLabels = decorator.getLabelsToUpdate();
for (final Iterator<DynamicLabel> currentStateLabelIter = allLabels
.iterator(); currentStateLabelIter.hasNext();) {
if(decorator instanceof IntegrationDecorator) {
// It's a standard disease model with a standard disease model label
final IntegrationLabel iLabel = (IntegrationLabel) currentStateLabelIter.next();
((IntegrationLabelValue)iLabel.getProbeValue()).set((IntegrationLabelValue)iLabel.getCurrentValue());
((IntegrationLabelValue)iLabel.getTempValue()).set((IntegrationLabelValue)iLabel.getCurrentValue());
((IntegrationLabelValue)iLabel.getTempValue()).prepareCycle();
((IntegrationLabelValue)iLabel.getProbeValue()).prepareCycle();
} else currentStateLabelIter.next();
}
}
if(jobs == null || jobs.length != num_threads) {
// Initialize the jobs if not done yet or of the number of threads changes
jobs = new FdJob[num_threads];
for(int i=0;i<num_threads;++i) {
final short threadnum = (short)i;
jobs[i] = new FdJob("Finite Difference Worker "+i, threadnum, this);
} // For each job
} // If not initialized
recursiveStep(time, timeDelta, cycle, 1.0);
return true;
}
protected void recursiveStep(STEMTime time, long timeDelta, int cycle, double scaling) {
// Compute deltas
for(FdJob j:jobs) {
j.cycle = cycle;
j.time = time;
j.timeDelta = timeDelta;
j.step = FdJob.COMPUTE_DELTAS;
j.schedule();
}
for(FdJob j : jobs) {
try {
j.join();
} catch(InterruptedException ie) {
Activator.logError(ie.getMessage(), ie);
}
}
// Scale deltas
scaleAllDeltas(scaling);
// Check deltas for adjustment
for(FdJob j:jobs) {
j.step = FdJob.CHECK_DELTAS;
j.schedule();
}
for(FdJob j : jobs) {
try {
j.join();
} catch(InterruptedException ie) {
Activator.logError(ie.getMessage(), ie);
}
}
double factor = 1.0;
for (FdJob j : jobs) {
factor = Math.min(factor, Double.parseDouble(j.getResult().getMessage()));
}
if (factor == 1.0) {
// Apply deltas
for(FdJob j:jobs) {
j.step = FdJob.APPLY_DELTAS;
j.schedule();
}
for(FdJob j : jobs) {
try {
j.join();
} catch(InterruptedException ie) {
Activator.logError(ie.getMessage(), ie);
}
}
} else if(factor > 0){
// Scale to avoid going negative
scaleAllDeltas(factor);
// Apply deltas
for(FdJob j:jobs) {
j.step = FdJob.APPLY_DELTAS;
j.schedule();
}
for(FdJob j : jobs) {
try {
j.join();
} catch(InterruptedException ie) {
Activator.logError(ie.getMessage(), ie);
}
}
// Call this method again for the rest of the time step
for(Decorator decorator:this.getDecorators()) {
EList<DynamicLabel>allLabels = decorator.getLabelsToUpdate();
for (final Iterator<DynamicLabel> currentStateLabelIter = allLabels
.iterator(); currentStateLabelIter.hasNext();) {
if(decorator instanceof IntegrationDecorator) {
// It's a standard disease model with a standard disease model label
final IntegrationLabel iLabel = (IntegrationLabel) currentStateLabelIter.next();
((IntegrationLabelValue)iLabel.getProbeValue()).set((IntegrationLabelValue)iLabel.getNextValue());
((IntegrationLabelValue)iLabel.getTempValue()).set((IntegrationLabelValue)iLabel.getNextValue());
} else currentStateLabelIter.next();
}
}
recursiveStep(time, timeDelta, cycle, (1-factor)*scaling);
} else {
Activator.logError("Attempted finite difference step rescaling but the scaling factor was 0", new Exception());
}
}
protected void computeDeltasStep(STEMTime time, long timeDelta, short threadnum) {
// Now give each decorator a chance to update its dynamic
// labels in the canonical graph, but only if it is enabled. A
// Decorator might not be enabled if it is the action of a Trigger
// and the Predicate of the trigger is false.
EList<IntegrationDecorator> iDecorators = new BasicEList<IntegrationDecorator>();
for (final Iterator<Decorator> decoratorIter = this
.getDecorators().iterator(); decoratorIter.hasNext();) {
final Decorator decorator = decoratorIter.next();
// Is the decorator enabled?
if (decorator.isEnabled() && decorator instanceof IntegrationDecorator) iDecorators.add((IntegrationDecorator)decorator);
}
for(IntegrationDecorator imodel:iDecorators)
imodel.calculateDelta(time, timeDelta, partitioner.partitionDecoratorLabels((Decorator)imodel, threadnum));
for(IntegrationDecorator imodel:iDecorators)
imodel.applyExternalDeltas(time, timeDelta, partitioner.partitionDecoratorLabels((Decorator)imodel, threadnum));
}
protected double checkDeltasStep(short threadnum) {
EList<IntegrationDecorator> iDecorators = new BasicEList<IntegrationDecorator>();
for (final Iterator<Decorator> decoratorIter = this
.getDecorators().iterator(); decoratorIter.hasNext();) {
final Decorator decorator = decoratorIter.next();
// Is the decorator enabled?
if (decorator.isEnabled() && decorator instanceof IntegrationDecorator) iDecorators.add((IntegrationDecorator)decorator);
}
double factor = 1.0;
for(IntegrationDecorator imodel:iDecorators)
factor = Math.min(factor, getDeltaAdjustment((Decorator)imodel, threadnum));
return factor;
}
protected void applyDeltasStep(short threadnum) {
EList<IntegrationDecorator> iDecorators = new BasicEList<IntegrationDecorator>();
for (final Iterator<Decorator> decoratorIter = this
.getDecorators().iterator(); decoratorIter.hasNext();) {
final Decorator decorator = decoratorIter.next();
// Is the decorator enabled?
if (decorator.isEnabled() && decorator instanceof IntegrationDecorator) iDecorators.add((IntegrationDecorator)decorator);
}
for(IntegrationDecorator imodel:iDecorators)
updateStandardDiseaseModelLabels((Decorator)imodel, threadnum);
}
protected void scaleAllDeltas(double scaling) {
for(Decorator decorator:this.getDecorators()) {
EList<DynamicLabel>allLabels = decorator.getLabelsToUpdate();
for (final Iterator<DynamicLabel> currentStateLabelIter = allLabels
.iterator(); currentStateLabelIter.hasNext();) {
if(decorator instanceof IntegrationDecorator) {
// It's a standard disease model with a standard disease model label
final IntegrationLabel iLabel = (IntegrationLabel) currentStateLabelIter.next();
((IntegrationLabelValue)iLabel.getDeltaValue()).scale(scaling);
} else currentStateLabelIter.next();
}
}
}
protected double getDeltaAdjustment(Decorator model, short threadnum) {
EList<DynamicLabel> myLabels = partitioner.partitionDecoratorLabels(model, threadnum);
double factor = 1.0;
for (final Iterator<DynamicLabel> currentStateLabelIter = myLabels
.iterator(); currentStateLabelIter.hasNext();) {
final IntegrationLabel label = (IntegrationLabel) currentStateLabelIter.next();
IntegrationLabelValue delta = (IntegrationLabelValue)label.getDeltaValue();
factor = Math.min(factor, delta.computeDeltaAdjustment((IntegrationLabelValue)label.getTempValue()));
}
return factor;
}
protected void updateStandardDiseaseModelLabels(Decorator model, short threadnum) {
EList<DynamicLabel> myLabels = partitioner.partitionDecoratorLabels(model, threadnum);
IntegrationDecorator imodel = (IntegrationDecorator)model;
int numLabels = myLabels.size();
int setProgressEveryNthNode = num_threads * numLabels/(MAX_PROGRESS_REPORTS);
if(setProgressEveryNthNode == 0) setProgressEveryNthNode = 1;
int n=0;
// Initialize the next value from the current value and add the delta
for (final Iterator<DynamicLabel> currentStateLabelIter = myLabels
.iterator(); currentStateLabelIter.hasNext();) {
final IntegrationLabel label = (IntegrationLabel) currentStateLabelIter.next();
LabelValue nextState = label.getNextValue();
LabelValue delta = ((IntegrationLabel)label).getDeltaValue();
// For finite difference, we need to make sure we don't
// move too many people from one state to another
((IntegrationLabelValue)delta).avoidNegative((IntegrationLabelValue)label.getProbeValue());
nextState.reset();
// Add delta, this will also add the incidence
((IntegrationLabelValue)nextState).add((IntegrationLabelValue)delta);
// Add the original value. Use the temp value since the incidence has been reset on it in the prepareCycle() call
((IntegrationLabelValue)nextState).add((IntegrationLabelValue)((IntegrationLabel)label).getTempValue());
// Do any model specific work for instance add noise
imodel.doModelSpecificAdjustments((LabelValue)nextState);
// The next value is valid now.
label.setNextValueValid(true);
// Now add in the population so we can compute the reciprocal
// next cycle.
// addToTotalPopulationCount(nextState.getPopulationCount());
double progress = (double)n/(double)numLabels;
jobs[threadnum].setProgress(progress);
if(n%setProgressEveryNthNode==0) {
// Get the progress for all threads
for(int i=0;i<num_threads;++i) if(i!=threadnum && jobs[i] != null) progress+=jobs[i].getProgress();
progress /= num_threads;
model.setProgress(progress);
}
++n;
}
// Done
// this.setProgress(1.0);
}
/**
* Reset the solver
* @generated NOT
*/
@Override
public void reset() {
this.setInitialized(false);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass() {
return FdPackage.Literals.FINITE_DIFFERENCE;
}
} //FiniteDifferenceImpl