teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5863: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5863: * documentation coming with Dive4Elements River for details. teichmann@5863: */ teichmann@5863: teichmann@5831: package org.dive4elements.river.artifacts.model.minfo; teichmann@5778: teichmann@5831: import org.dive4elements.artifactdatabase.state.Facet; teichmann@5778: teichmann@5831: import org.dive4elements.artifacts.Artifact; teichmann@5831: import org.dive4elements.artifacts.CallContext; teichmann@5778: teichmann@5831: import org.dive4elements.river.artifacts.FLYSArtifact; teichmann@5778: teichmann@5831: import org.dive4elements.river.artifacts.model.CalculationResult; teichmann@5831: import org.dive4elements.river.artifacts.model.DataFacet; teichmann@5831: import org.dive4elements.river.artifacts.model.FacetTypes; teichmann@5831: teichmann@5831: import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; teichmann@5831: teichmann@5831: import org.dive4elements.river.model.MeasurementStation; teichmann@5831: teichmann@5831: import org.dive4elements.river.utils.FLYSUtils; rrenkert@4372: felix@5645: import java.util.ArrayList; felix@5653: import java.util.Collections; felix@5645: import java.util.List; felix@5653: import java.util.Map; felix@5653: import java.util.TreeMap; felix@5645: teichmann@5778: import org.apache.log4j.Logger; felix@5645: rrenkert@4372: felix@5647: /** Facet to access various sediment loads. */ rrenkert@4372: public class SedimentLoadFacet rrenkert@4372: extends DataFacet rrenkert@4372: { felix@5645: /** Very own logger. */ rrenkert@4372: private static Logger logger = Logger.getLogger(SedimentLoadFacet.class); rrenkert@4372: felix@5647: /** Used as tolerance value when fetching measurement stations. */ felix@5645: private static double EPSILON = 1e-5; felix@5645: felix@5647: rrenkert@4372: public SedimentLoadFacet() { rrenkert@4372: } rrenkert@4372: rrenkert@4372: public SedimentLoadFacet(int idx, String name, String description, rrenkert@4372: ComputeType type, String stateId, String hash) { rrenkert@4372: super(idx, name, description, type, hash, stateId); rrenkert@4372: } rrenkert@4372: rrenkert@4372: public Object getData(Artifact artifact, CallContext context) { rrenkert@4372: logger.debug("Get data for sediment load at index: " + index); rrenkert@4372: rrenkert@4372: FLYSArtifact flys = (FLYSArtifact) artifact; rrenkert@4372: rrenkert@4372: CalculationResult res = (CalculationResult) flys.compute(context, hash, rrenkert@4372: stateId, type, false); rrenkert@4372: rrenkert@4372: Object[] data = rrenkert@4372: (SedimentLoadResult[]) res.getData(); // TODO CAST TO SPECIFIC CLASS rrenkert@4372: felix@5645: List allStations = FLYSUtils.getRiver(flys).getMeasurementStations(); felix@5645: SedimentLoadResult result = data != null && data.length > index ? (SedimentLoadResult)data[index] : null; felix@5645: if (result == null) { felix@5645: return null; felix@5645: } felix@5645: felix@5653: List sortedStarts = new ArrayList(); felix@5645: // Filter stations according to type. felix@5645: List stations = new ArrayList(); felix@5645: for (MeasurementStation station: allStations) { felix@5645: if (station.getRange() == null || station.getMeasurementType() == null) { felix@5645: continue; felix@5645: } felix@5647: if (FacetTypes.IS.SEDIMENT_LOAD_NO_FLOAT(this.getName()) felix@5653: && station.getMeasurementType().equals("Geschiebe")) { felix@5645: stations.add(station); felix@5653: sortedStarts.add(station.getStation()); felix@5653: } felix@5647: else if (!FacetTypes.IS.SEDIMENT_LOAD_NO_FLOAT(this.getName()) felix@5653: && station.getMeasurementType().equals("Schwebstoff")) { felix@5645: stations.add(station); felix@5653: sortedStarts.add(station.getStation()); felix@5653: } felix@5645: } felix@5653: Collections.sort(sortedStarts); felix@5645: felix@5645: // Access data according to type. felix@5648: double[][] sd = getLoadData(result); felix@5645: felix@5653: // Sort by km. felix@5653: TreeMap sortData = new TreeMap(); felix@5653: felix@5645: double[] km = sd[0]; felix@5645: double[] load = sd[1]; felix@5645: felix@5653: for (int i = 0 ; i < km.length; i++) { felix@5653: sortData.put(km[i], load[i]); felix@5653: } felix@5653: felix@5645: double[][] values = new double[2][]; felix@5653: values[0] = new double[km.length*3]; felix@5653: values[1] = new double[km.length*3]; felix@5653: felix@5653: List kmWithoutStation = new ArrayList(); felix@5645: felix@5645: // Find station via its station (km). felix@5653: // TODO use a binarySearch instead of linear absdiff approach felix@5653: int i = 0; felix@5653: for (Map.Entry entry: sortData.entrySet()) { felix@5645: boolean matchFound = false; felix@5653: // For now, ignore overlaps like (B> next A) felix@5645: for (MeasurementStation station: stations) { felix@5744: if (Math.abs(station.getStation() - entry.getKey()) < EPSILON || felix@5744: station.getRange().containsTolerant(entry.getKey())) { felix@5744: // TODO: In rare cases, two matches can be found. felix@5653: values[0][i*3] = station.getRange().getA().doubleValue() + EPSILON; felix@5653: values[1][i*3] = entry.getValue(); felix@5653: values[0][i*3+1] = station.getRange().getB().doubleValue() - EPSILON; felix@5653: values[1][i*3+1] = entry.getValue(); felix@5653: values[0][i*3+2] = station.getRange().getB().doubleValue(); felix@5653: values[1][i*3+2] = entry.getValue(); felix@5645: matchFound = true; felix@5645: } felix@5645: } felix@5653: // Store points without match for later assessment. felix@5645: if (!matchFound) { felix@5744: logger.warn("measurement without station ("+entry.getKey()+")!"); felix@5653: } felix@5653: i++; felix@5653: } felix@5653: felix@5653: for (int x = 0; x < values[0].length-1; x++) { felix@5653: // Introduce gaps where no data in measurement station. felix@5653: if (Math.abs(values[0][x+1] - values[0][x]) > 3*EPSILON felix@5653: && values[1][x+1] != values[1][x]) { felix@5653: values[0][x] = Double.NaN; felix@5653: values[1][x] = Double.NaN; felix@5645: } felix@5645: } felix@5653: felix@5645: return values; rrenkert@4372: } rrenkert@4372: felix@5645: felix@5648: /** Get data according to type of facet. */ felix@5648: private double[][] getLoadData(SedimentLoadResult result) { felix@5648: if (getName().equals(FacetTypes.SEDIMENT_LOAD_SAND)) felix@5648: return result.getSandData(); felix@5648: else if (getName().equals(FacetTypes.SEDIMENT_LOAD_COARSE)) felix@5648: return result.getCoarseData(); felix@5648: else if (getName().equals(FacetTypes.SEDIMENT_LOAD_FINEMIDDLE)) felix@5648: return result.getFineMiddleData(); felix@5648: else if (getName().equals(FacetTypes.SEDIMENT_LOAD_SUSP_SAND)) felix@5648: return result.getSuspSandData(); felix@5648: else if (getName().equals(FacetTypes.SEDIMENT_LOAD_SUSP_SAND_BED)) felix@5648: return result.getSuspSandBedData(); felix@5648: else if (getName().equals(FacetTypes.SEDIMENT_LOAD_SUSP_SEDIMENT)) felix@5648: return result.getSuspSedimentData(); felix@5648: else if (getName().equals(FacetTypes.SEDIMENT_LOAD_TOTAL_LOAD)) felix@5648: return result.getTotalLoadData(); felix@5648: else if (getName().equals(FacetTypes.SEDIMENT_LOAD_TOTAL)) felix@5648: return result.getTotalData(); felix@5648: else { felix@5648: logger.error("SedimentLoadFacet " + getName() + " cannot determine data type."); felix@5648: return null; felix@5648: } felix@5648: } felix@5648: rrenkert@4372: /** Copy deeply. */ rrenkert@4372: @Override rrenkert@4372: public Facet deepCopy() { rrenkert@4372: SedimentLoadFacet copy = new SedimentLoadFacet(); rrenkert@4372: copy.set(this); rrenkert@4372: copy.type = type; rrenkert@4372: copy.hash = hash; rrenkert@4372: copy.stateId = stateId; rrenkert@4372: return copy; rrenkert@4372: } rrenkert@4372: } rrenkert@4372: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :