# HG changeset patch # User Tom Gottfried # Date 1375976204 -7200 # Node ID bdbe704dd433bc4ee9c50acfa704b30fbc2c1ebd # Parent 962f6b805b48db22a14c3b227ef447bfed32dcc1# Parent 70b440dc53170d804e8f892be43f8ef45421b8d9 merged changes from default into longitudinal-symmetry branch diff -r 962f6b805b48 -r bdbe704dd433 artifacts/doc/conf/meta-data.xml --- a/artifacts/doc/conf/meta-data.xml Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/doc/conf/meta-data.xml Thu Aug 08 17:36:44 2013 +0200 @@ -347,6 +347,7 @@ + @@ -395,6 +396,7 @@ + diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurementFactory.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurementFactory.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurementFactory.java Thu Aug 08 17:36:44 2013 +0200 @@ -97,6 +97,7 @@ private QualityMeasurementResultTransformer() { } + /** tuples is a row. */ @Override public Object transformTuple(Object[] tuple, String[] aliases) { Map map = new HashMap(); @@ -175,6 +176,7 @@ return new QualityMeasurements(query.list()); } + /** Get all measurements. */ public static QualityMeasurements getBedMeasurements( String river, double from, diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java Thu Aug 08 17:36:44 2013 +0200 @@ -395,19 +395,24 @@ sqlQuery.setString("grain", "total"); List results = sqlQuery.list(); SedimentLoad load = new SedimentLoad(); - Object[] row = results.get(0); - load = new SedimentLoad( - (String) row[0], - (Date) row[1], - null, - false, - (String) row[4]); - getValues("coarse", sqlQuery, load, floatStations); - getValues("fine_middle", sqlQuery, load, floatStations); - getValues("sand", sqlQuery, load, floatStations); - getValues("suspended_sediment", sqlQuery, load, suspStations); - getValues("susp_sand_bed", sqlQuery, load, floatStations); - getValues("susp_sand", sqlQuery, load, floatStations); + if (results.isEmpty()) { + log.warn("Empty result for year calculation."); + } + else { + Object[] row = results.get(0); + load = new SedimentLoad( + (String) row[0], + (Date) row[1], + null, + false, + (String) row[4]); + } + load = getValues("coarse", sqlQuery, load, floatStations); + load = getValues("fine_middle", sqlQuery, load, floatStations); + load = getValues("sand", sqlQuery, load, floatStations); + load = getValues("suspended_sediment", sqlQuery, load, suspStations); + load = getValues("susp_sand_bed", sqlQuery, load, floatStations); + load = getValues("susp_sand", sqlQuery, load, floatStations); return load; } @@ -628,6 +633,7 @@ /** * Return sediment loads with 'unknown' fraction type. + * @param river Name of the river * @param unit Restrict result set to those of given unit. * @param type Type like year, epoch, off_epoch */ diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java Thu Aug 08 17:36:44 2013 +0200 @@ -9,7 +9,6 @@ package org.dive4elements.river.artifacts.model.sq; import org.dive4elements.river.artifacts.math.fitting.Function; -import org.dive4elements.river.artifacts.math.fitting.Linear; import java.util.ArrayList; import java.util.List; @@ -18,9 +17,8 @@ import org.apache.commons.math.optimization.fitting.CurveFitter; -import org.apache.commons.math.optimization.general.AbstractLeastSquaresOptimizer; -import org.apache.commons.math.optimization.general.GaussNewtonOptimizer; import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer; +import org.apache.commons.math.stat.regression.SimpleRegression; import org.apache.log4j.Logger; @@ -54,13 +52,15 @@ protected Callback callback; + protected SQ.View sqView; + public Fitting() { } - public Fitting(Function function, double stdDevFactor) { - this(); + public Fitting(Function function, double stdDevFactor, SQ.View sqView) { this.function = function; this.stdDevFactor = stdDevFactor; + this.sqView = sqView; } public Function getFunction() { @@ -82,57 +82,79 @@ @Override public void initialize(List sqs) throws MathException { - AbstractLeastSquaresOptimizer optimizer = getOptimizer(); + if (USE_NON_LINEAR_FITTING + || function.getInitialGuess().length != 2) { + nonLinearFitting(sqs); + } + else { + linearFitting(sqs); + } + } + + protected void linearFitting(List sqs) { + + coeffs = linearRegression(sqs); + + instance = function.instantiate(coeffs); + } + + protected double [] linearRegression(List sqs) { + + SimpleRegression reg = new SimpleRegression(); + + int invalidPoints = 0; + for (SQ sq: sqs) { + double s = sq.getS(); + double q = sq.getQ(); + if (s <= 0d || q <= 0d) { + ++invalidPoints; + continue; + } + reg.addData(Math.log(q), Math.log(s)); + } + + if (sqs.size() - invalidPoints < 2) { + log.debug("not enough points"); + return new double [] { 0, 0 }; + } + + double a = Math.exp(reg.getIntercept()); + double b = reg.getSlope(); + + if (log.isDebugEnabled()) { + log.debug("invalid points: " + + invalidPoints + " (" + sqs.size() + ")"); + log.debug("a: " + a + " (" + Math.log(a) + ")"); + log.debug("b: " + b); + } + + return new double [] { a, b }; + } + + + protected void nonLinearFitting(List sqs) throws MathException { + + LevenbergMarquardtOptimizer optimizer = + new LevenbergMarquardtOptimizer(); CurveFitter cf = new CurveFitter(optimizer); - double [] values = new double[2]; + for (SQ sq: sqs) { - values[0] = sq.getQ(); - values[1] = sq.getS(); - transformInputValues(values); - cf.addObservedPoint(values[0], values[1]); + cf.addObservedPoint(sq.getS(), sq.getQ()); } coeffs = cf.fit( function, function.getInitialGuess()); - transformCoeffsBack(coeffs); - instance = function.instantiate(coeffs); chiSqr = optimizer.getChiSquare(); } - protected Function getFunction(Function function) { - return USE_NON_LINEAR_FITTING - ? function - : Linear.INSTANCE; - } - - protected void transformInputValues(double [] values) { - if (!USE_NON_LINEAR_FITTING) { - for (int i = 0; i < values.length; ++i) { - values[i] = Math.log(values[i]); - } - } - } - - protected AbstractLeastSquaresOptimizer getOptimizer() { - return USE_NON_LINEAR_FITTING - ? new LevenbergMarquardtOptimizer() - : new GaussNewtonOptimizer(false); - } - - protected void transformCoeffsBack(double [] coeffs) { - if (!USE_NON_LINEAR_FITTING && coeffs.length > 0) { - coeffs[0] = Math.exp(coeffs[0]); - } - } - @Override public double eval(SQ sq) { - double s = instance.value(sq.q); - return sq.s - s; + double s = instance.value(sqView.getQ(sq)); + return sqView.getS(sq) - s; } @Override @@ -157,28 +179,15 @@ chiSqr); } - protected static final List onlyValid(List sqs) { - - List good = new ArrayList(sqs.size()); - - for (SQ sq: sqs) { - if (sq.isValid()) { - good.add(sq); - } - } - - return good; - } - - public boolean fit(List sqs, String method, Callback callback) { - - sqs = onlyValid(sqs); + public boolean fit(List sqs, String method, Callback callback) { if (sqs.size() < 2) { log.warn("Too less points for fitting."); return false; } + sqs = new ArrayList(sqs); + this.callback = callback; try { diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/MeasurementFactory.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/MeasurementFactory.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/MeasurementFactory.java Thu Aug 08 17:36:44 2013 +0200 @@ -190,9 +190,10 @@ } public static Measurements getMeasurements( - String river, - double location, - DateRange dateRange + String river, + double location, + DateRange dateRange, + SQ.Factory sqFactory ) { Session session = SedDBSessionHolder.HOLDER.get(); try { @@ -202,7 +203,7 @@ List accumulated = loadFractions( session, river, location, dateRange); - return new Measurements(totals, accumulated); + return new Measurements(totals, accumulated, sqFactory); } finally { session.close(); diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Measurements.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Measurements.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Measurements.java Thu Aug 08 17:36:44 2013 +0200 @@ -66,13 +66,17 @@ protected List measuments; protected List accumulated; + protected SQ.Factory sqFactory; + public Measurements() { } public Measurements( List measuments, - List accumulated + List accumulated, + SQ.Factory sqFactory ) { + this.sqFactory = sqFactory; if (log.isDebugEnabled()) { log.debug("number of measuments: " + measuments.size()); log.debug("number of accumulated: " + accumulated.size()); @@ -81,14 +85,14 @@ this.accumulated = accumulated; } - public static List extractSQ( + public List extractSQ( List measuments, SExtractor extractor ) { List result = new ArrayList(measuments.size()); int invalid = 0; for (Measurement measument: measuments) { - SQ sq = new SQ(extractor.getS(measument), measument.Q()); + SQ sq = sqFactory.createSQ(extractor.getS(measument), measument.Q()); if (sq.isValid()) { result.add(sq); } diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQ.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQ.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQ.java Thu Aug 08 17:36:44 2013 +0200 @@ -11,8 +11,37 @@ import java.io.Serializable; +/** Represents S/Q pairs. They are immutable! */ public class SQ implements Serializable { + public interface Factory { + SQ createSQ(double s, double q); + } + + public static final Factory SQ_FACTORY = new Factory() { + @Override + public SQ createSQ(double s, double q) { + return new SQ(s, q); + } + }; + + public interface View { + double getS(SQ sq); + double getQ(SQ sq); + } + + public static final View SQ_VIEW = new View() { + @Override + public double getS(SQ sq) { + return sq.getS(); + } + + @Override + public double getQ(SQ sq) { + return sq.getQ(); + } + }; + protected double s; protected double q; @@ -29,19 +58,10 @@ return s; } - public void setS(double s) { - this.s = s; - } - - public double getQ() { return q; } - public void setQ(double q) { - this.q = q; - } - public boolean isValid() { return !Double.isNaN(s) && !Double.isNaN(q); } diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java Thu Aug 08 17:36:44 2013 +0200 @@ -114,8 +114,12 @@ addProblem("sq.missing.sq.function"); } + SQ.View sqView = SQ.SQ_VIEW; + SQ.Factory sqFactory = SQ.SQ_FACTORY; + Measurements measurements = - MeasurementFactory.getMeasurements(river, location, period); + MeasurementFactory.getMeasurements( + river, location, period, sqFactory); SQFractionResult [] fractionResults = new SQFractionResult[SQResult.NUMBER_FRACTIONS]; @@ -126,7 +130,7 @@ SQFractionResult fractionResult; List iterations = - doFitting(function, sqs); + doFitting(function, sqs, sqView); if (iterations == null) { // TODO: i18n @@ -149,12 +153,13 @@ protected List doFitting( final Function function, - List sqs + List sqs, + SQ.View sqView ) { final List iterations = new ArrayList(); - boolean success = new Fitting(function, outliers).fit( + boolean success = new Fitting(function, outliers, sqView).fit( sqs, method, new Fitting.Callback() { diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/DifferencesState.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/DifferencesState.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/DifferencesState.java Thu Aug 08 17:36:44 2013 +0200 @@ -127,9 +127,7 @@ newFacets.add(new BedDiffYearFacet( idx, BED_DIFFERENCE_MORPH_WIDTH, - createBedDiffMorphDescription( - meta, - (BedDiffYearResult)results[idx]), + createBedDiffMorphDescription(meta), ComputeType.ADVANCE, stateId, hash)); @@ -342,12 +340,9 @@ } protected String createBedDiffMorphDescription( - CallMeta meta, - BedDiffYearResult result) { - String range = result.getStart() + " - " + result.getEnd(); - + CallMeta meta) { return Resources.getMsg(meta, I18N_FACET_BED_DIFF_MORPH, - I18N_FACET_BED_DIFF_MORPH, new Object[] { range }); + I18N_FACET_BED_DIFF_MORPH); } protected String createBedDiffAbsoluteDescription( diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java Thu Aug 08 17:36:44 2013 +0200 @@ -49,6 +49,7 @@ * the NaNs lead to gaps in graph. * @param distance if two consecutive entries in points[0] are more * than distance apart, create a NaN value to skip in display. + * Still, create a line segment. */ public static void addPoints(XYSeries series, double[][] points, boolean skipNANs, double distance) { if (points == null || points.length <= 1) { @@ -64,6 +65,11 @@ } // Create gap if distance >= distance. if (i != 0 && Math.abs(xPoints[i-1] - xPoints[i]) >= distance) { + // Create at least a small segment for last point. + if (!Double.isNaN(yPoints[i-1])) { + series.add(xPoints[i-1]+0.99d*(distance)/2.d, yPoints[i-1], false); + } + if (!Double.isNaN(yPoints[i-1]) && !Double.isNaN(yPoints[i])) { series.add((xPoints[i-1]+xPoints[i])/2.d, Double.NaN, false); } diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceEpochGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceEpochGenerator.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceEpochGenerator.java Thu Aug 08 17:36:44 2013 +0200 @@ -260,3 +260,4 @@ } } } +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityGenerator.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityGenerator.java Thu Aug 08 17:36:44 2013 +0200 @@ -138,6 +138,7 @@ * @param attr * theme for facet */ + @Override public void doOut(ArtifactAndFacet artifactAndFacet, Document attr, boolean visible) { String name = artifactAndFacet.getFacetName(); diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffHeightYearProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffHeightYearProcessor.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffHeightYearProcessor.java Thu Aug 08 17:36:44 2013 +0200 @@ -26,6 +26,8 @@ private final static Logger logger = Logger.getLogger(BedDiffHeightYearProcessor.class); + protected static double GAP_TOLERANCE = 0.101d; + @Override public void doOut( XYChartGenerator generator, @@ -62,7 +64,7 @@ int axidx) { XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - StyledSeriesBuilder.addPoints(series, data.getHeightPerYearData(), false, 0.101d); + StyledSeriesBuilder.addPoints(series, data.getHeightPerYearData(), false, GAP_TOLERANCE); generator.addAxisSeries(series, axidx, visible); } diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffYearProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffYearProcessor.java Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffYearProcessor.java Thu Aug 08 17:36:44 2013 +0200 @@ -26,6 +26,8 @@ private final static Logger logger = Logger.getLogger(BedDiffYearProcessor.class); + protected static double GAP_TOLERANCE = 0.101d; + @Override public void doOut( XYChartGenerator generator, @@ -71,10 +73,10 @@ XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), attr); if (idx == 0) { - StyledSeriesBuilder.addPoints(series, data.getHeights1Data(), false, 0.101d); + StyledSeriesBuilder.addPoints(series, data.getHeights1Data(), false, GAP_TOLERANCE); } else { - StyledSeriesBuilder.addPoints(series, data.getHeights2Data(), false, 0.101d); + StyledSeriesBuilder.addPoints(series, data.getHeights2Data(), false, GAP_TOLERANCE); } generator.addAxisSeries(series, axidx, visible); diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/resources/messages.properties --- a/artifacts/src/main/resources/messages.properties Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/resources/messages.properties Thu Aug 08 17:36:44 2013 +0200 @@ -287,7 +287,7 @@ bedquality.toplayer = 0.0m - 0.3m bedquality.sublayer = 0.1m - 0.5m facet.bedheight.diff.year = Bedheight Difference {0} -facet.bedheight.diff.morph = sounding Width {0} +facet.bedheight.diff.morph = sounding Width facet.bedheight.diff.height1 = Original Height Minuend {0} facet.bedheight.diff.height2 = Original Height Subtrahend {0} facet.bedheight.diff.absolute = Bedheight Difference/Year {0} diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/resources/messages_de.properties --- a/artifacts/src/main/resources/messages_de.properties Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/resources/messages_de.properties Thu Aug 08 17:36:44 2013 +0200 @@ -287,7 +287,7 @@ bedquality.toplayer = 0,0m - 0,3m bedquality.sublayer = 0,1m - 0,5m facet.bedheight.diff.year = Sohlh\u00f6hendifferenz {0} -facet.bedheight.diff.morph = gepeilte Breite {0} +facet.bedheight.diff.morph = gepeilte Breite facet.bedheight.diff.height1 = H\u00f6he Minuend {0} facet.bedheight.diff.height2 = H\u00f6he Subtrahend {0} facet.bedheight.diff.absolute = Sohlh\u00f6hendifferenz/Jahr {0} diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/resources/messages_de_DE.properties --- a/artifacts/src/main/resources/messages_de_DE.properties Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/resources/messages_de_DE.properties Thu Aug 08 17:36:44 2013 +0200 @@ -286,7 +286,7 @@ bedquality.sublayer = 0,1m - 0,5m facet.bedheight.diff.year = Sohlh\u00f6hendifferenz {0} facet.bedheight.diff.year.raw = Sohlh\u00f6hendifferenz {0} (Rohdaten) -facet.bedheight.diff.morph = gepeilte Breite {0} +facet.bedheight.diff.morph = gepeilte Breite facet.bedheight.diff.height1 = H\u00f6he Minuend {0} facet.bedheight.diff.height2 = H\u00f6he Subtrahend {0} facet.bedheight.diff.absolute = Sohlh\u00f6hendifferenz/Jahr {0} diff -r 962f6b805b48 -r bdbe704dd433 artifacts/src/main/resources/messages_en.properties --- a/artifacts/src/main/resources/messages_en.properties Wed Aug 07 18:57:29 2013 +0200 +++ b/artifacts/src/main/resources/messages_en.properties Thu Aug 08 17:36:44 2013 +0200 @@ -290,7 +290,7 @@ bedquality.toplayer = 0.0m - 0.3m bedquality.sublayer = 0.1m - 0.5m facet.bedheight.diff.year = Bedheight Difference {0} -facet.bedheight.diff.morph = sounding Width {0} +facet.bedheight.diff.morph = sounding Width facet.bedheight.diff.height1 = Original Height Minuend {0} facet.bedheight.diff.height2 = Original Height Subtrahend {0} facet.bedheight.diff.absolute = Bedheight Difference/Year {0}