comparison artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadDataFacet.java @ 8090:01f778f84330

Move the old data facet out of the way.
author Andre Heinecke <andre.heinecke@intevation.de>
date Fri, 15 Aug 2014 14:28:26 +0200
parents artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFacet.java@5e3f4b4fcb28
children bb0d35d32b01
comparison
equal deleted inserted replaced
8088:b834caf0a4f0 8090:01f778f84330
1 /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
2 * Software engineering by Intevation GmbH
3 *
4 * This file is Free Software under the GNU AGPL (>=v3)
5 * and comes with ABSOLUTELY NO WARRANTY! Check out the
6 * documentation coming with Dive4Elements River for details.
7 */
8
9 package org.dive4elements.river.artifacts.model.minfo;
10
11 import gnu.trove.TDoubleArrayList;
12
13 import org.dive4elements.artifactdatabase.state.Facet;
14
15 import org.dive4elements.artifacts.Artifact;
16 import org.dive4elements.artifacts.CallContext;
17
18 import org.dive4elements.river.artifacts.D4EArtifact;
19
20 import org.dive4elements.river.artifacts.model.CalculationResult;
21 import org.dive4elements.river.artifacts.model.DataFacet;
22 import org.dive4elements.river.artifacts.model.FacetTypes;
23
24 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
25
26 import org.dive4elements.river.model.MeasurementStation;
27
28 import org.dive4elements.river.utils.RiverUtils;
29
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.TreeSet;
35 import java.util.TreeMap;
36
37 import org.apache.log4j.Logger;
38
39
40 /** Facet to access various sediment loads. */
41 public class SedimentLoadFacet
42 extends DataFacet
43 {
44 /** Very own logger. */
45 private static Logger logger = Logger.getLogger(SedimentLoadFacet.class);
46
47 /** Used as tolerance value when fetching measurement stations. */
48 private static double EPSILON = 1e-5;
49
50
51 public SedimentLoadFacet() {
52 }
53
54 public SedimentLoadFacet(int idx, String name, String description,
55 ComputeType type, String stateId, String hash) {
56 super(idx, name, description, type, hash, stateId);
57 this.metaData.put("X", "chart.longitudinal.section.xaxis.label");
58 this.metaData.put("Y", "");
59 }
60
61 @Override
62 public Object getData(Artifact artifact, CallContext context) {
63 logger.debug("Get data for sediment load at index: " + index);
64
65 D4EArtifact flys = (D4EArtifact) artifact;
66
67 CalculationResult res = (CalculationResult) flys.compute(context, hash,
68 stateId, type, false);
69
70 Object[] data =
71 (SedimentLoadResult[]) res.getData(); // TODO CAST TO SPECIFIC CLASS
72
73 List<MeasurementStation> allStations = RiverUtils.getRiver(flys).getMeasurementStations();
74 SedimentLoadResult result = data != null && data.length > index ? (SedimentLoadResult)data[index] : null;
75 if (result == null) {
76 return null;
77 }
78
79 // These complicated calculations were necessary because
80 // SedimentLoad/Fraction did not contain the ranges of the given
81 // values. Since this changed, the code is somewhat obsolete, but stable.
82 // For an example of easier calculation, see the "total" part below.
83
84 List<Double> sortedStarts = new ArrayList<Double>();
85 // Filter stations according to type.
86 List<MeasurementStation> stations = new ArrayList<MeasurementStation>();
87 for (MeasurementStation station: allStations) {
88 if (station.getRange() == null || station.getMeasurementType() == null) {
89 continue;
90 }
91 if (this.getName().contains("susp_sediment")
92 && station.getMeasurementType().equals("Schwebstoff")) {
93 stations.add(station);
94 sortedStarts.add(station.getStation());
95 }
96 else if (!this.getName().contains("susp_sediment")
97 && station.getMeasurementType().equals("Geschiebe")) {
98 stations.add(station);
99 sortedStarts.add(station.getStation());
100 }
101 }
102 Collections.sort(sortedStarts);
103
104 // Handle sediment load differently, as it respects already
105 // the ranges that were added to SedimentLoad/Fraction.
106 if (getName().equals(FacetTypes.SEDIMENT_LOAD_TA_TOTAL)
107 ||getName().equals(FacetTypes.SEDIMENT_LOAD_M3A_TOTAL)) {
108 SedimentLoadLSData load = result.getLoad();
109 TDoubleArrayList xPos = new TDoubleArrayList();
110 TDoubleArrayList yPos = new TDoubleArrayList();
111 double lastX = -1d;
112 for (double km: new TreeSet<Double>(load.getKms())) {
113 SedimentLoadFraction fraction = load.getFraction(km);
114 if (fraction.getTotal() != 0) {
115 if (Math.abs(lastX-km) >= EPSILON) {
116 xPos.add(Double.NaN);
117 yPos.add(Double.NaN);
118 }
119 xPos.add(km);
120 yPos.add(fraction.getTotal());
121 xPos.add(fraction.getTotalRange().getEnd());
122 yPos.add(fraction.getTotal());
123 lastX = fraction.getTotalRange().getEnd();
124 }
125 }
126 return new double[][] {xPos.toNativeArray(), yPos.toNativeArray()};
127 }
128
129 // Access data according to type (except total - see above).
130 double[][] sd = getLoadData(result);
131
132 // Sort by km.
133 TreeMap<Double, Double> sortedKmLoad = new TreeMap<Double,Double>();
134
135 double[] km = sd[0];
136 double[] load = sd[1];
137
138 // Build map of km->load, but directly exclude the ones which do
139 // not match against a measurements station ranges start.
140 for (int i = 0 ; i < km.length; i++) {
141 for (MeasurementStation station: stations) {
142 if (Math.abs(station.getStation() - km[i]) <= EPSILON) {
143 sortedKmLoad.put(km[i], load[i]);
144 continue;
145 }
146 }
147 }
148
149 // [0] -> x, [1] -> y
150 double[][] values = new double[2][];
151 values[0] = new double[sortedKmLoad.size()*3];
152 values[1] = new double[sortedKmLoad.size()*3];
153
154 // Find station via its station (km).
155 // TODO use a binarySearch instead of linear absdiff approach
156 int i = 0;
157 for (Map.Entry<Double, Double> kmLoad: sortedKmLoad.entrySet()) {
158 boolean matchFound = false;
159 for (int k = 0, S = stations.size(); k < S; k++) {
160 MeasurementStation station = stations.get(k);
161 if (Math.abs(station.getStation() - kmLoad.getKey()) < EPSILON) {
162 // Value has been taken at measurement station.
163 values[0][i*3] = station.getRange().getA().doubleValue() + EPSILON;
164 values[1][i*3] = kmLoad.getValue();
165 double endValue = 0d;
166 // Valid until next measurements stations begin of range,
167 // or end of current range if last value.
168 if (k+2 <= S) {
169 endValue = stations.get(k+1).getRange().getA().doubleValue();
170 }
171 else {
172 endValue = station.getRange().getB().doubleValue();
173 }
174 values[0][i*3+1] = endValue;
175 values[1][i*3+1] = kmLoad.getValue();
176 values[0][i*3+2] = endValue;
177 values[1][i*3+2] = kmLoad.getValue();
178 matchFound = true;
179 break;
180 }
181 }
182 // Store points without match for later assessment.
183 if (!matchFound) {
184 logger.warn("measurement without station ("+kmLoad.getKey()+")!");
185 }
186 i++;
187 }
188
189 for (int x = 0; x < values[0].length-1; x++) {
190 // Introduce gaps where no data in measurement station.
191 if (Math.abs(values[0][x+1] - values[0][x]) > 3*EPSILON
192 && values[1][x+1] != values[1][x]) {
193 values[0][x] = Double.NaN;
194 values[1][x] = Double.NaN;
195 }
196 }
197
198 return values;
199 }
200
201
202 /** Get data according to type of facet. */
203 private double[][] getLoadData(SedimentLoadResult result) {
204 String name = getName();
205 if (FacetTypes.IS.SEDIMENT_LOAD_SAND(name))
206 return result.getSandData();
207 else if (FacetTypes.IS.SEDIMENT_LOAD_COARSE(name))
208 return result.getCoarseData();
209 else if (FacetTypes.IS.SEDIMENT_LOAD_FINEMIDDLE(name))
210 return result.getFineMiddleData();
211 else if (FacetTypes.IS.SEDIMENT_LOAD_SUSP_SAND(name))
212 return result.getSuspSandData();
213 else if (FacetTypes.IS.SEDIMENT_LOAD_SUSP_SAND_BED(name))
214 return result.getSuspSandBedData();
215 else if (FacetTypes.IS.SEDIMENT_LOAD_SUSP_SEDIMENT(name))
216 return result.getSuspSedimentData();
217 else if (FacetTypes.IS.SEDIMENT_LOAD_TOTAL_LOAD(name))
218 return result.getTotalLoadData();
219 else if (FacetTypes.IS.SEDIMENT_LOAD_TOTAL(name))
220 return result.getTotalData();
221 else {
222 logger.error("SedimentLoadFacet " + name + " cannot determine data type.");
223 return null;
224 }
225 }
226
227 /** Copy deeply. */
228 @Override
229 public Facet deepCopy() {
230 SedimentLoadFacet copy = new SedimentLoadFacet();
231 copy.set(this);
232 copy.type = type;
233 copy.hash = hash;
234 copy.stateId = stateId;
235 return copy;
236 }
237 }
238 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org