mschaefer@8898: /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde mschaefer@8898: * Software engineering by mschaefer@8898: * Björnsen Beratende Ingenieure GmbH mschaefer@8898: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt mschaefer@8898: * mschaefer@8898: * This file is Free Software under the GNU AGPL (>=v3) mschaefer@8898: * and comes with ABSOLUTELY NO WARRANTY! Check out the mschaefer@8898: * documentation coming with Dive4Elements River for details. mschaefer@8898: */ mschaefer@8898: gernotbelger@8915: package org.dive4elements.river.artifacts.sinfo.tkhcalculation; mschaefer@8898: mschaefer@8898: import java.util.List; mschaefer@8952: import java.util.Map.Entry; mschaefer@8952: import java.util.NavigableMap; mschaefer@8952: import java.util.TreeMap; mschaefer@8898: mschaefer@8898: import org.apache.commons.lang.math.DoubleRange; mschaefer@8898: import org.apache.commons.math.ArgumentOutsideDomainException; mschaefer@8952: import org.dive4elements.river.backend.SessionHolder; mschaefer@8898: import org.dive4elements.river.model.River; mschaefer@8952: import org.hibernate.SQLQuery; mschaefer@8952: import org.hibernate.Session; mschaefer@8952: import org.hibernate.type.StandardBasicTypes; mschaefer@8898: mschaefer@8898: mschaefer@8898: /** gernotbelger@8915: * @author Matthias Schäfer mschaefer@8898: */ gernotbelger@8915: final class SoilKindKmValueFinder { mschaefer@8952: mschaefer@8952: /***** FIELDS *****/ mschaefer@8952: gernotbelger@8915: // private static Logger log = Logger.getLogger(SoilKindKmValueFinder.class); gernotbelger@8915: mschaefer@8952: /** mschaefer@8952: * Query selecting the bed mobility attribute for a range of stations of a river mschaefer@8952: */ mschaefer@8952: private static final String SQL_BED_MOBILITY = "SELECT bmv.station, bmv.moving" mschaefer@8952: + " FROM bed_mobility bm INNER JOIN bed_mobility_values bmv ON bm.id = bmv.bed_mobility_id" mschaefer@8952: + " WHERE (bm.river_id=:river_id) AND (bmv.station BETWEEN (:fromkm-0.0001) AND (:tokm+0.0001))" mschaefer@8952: + " ORDER BY bmv.station ASC"; gernotbelger@8915: mschaefer@8952: private final NavigableMap kmMobility; mschaefer@8952: mschaefer@8952: mschaefer@8952: /***** CONSTRUCTORS *****/ mschaefer@8952: mschaefer@8952: private SoilKindKmValueFinder() { mschaefer@8952: /* only instantiate me via static constructor */ mschaefer@8952: this.kmMobility = null; mschaefer@8952: } mschaefer@8952: mschaefer@8952: private SoilKindKmValueFinder(final List queryRows) { mschaefer@8952: this.kmMobility = new TreeMap<>(); mschaefer@8952: for (int i = 0; i <= queryRows.size() - 1; i++) { mschaefer@8952: this.kmMobility.put(Double.valueOf((double) queryRows.get(i)[0]), (((int) queryRows.get(i)[1]) == 1) ? SoilKind.mobil : SoilKind.starr); mschaefer@8952: } mschaefer@8952: } mschaefer@8952: mschaefer@8952: /***** METHODS *****/ gernotbelger@8915: mschaefer@8898: /** gernotbelger@8915: * Loads the range of the river's kms with their soil kind. gernotbelger@8915: * gernotbelger@8915: * @return Whether the load has been successful mschaefer@8898: */ gernotbelger@8915: public static SoilKindKmValueFinder loadValues(final River river, final DoubleRange kmRange) { mschaefer@8952: final Session session = SessionHolder.HOLDER.get(); mschaefer@8952: final SQLQuery sqlQuery = session.createSQLQuery(SQL_BED_MOBILITY).addScalar("station", StandardBasicTypes.DOUBLE) mschaefer@8952: .addScalar("moving", StandardBasicTypes.INTEGER); mschaefer@8952: sqlQuery.setInteger("river_id", river.getId().intValue()); mschaefer@8952: sqlQuery.setDouble("fromkm", kmRange.getMinimumDouble()); mschaefer@8952: sqlQuery.setDouble("tokm", kmRange.getMaximumDouble()); mschaefer@8952: final List rows = sqlQuery.list(); mschaefer@8952: if (rows.size() >= 1) mschaefer@8952: return new SoilKindKmValueFinder(rows); mschaefer@8952: else mschaefer@8952: return null; gernotbelger@8915: } gernotbelger@8915: mschaefer@8898: /***** METHODS *****/ gernotbelger@8915: mschaefer@8898: /** mschaefer@8898: * Searches a km with its soil kind mschaefer@8898: */ gernotbelger@8915: public SoilKind findSoilKind(final double km) throws ArgumentOutsideDomainException { mschaefer@8952: if ((this.kmMobility == null) || this.kmMobility.isEmpty()) mschaefer@8898: throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN); mschaefer@8952: else if (this.kmMobility.containsKey(Double.valueOf(km))) mschaefer@8952: return this.kmMobility.get(Double.valueOf(km)); mschaefer@8952: else { mschaefer@8952: // FIXME: Assert minimum distance between neighbouring stations and candidate km? mschaefer@8952: final Entry streamUp = this.kmMobility.floorEntry(Double.valueOf(km)); mschaefer@8952: if (streamUp == null) mschaefer@8898: throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN); mschaefer@8952: else { mschaefer@8952: // Return the soil kind of the neighbouring station with the shorter distance to the candidate. mschaefer@8952: final Entry streamDown = this.kmMobility.ceilingEntry(Double.valueOf(km)); mschaefer@8952: if (streamDown == null) mschaefer@8952: return streamUp.getValue(); mschaefer@8952: else if ((streamUp.getKey().doubleValue() + streamDown.getKey().doubleValue()) / 2 <= km) mschaefer@8952: return streamUp.getValue(); mschaefer@8952: else mschaefer@8952: return streamDown.getValue(); mschaefer@8952: } mschaefer@8898: } mschaefer@8898: } gernotbelger@8915: }