blob: 08d25c9425b1085c919f7de99af9936fd0841587 [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
iterativeStep(time, timeDelta, cycle);
return true;
}
protected void iterativeStep(STEMTime time, long timeDelta, int cycle) {
double scaling = 1.0;
while (true) {
// 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, j.adjustmentFactor);
}
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);
}
}
break;
} 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);
}
}
// Set Probe and Temp Values and do the rest of the timestep.
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();
}
}
scaling -= factor * scaling;
} else {
Activator
.logError(
"Attempted finite difference step rescaling but the scaling factor was 0",
new Exception());
break;
}
}
}
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