| /** |
| * |
| */ |
| package org.eclipse.stem.util.analysis; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; |
| import org.eclipse.jface.operation.IRunnableContext; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.stem.analysis.impl.ReferenceScenarioDataMapImpl; |
| import org.eclipse.stem.analysis.impl.ReferenceScenarioDataMapImpl.ReferenceScenarioDataInstance; |
| import org.eclipse.stem.core.common.Identifiable; |
| import org.eclipse.stem.core.graph.Graph; |
| import org.eclipse.stem.definitions.labels.AreaLabel; |
| import org.eclipse.stem.definitions.labels.PopulationLabel; |
| import org.eclipse.stem.ui.Utility; |
| import org.eclipse.stem.util.analysis.views.EstimatorControl; |
| import org.eclipse.stem.util.analysis.views.Messages; |
| |
| /******************************************************************************* |
| * Copyright (c) 2007, 2008 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 |
| *******************************************************************************/ |
| |
| |
| /** |
| * Estimates rate constants for a scenario |
| */ |
| public class ScenarioParameterEstimator { |
| |
| /** |
| * The scenario data used for estimation |
| */ |
| |
| ReferenceScenarioDataMapImpl referenceScenarioDataMap = null; |
| |
| /** |
| * The Parameter Estimator method we use |
| */ |
| |
| ParameterEstimatorMethod parameterEstimatorMethod = null; |
| |
| /** |
| * This Set will contain locations with "good" data. Good data implies that at least |
| * the "I" state is defined and that maximum number of poeple in the "I" state at some time |
| * is large enough for the estimator to return an approximate beta coefficient |
| */ |
| Set<String> referenceLocations; |
| |
| /** |
| * areas of the reference locations |
| * loaded from the scenario graph by ID |
| */ |
| Map<String,Double> referenceAreaDataMap; |
| |
| /** |
| * populations of the reference locations |
| * loaded from the scenario graph by ID |
| */ |
| Map<String,Double> referencePopulationDataMap; |
| |
| /** |
| * remember the max Infectious at each location |
| */ |
| Map<String,Double> maxInfectiousMap = new HashMap<String,Double>(); |
| |
| ParameterEstimator estimator; |
| |
| /** |
| * Prefix for area. Format is |
| * stem://org.eclipse.stem/label/area/USA/2/US-GA-13307 |
| */ |
| private static final String AREA_URI_PREFIX = org.eclipse.stem.definitions.labels.AreaLabel.URI_TYPE_AREA_LABEL_SEGMENT; |
| |
| /** |
| * prefix for population. Format is |
| * stem://org.eclipse.stem/label/population/USA/2/US-GA-13307/human |
| * |
| */ |
| private static final String POPULATION_URI_PREFIX = org.eclipse.stem.definitions.labels.PopulationLabel.URI_TYPE_POPULATION_LABEL_SEGMENT; |
| |
| /** |
| * TODO make gui item |
| * syntax is |
| * stem://org.eclipse.stem/label/population/ISR/2/human/2006/IL-05-623 |
| * Human only for now |
| */ |
| private static final String SPECIES = "human"; |
| |
| |
| /** |
| * analysis mode using ALL data including zeros |
| */ |
| public static final int ALL_MODE = 0; |
| |
| /** |
| * analysis mode analyzing data only when S,E,I,R are all > 0.0; |
| */ |
| public static final int NON_ZERO_DATA_MODE = 1; |
| |
| |
| /** |
| * constant |
| */ |
| public static final String LEVEL_STRING = "level"; |
| |
| // fit all locations with max infectious populations >= FITTING_FRACTION * LARGEST Infectious Population |
| private static final double FITTING_FRACTION = 0.05; |
| |
| /** |
| * The parent control |
| */ |
| protected EstimatorControl control = null; |
| |
| /** |
| * |
| * @param scenarioDataMap |
| * @param parameterEstimatorMethod |
| */ |
| public ScenarioParameterEstimator(ReferenceScenarioDataMapImpl scenarioDataMap, ParameterEstimatorMethod parameterEstimatorMethod) { |
| referenceScenarioDataMap = scenarioDataMap; |
| this.parameterEstimatorMethod = parameterEstimatorMethod; |
| referenceLocations = getReferenceLocations(); |
| getAreaDataMap(); |
| getPopulationDataMap(); |
| } |
| |
| /** |
| * Estimate the rate parameters from the existing scenario data |
| * @param controlParamtersMap |
| * @param runnableContext Context for long running tasks |
| * @return map of parameters |
| */ |
| public Map<String,ModelParameters> estimateParameters(Map<String,Object> controlParamtersMap, IRunnableContext runnableContext) { |
| final Map<String,Object> finalParameterMap = controlParamtersMap; |
| |
| final ParameterEstimatorMethod method = this.parameterEstimatorMethod; |
| |
| IScenarioParameterEstimatorRunnableWithProgress analysisTask = new IScenarioParameterEstimatorRunnableWithProgress() { |
| public Map<String,ModelParameters> fittedParameters = new HashMap<String,ModelParameters>(); |
| public void run(IProgressMonitor progress) { |
| Iterator<String> iter = referenceLocations.iterator(); |
| int icount = 0; |
| progress.beginTask("Estimating parameters", referenceLocations.size()); |
| // TODO START this code exists only to TEST the CycleCompressor class |
| // TODO START this code exists only to TEST the CycleCompressor class |
| // TODO SHOULD EVENTUALLY BE PART OF RONI's new VIEW |
| //List<String> allIDs = new ArrayList<String>(); |
| //List<double[]> allCompressedIncidence = new ArrayList<double[]>(); |
| // TODO END this code exists only to TEST the CycleCompressor class |
| // TODO END this code exists only to TEST the CycleCompressor class |
| |
| |
| while(iter.hasNext()) { |
| icount ++; |
| //if (icount%100==0) Activator.logInformation("."); |
| |
| String id = iter.next(); |
| |
| ReferenceScenarioDataInstance locationDataMap = referenceScenarioDataMap.getLocation(id); |
| |
| // TODO START this code exists only to TEST the CycleCompressor class |
| // TODO START this code exists only to TEST the CycleCompressor class |
| // TODO SHOULD EVENTUALLY BE PART OF RONI's new VIEW |
| //allIDs.add(id); |
| //CycleCompressor compressor = new CycleCompressor(locationDataMap); |
| //double[] result = compressor.getCompressedData(); |
| //allCompressedIncidence.add(result); |
| // TODO END this code exists only to TEST the CycleCompressor class |
| // TODO END this code exists only to TEST the CycleCompressor class |
| |
| |
| estimator = ParameterEstimatorFactory.createEstimator(method, locationDataMap); |
| estimator.setAllParameters(finalParameterMap); |
| |
| double localArea = getArea(id).doubleValue(); |
| assert(localArea > 0.0); |
| if(localArea == 0) localArea = 1.0; // should never happen |
| final double localPopulation = getPopulation(id).doubleValue(); |
| final double localDensity = localPopulation/localArea; |
| ModelParameters parameters = estimator.estimate(localDensity, localPopulation,id); |
| //Activator.logInformation("got parameters "+parameters.toString()); |
| fittedParameters.put(id, parameters); |
| if (progress.isCanceled()) |
| throw new OperationCanceledException(); |
| progress.worked(1); |
| } // while |
| |
| // TODO START this code exists only to TEST the CycleCompressor class |
| // TODO START this code exists only to TEST the CycleCompressor class |
| // TODO SHOULD EVENTUALLY BE PART OF RONI's new VIEW |
| //CSVAnalysisWriter writer = new CSVAnalysisWriter("C:/runtime-stem.product/Mecids/recordedsimulations/Influenza/cycleCompressed/","Incidence"); |
| //writer.logData(allIDs, allCompressedIncidence); |
| // TODO END this code exists only to TEST the CycleCompressor class |
| // TODO END this code exists only to TEST the CycleCompressor class |
| |
| |
| |
| |
| progress.done(); |
| } |
| |
| /** |
| * Return the fitted parameters |
| * @return Map<String, ModelParameters> result |
| */ |
| public Map<String, ModelParameters> getFittedParameters() { |
| return this.fittedParameters; |
| } |
| }; |
| try { |
| runnableContext.run(true, true, analysisTask); |
| } catch(InterruptedException ie) { |
| Activator.logError("", ie); |
| return null; |
| } catch(InvocationTargetException ite) { |
| Activator.logError("", ite); |
| return null; |
| } |
| return analysisTask.getFittedParameters(); |
| }//estimateParameters() |
| |
| /** |
| * Average All data THEN Estimate the rate parameters from the averaged scenario data |
| * @param controlParamtersMap |
| * @param runnableContext Context for long running tasks |
| * @return map of parameters |
| */ |
| public ModelParameters averageThenEstimateParameters(Map<String,Object> controlParamtersMap, IRunnableContext runnableContext) { |
| final Map<String,Object> finalParameterMap = controlParamtersMap; |
| final ParameterEstimatorMethod method = this.parameterEstimatorMethod; |
| |
| IAveragedParameterEstimatorRunnableWithProgress analysisTask = new IAveragedParameterEstimatorRunnableWithProgress() { |
| ModelParameters modelParameters = null; |
| public void run(IProgressMonitor progress) { |
| Iterator<String> iter = referenceLocations.iterator(); |
| |
| progress.beginTask("Averaging data", referenceLocations.size()); |
| ReferenceScenarioDataInstance averagedDataMap = null; |
| double localArea = 0.0; |
| double localPopulation = 0.0; |
| referenceScenarioDataMap.findMaxIncidence(); |
| String idMax = referenceScenarioDataMap.getMaxIncidenceLocation(); |
| //double max = referenceScenarioDataMap.getMaxIncidence(); |
| //Activator.logInformation(" max incidence is "+max+" at "+idMax); |
| localArea += getArea(idMax).doubleValue(); |
| localPopulation += getPopulation(idMax).doubleValue(); |
| ReferenceScenarioDataInstance maxlocationDataMap = referenceScenarioDataMap.getLocation(idMax); |
| averagedDataMap = maxlocationDataMap.clone(); |
| // PhaseSynchronizer synchronizer = new PhaseSynchronizer(averagedDataMap); |
| |
| while(iter.hasNext()) { |
| String id = iter.next(); |
| if(!id.equalsIgnoreCase(idMax)) { |
| localArea += getArea(id).doubleValue(); |
| localPopulation += getPopulation(id).doubleValue(); |
| ReferenceScenarioDataInstance locationDataMap = referenceScenarioDataMap.getLocation(id); |
| averagedDataMap.integrateData(locationDataMap.instance); |
| } |
| } |
| |
| estimator = ParameterEstimatorFactory.createEstimator(method, averagedDataMap); |
| estimator.setAllParameters(finalParameterMap); |
| assert(localArea > 0.0); |
| if(localArea == 0) localArea = 1.0; // should never happen |
| final double localDensity = localPopulation/localArea; |
| |
| modelParameters = estimator.estimate(localDensity, localPopulation, Messages.getString("EST.AVERAGE")); |
| |
| if (progress.isCanceled()) |
| throw new OperationCanceledException(); |
| progress.worked(1); |
| |
| progress.done(); |
| } |
| |
| /** |
| * Return the fitted parameters |
| * @return Map<String, ModelParameters> result |
| */ |
| public ModelParameters getModelParameters() { |
| return this.modelParameters; |
| } |
| }; |
| try { |
| runnableContext.run(true, true, analysisTask); |
| } catch(InterruptedException ie) { |
| Activator.logError("", ie); |
| return null; |
| } catch(InvocationTargetException ite) { |
| Activator.logError("", ite); |
| return null; |
| } |
| return analysisTask.getModelParameters(); |
| }//averageThenEstimateParameters() |
| |
| /** |
| * Returns a set of locations where the max Infectious population satisfies the criterion: |
| * localMaxI >= FITTING_FRACTION*globalMaxI |
| * There is not point in analyzing locations where no-one gets sick |
| * @return set of referenceLocations |
| */ |
| private Set<String> getReferenceLocations() { |
| Set<String> locationsToFit = new HashSet<String>(); |
| Set<String> allLocations = referenceScenarioDataMap.getLocations(); |
| |
| double globalMaxI = 0.0; |
| |
| // 1. get the local max infectious count by region id for all regions |
| Iterator<String> iter = allLocations.iterator(); |
| while((iter!=null)&&(iter.hasNext())) { |
| String id = iter.next(); |
| ReferenceScenarioDataInstance locationDataMap = referenceScenarioDataMap.getLocation(id); |
| List<Double> iData = locationDataMap.getItotals(); |
| double localMax = 0.0; |
| |
| for(int i = 0; i < iData.size(); i ++) { |
| double infectious = iData.get(i).doubleValue(); |
| if (localMax < infectious) localMax = infectious; |
| if (globalMaxI < localMax) globalMaxI = localMax; |
| } |
| maxInfectiousMap.put(id,new Double(localMax)); |
| |
| } |
| |
| // 2. Select those regions with max infectious count >= FITTING_FRACTION * LARGEST Infectious Population |
| Iterator<String> iter2 = maxInfectiousMap.keySet().iterator(); |
| while((iter2!=null)&&(iter2.hasNext())) { |
| String id = iter2.next(); |
| double localMaxI = maxInfectiousMap.get(id).doubleValue(); |
| if (localMaxI >= FITTING_FRACTION*globalMaxI) { |
| locationsToFit.add(id); |
| } |
| |
| } |
| |
| return locationsToFit; |
| } |
| |
| /** |
| * |
| * @param ID |
| * @return |
| */ |
| Double getArea(String id) { |
| double area = 0.0; |
| URI uri = getAreaURI(id); |
| // New utility method |
| AreaLabel areaLabel = (AreaLabel)org.eclipse.stem.ui.Utility.getLabel(uri); |
| if(areaLabel==null) Activator.logError("area label is null", new NumberFormatException("null area")); |
| area = areaLabel.getCurrentAreaValue().getArea(); |
| return new Double(area); |
| } |
| |
| /** |
| * |
| * @param ID |
| * @return |
| */ |
| Double getPopulation(String id) { |
| double pop = 0.0; |
| URI uri = getPopulationURI(id); |
| // New utility method |
| PopulationLabel popLabel = (PopulationLabel)org.eclipse.stem.ui.Utility.getLabel(uri); |
| if(popLabel==null) Activator.logError("Population label is null", new NumberFormatException("null population")); |
| pop = popLabel.getCurrentPopulationValue().getCount(); |
| return new Double(pop); |
| } |
| |
| /** |
| * |
| * @return the area map |
| */ |
| Map<String,Double> getAreaDataMap() { |
| Map<String,Double> areaMap = new HashMap<String,Double>(); |
| Iterator<String> iter = referenceLocations.iterator(); |
| while(iter.hasNext()) { |
| String id = iter.next(); |
| Double area = getArea(id); |
| areaMap.put(id, area); |
| } |
| return areaMap; |
| } |
| |
| /** |
| * |
| * @return the population map |
| */ |
| Map<String,Double> getPopulationDataMap() { |
| Map<String,Double> popMap = new HashMap<String,Double>(); |
| Iterator<String> iter = referenceLocations.iterator(); |
| while(iter.hasNext()) { |
| String id = iter.next(); |
| Double population = getPopulation(id); |
| popMap.put(id, population); |
| } |
| return popMap; |
| } |
| |
| /** |
| * convert a List of String into and array of double |
| * @param dataList |
| * @return double[] of values |
| */ |
| public static double[] getDoubleValues(List<String> dataList) { |
| double[] retValue = new double[dataList.size()]; |
| try { |
| for (int i = 0; i < dataList.size(); i ++) { |
| Double dbleObj = new Double(dataList.get(i)); |
| retValue[i] = dbleObj.doubleValue(); |
| } |
| } catch(Exception e) { |
| Activator.logError("String Data not valid. Expecting Double values", e); |
| } |
| |
| return retValue; |
| } |
| |
| |
| |
| /** |
| * @return the Estimator |
| */ |
| public ParameterEstimator getEstimator() { |
| return estimator; |
| } |
| |
| |
| /** |
| * |
| * @param id |
| * @return |
| */ |
| URI getAreaURI(String id) { |
| int level = getLevel(id); |
| String countryCode; |
| // need uri of form: stem://org.eclipse.stem/label/area/USA/2/US-GA-13307 |
| if (level == 0) { |
| countryCode = id; |
| } else { |
| String twoLetterCode = id.substring(0,2); |
| countryCode = org.eclipse.stem.data.geography.GeographicMapper.getAlpha3(twoLetterCode); |
| } |
| String composite = "stem://org.eclipse.stem/"+AREA_URI_PREFIX + "/" + countryCode +"/"+getLevel(id)+"/"+id; |
| URI uri = URI.createURI(composite); |
| return uri; |
| }// getAreaURI |
| |
| |
| /** |
| * |
| * @param id |
| * @return |
| */ |
| URI getPopulationURI(String id) { |
| int level = getLevel(id); |
| String countryCode; |
| // compose the input string |
| if (level == 0) { |
| countryCode = id; |
| } else { |
| String twoLetterCode = id.substring(0,2); |
| countryCode = org.eclipse.stem.data.geography.GeographicMapper.getAlpha3(twoLetterCode); |
| } |
| // syntax is |
| // stem://org.eclipse.stem/label/population/ISR/2/human/2006/IL-05-623 |
| |
| // Hack to fix year problem. We don't know the year, try until we guess right |
| String composite = null; |
| for(int year=2000;year<2020;++year) { |
| composite = "stem://org.eclipse.stem/"+POPULATION_URI_PREFIX + "/" + countryCode +"/"+getLevel(id)+"/"+SPECIES+"/"+year+"/"+id; |
| |
| try { |
| final URI populationGraphURI = Utility.createPopulationGraphURI(URI.createURI(composite)); |
| |
| // need to catch any exception here...we take the data for any year for this estimate |
| final ResourceSet resourceSet = new ResourceSetImpl(); |
| resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new XMIResourceFactoryImpl()); |
| resourceSet.getResourceFactoryRegistry().getProtocolToFactoryMap().put("platform", new XMIResourceFactoryImpl()); |
| final Resource resource = resourceSet.getResource(populationGraphURI,true); |
| Identifiable ident = (Identifiable) resource.getContents().get(0); |
| final Graph populationGraph = (Graph) ident; |
| |
| // did we get the data |
| if(populationGraph != null) break; |
| } catch (Exception e) { |
| //do nothing. not an error Activator.logInformation("No Error looking for data: "+composite); |
| } |
| |
| } |
| URI uri = URI.createURI(composite); |
| return uri; |
| }// getPopulationURI |
| |
| /** |
| * finds the admin level of the id by counting '-' characters |
| * @param id |
| * @return |
| */ |
| private int getLevel(String id) { |
| |
| if(id.indexOf("-") ==-1) return 0; |
| |
| int idx1 = id.indexOf("-"); |
| String firstPart = id.substring(idx1+1,id.length()); |
| if(firstPart.indexOf("-") ==-1) return 1; |
| |
| int idx2 = firstPart.indexOf("-"); |
| String secondPart = firstPart.substring(idx2+1,firstPart.length()); |
| if(secondPart.indexOf("-") ==-1) return 2; |
| |
| |
| int idx3 = secondPart.indexOf("-"); |
| String thirdPart = secondPart.substring(idx3+1,secondPart.length()); |
| if(thirdPart.indexOf("-") ==-1) { |
| return 3; |
| } |
| // TODO should generalize this. |
| return 4; // two levels past where we now have data.... |
| |
| } |
| |
| |
| |
| |
| |
| /** |
| * Internal interface for long running task |
| */ |
| private interface IScenarioParameterEstimatorRunnableWithProgress extends IRunnableWithProgress { |
| /** |
| * Return the fitted parameters |
| * @return Map<String, ModelParameters> result |
| */ |
| public Map<String, ModelParameters> getFittedParameters(); |
| } |
| |
| |
| |
| /** |
| * Internal interface for long running task |
| */ |
| private interface IAveragedParameterEstimatorRunnableWithProgress extends IRunnableWithProgress { |
| /** |
| * Return the fitted parameters |
| * @return ModelParameters result |
| */ |
| public ModelParameters getModelParameters(); |
| } |
| |
| /** |
| * Get the values to plot from the estimator |
| * @param chartIndex |
| * @param state |
| * @return the array of data to plot |
| */ |
| public double[] getValues(int chartIndex, int state) { |
| return estimator.getValues(chartIndex, state); |
| } |
| |
| }// getLevel |