gernotbelger@9067: /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde gernotbelger@9067: * Software engineering by gernotbelger@9067: * Björnsen Beratende Ingenieure GmbH gernotbelger@9067: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt gernotbelger@9067: * gernotbelger@9067: * This file is Free Software under the GNU AGPL (>=v3) gernotbelger@9067: * and comes with ABSOLUTELY NO WARRANTY! Check out the gernotbelger@9067: * documentation coming with Dive4Elements River for details. gernotbelger@9067: */ gernotbelger@9067: package org.dive4elements.river.artifacts.sinfo.collision; gernotbelger@9067: gernotbelger@9150: import java.util.ArrayList; gernotbelger@9150: import java.util.Collection; mschaefer@9157: import java.util.HashMap; mschaefer@9157: import java.util.Map; gernotbelger@9150: gernotbelger@9067: import org.apache.commons.lang.math.DoubleRange; gernotbelger@9067: import org.dive4elements.artifacts.CallContext; gernotbelger@9150: import org.dive4elements.river.artifacts.common.GeneralResultType; gernotbelger@9150: import org.dive4elements.river.artifacts.common.ResultRow; gernotbelger@9067: import org.dive4elements.river.artifacts.model.Calculation; gernotbelger@9067: import org.dive4elements.river.artifacts.model.CalculationResult; mschaefer@9157: import org.dive4elements.river.artifacts.model.DateRange; gernotbelger@9067: import org.dive4elements.river.artifacts.resources.Resources; gernotbelger@9067: import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; mschaefer@9176: import org.dive4elements.river.artifacts.sinfo.common.GaugeDischargeValuesFinder; mschaefer@9202: import org.dive4elements.river.artifacts.sinfo.common.GaugeMainValueFinder; gernotbelger@9067: import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; mschaefer@9157: import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; gernotbelger@9067: import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; gernotbelger@9067: import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; mschaefer@9157: import org.dive4elements.river.backend.utils.DateUtil; mschaefer@9157: import org.dive4elements.river.model.Gauge; mschaefer@9176: import org.dive4elements.river.model.MainValueType.MainValueTypeKey; gernotbelger@9067: import org.dive4elements.river.model.River; mschaefer@9157: import org.dive4elements.river.model.sinfo.CollisionAggregateValue; mschaefer@9157: import org.dive4elements.river.model.sinfo.CollisionValue; gernotbelger@9067: gernotbelger@9067: class CollisionCalculation { gernotbelger@9067: gernotbelger@9067: // private static Logger log = Logger.getLogger(FloodDurationCalculation.class); gernotbelger@9067: gernotbelger@9067: private final CallContext context; gernotbelger@9067: gernotbelger@9067: public CollisionCalculation(final CallContext context) { gernotbelger@9067: this.context = context; gernotbelger@9067: } gernotbelger@9067: gernotbelger@9067: public CalculationResult calculate(final SINFOArtifact sinfo) { gernotbelger@9067: gernotbelger@9067: final String user = CalculationUtils.findArtifactUser(this.context, sinfo); gernotbelger@9067: mschaefer@9157: // access input data gernotbelger@9067: final CollisionAccess access = new CollisionAccess(sinfo); gernotbelger@9067: final River river = access.getRiver(); gernotbelger@9067: final RiverInfo riverInfo = new RiverInfo(river); gernotbelger@9067: gernotbelger@9067: final DoubleRange calcRange = access.getRange(); gernotbelger@9067: mschaefer@9157: // calculate results for each year or epoch gernotbelger@9067: final Calculation problems = new Calculation(); gernotbelger@9067: gernotbelger@9067: final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); gernotbelger@9067: mschaefer@9157: final CollisionCalculationResults results = new CollisionCalculationResults(calcModeLabel, user, riverInfo, calcRange, access.getYearsHeader()); gernotbelger@9067: gernotbelger@9150: final Collection overViewRows = new ArrayList<>(); mschaefer@9157: mschaefer@9157: if (access.getYears() != null) { mschaefer@9157: for (final int year : access.getYears()) mschaefer@9157: calculateOverview(overViewRows, river, access.getLowerKm(), access.getUpperKm(), year, year, false); gernotbelger@9318: } else { mschaefer@9157: for (final DateRange dr : access.getEpochs()) mschaefer@9157: calculateOverview(overViewRows, river, access.getLowerKm(), access.getUpperKm(), dr.getFromYear(), dr.getToYear(), true); mschaefer@9157: } mschaefer@9204: final CollisionCalcOverviewResult overviewResult = new CollisionCalcOverviewResult(access.getYearsHeader(), access.getYears(), overViewRows); mschaefer@9157: results.addResult(overviewResult, problems); mschaefer@9157: mschaefer@9157: // create q-for-w-finders for all gauges of the calculation km range mschaefer@9157: final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange); mschaefer@9157: final Map qFinders = new HashMap<>(); mschaefer@9202: final Map zoneFinders = new HashMap<>(); mschaefer@9157: for (final Gauge gauge : river.determineGauges(calcRange.getMinimumDouble(), calcRange.getMaximumDouble())) { mschaefer@9157: qFinders.put(gauge, GaugeDischargeValuesFinder.loadValues(gauge, problems)); mschaefer@9202: zoneFinders.put(gauge, GaugeMainValueFinder.loadValues(MainValueTypeKey.Q, gauge, problems)); mschaefer@9157: } gernotbelger@9150: final Collection detailsRows = new ArrayList<>(); gernotbelger@9150: mschaefer@9157: // calculate secondary results for each year or epoch mschaefer@9157: if (access.getYears() != null) { mschaefer@9157: for (final int year : access.getYears()) mschaefer@9157: calculateDetails(detailsRows, infoProvider, access.getLowerKm(), access.getUpperKm(), year, year, qFinders, zoneFinders); gernotbelger@9318: } else { mschaefer@9157: for (final DateRange dr : access.getEpochs()) mschaefer@9157: calculateDetails(detailsRows, infoProvider, access.getLowerKm(), access.getUpperKm(), dr.getFromYear(), dr.getToYear(), qFinders, zoneFinders); gernotbelger@9150: } gernotbelger@9150: final CollisionCalcDetailResult detailResult = new CollisionCalcDetailResult("Details", detailsRows); gernotbelger@9150: results.addResult(detailResult, problems); gernotbelger@9150: gernotbelger@9150: return new CalculationResult(results, problems); gernotbelger@9067: } mschaefer@9157: mschaefer@9157: /** mschaefer@9157: * Calculates the collision counts for a km range of a river and a year or year range (epoch), mschaefer@9157: * and adds them to a ResultRow collection mschaefer@9157: */ mschaefer@9157: private void calculateOverview(final Collection rows, final River river, final double fromKm, final double toKm, final int fromYear, mschaefer@9157: final int toYear, final boolean isEpoch) { mschaefer@9157: for (final CollisionAggregateValue aggregate : CollisionAggregateValue.getValuesByKm(river, fromKm, toKm, fromYear, toYear)) { mschaefer@9157: rows.add(ResultRow.create().putValue(GeneralResultType.station, aggregate.getStation()) gernotbelger@9318: .putValue(SInfoResultType.years, (isEpoch ? String.format("%d-%d", fromYear, toYear) : Integer.toString(fromYear))) mschaefer@9157: .putValue(SInfoResultType.collisionCount, aggregate.getCount())); mschaefer@9157: } mschaefer@9157: } mschaefer@9157: mschaefer@9157: /** mschaefer@9157: * Calculates the collision details for a km range of a river and a year or year range (epoch), mschaefer@9157: * and adds them to a ResultRow collection mschaefer@9157: */ mschaefer@9157: private void calculateDetails(final Collection rows, final RiverInfoProvider riverInfo, final double fromKm, final double toKm, gernotbelger@9318: final int fromYear, final int toYear, final Map qFinders, final Map zoneFinders) { mschaefer@9157: for (final CollisionValue collision : CollisionValue.getValues(riverInfo.getRiver(), fromKm, toKm, DateUtil.getStartDateFromYear(fromYear), mschaefer@9157: DateUtil.getEndDateFromYear(toYear))) { mschaefer@9157: final Gauge gauge = riverInfo.getGauge(collision.getStation(), true); mschaefer@9157: final double q = qFinders.get(gauge).getDischarge(collision.getGaugeW()); mschaefer@9157: final double qOut = Double.isInfinite(q) ? Double.NaN : q; mschaefer@9157: rows.add(ResultRow.create().putValue(GeneralResultType.station, collision.getStation()) gernotbelger@9318: .putValue(GeneralResultType.dateShort, collision.getEventDate()).putValue(SInfoResultType.collisionGaugeW, collision.getGaugeW()) gernotbelger@9318: .putValue(GeneralResultType.gaugeLabelCm, collision.getGaugeName()).putValue(SInfoResultType.dischargeLong, qOut) mschaefer@9202: .putValue(SInfoResultType.dischargeZone, zoneFinders.get(gauge).findZoneName(q))); mschaefer@9157: } mschaefer@9157: } gernotbelger@9067: }