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 |