comparison artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculator.java @ 9504:76c0665888a3

No rounding during calculation (Meilenstein-2 2.4.2 and 2.9), delta-w-cm as double (for historical scenario)
author mschaefer
date Fri, 28 Sep 2018 10:13:09 +0200
parents 853f2dafc16e
children 8b7bf26b8782
comparison
equal deleted inserted replaced
9503:83e6acdf8fc6 9504:76c0665888a3
7 * and comes with ABSOLUTELY NO WARRANTY! Check out the 7 * and comes with ABSOLUTELY NO WARRANTY! Check out the
8 * documentation coming with Dive4Elements River for details. 8 * documentation coming with Dive4Elements River for details.
9 */ 9 */
10 package org.dive4elements.river.artifacts.uinfo.salix; 10 package org.dive4elements.river.artifacts.uinfo.salix;
11 11
12 import java.math.BigDecimal;
13 import java.util.ArrayList; 12 import java.util.ArrayList;
14 import java.util.Collection; 13 import java.util.Collection;
15 import java.util.List; 14 import java.util.List;
16 import java.util.Map.Entry; 15 import java.util.Map.Entry;
17 import java.util.NavigableMap; 16 import java.util.NavigableMap;
18 17
19 import org.dive4elements.river.artifacts.WINFOArtifact; 18 import org.dive4elements.river.artifacts.WINFOArtifact;
20 import org.dive4elements.river.artifacts.access.ComputationRangeAccess; 19 import org.dive4elements.river.artifacts.access.ComputationRangeAccess;
21 import org.dive4elements.river.artifacts.common.AbstractResultType;
22 import org.dive4elements.river.artifacts.common.GeneralResultType; 20 import org.dive4elements.river.artifacts.common.GeneralResultType;
23 import org.dive4elements.river.artifacts.common.ResultRow; 21 import org.dive4elements.river.artifacts.common.ResultRow;
24 import org.dive4elements.river.artifacts.model.Calculation; 22 import org.dive4elements.river.artifacts.model.Calculation;
25 import org.dive4elements.river.artifacts.model.river.MainWstValuesCalculator; 23 import org.dive4elements.river.artifacts.model.river.MainWstValuesCalculator;
26 import org.dive4elements.river.artifacts.model.river.RiverInfoProvider; 24 import org.dive4elements.river.artifacts.model.river.RiverInfoProvider;
27 import org.dive4elements.river.artifacts.sinfo.tkhstate.WinfoArtifactWrapper; 25 import org.dive4elements.river.artifacts.sinfo.tkhstate.WinfoArtifactWrapper;
28 import org.dive4elements.river.artifacts.uinfo.UINFOArtifact; 26 import org.dive4elements.river.artifacts.uinfo.UINFOArtifact;
29 import org.dive4elements.river.artifacts.uinfo.common.UInfoResultType; 27 import org.dive4elements.river.artifacts.uinfo.common.UInfoResultType;
30 import org.dive4elements.river.artifacts.uinfo.salix.SalixLineAccess.ScenarioType; 28 import org.dive4elements.river.artifacts.uinfo.salix.SalixLineAccess.ScenarioType;
31 import org.dive4elements.river.artifacts.uinfo.vegetationzones.VegetationZoneServerClientXChange;
32 import org.dive4elements.river.utils.Formatter;
33 29
34 /** 30 /**
35 * Calculation of the result rows of the u-info salix line calc mode 31 * Calculation of the result rows of the u-info salix line calc mode
36 * 32 *
37 * @author Matthias Schäfer 33 * @author Matthias Schäfer
38 */ 34 */
39 final class SalixLineCalculator { 35 final class SalixLineCalculator {
40 36
41 private static final String MAIN_VALUE_MNQ = "mnq"; 37 private static final String MAIN_VALUE_MNQ = "MNQ";
42 38
43 private static final String MAIN_VALUE_MQ = "mq"; 39 private static final String MAIN_VALUE_MQ = "MQ";
44 40
45 private static final String MAIN_VALUE_MHQ = "mhq"; 41 private static final String MAIN_VALUE_MHQ = "MHQ";
46 42
47 private static final String MAIN_VALUE_HQ5 = "hq5"; 43 private static final String MAIN_VALUE_HQ5 = "HQ5";
48 44
49 private static final BigDecimal SALIX_DISTANCE = new BigDecimal("2.31"); 45 private static final double SALIX_DISTANCE = 2.31;
50 private final List<ResultRow> rows = new ArrayList<>(); 46 private final List<ResultRow> rows = new ArrayList<>();
51 47
52 private final RiverInfoProvider riverInfoProvider; 48 private final RiverInfoProvider riverInfoProvider;
53 49
50
54 public SalixLineCalculator(final RiverInfoProvider riverInfoProvider) { 51 public SalixLineCalculator(final RiverInfoProvider riverInfoProvider) {
55 this.riverInfoProvider = riverInfoProvider; 52 this.riverInfoProvider = riverInfoProvider;
56 } 53 }
54
57 55
58 /** 56 /**
59 * Calculate the salix line result rows 57 * Calculate the salix line result rows
60 */ 58 */
61 public void execute(final Calculation problems, final UINFOArtifact uinfo, final NavigableMap<Double, List<Double>> rangeScenarios, 59 public void execute(final Calculation problems, final UINFOArtifact uinfo, final NavigableMap<Double, List<Double>> rangeScenarios,
96 return mainWstValues; 94 return mainWstValues;
97 } 95 }
98 96
99 /** 97 /**
100 * Create a result row for a station and its gauge, and add w-q-values as selected 98 * Create a result row for a station and its gauge, and add w-q-values as selected
101 *
102 * @param mainWstValues
103 */ 99 */
104 private ResultRow createRow(final MainWstValuesCalculator mainWstValues, final double station, final NavigableMap<Double, List<Double>> rangeScenarios) { 100 private ResultRow createRow(final MainWstValuesCalculator mainWstValues, final double station, final NavigableMap<Double, List<Double>> rangeScenarios) {
105 101
106 final ResultRow row = ResultRow.create(); 102 final ResultRow row = ResultRow.create();
107 row.putValue(GeneralResultType.station, station); 103 row.putValue(GeneralResultType.station, station);
121 row.putValue(UInfoResultType.waterlevelMH5, hw5); 117 row.putValue(UInfoResultType.waterlevelMH5, hw5);
122 118
123 // Calc salix-line and mw-mnw 119 // Calc salix-line and mw-mnw
124 row.putValue(UInfoResultType.salixline, calcSalix(mhw, mw, 0.0)); 120 row.putValue(UInfoResultType.salixline, calcSalix(mhw, mw, 0.0));
125 row.putValue(UInfoResultType.salix_mw_mnw, calcMwmnw(mw, mnw)); 121 row.putValue(UInfoResultType.salix_mw_mnw, calcMwmnw(mw, mnw));
126 final double salixw = Formatter.roundW(mhw).subtract(SALIX_DISTANCE).doubleValue(); 122 final double salixw = mhw - SALIX_DISTANCE;
127 row.putValue(UInfoResultType.salixw, salixw); 123 row.putValue(UInfoResultType.salixw, salixw);
128 // Calc scenario values (always all scenario types set, Result variant extracts the fields needed) 124 // Calc scenario values (always all scenario types set, Result variant extracts the fields needed)
129 final List<SalixScenario> scenarios = new ArrayList<>(); 125 final List<SalixScenario> scenarios = new ArrayList<>();
130 final List<Double> deltaws = getDeltaWs(station, rangeScenarios); 126 final List<Double> deltaws = getDeltaWs(station, rangeScenarios);
131 for (final Double deltaw : deltaws) { 127 for (final Double deltaw : deltaws) {
132 if (deltaw != null) { 128 if (deltaw != null) {
133 final double salix = calcSalix(mhw, mw, deltaw.doubleValue()); 129 final double salix = calcSalix(mhw, mw, deltaw.doubleValue());
134 final double scen = calcSalix(mhw, 0.0, deltaw.doubleValue()); 130 final double scen = calcSalix(mhw, 0.0, deltaw.doubleValue());
135 scenarios.add(new SalixScenario((int) (deltaw * 100), salix, scen)); 131 scenarios.add(new SalixScenario(deltaw * 100, salix, scen));
136 } else { 132 } else {
137 scenarios.add(null); 133 scenarios.add(null);
138 } 134 }
139 } 135 }
140 row.putValue(UInfoResultType.customMultiRowColSalixScenarios, scenarios); 136 row.putValue(UInfoResultType.customMultiRowColSalixScenarios, scenarios);
146 * Calculates the salix value 142 * Calculates the salix value
147 */ 143 */
148 private double calcSalix(final double mhw, final double mw, final double deltamw) { 144 private double calcSalix(final double mhw, final double mw, final double deltamw) {
149 if (Double.isNaN(mw) || Double.isInfinite(mw) || Double.isNaN(mhw) || Double.isInfinite(mhw)) 145 if (Double.isNaN(mw) || Double.isInfinite(mw) || Double.isNaN(mhw) || Double.isInfinite(mhw))
150 return mhw - mw; // preserving NaN or Infinity 146 return mhw - mw; // preserving NaN or Infinity
151 return Formatter.roundW(mhw).subtract(SALIX_DISTANCE).subtract(Formatter.roundW(mw).add(Formatter.roundW(deltamw))).doubleValue(); 147 return mhw - SALIX_DISTANCE - mw - deltamw;
152 } 148 }
153 149
154 /** 150 /**
155 * Calculates the inverse MW-MNW difference 151 * Calculates the inverse MW-MNW difference
156 */ 152 */
157 private double calcMwmnw(final double mw, final double mnw) { 153 private double calcMwmnw(final double mw, final double mnw) {
158 if (Double.isNaN(mw) || Double.isInfinite(mw) || Double.isNaN(mnw) || Double.isInfinite(mnw)) 154 if (Double.isNaN(mw) || Double.isInfinite(mw) || Double.isNaN(mnw) || Double.isInfinite(mnw))
159 return mnw - mw; // preserving NaN or Inifinity 155 return mnw - mw; // preserving NaN or Inifinity
160 return Formatter.roundW(mnw).subtract(Formatter.roundW(mw)).doubleValue(); 156 return mnw - mw;
161 } 157 }
162 158
163 /** 159 /**
164 * Gets the station-specific list of delta-ws of the active scenario, at least with one null item in any case 160 * Gets the station-specific list of delta-ws of the active scenario, at least with one null item in any case
165 */ 161 */
172 noScen.add(null); 168 noScen.add(null);
173 return noScen; 169 return noScen;
174 } 170 }
175 171
176 /** 172 /**
177 * Find and return a height (iota, w main value) of a station in a previously calculated result
178 */
179 public double fetchStationHeight(final Calculation problems, final double station, final AbstractResultType resultType,
180 final SalixLineCalculationResult result) {
181
182 // Search the station in the previously calculated result rows
183 final ResultRow stationRow = searchStation(station, result.getRows());
184 if (stationRow != null)
185 return stationRow.getDoubleValue(resultType);
186 return Double.NaN;
187 }
188
189 /**
190 * Searches the row of a station in a result rows collection 173 * Searches the row of a station in a result rows collection
191 */ 174 */
192 private ResultRow searchStation(final double station, final Collection<ResultRow> rows) { 175 private ResultRow searchStation(final double station, final Collection<ResultRow> rows) {
193 for (final ResultRow row : rows) { 176 for (final ResultRow row : rows) {
194 if (row.getDoubleValue(GeneralResultType.station) > station + 0.0001) 177 if (row.getDoubleValue(GeneralResultType.station) > station + 0.0001)
195 return row; 178 return row;
196 } 179 }
197 return null; 180 return null;
198 } 181 }
199
200 /**
201 * Computes the height of a vegetation zone limit for a station and a previously computed salix line result
202 */
203 public double computeVegetationZoneHeight(final Calculation problems, final double station, final int vegetationZoneType,
204 final SalixLineCalculationResult result) {
205
206 // Search the station in the previously calculated result rows
207 final ResultRow stationRow = searchStation(station, result.getRows());
208 if (stationRow == null)
209 return Double.NaN;
210
211 // Compute height from overflow duration days
212 final List<VegetationZoneServerClientXChange> vzs = VegetationZoneServerClientXChange.getStandardList(null, null); // TODO river, context
213 if ((vegetationZoneType >= 1) && (vegetationZoneType <= vzs.size())) {
214 final int uefd = vzs.get(vegetationZoneType - 1).getMin_day_overflow();
215 // Üfd = -70,559 ∗ ln((DGM - MW) + 0,5) + 80,711
216 final double f1 = -70.559;
217 final double f2 = -88.711;
218 final double mw = stationRow.getDoubleValue(UInfoResultType.waterlevelMW);
219 final double dgm = Math.exp((uefd - f2) / f1) + mw - 0.5;
220 return dgm;
221 }
222 return Double.NaN;
223 }
224 } 182 }

http://dive4elements.wald.intevation.org