# HG changeset patch # User mschaefer # Date 1537266077 -7200 # Node ID 504f63512379359f3a76292ab64666926966c050 # Parent ce13a2f072903b4e179d05c4ca6d1e2a4c9a807e Sinfo collisions: calculation of multiple epochs, avoiding duplicate collision events in the details report diff -r ce13a2f07290 -r 504f63512379 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcFacet.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcFacet.java Mon Sep 17 19:07:57 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcFacet.java Tue Sep 18 12:21:17 2018 +0200 @@ -22,22 +22,22 @@ public class CollisionCalcFacet extends ResultFacet { private static final long serialVersionUID = 1; - private int year; + private String years; private CollisionCalcFacet() { super(); // required for clone operation deepCopy() } - public CollisionCalcFacet(final int facetIndex, final int resultIndex, final int year, final String name, final String description, + public CollisionCalcFacet(final int facetIndex, final int resultIndex, final String years, final String name, final String description, final String yAxisLabelKey, final ComputeType type, final String hash, final String stateId) { + super(facetIndex, resultIndex, name, description, yAxisLabelKey, type, stateId, hash); - - this.year = year; + this.years = years; } - public int getYear() { - return this.year; + public String getYears() { + return this.years; } /** Copy deeply. */ @@ -50,7 +50,7 @@ copy.type = this.type; copy.hash = this.hash; copy.stateId = this.stateId; - copy.year = this.year; + copy.years = this.years; return copy; } } \ No newline at end of file diff -r ce13a2f07290 -r 504f63512379 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcOverviewResult.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcOverviewResult.java Mon Sep 17 19:07:57 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcOverviewResult.java Tue Sep 18 12:21:17 2018 +0200 @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.List; import org.apache.commons.collections.Predicate; import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult; @@ -20,6 +21,7 @@ import org.dive4elements.river.artifacts.common.IResultType; import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource; import org.dive4elements.river.artifacts.common.ResultRow; +import org.dive4elements.river.artifacts.model.DateRange; import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; @@ -34,24 +36,31 @@ private static final String JASPER_FILE = "/jasper/templates/sinfo.collision.overview.jrxml"; - private final int[] singleYears; + private final boolean isEpochs; - public CollisionCalcOverviewResult(final String label, final int[] singleYears, final Collection rows) { + private final List years; + + public CollisionCalcOverviewResult(final String label, final boolean isEpochs, final Collection years, final Collection rows) { super(label, rows); - this.singleYears = singleYears; + this.isEpochs = isEpochs; + this.years = new ArrayList<>(years); } - public int[] getSingleYears() { - return this.singleYears; + public boolean getIsEpochs() { + return this.isEpochs; } - public double[][] getStationPointsByYear(final IResultType type, final int year) { + public List getYears() { + return this.years; + } + + public double[][] getStationPointsByYear(final IResultType type, final String years) { final Predicate filter = new Predicate() { @Override public boolean evaluate(final Object object) { final ResultRow row = (ResultRow) object; - return getSingleYears() == null || Integer.valueOf(row.getValue(SInfoResultType.years).toString()) == year; + return row.getValue(SInfoResultType.years).toString().equals(years); } }; diff -r ce13a2f07290 -r 504f63512379 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcProcessor.java Mon Sep 17 19:07:57 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcProcessor.java Tue Sep 18 12:21:17 2018 +0200 @@ -60,11 +60,10 @@ protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { final CollisionCalcFacet facet = (CollisionCalcFacet) bundle.getFacet(); - final int year = facet.getYear(); final CollisionCalcOverviewResult result = (CollisionCalcOverviewResult) getResult(generator, bundle); - final double[][] points = result.getStationPointsByYear(SInfoResultType.collisionCount, year); + final double[][] points = result.getStationPointsByYear(SInfoResultType.collisionCount, facet.getYears()); return buildSeriesForPoints(points, generator, bundle, theme, visible, null); } @@ -76,14 +75,9 @@ // result index; however name and index are used on client side as unique id. final CollisionCalcOverviewResult ccoResult = (CollisionCalcOverviewResult) result; - if (ccoResult.getSingleYears() == null) { - final String facetDescription = Resources.getMsg(context.getMeta(), I18N_SERIES_NAME_PATTERN, I18N_SERIES_NAME_PATTERN, result.getLabel()); - return new CollisionCalcFacet(themeCount, resultIndex, -1, FACET_COLLISION_CALC_COUNT, facetDescription, I18N_AXIS_LABEL, ComputeType.ADVANCE, hash, - id); - } else { - final String facetDescription = Resources.getMsg(context.getMeta(), I18N_SERIES_NAME_PATTERN, I18N_SERIES_NAME_PATTERN, Integer.toString(year)); - return new CollisionCalcFacet(themeCount, resultIndex, year, COLLISION_FACETS[themeCount % 3], facetDescription, I18N_AXIS_LABEL, - ComputeType.ADVANCE, hash, id); - } + final String years = CollisionCalculation.yearsToString(ccoResult.getIsEpochs(), ccoResult.getYears().get(themeCount)); + final String facetDescription = Resources.getMsg(context.getMeta(), I18N_SERIES_NAME_PATTERN, I18N_SERIES_NAME_PATTERN, years); + return new CollisionCalcFacet(themeCount, resultIndex, years, COLLISION_FACETS[themeCount % 3], facetDescription, I18N_AXIS_LABEL, + ComputeType.ADVANCE, hash, id); } } \ No newline at end of file diff -r ce13a2f07290 -r 504f63512379 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculation.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculation.java Mon Sep 17 19:07:57 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculation.java Tue Sep 18 12:21:17 2018 +0200 @@ -12,7 +12,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.NavigableSet; +import java.util.TreeSet; import org.apache.commons.lang.math.DoubleRange; import org.dive4elements.artifacts.CallContext; @@ -66,14 +69,23 @@ final Collection overViewRows = new ArrayList<>(); + final List years = new ArrayList<>(); + final NavigableSet detailYears = new TreeSet<>(); if (access.getYears() != null) { - for (final int year : access.getYears()) + for (final int year : access.getYears()) { calculateOverview(overViewRows, river, access.getLowerKm(), access.getUpperKm(), year, year, false); + years.add(new DateRange(DateUtil.getStartDateFromYear(year), DateUtil.getEndDateFromYear(year))); + detailYears.add(Integer.valueOf(year)); + } } else { - for (final DateRange dr : access.getEpochs()) + for (final DateRange dr : access.getEpochs()) { calculateOverview(overViewRows, river, access.getLowerKm(), access.getUpperKm(), dr.getFromYear(), dr.getToYear(), true); + years.add(dr); + detailYearsAdd(detailYears, dr); + } } - final CollisionCalcOverviewResult overviewResult = new CollisionCalcOverviewResult(access.getYearsHeader(), access.getYears(), overViewRows); + final CollisionCalcOverviewResult overviewResult = new CollisionCalcOverviewResult(access.getYearsHeader(), (access.getYears() == null), years, + overViewRows); results.addResult(overviewResult, problems); // create q-for-w-finders for all gauges of the calculation km range @@ -86,14 +98,9 @@ } final Collection detailsRows = new ArrayList<>(); - // calculate secondary results for each year or epoch - if (access.getYears() != null) { - for (final int year : access.getYears()) - calculateDetails(detailsRows, infoProvider, access.getLowerKm(), access.getUpperKm(), year, year, qFinders, zoneFinders); - } else { - for (final DateRange dr : access.getEpochs()) - calculateDetails(detailsRows, infoProvider, access.getLowerKm(), access.getUpperKm(), dr.getFromYear(), dr.getToYear(), qFinders, zoneFinders); - } + // calculate secondary results for each year + for (final Integer year : detailYears) + calculateDetails(detailsRows, infoProvider, access.getLowerKm(), access.getUpperKm(), year, qFinders, zoneFinders); final CollisionCalcDetailResult detailResult = new CollisionCalcDetailResult("Details", detailsRows); results.addResult(detailResult, problems); @@ -101,6 +108,14 @@ } /** + * Adds all years of an epoch to a set + */ + private void detailYearsAdd(final NavigableSet detailYears, final DateRange epoch) { + for (int year = epoch.getFromYear(); year <= epoch.getToYear(); year++) + detailYears.add(Integer.valueOf(year)); + } + + /** * Calculates the collision counts for a km range of a river and a year or year range (epoch), * and adds them to a ResultRow collection */ @@ -108,19 +123,32 @@ final int toYear, final boolean isEpoch) { for (final CollisionAggregateValue aggregate : CollisionAggregateValue.getValuesByKm(river, fromKm, toKm, fromYear, toYear)) { rows.add(ResultRow.create().putValue(GeneralResultType.station, aggregate.getStation()) - .putValue(SInfoResultType.years, (isEpoch ? String.format("%d-%d", fromYear, toYear) : Integer.toString(fromYear))) + .putValue(SInfoResultType.years, yearsToString(isEpoch, fromYear, toYear)) .putValue(SInfoResultType.collisionCount, aggregate.getCount())); } } /** - * Calculates the collision details for a km range of a river and a year or year range (epoch), - * and adds them to a ResultRow collection + * Returns the string representation of a year or epoch + */ + public static String yearsToString(final boolean isEpoch, final DateRange years) { + return yearsToString(isEpoch, years.getFromYear(), years.getToYear()); + } + + /** + * Returns the string representation of a year or epoch + */ + public static String yearsToString(final boolean isEpoch, final int fromYear, final int toYear) { + return (isEpoch ? String.format("%d-%d", fromYear, toYear) : Integer.toString(fromYear)); + } + + /** + * Calculates the collision details for a km range of a river and a year, and adds them to a ResultRow collection */ private void calculateDetails(final Collection rows, final RiverInfoProvider riverInfo, final double fromKm, final double toKm, - final int fromYear, final int toYear, final Map qFinders, final Map zoneFinders) { - for (final CollisionValue collision : CollisionValue.getValues(riverInfo.getRiver(), fromKm, toKm, DateUtil.getStartDateFromYear(fromYear), - DateUtil.getEndDateFromYear(toYear))) { + final int year, final Map qFinders, final Map zoneFinders) { + for (final CollisionValue collision : CollisionValue.getValues(riverInfo.getRiver(), fromKm, toKm, DateUtil.getStartDateFromYear(year), + DateUtil.getEndDateFromYear(year))) { final Gauge gauge = riverInfo.getGauge(collision.getStation(), true); final double q = qFinders.get(gauge).getDischarge(collision.getGaugeW()); final double qOut = Double.isInfinite(q) ? Double.NaN : q; diff -r ce13a2f07290 -r 504f63512379 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionState.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionState.java Mon Sep 17 19:07:57 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionState.java Tue Sep 18 12:21:17 2018 +0200 @@ -18,6 +18,7 @@ import org.dive4elements.river.artifacts.model.Calculation; import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.DataFacet; +import org.dive4elements.river.artifacts.model.DateRange; import org.dive4elements.river.artifacts.model.EmptyFacet; import org.dive4elements.river.artifacts.model.FacetTypes; import org.dive4elements.river.artifacts.model.ReportFacet; @@ -81,15 +82,8 @@ for (int index = 0; index < resultList.size(); index++) { if (resultList.get(index) instanceof CollisionCalcOverviewResult) { final CollisionCalcOverviewResult result = (CollisionCalcOverviewResult) resultList.get(index); - - final int[] singleYears = result.getSingleYears(); - - if (singleYears == null) - facets.add(CollisionCalcProcessor.createFacet(context, hash, this.id, result, index, -1, themeCount++)); - else { - for (final int singleYear : singleYears) - facets.add(CollisionCalcProcessor.createFacet(context, hash, this.id, result, index, singleYear, themeCount++)); - } + for (final DateRange dr : result.getYears()) + facets.add(CollisionCalcProcessor.createFacet(context, hash, this.id, result, index, dr.getFromYear(), themeCount++)); } }