comparison artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculation.java @ 9394:439699ff9b2d

Added U-Info iota (prev. salix) calculation for historical scenario
author mschaefer
date Fri, 10 Aug 2018 17:31:46 +0200
parents 2da486c7c05f
children 6e7094368e97
comparison
equal deleted inserted replaced
9393:6174daaf5e56 9394:439699ff9b2d
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.util.ArrayList; 12 import java.util.ArrayList;
13 import java.util.Collection;
13 import java.util.List; 14 import java.util.List;
14 import java.util.NavigableMap; 15 import java.util.NavigableMap;
15 import java.util.TreeMap; 16 import java.util.TreeMap;
16 17
17 import org.apache.commons.lang.math.DoubleRange; 18 import org.apache.commons.lang.math.DoubleRange;
20 import org.dive4elements.river.artifacts.common.GeneralResultType; 21 import org.dive4elements.river.artifacts.common.GeneralResultType;
21 import org.dive4elements.river.artifacts.model.Calculation; 22 import org.dive4elements.river.artifacts.model.Calculation;
22 import org.dive4elements.river.artifacts.model.CalculationResult; 23 import org.dive4elements.river.artifacts.model.CalculationResult;
23 import org.dive4elements.river.artifacts.resources.Resources; 24 import org.dive4elements.river.artifacts.resources.Resources;
24 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; 25 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
26 import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder;
27 import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsUtils;
28 import org.dive4elements.river.artifacts.sinfo.tkhstate.DefaultBedHeights;
25 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; 29 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils;
26 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; 30 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
27 import org.dive4elements.river.artifacts.uinfo.UINFOArtifact; 31 import org.dive4elements.river.artifacts.uinfo.UINFOArtifact;
28 import org.dive4elements.river.artifacts.uinfo.salix.SalixLineAccess.ScenarioType; 32 import org.dive4elements.river.artifacts.uinfo.salix.SalixLineAccess.ScenarioType;
33 import org.dive4elements.river.model.BedHeight;
29 import org.dive4elements.river.model.River; 34 import org.dive4elements.river.model.River;
35 import org.dive4elements.river.utils.Formatter;
30 36
31 /** 37 /**
38 * Calculation of a iota (former salix) longitudinal section, optionally with a delta scenario
39 *
32 * @author Domenico Nardi Tironi 40 * @author Domenico Nardi Tironi
41 * @author Matthias Schäfer
33 * 42 *
34 */ 43 */
35 final class SalixLineCalculation { 44 final class SalixLineCalculation {
36 45
37 private final CallContext context; 46 private final CallContext context;
38 47
48 private Calculation problems;
49
39 public SalixLineCalculation(final CallContext context) { 50 public SalixLineCalculation(final CallContext context) {
40 this.context = context; 51 this.context = context;
41 } 52 }
42 53
54 /**
55 * Calculates the iota longitudinal section and delta scenario of a uinfo artifact
56 */
43 public CalculationResult calculate(final UINFOArtifact uinfo) { 57 public CalculationResult calculate(final UINFOArtifact uinfo) {
44 final Calculation problems = new Calculation(); 58 this.problems = new Calculation();
45 59
46 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), uinfo.getCalculationMode().name()); 60 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), uinfo.getCalculationMode().name());
47 final String user = CalculationUtils.findArtifactUser(this.context, uinfo); 61 final String user = CalculationUtils.findArtifactUser(this.context, uinfo);
48 62
49 final SalixLineAccess accessSalix = new SalixLineAccess(uinfo); 63 final SalixLineAccess accessSalix = new SalixLineAccess(uinfo);
60 final SalixLineCalculationResults results = new SalixLineCalculationResults(calcModeLabel, user, riverInfo, range); 74 final SalixLineCalculationResults results = new SalixLineCalculationResults(calcModeLabel, user, riverInfo, range);
61 75
62 final SalixLineCalculator calculator = new SalixLineCalculator(riverInfoProvider); 76 final SalixLineCalculator calculator = new SalixLineCalculator(riverInfoProvider);
63 final NavigableMap<Double, List<Double>> rangeScenarios = buildRangeScenarios(accessSalix); 77 final NavigableMap<Double, List<Double>> rangeScenarios = buildRangeScenarios(accessSalix);
64 78
65 calculator.execute(problems, uinfo, rangeScenarios, scenarioType, buildScenarioLabels(accessSalix), buildPartialRangeString(accessSalix), 79 calculator.execute(this.problems, uinfo, rangeScenarios, scenarioType, buildScenarioLabels(accessSalix), buildPartialRangeString(accessSalix),
66 buildAdditionalString(accessSalix), results); 80 buildAdditionalString(accessSalix), results);
67 81
68 return new CalculationResult(results, problems); 82 return new CalculationResult(results, this.problems);
69 } 83 }
70 84
71 /** 85 /**
72 * Build a map of delta-Ws by from-km for the selected scenario 86 * Builds a map of delta-Ws by from-km for the selected scenario
73 */ 87 */
74 private NavigableMap<Double, List<Double>> buildRangeScenarios(final SalixLineAccess access) { 88 private NavigableMap<Double, List<Double>> buildRangeScenarios(final SalixLineAccess access) {
75 final NavigableMap<Double, List<Double>> rangeScenarios = new TreeMap<>(); 89 final NavigableMap<Double, List<Double>> rangeScenarios = new TreeMap<>();
76 if (access.getScenario() == ScenarioType.REGIONAL) 90 if (access.getScenario() == ScenarioType.REGIONAL)
77 fillRangeScenarios(rangeScenarios, access, access.getFromPart().doubleValue(), access.getToPart().doubleValue(), 91 fillRangeScenarios(rangeScenarios, access, access.getFromPart().doubleValue(), access.getToPart().doubleValue(),
78 access.getRegionalScenarioIntegers()); 92 access.getRegionalScenarioIntegers());
79 else if (access.getScenario() == ScenarioType.SUPRAREGIONAL) 93 else if (access.getScenario() == ScenarioType.SUPRAREGIONAL)
80 fillRangeScenarios(rangeScenarios, access.getSupraRegionalString()); 94 fillRangeScenarios(rangeScenarios, access.getSupraRegionalString());
81 // TODO else if (access.getScenario().equals(ScenarioType.HISTORICAL.getKey())) 95 else if (access.getScenario() == ScenarioType.HISTORICAL)
82 // historisches Szenario aus MSH etc. 96 fillRangeScenarios(rangeScenarios, access, access.getFromPart().doubleValue(), access.getToPart().doubleValue(), access.getBedHeightId());
83 else 97 else
84 fillRangeScenarios(rangeScenarios, access); 98 fillRangeScenarios(rangeScenarios, access);
85 99
86 return rangeScenarios; 100 return rangeScenarios;
87 } 101 }
88 102
89 /** 103 /**
90 * Fill a map of delta-Ws with only one 0-delta for the whole calc range (no scenario) 104 * Fills a map of delta-Ws with only one 0-delta for the whole calc range (no scenario)
91 */ 105 */
92 private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final RangeAccess calcRange) { 106 private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final RangeAccess calcRange) {
93 final List<Double> nulls = new ArrayList<>(); 107 final List<Double> nulls = new ArrayList<>();
94 nulls.add(0.0); 108 nulls.add(null);
95 rangeScenarios.put(Double.valueOf(calcRange.getLowerKm() - 0.0001), nulls); 109 rangeScenarios.put(Double.valueOf(calcRange.getLowerKm() - 0.0001), nulls);
96 } 110 }
97 111
98 /** 112 /**
99 * Fill a map of delta-Ws by km-range from the regional scenario input data 113 * Fills a map of delta-Ws by km-range from the regional scenario input data
100 */ 114 */
101 private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final RangeAccess calcRange, final double partFrom, 115 private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final RangeAccess calcRange,
102 final double partTo, final int[] deltaWs) { 116 final double partFrom, final double partTo, final int[] deltaWs) {
103 final List<Double> nulls = new ArrayList<>(); 117 final List<Double> nulls = new ArrayList<>();
104 final List<Double> dwsm = new ArrayList<>(); 118 final List<Double> dwsm = new ArrayList<>();
105 for (int i = 0; i <= deltaWs.length - 1; i++) { 119 for (int i = 0; i <= deltaWs.length - 1; i++) {
106 nulls.add(0.0); 120 nulls.add(null);
107 dwsm.add(deltaWs[i] / 100.0); 121 dwsm.add(deltaWs[i] / 100.0);
108 } 122 }
109 rangeScenarios.put(Double.valueOf(calcRange.getLowerKm() - 0.0001), nulls); 123 rangeScenarios.put(Double.valueOf(calcRange.getLowerKm() - 0.0001), nulls);
110 rangeScenarios.put(Double.valueOf(partFrom - 0.0001), dwsm); 124 rangeScenarios.put(Double.valueOf(partFrom - 0.0001), dwsm);
111 rangeScenarios.put(Double.valueOf(partTo + 0.0001), nulls); 125 rangeScenarios.put(Double.valueOf(partTo + 0.0001), nulls);
112 } 126 }
113 127
114 /** 128 /**
115 * Fill a map of delta-Ws by km-range from the supraregional scenario input data 129 * Fills a map of delta-Ws by km-range from the supraregional scenario input data
116 * (the zones input by the user cover the calc range completely) 130 * (the zones input by the user cover the calc range completely)
117 */ 131 */
118 private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final String zones) { 132 private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final String zones) {
119 final List<SalixZone> parts = SalixZone.parse(zones); 133 final List<SalixZone> parts = SalixZone.parse(zones);
120 for (final SalixZone part : parts) { 134 for (final SalixZone part : parts) {
121 final List<Double> dwsm = new ArrayList<>(); 135 final List<Double> dwsm = new ArrayList<>();
122 dwsm.add(part.getDwsplValue() / 100.0); 136 if (part.getDwsplValue() == 0)
137 dwsm.add(null);
138 else
139 dwsm.add(part.getDwsplValue() / 100.0);
123 rangeScenarios.put(Double.valueOf(part.getFromKm().doubleValue() - 0.0001), dwsm); 140 rangeScenarios.put(Double.valueOf(part.getFromKm().doubleValue() - 0.0001), dwsm);
124 } 141 }
125 } 142 }
126 143
127 /** 144 /**
128 * Build the list of delta-w labels for the scenario type 145 * Fetches historical and reference bed heights and fills a map of delta-MSHs for all fetched stations in the calc range
146 */
147 private void fillRangeScenarios(final NavigableMap<Double, List<Double>> rangeScenarios, final RangeAccess calcRange,
148 final double partFrom, final double partTo, final int historicalBedHeightId) {
149
150 // Find relevant default bed-heights
151 final River river = calcRange.getRiver();
152 final List<BedHeight> defaultBedHeights = new DefaultBedHeights(river).getBedHeights(this.problems);
153 if (defaultBedHeights.isEmpty())
154 return;
155 final DoubleRange scenarioRange = new DoubleRange(partFrom, partTo);
156 final Collection<BedHeightsFinder> allFinders = BedHeightsFinder.createTkhBedHeights(this.problems, scenarioRange, defaultBedHeights);
157 final Collection<BedHeightsFinder> currentFinders = new ArrayList<>(allFinders);
158
159 // Add historical bed-heights
160 final BedHeightsFinder historicalFinder = BedHeightsFinder.forId(this.problems, historicalBedHeightId, scenarioRange);
161 allFinders.add(historicalFinder);
162 final Collection<Double> stations = BedHeightsUtils.extractStationCollection(allFinders, true);
163 final List<Double> nulls = new ArrayList<>();
164 nulls.add(null);
165 rangeScenarios.put(Double.valueOf(calcRange.getLowerKm() - 0.0001), nulls);
166 for (final Double station : stations) {
167 rangeScenarios.put(station, new ArrayList<Double>());
168 rangeScenarios.get(station).add(Double.valueOf(bedHeightDifference(station.doubleValue(), currentFinders, historicalFinder)));
169 }
170 rangeScenarios.put(Double.valueOf(partTo + 0.0001), nulls);
171 }
172
173 /**
174 * Gets the difference of a historical bed height against a current one for a station
175 */
176 private double bedHeightDifference(final double station, final Collection<BedHeightsFinder> currentFinders, final BedHeightsFinder historicalFinder) {
177 double currentMSH = Double.NaN;
178 for (final BedHeightsFinder bhf : currentFinders) {
179 currentMSH = bhf.getMeanBedHeight(station);
180 if (!Double.isNaN(currentMSH))
181 break;
182 }
183 return Formatter.roundFlowDepth(historicalFinder.getMeanBedHeight(station)).subtract(Formatter.roundFlowDepth(currentMSH)).doubleValue();
184 }
185
186 /**
187 * Builds the list of delta-w labels for the scenario type
129 */ 188 */
130 private String[] buildScenarioLabels(final SalixLineAccess access) { 189 private String[] buildScenarioLabels(final SalixLineAccess access) {
131 final List<String> labels = new ArrayList<>(); 190 final List<String> labels = new ArrayList<>();
132 if (access.getScenario() == ScenarioType.REGIONAL) { 191 if (access.getScenario() == ScenarioType.REGIONAL) {
133 final int[] deltaws = access.getRegionalScenarioIntegers(); 192 final int[] deltaws = access.getRegionalScenarioIntegers();
140 labels.add(Resources.getMsg(this.context.getMeta(), "uinfo_salix_scenario_historical")); 199 labels.add(Resources.getMsg(this.context.getMeta(), "uinfo_salix_scenario_historical"));
141 return labels.toArray(new String[labels.size()]); 200 return labels.toArray(new String[labels.size()]);
142 } 201 }
143 202
144 /** 203 /**
145 * Build the km range string for the scenario type 204 * Builds the km range string for the scenario type
146 */ 205 */
147 private String buildPartialRangeString(final SalixLineAccess access) { 206 private String buildPartialRangeString(final SalixLineAccess access) {
148 if ((access.getScenario() == ScenarioType.REGIONAL) || (access.getScenario() == ScenarioType.HISTORICAL)) { 207 if ((access.getScenario() == ScenarioType.REGIONAL) || (access.getScenario() == ScenarioType.HISTORICAL)) {
149 return String.format("%s - %s", GeneralResultType.station.exportValue(this.context, access.getFromPart().doubleValue()), 208 return String.format("%s - %s", GeneralResultType.station.exportValue(this.context, access.getFromPart().doubleValue()),
150 GeneralResultType.station.exportValue(this.context, access.getToPart().doubleValue())); 209 GeneralResultType.station.exportValue(this.context, access.getToPart().doubleValue()));
164 } 223 }
165 return ""; 224 return "";
166 } 225 }
167 226
168 /** 227 /**
169 * Build the delta w or time string for the scenario type 228 * Builds the delta w or time string for the scenario type
170 */ 229 */
171 private String buildAdditionalString(final SalixLineAccess access) { 230 private String buildAdditionalString(final SalixLineAccess access) {
172 if (access.getScenario() == ScenarioType.REGIONAL) { 231 if (access.getScenario() == ScenarioType.REGIONAL) {
173 String deltas = ""; 232 String deltas = "";
174 String sep = ""; 233 String sep = "";

http://dive4elements.wald.intevation.org