Mercurial > dive4elements > river
view artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculation.java @ 9573:b9c87bbff6a4
mean bed height -> mean bed LEVEL
author | gernotbelger |
---|---|
date | Tue, 06 Nov 2018 10:56:22 +0100 |
parents | 429b62373633 |
children | 5395c6d4ca50 |
line wrap: on
line source
/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde * Software engineering by * Björnsen Beratende Ingenieure GmbH * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt * * 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.uinfo.salix; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.NavigableMap; import java.util.TreeMap; import org.apache.commons.lang.math.DoubleRange; import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.access.RangeAccess; import org.dive4elements.river.artifacts.common.GeneralResultType; import org.dive4elements.river.artifacts.model.Calculation; import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.river.RiverInfoProvider; import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder; import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsUtils; import org.dive4elements.river.artifacts.sinfo.tkhstate.DefaultBedHeights; import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; import org.dive4elements.river.artifacts.uinfo.UINFOArtifact; import org.dive4elements.river.artifacts.uinfo.salix.SalixLineAccess.ScenarioType; import org.dive4elements.river.model.BedHeight; import org.dive4elements.river.model.Gauge; import org.dive4elements.river.model.River; /** * Calculation of a iota (former salix) longitudinal section, optionally with a delta scenario * * @author Domenico Nardi Tironi * @author Matthias Schäfer * */ final class SalixLineCalculation { private final CallContext context; private Calculation problems; public SalixLineCalculation(final CallContext context) { this.context = context; } /** * Calculates the iota longitudinal section and delta scenario of a uinfo artifact */ public CalculationResult calculate(final UINFOArtifact uinfo) { this.problems = new Calculation(); final String calcModeLabel = Resources.getMsg(this.context.getMeta(), uinfo.getCalculationMode().name()); final String user = CalculationUtils.findArtifactUser(this.context, uinfo); final SalixLineAccess accessSalix = new SalixLineAccess(uinfo); final River river = accessSalix.getRiver(); final RiverInfo riverInfo = new RiverInfo(river); final DoubleRange range = accessSalix.getRange(); final ScenarioType scenarioType = accessSalix.getScenario(); final Gauge firstUpstreamGauge = river.firstUpstreamGauge(); final DoubleRange maxRange = new DoubleRange(firstUpstreamGauge.getRange().getA(), river.getKmUp() ? -99999.999 : 99999.999); final RiverInfoProvider riverInfoProvider1 = RiverInfoProvider.forRange(this.context, river, maxRange); final RiverInfoProvider riverInfoProvider = riverInfoProvider1.forReferenceRange(maxRange, false); final SalixLineCalculationResults results = new SalixLineCalculationResults(calcModeLabel, user, riverInfo, range); final SalixLineCalculator calculator = new SalixLineCalculator(riverInfoProvider); final NavigableMap<Double, List<Double>> rangeScenarios = buildRangeScenarios(accessSalix); calculator.execute(this.problems, uinfo, rangeScenarios, scenarioType, buildScenarioLabels(accessSalix), buildPartialRangeString(accessSalix), buildAdditionalString(accessSalix), results); return new CalculationResult(results, this.problems); } /** * Builds a map of delta-Ws by from-km for the selected scenario */ private NavigableMap<Double, List<Double>> buildRangeScenarios(final SalixLineAccess access) { final NavigableMap<Double, List<Double>> rangeScenarios = new TreeMap<>(); if (access.getScenario() == ScenarioType.REGIONAL) fillRangeScenarios(rangeScenarios, access, access.getFromPart().doubleValue(), access.getToPart().doubleValue(), access.getRegionalScenarioIntegers()); else if (access.getScenario() == ScenarioType.SUPRAREGIONAL) fillRangeScenarios(rangeScenarios, access.getSupraRegionalString()); else if (access.getScenario() == ScenarioType.HISTORICAL) fillRangeScenarios(rangeScenarios, access, access.getFromPart().doubleValue(), access.getToPart().doubleValue(), access.getBedHeightId()); else fillRangeScenarios(rangeScenarios, access); return rangeScenarios; } /** * Fills a map of delta-Ws with only one 0-delta for the whole calc range (no scenario) */ private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final RangeAccess calcRange) { final List<Double> nulls = new ArrayList<>(); nulls.add(null); rangeScenarios.put(Double.valueOf(calcRange.getLowerKm() - 0.0001), nulls); } /** * Fills a map of delta-Ws by km-range from the regional scenario input data */ private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final RangeAccess calcRange, final double partFrom, final double partTo, final int[] deltaWs) { final List<Double> nulls = new ArrayList<>(); final List<Double> dwsm = new ArrayList<>(); for (int i = 0; i <= deltaWs.length - 1; i++) { nulls.add(null); dwsm.add(deltaWs[i] / 100.0); } rangeScenarios.put(Double.valueOf(calcRange.getLowerKm() - 0.0001), nulls); rangeScenarios.put(Double.valueOf(partFrom - 0.0001), dwsm); rangeScenarios.put(Double.valueOf(partTo + 0.0001), nulls); } /** * Fills a map of delta-Ws by km-range from the supraregional scenario input data * (the zones input by the user cover the calc range completely) */ private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final String zones) { final List<SalixZone> parts = SalixZone.parse(zones); for (final SalixZone part : parts) { final List<Double> dwsm = new ArrayList<>(); if (part.getDwsplValue() == 0) dwsm.add(null); else dwsm.add(part.getDwsplValue() / 100.0); rangeScenarios.put(Double.valueOf(part.getFromKm().doubleValue() - 0.0001), dwsm); } } /** * Fetches historical and reference bed levels and fills a map of delta-MSHs for all fetched stations in the calc range */ private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final RangeAccess calcRange, final double partFrom, final double partTo, final int historicalBedHeightId) { // Find relevant default bed-heights final River river = calcRange.getRiver(); final List<BedHeight> defaultBedHeights = new DefaultBedHeights(river).getBedHeights(this.problems); if (defaultBedHeights.isEmpty()) return; final DoubleRange scenarioRange = new DoubleRange(partFrom, partTo); final Collection<BedHeightsFinder> allFinders = BedHeightsFinder.createTkhBedHeights(this.problems, scenarioRange, defaultBedHeights); final Collection<BedHeightsFinder> currentFinders = new ArrayList<>(allFinders); // Add historical bed-heights final BedHeightsFinder historicalFinder = BedHeightsFinder.forId(this.problems, historicalBedHeightId, scenarioRange); allFinders.add(historicalFinder); final Collection<Double> stations = BedHeightsUtils.extractStationCollection(allFinders, true); final List<Double> nulls = new ArrayList<>(); nulls.add(null); rangeScenarios.put(Double.valueOf(calcRange.getLowerKm() - 0.0001), nulls); for (final Double station : stations) { rangeScenarios.put(station, new ArrayList<Double>()); final double delta = bedHeightDifference(station, currentFinders, historicalFinder); if (Double.isNaN(delta)) { rangeScenarios.get(station).add(null); if (!this.problems.hasProblems()) { final String msg = Resources.getMsg(this.context.getMeta(), "uinfo_salix_calc.warning.missing_bedheights"); this.problems.addProblem(station, msg); } } else rangeScenarios.get(station).add(Double.valueOf(delta)); } rangeScenarios.put(Double.valueOf(partTo + 0.0001), nulls); } /** * Gets the difference of a historical bed level against a current one for a station */ private double bedHeightDifference(final double station, final Collection<BedHeightsFinder> currentFinders, final BedHeightsFinder historicalFinder) { double currentMSH = Double.NaN; for (final BedHeightsFinder bhf : currentFinders) { currentMSH = bhf.getMeanBedHeight(station); if (!Double.isNaN(currentMSH)) break; } if (Double.isNaN(currentMSH)) return Double.NaN; final double historicalMSH = historicalFinder.getMeanBedHeight(station); if (Double.isNaN(historicalMSH)) return Double.NaN; return (historicalMSH - currentMSH); } /** * Builds the list of delta-w labels for the scenario type */ private String[] buildScenarioLabels(final SalixLineAccess access) { final List<String> labels = new ArrayList<>(); if (access.getScenario() == ScenarioType.REGIONAL) { final int[] deltaws = access.getRegionalScenarioIntegers(); for (int i = 0; i <= deltaws.length - 1; i++) if (deltaws[i] != 0) labels.add(Integer.toString(deltaws[i]) + " cm"); } else if (access.getScenario() == ScenarioType.SUPRAREGIONAL) labels.add(Resources.getMsg(this.context.getMeta(), "uinfo_salix_scenario_supraregional")); else if (access.getScenario() == ScenarioType.HISTORICAL) labels.add(Resources.getMsg(this.context.getMeta(), "uinfo_salix_scenario_historical")); return labels.toArray(new String[labels.size()]); } /** * Builds the km range string for the scenario type */ private String buildPartialRangeString(final SalixLineAccess access) { if ((access.getScenario() == ScenarioType.REGIONAL) || (access.getScenario() == ScenarioType.HISTORICAL)) { return String.format("%s - %s", GeneralResultType.station.exportValue(this.context, access.getFromPart().doubleValue()), GeneralResultType.station.exportValue(this.context, access.getToPart().doubleValue())); } if (access.getScenario() == ScenarioType.SUPRAREGIONAL) { String ranges = ""; String sep = ""; final List<SalixZone> parts = SalixZone.parse(access.getSupraRegionalString()); for (final SalixZone part : parts) { if (part.getDwsplValue() != 0) { ranges = ranges + sep + String.format("%s - %s", GeneralResultType.station.exportValue(this.context, part.getFromKm().doubleValue()), GeneralResultType.station.exportValue(this.context, part.getToKm().doubleValue())); sep = ", "; } } return ranges; } return ""; } /** * Builds the delta w or time string for the scenario type */ private String buildAdditionalString(final SalixLineAccess access) { if (access.getScenario() == ScenarioType.REGIONAL) { String deltas = ""; String sep = ""; for (final int d : access.getRegionalScenarioIntegers()) { deltas = deltas + sep + Integer.toString(d); sep = ", "; } return deltas; } if (access.getScenario() == ScenarioType.HISTORICAL) { return String.valueOf(access.getYearEpoch()); } if (access.getScenario() == ScenarioType.SUPRAREGIONAL) { String deltas = ""; String sep = ""; final List<SalixZone> parts = SalixZone.parse(access.getSupraRegionalString()); for (final SalixZone part : parts) { if (part.getDwsplValue() != 0) { deltas = deltas + sep + Integer.toString(part.getDwsplValue()); sep = ", "; } } return deltas; } return ""; } }