# HG changeset patch # User Andre Heinecke # Date 1408118621 -7200 # Node ID 8a5466f82b70b26c7aa7a0f1cdc75020149c21a4 # Parent 01f778f843305d4c12265a7ea0539f201498fa2a# Parent 7e55790da464499528c217a54fa1568ba55b69f2 merge diff -r 7e55790da464 -r 8a5466f82b70 artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadDataFacet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadDataFacet.java Fri Aug 15 18:03:41 2014 +0200 @@ -0,0 +1,238 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.model.minfo; + +import gnu.trove.TDoubleArrayList; + +import org.dive4elements.artifactdatabase.state.Facet; + +import org.dive4elements.artifacts.Artifact; +import org.dive4elements.artifacts.CallContext; + +import org.dive4elements.river.artifacts.D4EArtifact; + +import org.dive4elements.river.artifacts.model.CalculationResult; +import org.dive4elements.river.artifacts.model.DataFacet; +import org.dive4elements.river.artifacts.model.FacetTypes; + +import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; + +import org.dive4elements.river.model.MeasurementStation; + +import org.dive4elements.river.utils.RiverUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.TreeMap; + +import org.apache.log4j.Logger; + + +/** 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); + this.metaData.put("X", "chart.longitudinal.section.xaxis.label"); + this.metaData.put("Y", ""); + } + + @Override + public Object getData(Artifact artifact, CallContext context) { + logger.debug("Get data for sediment load at index: " + index); + + D4EArtifact flys = (D4EArtifact) artifact; + + CalculationResult res = (CalculationResult) flys.compute(context, hash, + stateId, type, false); + + Object[] data = + (SedimentLoadResult[]) res.getData(); // TODO CAST TO SPECIFIC CLASS + + List allStations = RiverUtils.getRiver(flys).getMeasurementStations(); + SedimentLoadResult result = data != null && data.length > index ? (SedimentLoadResult)data[index] : null; + if (result == null) { + return null; + } + + // These complicated calculations were necessary because + // SedimentLoad/Fraction did not contain the ranges of the given + // values. Since this changed, the code is somewhat obsolete, but stable. + // For an example of easier calculation, see the "total" part below. + + List sortedStarts = new ArrayList(); + // Filter stations according to type. + List stations = new ArrayList(); + for (MeasurementStation station: allStations) { + if (station.getRange() == null || station.getMeasurementType() == null) { + continue; + } + if (this.getName().contains("susp_sediment") + && station.getMeasurementType().equals("Schwebstoff")) { + stations.add(station); + sortedStarts.add(station.getStation()); + } + else if (!this.getName().contains("susp_sediment") + && station.getMeasurementType().equals("Geschiebe")) { + stations.add(station); + sortedStarts.add(station.getStation()); + } + } + Collections.sort(sortedStarts); + + // Handle sediment load differently, as it respects already + // the ranges that were added to SedimentLoad/Fraction. + if (getName().equals(FacetTypes.SEDIMENT_LOAD_TA_TOTAL) + ||getName().equals(FacetTypes.SEDIMENT_LOAD_M3A_TOTAL)) { + SedimentLoadLSData load = result.getLoad(); + TDoubleArrayList xPos = new TDoubleArrayList(); + TDoubleArrayList yPos = new TDoubleArrayList(); + double lastX = -1d; + for (double km: new TreeSet(load.getKms())) { + SedimentLoadFraction fraction = load.getFraction(km); + if (fraction.getTotal() != 0) { + if (Math.abs(lastX-km) >= EPSILON) { + xPos.add(Double.NaN); + yPos.add(Double.NaN); + } + xPos.add(km); + yPos.add(fraction.getTotal()); + xPos.add(fraction.getTotalRange().getEnd()); + yPos.add(fraction.getTotal()); + lastX = fraction.getTotalRange().getEnd(); + } + } + return new double[][] {xPos.toNativeArray(), yPos.toNativeArray()}; + } + + // Access data according to type (except total - see above). + double[][] sd = getLoadData(result); + + // Sort by km. + TreeMap sortedKmLoad = new TreeMap(); + + double[] km = sd[0]; + double[] load = sd[1]; + + // Build map of km->load, but directly exclude the ones which do + // not match against a measurements station ranges start. + for (int i = 0 ; i < km.length; i++) { + for (MeasurementStation station: stations) { + if (Math.abs(station.getStation() - km[i]) <= EPSILON) { + sortedKmLoad.put(km[i], load[i]); + continue; + } + } + } + + // [0] -> x, [1] -> y + double[][] values = new double[2][]; + values[0] = new double[sortedKmLoad.size()*3]; + values[1] = new double[sortedKmLoad.size()*3]; + + // Find station via its station (km). + // TODO use a binarySearch instead of linear absdiff approach + int i = 0; + for (Map.Entry kmLoad: sortedKmLoad.entrySet()) { + boolean matchFound = false; + for (int k = 0, S = stations.size(); k < S; k++) { + MeasurementStation station = stations.get(k); + if (Math.abs(station.getStation() - kmLoad.getKey()) < EPSILON) { + // Value has been taken at measurement station. + values[0][i*3] = station.getRange().getA().doubleValue() + EPSILON; + values[1][i*3] = kmLoad.getValue(); + double endValue = 0d; + // Valid until next measurements stations begin of range, + // or end of current range if last value. + if (k+2 <= S) { + endValue = stations.get(k+1).getRange().getA().doubleValue(); + } + else { + endValue = station.getRange().getB().doubleValue(); + } + values[0][i*3+1] = endValue; + values[1][i*3+1] = kmLoad.getValue(); + values[0][i*3+2] = endValue; + values[1][i*3+2] = kmLoad.getValue(); + matchFound = true; + break; + } + } + // Store points without match for later assessment. + if (!matchFound) { + logger.warn("measurement without station ("+kmLoad.getKey()+")!"); + } + i++; + } + + for (int x = 0; x < values[0].length-1; x++) { + // 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) { + String name = getName(); + if (FacetTypes.IS.SEDIMENT_LOAD_SAND(name)) + return result.getSandData(); + else if (FacetTypes.IS.SEDIMENT_LOAD_COARSE(name)) + return result.getCoarseData(); + else if (FacetTypes.IS.SEDIMENT_LOAD_FINEMIDDLE(name)) + return result.getFineMiddleData(); + else if (FacetTypes.IS.SEDIMENT_LOAD_SUSP_SAND(name)) + return result.getSuspSandData(); + else if (FacetTypes.IS.SEDIMENT_LOAD_SUSP_SAND_BED(name)) + return result.getSuspSandBedData(); + else if (FacetTypes.IS.SEDIMENT_LOAD_SUSP_SEDIMENT(name)) + return result.getSuspSedimentData(); + else if (FacetTypes.IS.SEDIMENT_LOAD_TOTAL_LOAD(name)) + return result.getTotalLoadData(); + else if (FacetTypes.IS.SEDIMENT_LOAD_TOTAL(name)) + return result.getTotalData(); + else { + logger.error("SedimentLoadFacet " + name + " 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 : diff -r 7e55790da464 -r 8a5466f82b70 artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFacet.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFacet.java Fri Aug 15 18:01:06 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde - * Software engineering by Intevation GmbH - * - * This file is Free Software under the GNU AGPL (>=v3) - * and comes with ABSOLUTELY NO WARRANTY! Check out the - * documentation coming with Dive4Elements River for details. - */ - -package org.dive4elements.river.artifacts.model.minfo; - -import gnu.trove.TDoubleArrayList; - -import org.dive4elements.artifactdatabase.state.Facet; - -import org.dive4elements.artifacts.Artifact; -import org.dive4elements.artifacts.CallContext; - -import org.dive4elements.river.artifacts.D4EArtifact; - -import org.dive4elements.river.artifacts.model.CalculationResult; -import org.dive4elements.river.artifacts.model.DataFacet; -import org.dive4elements.river.artifacts.model.FacetTypes; - -import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; - -import org.dive4elements.river.model.MeasurementStation; - -import org.dive4elements.river.utils.RiverUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.TreeSet; -import java.util.TreeMap; - -import org.apache.log4j.Logger; - - -/** 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); - this.metaData.put("X", "chart.longitudinal.section.xaxis.label"); - this.metaData.put("Y", ""); - } - - @Override - public Object getData(Artifact artifact, CallContext context) { - logger.debug("Get data for sediment load at index: " + index); - - D4EArtifact flys = (D4EArtifact) artifact; - - CalculationResult res = (CalculationResult) flys.compute(context, hash, - stateId, type, false); - - Object[] data = - (SedimentLoadResult[]) res.getData(); // TODO CAST TO SPECIFIC CLASS - - List allStations = RiverUtils.getRiver(flys).getMeasurementStations(); - SedimentLoadResult result = data != null && data.length > index ? (SedimentLoadResult)data[index] : null; - if (result == null) { - return null; - } - - // These complicated calculations were necessary because - // SedimentLoad/Fraction did not contain the ranges of the given - // values. Since this changed, the code is somewhat obsolete, but stable. - // For an example of easier calculation, see the "total" part below. - - List sortedStarts = new ArrayList(); - // Filter stations according to type. - List stations = new ArrayList(); - for (MeasurementStation station: allStations) { - if (station.getRange() == null || station.getMeasurementType() == null) { - continue; - } - if (this.getName().contains("susp_sediment") - && station.getMeasurementType().equals("Schwebstoff")) { - stations.add(station); - sortedStarts.add(station.getStation()); - } - else if (!this.getName().contains("susp_sediment") - && station.getMeasurementType().equals("Geschiebe")) { - stations.add(station); - sortedStarts.add(station.getStation()); - } - } - Collections.sort(sortedStarts); - - // Handle sediment load differently, as it respects already - // the ranges that were added to SedimentLoad/Fraction. - if (getName().equals(FacetTypes.SEDIMENT_LOAD_TA_TOTAL) - ||getName().equals(FacetTypes.SEDIMENT_LOAD_M3A_TOTAL)) { - SedimentLoadLSData load = result.getLoad(); - TDoubleArrayList xPos = new TDoubleArrayList(); - TDoubleArrayList yPos = new TDoubleArrayList(); - double lastX = -1d; - for (double km: new TreeSet(load.getKms())) { - SedimentLoadFraction fraction = load.getFraction(km); - if (fraction.getTotal() != 0) { - if (Math.abs(lastX-km) >= EPSILON) { - xPos.add(Double.NaN); - yPos.add(Double.NaN); - } - xPos.add(km); - yPos.add(fraction.getTotal()); - xPos.add(fraction.getTotalRange().getEnd()); - yPos.add(fraction.getTotal()); - lastX = fraction.getTotalRange().getEnd(); - } - } - return new double[][] {xPos.toNativeArray(), yPos.toNativeArray()}; - } - - // Access data according to type (except total - see above). - double[][] sd = getLoadData(result); - - // Sort by km. - TreeMap sortedKmLoad = new TreeMap(); - - double[] km = sd[0]; - double[] load = sd[1]; - - // Build map of km->load, but directly exclude the ones which do - // not match against a measurements station ranges start. - for (int i = 0 ; i < km.length; i++) { - for (MeasurementStation station: stations) { - if (Math.abs(station.getStation() - km[i]) <= EPSILON) { - sortedKmLoad.put(km[i], load[i]); - continue; - } - } - } - - // [0] -> x, [1] -> y - double[][] values = new double[2][]; - values[0] = new double[sortedKmLoad.size()*3]; - values[1] = new double[sortedKmLoad.size()*3]; - - // Find station via its station (km). - // TODO use a binarySearch instead of linear absdiff approach - int i = 0; - for (Map.Entry kmLoad: sortedKmLoad.entrySet()) { - boolean matchFound = false; - for (int k = 0, S = stations.size(); k < S; k++) { - MeasurementStation station = stations.get(k); - if (Math.abs(station.getStation() - kmLoad.getKey()) < EPSILON) { - // Value has been taken at measurement station. - values[0][i*3] = station.getRange().getA().doubleValue() + EPSILON; - values[1][i*3] = kmLoad.getValue(); - double endValue = 0d; - // Valid until next measurements stations begin of range, - // or end of current range if last value. - if (k+2 <= S) { - endValue = stations.get(k+1).getRange().getA().doubleValue(); - } - else { - endValue = station.getRange().getB().doubleValue(); - } - values[0][i*3+1] = endValue; - values[1][i*3+1] = kmLoad.getValue(); - values[0][i*3+2] = endValue; - values[1][i*3+2] = kmLoad.getValue(); - matchFound = true; - break; - } - } - // Store points without match for later assessment. - if (!matchFound) { - logger.warn("measurement without station ("+kmLoad.getKey()+")!"); - } - i++; - } - - for (int x = 0; x < values[0].length-1; x++) { - // 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) { - String name = getName(); - if (FacetTypes.IS.SEDIMENT_LOAD_SAND(name)) - return result.getSandData(); - else if (FacetTypes.IS.SEDIMENT_LOAD_COARSE(name)) - return result.getCoarseData(); - else if (FacetTypes.IS.SEDIMENT_LOAD_FINEMIDDLE(name)) - return result.getFineMiddleData(); - else if (FacetTypes.IS.SEDIMENT_LOAD_SUSP_SAND(name)) - return result.getSuspSandData(); - else if (FacetTypes.IS.SEDIMENT_LOAD_SUSP_SAND_BED(name)) - return result.getSuspSandBedData(); - else if (FacetTypes.IS.SEDIMENT_LOAD_SUSP_SEDIMENT(name)) - return result.getSuspSedimentData(); - else if (FacetTypes.IS.SEDIMENT_LOAD_TOTAL_LOAD(name)) - return result.getTotalLoadData(); - else if (FacetTypes.IS.SEDIMENT_LOAD_TOTAL(name)) - return result.getTotalData(); - else { - logger.error("SedimentLoadFacet " + name + " 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 :