Mercurial > dive4elements > river
view artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadDataCalculation.java @ 8060:25feef564d09
Sediment load: More of official epochs.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Fri, 18 Jul 2014 18:55:39 +0200 |
parents | 555dc5a9b282 |
children | 8489565ff563 |
line wrap: on
line source
/* Copyright (C) 2014 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 java.util.List; import java.util.Set; import java.util.TreeSet; import org.dive4elements.river.artifacts.access.SedimentLoadAccess; import org.dive4elements.river.artifacts.model.Calculation; import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.RiverFactory; import org.apache.log4j.Logger; import org.dive4elements.river.artifacts.model.minfo.SedimentLoadData; import org.dive4elements.river.artifacts.model.minfo.SedimentLoadData.Value; import org.dive4elements.river.artifacts.model.minfo.SedimentLoadData.Station; import org.dive4elements.river.artifacts.model.minfo.SedimentLoadDataValueFilter.And; import org.dive4elements.river.artifacts.model.minfo.SedimentLoadDataValueFilter.IsEpoch; import org.dive4elements.river.artifacts.model.minfo.SedimentLoadDataValueFilter.IsOfficial; import org.dive4elements.river.artifacts.model.minfo.SedimentLoadDataValueFilter.Not; import org.dive4elements.river.artifacts.model.minfo.SedimentLoadDataValueFilter.TimeRangeIntersects; import org.dive4elements.river.model.River; import org.dive4elements.river.utils.DoubleUtil; public class SedimentLoadDataCalculation extends Calculation { private static final Logger log = Logger .getLogger(SedimentLoadDataCalculation.class); public static final int [] TOTAL_LOAD_FLYS = { SedimentLoadData.GF_COARSE, SedimentLoadData.GF_FINE_MIDDLE, SedimentLoadData.GF_SAND, SedimentLoadData.GF_SUSP_SEDIMENT }; public static final int [] BED_LOAD_FLYS = { SedimentLoadData.GF_COARSE, SedimentLoadData.GF_FINE_MIDDLE, SedimentLoadData.GF_SAND }; public static final int [] BED_LOAD_SUSP_SAND_FLYS = { SedimentLoadData.GF_COARSE, SedimentLoadData.GF_FINE_MIDDLE, SedimentLoadData.GF_SAND, SedimentLoadData.GF_SUSP_SAND }; public static final int [] TOTAL_LOAD_BFG = { SedimentLoadData.GF_TOTAL }; public static final int [] BED_LOAD_BFG = { SedimentLoadData.GF_BED_LOAD }; public static final int [] SUSPENDED_LOAD_BFG = { SedimentLoadData.GF_SUSPENDED_LOAD }; public static final int [] COARSE_FLYS = { SedimentLoadData.GF_COARSE }; public static final int [] FINE_MIDDLE_FLYS = { SedimentLoadData.GF_FINE_MIDDLE }; public static final int [] SAND_FLYS = { SedimentLoadData.GF_SAND }; public static final int [] SUSP_SAND_FLYS = { SedimentLoadData.GF_SUSP_SAND }; public static final int [] SUSP_SAND_BED_FLYS = { SedimentLoadData.GF_SUSP_SAND_BED }; public static final int [] SUSP_SEDIMENT_FLYS = { SedimentLoadData.GF_SUSP_SEDIMENT }; public static final class GrainFraction { private String description; private int [] grainFractions; public GrainFraction(String description, int [] grainFractions) { this.description = description; this.grainFractions = grainFractions; } public static final GrainFraction make(String description, int [] grainFractions) { return new GrainFraction(description, grainFractions); } public String getDescription() { return description; } public int [] getGrainFractions() { return grainFractions; } } // class GrainFraction public static final GrainFraction [] GRAIN_FRACTIONS = { // TODO: i18n GrainFraction.make("minfo.total.load.flys", TOTAL_LOAD_FLYS), GrainFraction.make("minfo.bed.load.flys", BED_LOAD_FLYS), GrainFraction.make("minfo.bed.load.susp.sand.flys", BED_LOAD_SUSP_SAND_FLYS), GrainFraction.make("minfo.total.load.bfg", TOTAL_LOAD_BFG), GrainFraction.make("minfo.bed.load.bfg", BED_LOAD_BFG), GrainFraction.make("minfo.suspended.load.bfg", SUSPENDED_LOAD_BFG), GrainFraction.make("minfo.coarse.flys", COARSE_FLYS), GrainFraction.make("minfo.fine.middle.flys", FINE_MIDDLE_FLYS), GrainFraction.make("minfo.sand.flys", SAND_FLYS) , GrainFraction.make("minfo.susp.sand.flys", SUSP_SAND_FLYS), GrainFraction.make("minfo.susp.sand.bed.flys", SUSP_SAND_BED_FLYS), GrainFraction.make("minfo.susp.sediment.flys", SUSP_SEDIMENT_FLYS), }; public static class Sum implements Value.Visitor { protected int n; protected double sum; public Sum() { } public double getSum() { return sum; } public int getN() { return n; } public void reset() { n = 0; sum = 0.0; } @Override public void visit(Value value) { sum += value.getValue(); ++n; } } // class Sum public static final class Avg extends Sum { public Avg() { } @Override public double getSum() { return n == 0 ? 0.0 : sum/(double)n; } } // class Sum private String river; private String yearEpoch; private String unit; private int [][] epochs; private int [] years; private double from; private double to; public SedimentLoadDataCalculation() { } public CalculationResult calculate(SedimentLoadAccess access) { log.info("SedimentLoadDataCalculation.calculate"); String river = access.getRiverName(); String yearEpoch = access.getYearEpoch(); String unit = access.getUnit(); int [] years = null; int [][] epochs = null; double from = access.getLowerKM(); double to = access.getUpperKM(); if (yearEpoch.equals("year")) { years = access.getPeriod(); } else if (yearEpoch.equals("epoch") || yearEpoch.equals("off_epoch")) { epochs = access.getEpochs(); } else { addProblem("minfo.missing.year_epoch"); } if (river == null) { // TODO: i18n addProblem("minfo.missing.river"); } if (years == null && epochs == null) { addProblem("minfo.missing.time"); } if (!hasProblems()) { this.river = river; this.yearEpoch = yearEpoch; this.unit = unit; this.years = years; this.epochs = epochs; this.from = from; this.to = to; return internalCalculate(); } return error(null); } private CalculationResult error(String msg) { if (msg != null) addProblem(msg); return new CalculationResult(this); } private CalculationResult internalCalculate() { if ("year".equals(yearEpoch)) return calculateYears(); if ("epoch".equals(yearEpoch)) return calculateEpochs(); if ("off_epoch".equals(yearEpoch)) return calculateOffEpochs(); // TODO: i18n return error("minfo.sediment.load.unknown.calc.mode"); } private CalculationResult calculateYears() { SedimentLoadData sld = SedimentLoadDataFactory.INSTANCE.getSedimentLoadData(river); if (sld == null) { // TODO: i18n return error("minfo.sediment.load.no.data"); } boolean isKmUp = isKmUp(); Set<Integer> missingFractions = new TreeSet<Integer>(); Not notEpochs = new Not(IsEpoch.INSTANCE); Sum sum = new Sum(); for (int year: years) { Value.Filter filter = new And() .add(notEpochs) .add(new TimeRangeIntersects(year)); for (GrainFraction gf: GRAIN_FRACTIONS) { double [][] result = sum( sld, gf.getGrainFractions(), filter, sum, isKmUp, missingFractions); if (result[0].length == 0 || DoubleUtil.isNaN(result[1])) { // TODO: resolve i18n addProblem("minfo.sediment.load.no.fractions", gf.getDescription()); continue; } // TODO: Generate result data set for calculation. // TODO: Optionally transform units. } } // TODO: Generate messages for missing fractions. // TODO: Bundle sub results. return null; } private CalculationResult calculateEpochs() { SedimentLoadData sld = SedimentLoadDataFactory.INSTANCE.getSedimentLoadData(river); if (sld == null) { // TODO: i18n return error("minfo.sediment.load.no.data"); } boolean isKmUp = isKmUp(); Set<Integer> missingFractions = new TreeSet<Integer>(); // They are not epochs, they are single years! Not notEpochs = new Not(IsEpoch.INSTANCE); for (int [] epoch: epochs) { Value.Filter filter = new And() .add(notEpochs) .add(new TimeRangeIntersects(epoch[0], epoch[1])); Avg avg = new Avg(); for (GrainFraction gf: GRAIN_FRACTIONS) { double [][] result = sum( sld, gf.getGrainFractions(), filter, avg, isKmUp, missingFractions); if (result[0].length == 0 || DoubleUtil.isNaN(result[1])) { // TODO: resolve i18n addProblem("minfo.sediment.load.no.fractions", gf.getDescription()); continue; } // TODO: Generate result data set for calculation. // TODO: Optionally transform units. } } // TODO: Generate messages for missing fractions. // TODO: Bundle sub results. return null; } private CalculationResult calculateOffEpochs() { SedimentLoadData sld = SedimentLoadDataFactory.INSTANCE.getSedimentLoadData(river); if (sld == null) { // TODO: i18n return error("minfo.sediment.load.no.data"); } boolean isKmUp = isKmUp(); Set<Integer> missingFractions = new TreeSet<Integer>(); for (int [] epoch: epochs) { Value.Filter filter = new And() .add(IsOfficial.INSTANCE) .add(new TimeRangeIntersects(epoch[0], epoch[1])); Sum sum = new Sum(); for (GrainFraction gf: GRAIN_FRACTIONS) { double [][] result = sum( sld, gf.getGrainFractions(), filter, sum, isKmUp, missingFractions); if (result[0].length == 0 || DoubleUtil.isNaN(result[1])) { // TODO: resolve i18n addProblem("minfo.sediment.load.no.fractions", gf.getDescription()); continue; } // TODO: Generate result data set for calculation. // TODO: Optionally transform units. } } // TODO: Generate messages for missing fractions. // TODO: Bundle sub results. // TODO: Implement me! return null; } /** Figure out flow direction of river. */ private boolean isKmUp() { River r = RiverFactory.getRiver(river); if (r == null) { addProblem("minfo.missing.river"); return true; } return r.getKmUp(); } public double[][] sum( SedimentLoadData sld, int [] grainFractions, Value.Filter filter, Sum sum, boolean isKMUp, Set<Integer> missingFractions ) { List<Station> stations = sld.findStations(from, to); double [] values = new double[grainFractions.length]; double [][] result = new double[2][stations.size()]; for (int j = 0, S = stations.size(); j < S; ++j) { Station station = stations.get(j); for (int i = 0; i < grainFractions.length; ++i) { int gf = grainFractions[i]; sum.reset(); station.filterGrainFraction(gf, filter, sum); if (sum.getN() == 0) { // No values found int msType = SedimentLoadData.measurementStationType(gf); // Station of right fraction type already? No: take previous. if (!station.isType(msType)) { Station prev = station.prevByType(msType, isKMUp); if (prev != null) { prev.filterGrainFraction(gf, filter, sum); } } } if (sum.getN() == 0) { missingFractions.add(gf); values[i] = Double.NaN; } else { values[i] = sum.getSum(); } } result[0][j] = station.getStation(); result[1][j] = DoubleUtil.sum(values); } // TODO: Handle 'virtual' measument stations 'from' and 'to'. return result; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :