Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/SedimentLoadFacet.java @ 5653:5231e6b849ce
issue1077: Handle overlapping measurement station ranges, refactored Generator,
Allow gaps in graph (not sorting, living with NaNs).
author | Felix Wolfsteller <felix.wolfsteller@intevation.de> |
---|---|
date | Thu, 11 Apr 2013 10:52:56 +0200 |
parents | 4feda81c38bc |
children | 5bb179d4fd5f |
line wrap: on
line source
package de.intevation.flys.artifacts.model.minfo; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.TreeMap; import de.intevation.artifactdatabase.state.Facet; import de.intevation.artifacts.Artifact; import de.intevation.artifacts.CallContext; import de.intevation.flys.artifacts.FLYSArtifact; import de.intevation.flys.artifacts.model.CalculationResult; import de.intevation.flys.artifacts.model.DataFacet; import de.intevation.flys.model.MeasurementStation; import de.intevation.flys.artifacts.model.FacetTypes; import de.intevation.flys.artifacts.states.DefaultState.ComputeType; import de.intevation.flys.utils.FLYSUtils; /** Facet to access various sediment loads. */ public class SedimentLoadFacet extends DataFacet { /** Very own logger. */ private static Logger logger = Logger.getLogger(SedimentLoadFacet.class); /** Used as tolerance value when fetching measurement stations. */ private static double EPSILON = 1e-5; public SedimentLoadFacet() { } public SedimentLoadFacet(int idx, String name, String description, ComputeType type, String stateId, String hash) { super(idx, name, description, type, hash, stateId); } public Object getData(Artifact artifact, CallContext context) { logger.debug("Get data for sediment load at index: " + index); FLYSArtifact flys = (FLYSArtifact) artifact; CalculationResult res = (CalculationResult) flys.compute(context, hash, stateId, type, false); Object[] data = (SedimentLoadResult[]) res.getData(); // TODO CAST TO SPECIFIC CLASS List<MeasurementStation> allStations = FLYSUtils.getRiver(flys).getMeasurementStations(); SedimentLoadResult result = data != null && data.length > index ? (SedimentLoadResult)data[index] : null; if (result == null) { return null; } List<Double> sortedStarts = new ArrayList<Double>(); // Filter stations according to type. List<MeasurementStation> stations = new ArrayList<MeasurementStation>(); for (MeasurementStation station: allStations) { if (station.getRange() == null || station.getMeasurementType() == null) { continue; } if (FacetTypes.IS.SEDIMENT_LOAD_NO_FLOAT(this.getName()) && station.getMeasurementType().equals("Geschiebe")) { stations.add(station); sortedStarts.add(station.getStation()); } else if (!FacetTypes.IS.SEDIMENT_LOAD_NO_FLOAT(this.getName()) && station.getMeasurementType().equals("Schwebstoff")) { stations.add(station); sortedStarts.add(station.getStation()); } } Collections.sort(sortedStarts); // Access data according to type. double[][] sd = getLoadData(result); // Sort by km. TreeMap<Double, Double> sortData = new TreeMap<Double,Double>(); double[] km = sd[0]; double[] load = sd[1]; for (int i = 0 ; i < km.length; i++) { sortData.put(km[i], load[i]); } double[][] values = new double[2][]; values[0] = new double[km.length*3]; values[1] = new double[km.length*3]; List<double[]> kmWithoutStation = new ArrayList<double[]>(); // Find station via its station (km). // TODO use a binarySearch instead of linear absdiff approach int i = 0; for (Map.Entry<Double, Double> entry: sortData.entrySet()) { boolean matchFound = false; // For now, ignore overlaps like (B> next A) for (MeasurementStation station: stations) { if (Math.abs(station.getStation() - entry.getKey()) < EPSILON) { values[0][i*3] = station.getRange().getA().doubleValue() + EPSILON; values[1][i*3] = entry.getValue(); values[0][i*3+1] = station.getRange().getB().doubleValue() - EPSILON; values[1][i*3+1] = entry.getValue(); values[0][i*3+2] = station.getRange().getB().doubleValue(); values[1][i*3+2] = entry.getValue(); matchFound = true; } } // Store points without match for later assessment. if (!matchFound) { kmWithoutStation.add(new double[] {entry.getKey(), entry.getValue(), i}); } i++; } // Find fitting measurement stations for values without match. for (double misses[]: kmWithoutStation) { int idc = Math.abs(Collections.binarySearch(sortedStarts, misses[0])); double locationA = sortedStarts.get(idc-2); double locationB = sortedStarts.get(idc-1); values[0][(int)misses[2]*3] = locationA + EPSILON; values[1][(int)misses[2]*3] = misses[1]; values[0][(int)misses[2]*3+1] = locationB - EPSILON; values[1][(int)misses[2]*3+1] = misses[1]; values[0][(int)misses[2]*3+2] = locationB ; values[1][(int)misses[2]*3+2] = misses[1]; } for (int x = 0; x < values[0].length-1; x++) { // Correct measurement stationo overlap. if (values[0][x] > values[0][x+1]) { values[0][x+1] = values[0][x] + EPSILON; } // Introduce gaps where no data in measurement station. if (Math.abs(values[0][x+1] - values[0][x]) > 3*EPSILON && values[1][x+1] != values[1][x]) { values[0][x] = Double.NaN; values[1][x] = Double.NaN; } } return values; } /** Get data according to type of facet. */ private double[][] getLoadData(SedimentLoadResult result) { if (getName().equals(FacetTypes.SEDIMENT_LOAD_SAND)) return result.getSandData(); else if (getName().equals(FacetTypes.SEDIMENT_LOAD_COARSE)) return result.getCoarseData(); else if (getName().equals(FacetTypes.SEDIMENT_LOAD_FINEMIDDLE)) return result.getFineMiddleData(); else if (getName().equals(FacetTypes.SEDIMENT_LOAD_SUSP_SAND)) return result.getSuspSandData(); else if (getName().equals(FacetTypes.SEDIMENT_LOAD_SUSP_SAND_BED)) return result.getSuspSandBedData(); else if (getName().equals(FacetTypes.SEDIMENT_LOAD_SUSP_SEDIMENT)) return result.getSuspSedimentData(); else if (getName().equals(FacetTypes.SEDIMENT_LOAD_TOTAL_LOAD)) return result.getTotalLoadData(); else if (getName().equals(FacetTypes.SEDIMENT_LOAD_TOTAL)) return result.getTotalData(); else { logger.error("SedimentLoadFacet " + getName() + " cannot determine data type."); return null; } } /** Copy deeply. */ @Override public Facet deepCopy() { SedimentLoadFacet copy = new SedimentLoadFacet(); copy.set(this); copy.type = type; copy.hash = hash; copy.stateId = stateId; return copy; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :