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.model.TransformationDecorator; | |
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.getCanonicalGraph().getDecorators()) { | |
if (decorator instanceof Trigger || decorator instanceof TransformationDecorator) { | |
decorator.updateLabels(time, timeDelta, cycle); | |
} | |
} | |
// First initialize the Y and temp label values from the current | |
// label values. | |
for (Decorator decorator : this.getCanonicalGraph().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.getCanonicalGraph().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>(); | |
EList<TransformationDecorator> transDecorators = new BasicEList<TransformationDecorator>(); | |
for (final Iterator<Decorator> decoratorIter = this.getCanonicalGraph().getDecorators() | |
.iterator(); decoratorIter.hasNext();) { | |
final Decorator decorator = decoratorIter.next(); | |
// Is the decorator enabled? | |
if (decorator.isEnabled()&& decorator instanceof IntegrationDecorator) | |
iDecorators.add((IntegrationDecorator) decorator); | |
if(decorator instanceof TransformationDecorator) transDecorators.add((TransformationDecorator)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.getCanonicalGraph().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.getCanonicalGraph().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.getCanonicalGraph().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 |