Mercurial > dive4elements > river
view artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculator.java @ 9321:a978b601a034
Salix: Fixed ArrrayoutOfBoundsException; minor cleanup
author | gernotbelger |
---|---|
date | Fri, 27 Jul 2018 10:25:09 +0200 |
parents | 72b3270e1568 |
children | b3d3c958a594 |
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.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NavigableMap; import org.dive4elements.river.artifacts.WINFOArtifact; import org.dive4elements.river.artifacts.access.ComputationRangeAccess; import org.dive4elements.river.artifacts.common.GeneralResultType; import org.dive4elements.river.artifacts.common.ResultRow; import org.dive4elements.river.artifacts.model.Calculation; import org.dive4elements.river.artifacts.model.WstValueTable; import org.dive4elements.river.artifacts.model.WstValueTable.QPosition; import org.dive4elements.river.artifacts.model.WstValueTableFactory; import org.dive4elements.river.artifacts.sinfo.common.GaugeDischargeValuesFinder; import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; import org.dive4elements.river.artifacts.sinfo.tkhstate.WinfoArtifactWrapper; import org.dive4elements.river.artifacts.uinfo.UINFOArtifact; import org.dive4elements.river.artifacts.uinfo.commons.UInfoResultType; import org.dive4elements.river.artifacts.uinfo.salix.SalixLineAccess.ScenarioType; import org.dive4elements.river.model.Gauge; import org.dive4elements.river.model.MainValue; import org.dive4elements.river.model.MainValueType.MainValueTypeKey; /** * Calculation of the result rows of the u-info salix line calc mode * * @author Matthias Schäfer */ final class SalixLineCalculator { private final List<ResultRow> rows = new ArrayList<>(); private final RiverInfoProvider riverInfoProvider; private final Map<Gauge, QPosition> gaugeMwPos; private final Map<Gauge, QPosition> gaugeMnwPos; private final Map<Gauge, QPosition> gaugeMhwPos; private Calculation problems; private WstValueTable wst; public SalixLineCalculator(final RiverInfoProvider riverInfoProvider) { this.riverInfoProvider = riverInfoProvider; this.gaugeMwPos = new HashMap<>(); this.gaugeMnwPos = new HashMap<>(); this.gaugeMhwPos = new HashMap<>(); } /** * Calculate the salix line result rows */ public void execute(final Calculation problems, final UINFOArtifact uinfo, final NavigableMap<Double, List<Double>> rangeScenarios, final ScenarioType scenarioType, final String[] scenarioLabels, final SalixLineCalculationResults results) { this.problems = problems; this.wst = WstValueTableFactory.getTable(this.riverInfoProvider.getRiver()); fetchGaugeMainValuePositions(); final WINFOArtifact winfo = new WinfoArtifactWrapper(uinfo); winfo.addStringData("ld_mode", "distance"); winfo.addStringData("ld_step", "100"); for (final double station : new ComputationRangeAccess(winfo).getKms()) { this.rows.add(createRow(station, rangeScenarios)); } if (scenarioType == ScenarioType.REGIONAL) results.addResult(new SalixLineCalculationRegionalResult("Salix", scenarioLabels, this.rows), problems); else if (scenarioType == ScenarioType.SUPRAREGIONAL) results.addResult(new SalixLineCalculationSupraRegionalResult("Salix", this.rows), problems); else if (scenarioType == ScenarioType.HISTORICAL) results.addResult(new SalixLineCalculationHistoricalResult("Salix", this.rows), problems); else results.addResult(new SalixLineCalculationNoScenarioResult("Salix", this.rows), problems); } /** * Fetch MW, MNW and MHW of all gauges and determine the wst QPosition for each one */ private void fetchGaugeMainValuePositions() { this.gaugeMwPos.clear(); this.gaugeMnwPos.clear(); this.gaugeMhwPos.clear(); for (final Gauge gauge : this.riverInfoProvider.getGauges()) { this.gaugeMwPos.put(gauge, null); this.gaugeMnwPos.put(gauge, null); this.gaugeMhwPos.put(gauge, null); final GaugeDischargeValuesFinder finder = GaugeDischargeValuesFinder.loadValues(gauge, this.problems); if (finder == null) continue; final double gaugeKm = gauge.getStation().doubleValue(); for (final MainValue mv : MainValue.getValuesOfGaugeAndType(gauge, MainValueTypeKey.W)) { if (mv.getMainValue().getName().equalsIgnoreCase("mw")) this.gaugeMwPos.put(gauge, this.wst.getQPosition(gaugeKm, finder.getDischarge(mv.getValue().doubleValue()))); else if (mv.getMainValue().getName().equalsIgnoreCase("mnw")) this.gaugeMnwPos.put(gauge, this.wst.getQPosition(gaugeKm, finder.getDischarge(mv.getValue().doubleValue()))); else if (mv.getMainValue().getName().equalsIgnoreCase("mhw")) this.gaugeMhwPos.put(gauge, this.wst.getQPosition(gaugeKm, finder.getDischarge(mv.getValue().doubleValue()))); } } } /** * Create a result row for a station and its gauge, and add w-q-values as selected * * @param rangeScenarios2 */ private ResultRow createRow(final double station, final NavigableMap<Double, List<Double>> rangeScenarios) { final ResultRow row = ResultRow.create(); // Find station's gauge final Gauge gauge = this.riverInfoProvider.getGauge(station, true); row.putValue(GeneralResultType.station, station); // Interpolate mnw, mw, and mhw final double mnw = interpolateW(station, this.gaugeMnwPos.get(gauge)); final double mw = interpolateW(station, this.gaugeMwPos.get(gauge)); final double mhw = interpolateW(station, this.gaugeMhwPos.get(gauge)); row.putValue(SInfoResultType.waterlevel, mnw); row.putValue(SInfoResultType.waterlevel1, mw); row.putValue(SInfoResultType.waterlevel2, mhw); // Calc salix-line and mw-mnw row.putValue(UInfoResultType.salixline, calcSalix(mhw, mw)); row.putValue(UInfoResultType.salix_delta_mw, calcMwmnw(mw, mnw)); // Calc scenario values (always all scenario types set, Result variant extracts the fields needed) final List<SalixScenario> scenarios = new ArrayList<>(); final double[] deltaws = getDeltaWs(station, rangeScenarios); for (int i = 0; i <= deltaws.length - 1; i++) { if (Math.abs(deltaws[i]) < 0.0001) { row.putValue(UInfoResultType.salix_line_scenario, Double.NaN); row.putValue(UInfoResultType.salix_line_scenario_dwspl, 0); // TODO NaN when changed from int to double /* always need to add a member, so the exporter will produce empty columns */ scenarios.add(null); } else { final double salix = calcSalix(mhw, mw + deltaws[i]); row.putValue(UInfoResultType.salix_line_scenario, salix); row.putValue(UInfoResultType.salix_line_scenario_dwspl, (int) (deltaws[i] * 100)); scenarios.add(new SalixScenario((int) (deltaws[i] * 100), salix)); } } row.putValue(UInfoResultType.customMultiRowColSalixRegionalValue_Dwspl, scenarios); return row; } /** * Interpolates the W for a station with a fixed (virtual) wst column position */ private double interpolateW(final double station, final QPosition qPosition) { if (qPosition != null) return this.wst.interpolateW(station, qPosition, this.problems); return Double.NaN; } /** * Calculates the salix value */ private double calcSalix(final double mhw, final double mw) { return mhw - 2.31 - mw; } /** * Calculates the inverse MW-MNW difference */ private double calcMwmnw(final double mw, final double mnw) { return mnw - mw; } /** * Gets the station-specific list of delta-ws of the active scenario, at least with one 0 item in any case * * @param rangeScenarios */ private double[] getDeltaWs(final double station, final NavigableMap<Double, List<Double>> rangeScenarios) { final Entry<Double, List<Double>> stationScenarios = rangeScenarios.floorEntry(station); if (stationScenarios == null) return new double[] { 0.0 }; final double[] deltaws = new double[stationScenarios.getValue().size()]; for (int i = 0; i <= stationScenarios.getValue().size() - 1; i++) deltaws[i] = stationScenarios.getValue().get(i); return deltaws; } }