Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculation.java @ 9617:1d4262a68f1f
#12 Minuend/Subtrahend + MergeConflict #19 CollisionCalculation
author | dnt_bjoernsen <d.tironi@bjoernsen.de> |
---|---|
date | Thu, 10 Oct 2019 15:29:02 +0200 |
parents | f2473dc34535 |
children |
comparison
equal
deleted
inserted
replaced
9616:cedcee24a21a | 9617:1d4262a68f1f |
---|---|
1 /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde | 1 /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde |
2 * Software engineering by | 2 * Software engineering by |
3 * Björnsen Beratende Ingenieure GmbH | 3 * Björnsen Beratende Ingenieure GmbH |
4 * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt | 4 * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt |
5 * | 5 * |
6 * This file is Free Software under the GNU AGPL (>=v3) | 6 * This file is Free Software under the GNU AGPL (>=v3) |
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.sinfo.collision; | 10 package org.dive4elements.river.artifacts.sinfo.collision; |
11 | 11 |
12 import java.util.ArrayList; | 12 import java.util.ArrayList; |
13 import java.util.Collection; | 13 import java.util.Collection; |
14 import java.util.Collections; | |
14 import java.util.Date; | 15 import java.util.Date; |
15 import java.util.HashMap; | 16 import java.util.HashMap; |
16 import java.util.List; | 17 import java.util.List; |
17 import java.util.Map; | 18 import java.util.Map; |
18 import java.util.Map.Entry; | 19 import java.util.Map.Entry; |
46 | 47 |
47 // private static Logger log = Logger.getLogger(FloodDurationCalculation.class); | 48 // private static Logger log = Logger.getLogger(FloodDurationCalculation.class); |
48 | 49 |
49 private final CallContext context; | 50 private final CallContext context; |
50 | 51 |
51 private CollisionAccess access; | |
52 private River river; | |
53 private List<DateRange> years; | |
54 private Calculation problems; | |
55 private int qfinderProblemCount; | |
56 | |
57 public CollisionCalculation(final CallContext context) { | 52 public CollisionCalculation(final CallContext context) { |
58 this.context = context; | 53 this.context = context; |
59 } | 54 } |
60 | 55 |
61 public CalculationResult calculate(final SINFOArtifact sinfo) { | 56 public CalculationResult calculate(final SINFOArtifact sinfo) { |
62 | 57 |
63 final String user = CalculationUtils.findArtifactUser(this.context, sinfo); | 58 final String user = CalculationUtils.findArtifactUser(this.context, sinfo); |
64 | 59 |
60 final int qfinderProblemCount = 0; | |
61 | |
65 // access input data | 62 // access input data |
66 this.access = new CollisionAccess(sinfo); | 63 final CollisionAccess access = new CollisionAccess(sinfo); |
67 this.river = this.access.getRiver(); | 64 final River river = access.getRiver(); |
68 final RiverInfo riverInfo = new RiverInfo(this.river); | 65 final RiverInfo riverInfo = new RiverInfo(river); |
69 final DoubleRange calcRange = this.access.getRange(); | 66 |
67 final DoubleRange calcRange = access.getRange(); | |
70 | 68 |
71 // calculate results for each year or epoch | 69 // calculate results for each year or epoch |
72 this.problems = new Calculation(); | 70 final Calculation problems = new Calculation(); |
73 this.qfinderProblemCount = 0; | 71 |
74 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); | 72 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); |
75 | 73 |
76 final CollisionCalculationResults results = new CollisionCalculationResults(calcModeLabel, user, riverInfo, calcRange, this.access.getYearsHeader()); | 74 final CollisionCalculationResults results = new CollisionCalculationResults(calcModeLabel, user, riverInfo, calcRange, access.getYearsHeader()); |
77 | 75 |
78 final Collection<ResultRow> overViewRows = new ArrayList<>(); | 76 final Collection<ResultRow> overViewRows = new ArrayList<>(); |
79 | 77 |
80 this.years = new ArrayList<>(); | 78 final List<DateRange> years = new ArrayList<>(); |
81 final NavigableSet<Integer> detailYears = new TreeSet<>(); | 79 final NavigableSet<Integer> detailYears = new TreeSet<>(); |
82 if (this.access.getYears() != null) { | 80 final List<CollisionCalcOverviewResult> singleYearResults = new ArrayList<>(); |
83 for (final int year : this.access.getYears()) { | 81 if (access.getYears() != null) { |
84 calculateOverview(overViewRows, year, year, false); | 82 for (final int year : access.getYears()) { |
85 this.years.add(new DateRange(DateUtil.getStartDateFromYear(year), DateUtil.getEndDateFromYear(year))); | 83 calculateOverview(overViewRows, river, access.getLowerKm(), access.getUpperKm(), year, year, false); |
84 years.add(new DateRange(DateUtil.getStartDateFromYear(year), DateUtil.getEndDateFromYear(year))); | |
86 detailYears.add(Integer.valueOf(year)); | 85 detailYears.add(Integer.valueOf(year)); |
87 } | 86 } |
88 } else { | 87 } else { |
89 for (final DateRange dr : this.access.getEpochs()) { | 88 for (final DateRange dr : access.getEpochs()) { |
90 calculateOverview(overViewRows, dr.getFromYear(), dr.getToYear(), true); | 89 calculateOverview(overViewRows, river, access.getLowerKm(), access.getUpperKm(), dr.getFromYear(), dr.getToYear(), true); |
91 this.years.add(dr); | 90 years.add(dr); |
92 detailYearsAdd(detailYears, dr); | 91 detailYearsAdd(detailYears, dr); |
93 } | 92 } |
94 } | 93 |
95 final CollisionCalcOverviewResult overviewResult = new CollisionCalcOverviewResult(this.access.getYearsHeader(), (this.access.getYears() == null), | 94 for (final Integer year : detailYears) { |
96 this.years, overViewRows); | 95 |
97 results.addResult(overviewResult, this.problems); | 96 final Collection<ResultRow> yearRows = new ArrayList<>(); |
97 calculateOverview(yearRows, river, access.getLowerKm(), access.getUpperKm(), year, year, false); | |
98 | |
99 if (!yearRows.isEmpty()) { | |
100 final DateRange yearRange = new DateRange(DateUtil.getStartDateFromYear(year), DateUtil.getEndDateFromYear(year)); | |
101 final CollisionCalcOverviewResult yearResult = new CollisionCalcOverviewResult(Integer.toString(year), false, | |
102 Collections.singleton(yearRange), yearRows); | |
103 singleYearResults.add(yearResult); | |
104 } | |
105 } | |
106 } | |
107 final CollisionCalcOverviewResult overviewResult = new CollisionCalcOverviewResult(access.getYearsHeader(), (access.getYears() == null), years, | |
108 overViewRows); | |
109 results.addResult(overviewResult, problems); | |
110 | |
111 /* add the single year from epochs, after the epochs, so they will be exported at the end of the table etc. */ | |
112 for (final CollisionCalcOverviewResult result : singleYearResults) | |
113 results.addResult(result, problems); | |
98 | 114 |
99 // calculate secondary results for each year | 115 // calculate secondary results for each year |
100 final Map<String, TreeMap<Date, GaugeDischargeValuesFinder>> qFinders = new HashMap<>(); | 116 final Map<String, TreeMap<Date, GaugeDischargeValuesFinder>> qFinders = new HashMap<>(); |
101 final Map<String, GaugeMainValueFinder> zoneFinders = new HashMap<>(); | 117 final Map<String, GaugeMainValueFinder> zoneFinders = new HashMap<>(); |
102 final Collection<ResultRow> detailsRows = new ArrayList<>(); | 118 final Collection<ResultRow> detailsRows = new ArrayList<>(); |
103 for (final Integer year : detailYears) | 119 for (final Integer year : detailYears) |
104 calculateDetails(detailsRows, year, qFinders, zoneFinders); | 120 calculateDetails(detailsRows, river, access, year, qFinders, zoneFinders, problems, years, qfinderProblemCount); |
105 final CollisionCalcDetailResult detailResult = new CollisionCalcDetailResult("Details", detailsRows); | 121 final CollisionCalcDetailResult detailResult = new CollisionCalcDetailResult("Details", detailsRows); |
106 results.addResult(detailResult, this.problems); | 122 results.addResult(detailResult, problems); |
107 | 123 |
108 return new CalculationResult(results, this.problems); | 124 return new CalculationResult(results, problems); |
109 } | 125 } |
110 | 126 |
111 /** | 127 /** |
112 * Adds all years of an epoch to a set | 128 * Adds all years of an epoch to a set |
113 */ | 129 */ |
118 | 134 |
119 /** | 135 /** |
120 * Calculates the collision counts for a km range of a river and a year or year range (epoch), | 136 * Calculates the collision counts for a km range of a river and a year or year range (epoch), |
121 * and adds them to a ResultRow collection | 137 * and adds them to a ResultRow collection |
122 */ | 138 */ |
123 private void calculateOverview(final Collection<ResultRow> rows, final int fromYear, final int toYear, final boolean isEpoch) { | 139 private void calculateOverview(final Collection<ResultRow> rows, final River river, final double fromKm, final double toKm, final int fromYear, |
124 for (final CollisionAggregateValue aggregate : CollisionAggregateValue.getValuesByKm(this.river, this.access.getLowerKm(), this.access.getUpperKm(), | 140 final int toYear, final boolean isEpoch) { |
125 fromYear, toYear)) { | 141 for (final CollisionAggregateValue aggregate : CollisionAggregateValue.getValuesByKm(river, fromKm, toKm, fromYear, toYear)) { |
126 rows.add(ResultRow.create().putValue(GeneralResultType.station, aggregate.getStation()) | 142 rows.add(ResultRow.create().putValue(GeneralResultType.station, aggregate.getStation()) |
127 .putValue(SInfoResultType.years, yearsToString(isEpoch, fromYear, toYear)).putValue(SInfoResultType.collisionCount, aggregate.getCount())); | 143 .putValue(SInfoResultType.years, yearsToString(isEpoch, fromYear, toYear)).putValue(SInfoResultType.collisionCount, aggregate.getCount())); |
128 } | 144 } |
129 } | 145 } |
130 | 146 |
142 return (isEpoch ? String.format("%d-%d", fromYear, toYear) : Integer.toString(fromYear)); | 158 return (isEpoch ? String.format("%d-%d", fromYear, toYear) : Integer.toString(fromYear)); |
143 } | 159 } |
144 | 160 |
145 /** | 161 /** |
146 * Calculates the collision details for a km range of a river and a year, and adds them to a ResultRow collection | 162 * Calculates the collision details for a km range of a river and a year, and adds them to a ResultRow collection |
147 */ | 163 * |
148 private void calculateDetails(final Collection<ResultRow> rows, final int year, final Map<String, TreeMap<Date, GaugeDischargeValuesFinder>> qFinders, | 164 * @param qfinderProblemCount |
149 final Map<String, GaugeMainValueFinder> zoneFinders) { | 165 */ |
150 | 166 private void calculateDetails(final Collection<ResultRow> rows, final River river, final CollisionAccess access, final int year, |
151 for (final CollisionValue collision : CollisionValue.getValues(this.river, this.access.getLowerKm(), this.access.getUpperKm(), | 167 final Map<String, TreeMap<Date, GaugeDischargeValuesFinder>> qFinders, final Map<String, GaugeMainValueFinder> zoneFinders, |
152 DateUtil.getStartDateFromYear(year), DateUtil.getEndDateFromYear(year))) { | 168 final Calculation problems, final List<DateRange> years, final int qfinderProblemCount) { |
169 | |
170 final double fromKm = access.getLowerKm(); | |
171 final double toKm = access.getUpperKm(); | |
172 | |
173 for (final CollisionValue collision : CollisionValue.getValues(river, fromKm, toKm, DateUtil.getStartDateFromYear(year), | |
174 DateUtil.getEndDateFromYear(year))) { | |
153 final String gaugeName = collision.getGaugeName(); | 175 final String gaugeName = collision.getGaugeName(); |
154 final double q = getQ(qFinders, gaugeName, collision.getGaugeW().doubleValue(), collision.getEventDate()); | 176 final double q = getQ(qFinders, gaugeName, collision.getGaugeW().doubleValue(), collision.getEventDate(), river, problems, years, |
177 qfinderProblemCount); | |
155 final double qOut = Double.isInfinite(q) ? Double.NaN : q; | 178 final double qOut = Double.isInfinite(q) ? Double.NaN : q; |
156 final String zone = getZone(zoneFinders, gaugeName, q); | 179 final String zone = getZone(zoneFinders, gaugeName, q, river, problems); |
157 rows.add(ResultRow.create().putValue(GeneralResultType.station, collision.getStation()) | 180 rows.add(ResultRow.create().putValue(GeneralResultType.station, collision.getStation()) |
158 .putValue(GeneralResultType.dateShort, collision.getEventDate()).putValue(SInfoResultType.collisionGaugeW, collision.getGaugeW()) | 181 .putValue(GeneralResultType.dateShort, collision.getEventDate()).putValue(SInfoResultType.collisionGaugeW, collision.getGaugeW()) |
159 .putValue(GeneralResultType.gaugeLabel, gaugeName).putValue(SInfoResultType.dischargeLong, qOut) | 182 .putValue(GeneralResultType.gaugeLabel, gaugeName).putValue(SInfoResultType.dischargeLong, qOut) |
160 .putValue(SInfoResultType.dischargeZone, zone)); | 183 .putValue(SInfoResultType.dischargeZone, zone)); |
161 } | 184 } |
162 } | 185 } |
163 | 186 |
164 /** | 187 /** |
165 * Gets the discharge of a gauge and a W | 188 * Gets the discharge of a gauge and a W |
166 */ | 189 * |
167 private double getQ(final Map<String, TreeMap<Date, GaugeDischargeValuesFinder>> qFinders, final String gaugeName, final double w, final Date when) { | 190 * @param years |
191 * @param qfinderProblemCount | |
192 */ | |
193 private double getQ(final Map<String, TreeMap<Date, GaugeDischargeValuesFinder>> qFinders, final String gaugeName, final double w, final Date when, | |
194 final River river, final Calculation problems, final List<DateRange> years, int qfinderProblemCount) { | |
168 // Find the gauge and load its discharge table, if not already in the map | 195 // Find the gauge and load its discharge table, if not already in the map |
169 final String gnKey = gaugeName.toLowerCase(); | 196 final String gnKey = gaugeName.toLowerCase(); |
170 if (!qFinders.containsKey(gnKey)) | 197 if (!qFinders.containsKey(gnKey)) |
171 addQFinders(qFinders, gaugeName); | 198 addQFinders(qFinders, gaugeName, problems, river, years); |
199 | |
200 // Interpolate W. | |
172 // Interpolate W. | 201 // Interpolate W. |
173 final GaugeDischargeValuesFinder qFinder = getQFinder(qFinders.get(gnKey), when); | 202 final GaugeDischargeValuesFinder qFinder = getQFinder(qFinders.get(gnKey), when); |
174 if (qFinder == null) { | 203 if (qFinder == null) { |
175 this.qfinderProblemCount++; | 204 qfinderProblemCount++; |
176 if (this.qfinderProblemCount == 1) | 205 if (qfinderProblemCount == 1) |
177 this.problems.addProblem("gauge_discharge_table.missing", gaugeName); | 206 problems.addProblem("gauge_discharge_table.missing", gaugeName); |
178 return Double.NaN; | 207 return Double.NaN; |
179 } | 208 } |
180 return qFinder.getDischarge(w); | 209 return qFinder.getDischarge(w); |
181 } | 210 } |
182 | 211 |
183 /** | 212 /** |
184 * Add the discharge finders for a gauge and the active time period | 213 * Add the discharge finders for a gauge and the active time period |
185 */ | 214 */ |
186 private void addQFinders(final Map<String, TreeMap<Date, GaugeDischargeValuesFinder>> qFinders, final String gaugeName) { | 215 private void addQFinders(final Map<String, TreeMap<Date, GaugeDischargeValuesFinder>> qFinders, final String gaugeName, final Calculation problems, |
216 final River river, final List<DateRange> years) { | |
187 final String gnKey = gaugeName.toLowerCase(); | 217 final String gnKey = gaugeName.toLowerCase(); |
188 final Gauge gauge = this.river.determineGaugeByName(gaugeName); | 218 final Gauge gauge = river.determineGaugeByName(gaugeName); |
189 if (gauge == null) { | 219 if (gauge == null) { |
190 qFinders.put(gnKey, new TreeMap<Date, GaugeDischargeValuesFinder>()); | 220 qFinders.put(gnKey, new TreeMap<Date, GaugeDischargeValuesFinder>()); |
191 return; | 221 return; |
192 } | 222 } |
193 final List<DischargeTable> qtables = DischargeTable.fetchHistoricalDischargeTables(gauge, this.years.get(0).getFrom(), | 223 final List<DischargeTable> qtables = DischargeTable.fetchHistoricalDischargeTables(gauge, years.get(0).getFrom(), years.get(years.size() - 1).getTo()); |
194 this.years.get(this.years.size() - 1).getTo()); | |
195 qFinders.put(gnKey, new TreeMap<Date, GaugeDischargeValuesFinder>()); | 224 qFinders.put(gnKey, new TreeMap<Date, GaugeDischargeValuesFinder>()); |
196 for (final DischargeTable qtable : qtables) | 225 for (final DischargeTable qtable : qtables) |
197 qFinders.get(gnKey).put(qtable.getTimeInterval().getStartTime(), | 226 qFinders.get(gnKey).put(qtable.getTimeInterval().getStartTime(), GaugeDischargeValuesFinder.loadValues(qtable, river, gaugeName, problems)); |
198 GaugeDischargeValuesFinder.loadValues(qtable, this.river, gaugeName, this.problems)); | |
199 } | 227 } |
200 | 228 |
201 /** | 229 /** |
202 * Searches a q values finder map for a date time | 230 * Searches a q values finder map for a date time |
203 */ | 231 */ |
213 } | 241 } |
214 | 242 |
215 /** | 243 /** |
216 * Gets the main value zone name of a gauge and a Q | 244 * Gets the main value zone name of a gauge and a Q |
217 */ | 245 */ |
218 private String getZone(final Map<String, GaugeMainValueFinder> zoneFinders, final String gaugeName, final double q) { | 246 private String getZone(final Map<String, GaugeMainValueFinder> zoneFinders, final String gaugeName, final double q, final River river, |
247 final Calculation problems) { | |
219 // Find the gauge and load its main value list, if not already in the map | 248 // Find the gauge and load its main value list, if not already in the map |
220 final String gnKey = gaugeName.toLowerCase(); | 249 final String gnKey = gaugeName.toLowerCase(); |
221 if (!zoneFinders.containsKey(gnKey)) | 250 if (!zoneFinders.containsKey(gnKey)) |
222 zoneFinders.put(gnKey, GaugeMainValueFinder.loadValues(MainValueTypeKey.Q, this.river, gaugeName, this.problems, "GLQ")); | 251 zoneFinders.put(gnKey, GaugeMainValueFinder.loadValues(MainValueTypeKey.Q, river, gaugeName, problems, "GLQ")); |
223 // Build the zone name | 252 // Build the zone name |
224 if (zoneFinders.get(gnKey) == null) | 253 if (zoneFinders.get(gnKey) == null) |
225 return ""; | 254 return ""; |
226 return zoneFinders.get(gnKey).findZoneName(q); | 255 return zoneFinders.get(gnKey).findZoneName(q); |
227 } | 256 } |