view artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java @ 6665:b7945db8a43b

issue1413: Only show unknown sediment loads of selected unit type. Therefore, adjusted the factory to take the units name. Unfortunately, names in db do not match values of data items. Thus do manual replacing. In Facet and Calculate, take the chosen unit via access and to the string replacement. In Facet, do not transform data (we assume it comes in unit as labeled in the db), and removed the possibility of m3/a-data of unknown yields in a t/a diagram and vice versa.
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Thu, 25 Jul 2013 15:08:13 +0200
parents a4f60641e445
children 7ea933f9c6ea
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */

package org.dive4elements.river.artifacts.model.minfo;

import gnu.trove.TDoubleArrayList;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TreeMap;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

import org.apache.log4j.Logger;
import org.dive4elements.river.artifacts.cache.CacheFactory;
import org.dive4elements.river.artifacts.model.Range;
import org.dive4elements.river.artifacts.model.RiverFactory;
import org.dive4elements.river.artifacts.model.StaticSedimentLoadCacheKey;
import org.dive4elements.river.backend.SessionHolder;
import org.dive4elements.river.model.MeasurementStation;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.type.StandardBasicTypes;

/** Pull Sediment Loads out of db. */
public class SedimentLoadFactory
{
    /** Private logger to use here. */
    private static Logger log = Logger.getLogger(SedimentLoadFactory.class);

    public static final String LOADS_CACHE_NAME = "sedimentloads";
    public static final String LOAD_DATA_CACHE_NAME = "sedimentload-data";

    /** Query to get km and ws for wst_id and column_pos. */
    public static final String SQL_SELECT_SINGLES =
        "SELECT DISTINCT " +
        "       sy.description AS description, " +
        "       ti.start_time AS year " +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "   WHERE   r.name = :name " +
        "       AND ti.stop_time IS NULL " +
        "       AND syv.station BETWEEN :startKm AND :endKm";

    /** Query to get name for wst_id and column_pos. */
    public static final String SQL_SELECT_EPOCHS =
        "SELECT DISTINCT " +
        "       sy.description AS description, " +
        "       ti.start_time AS startYear, " +
        "       ti.stop_time AS end, " +
        "       u.name AS unit" +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "       JOIN units u ON u.id = sy.unit_id " +
        "   WHERE   r.name = :name " +
        "       AND ti.stop_time IS NOT NULL " +
        "       AND syv.station BETWEEN :startKm AND :endKm";

    public static final String SQL_SELECT_SINGLES_DATA =
        "SELECT" +
        "       sy.description AS description, " +
        "       ti.start_time AS year, " +
        "       syv.value AS load, " +
        "       syv.station AS km, " +
        "       u.name AS unit " +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " +
        "       JOIN units u ON u.id = sy.unit_id" +
        "   WHERE   r.name = :name " +
        "       AND ti.start_time BETWEEN :begin AND :end " +
        "       AND ti.stop_time IS NULL " +
        "       AND gf.name = :grain " +
        "       AND syv.station BETWEEN :startKm AND :endKm " +
        "   ORDER BY syv.station";

    public static final String SQL_SELECT_UNKNOWN_DATA =
        "SELECT" +
        "       sy.description AS description, " +
        "       ti.start_time AS startYear, " +
        "       ti.stop_time AS end, " +
        "       syv.value AS load, " +
        "       syv.station AS km, " +
        "       u.name AS unit " +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " +
        "       JOIN units u ON u.id = sy.unit_id" +
        "   WHERE   r.name = :name " +
        "       AND sy.description = :descr " +
        "       AND gf.name = 'unknown' " +
        "   ORDER BY syv.station";

    public static final String SQL_SELECT_UNKNOWN =
        "SELECT DISTINCT " +
        "    sy.description AS description, " +
        "    ti.start_time AS startYear, " +
        "    ti.stop_time AS end " +
        "FROM sediment_yield sy " +
        "    JOIN rivers r ON sy.river_id = r.id " +
        "    JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "    JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " +
        "    JOIN units u ON sy.unit_id = u.id " +
        "WHERE r.name = :river " +
        "    AND gf.name = 'unknown' " +
        "    AND u.name = :unit";

    public static final String SQL_SELECT_EPOCHS_DATA =
        "SELECT" +
        "       sy.description AS description, " +
        "       ti.start_time AS startYear, " +
        "       syv.value AS load, " +
        "       syv.station AS km," +
        "       ti.stop_time AS endYear, " +
        "       u.name AS unit" +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " +
        "       JOIN units u ON u.id = sy.unit_id " +
        "   WHERE   r.name = :name " +
        "       AND ti.start_time BETWEEN :sbegin AND :send " +
        "       AND ti.stop_time BETWEEN :ebegin AND :eend " +
        "       AND gf.name = :grain " +
        "       AND syv.station BETWEEN :startKm AND :endKm " +
        "   ORDER BY syv.station";

    private SedimentLoadFactory() {
    }

    /**
     *
     */
    public static SedimentLoad[] getLoads(
        String river,
        String type,
        double startKm,
        double endKm
    ) {
        log.debug("SedimentLoadFactory.getLoads");
        Cache cache = CacheFactory.getCache(LOADS_CACHE_NAME);

        if (cache == null) {
            log.debug("Cache not configured.");
            return getSedimentLoadsUncached(river, type, startKm, endKm);
        }

        StaticSedimentLoadCacheKey key =
            new StaticSedimentLoadCacheKey(river, startKm, endKm, 0, 0);

        Element element = cache.get(key);

        if (element != null) {
            log.debug("SedimentLoad found in cache");
            return (SedimentLoad[])element.getValue();
        }

        SedimentLoad[] values =
            getSedimentLoadsUncached(river, type, startKm, endKm);

        if (values != null && key != null) {
            log.debug("Store static sediment load values in cache.");
            element = new Element(key, values);
            cache.put(element);
        }
        return values;
    }

    public static SedimentLoad getLoadWithData(
        String river,
        String type,
        double startKm,
        double endKm,
        int syear,
        int eyear
    ) {
        log.debug("SedimentLoadFactory.getLoadWithData");
        Cache cache = CacheFactory.getCache(LOAD_DATA_CACHE_NAME);

        if (cache == null) {
            log.debug("Cache not configured.");
            return getSedimentLoadWithDataUncached(
                river,
                type,
                startKm,
                endKm,
                syear,
                eyear);
        }

        StaticSedimentLoadCacheKey key =
            new StaticSedimentLoadCacheKey(river, startKm, endKm, syear, eyear);

        Element element = cache.get(key);

        if (element != null) {
            log.debug("SedimentLoad found in cache");
            return (SedimentLoad)element.getValue();
        }

        SedimentLoad values = getSedimentLoadWithDataUncached(
            river,
            type,
            startKm,
            endKm,
            syear,
            eyear);

        if (values != null && key != null) {
            log.debug("Store static bed height values in cache.");
            element = new Element(key, values);
            cache.put(element);
        }
        return values;
    }

    /**
     * Get sediment loads from db.
     * @param river the river
     * @param type the sediment load type (year or epoch)
     * @return according sediment loads.
     */
    public static SedimentLoad[] getSedimentLoadsUncached(
        String river,
        String type,
        double startKm,
        double endKm
    ) {
        log.debug("SedimentLoadFactory.getSedimentLoadsUncached");

        Session session = SessionHolder.HOLDER.get();
        SQLQuery sqlQuery = null;

        if (type.equals("single")) {
            sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLES)
                .addScalar("description", StandardBasicTypes.STRING)
                .addScalar("year", StandardBasicTypes.DATE);
            sqlQuery.setString("name", river);
            sqlQuery.setDouble("startKm", startKm);
            sqlQuery.setDouble("endKm", endKm);
            List<Object []> results = sqlQuery.list();
            SedimentLoad[] loads = new SedimentLoad[results.size()];
            for (int i = 0; i < results.size(); i++) {
                Object[] row = results.get(i);
                loads[i] = new SedimentLoad(
                    (String) row[0],
                    (Date) row[1],
                    null,
                    false,
                    "");
            }
            return loads;
        }
        else if (type.equals("epoch")) {
            sqlQuery = session.createSQLQuery(SQL_SELECT_EPOCHS)
                .addScalar("description", StandardBasicTypes.STRING)
                .addScalar("startYear", StandardBasicTypes.DATE)
                .addScalar("end", StandardBasicTypes.DATE);
            sqlQuery.setString("name", river);
            sqlQuery.setDouble("startKm", startKm);
            sqlQuery.setDouble("endKm", endKm);
            List<Object []> results = sqlQuery.list();

            SedimentLoad[] loads = new SedimentLoad[results.size()];
            for (int i = 0; i < results.size(); i++) {
                Object[] row = results.get(i);
                loads[i] = new SedimentLoad(
                    (String) row[0],
                    (Date) row[1],
                    (Date) row[2],
                    true,
                    "");
            }
            return loads;
        }
        return new SedimentLoad[0];
    }

    /**
     * Get sediment loads from db.
     * @param river the river
     * @param type the sediment load type (year or epoch)
     * @return according sediment loads.
     */
    public static SedimentLoad getSedimentLoadWithDataUncached(
        String river,
        String type,
        double startKm,
        double endKm,
        int syear,
        int eyear
    ) {
        log.debug("SedimentLoadFactory.getSedimentLoadWithDataUncached");
        Session session = SessionHolder.HOLDER.get();
        SQLQuery sqlQuery = null;

        List<MeasurementStation> allStations = RiverFactory.getRiver(river).getMeasurementStations();
        TreeMap<Double,MeasurementStation> floatStations = new TreeMap<Double, MeasurementStation>();
        TreeMap<Double,MeasurementStation> suspStations = new TreeMap<Double, MeasurementStation>();
        for (MeasurementStation measurementStation: allStations) {
            if (measurementStation.getMeasurementType() == null ||
                measurementStation.getRange() == null) {
                continue;
            }
            if (measurementStation.getMeasurementType().equals("Schwebstoff")) {
                suspStations.put(measurementStation.getRange().getA().doubleValue(), measurementStation);
            }
            else if (measurementStation.getMeasurementType().equals("Geschiebe")) {
                floatStations.put(measurementStation.getRange().getA().doubleValue(), measurementStation);
            }
        }

        Calendar start = Calendar.getInstance();
        start.set(syear - 1, 11, 31);
        Calendar end = Calendar.getInstance();
        end.set(syear, 11, 30);

        if (type.equals("year") || type.equals("epoch")) {
            sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLES_DATA)
                .addScalar("description", StandardBasicTypes.STRING)
                .addScalar("year", StandardBasicTypes.DATE)
                .addScalar("load", StandardBasicTypes.DOUBLE)
                .addScalar("km", StandardBasicTypes.DOUBLE)
                .addScalar("unit", StandardBasicTypes.STRING);
            sqlQuery.setString("name", river);
            sqlQuery.setDouble("startKm", startKm);
            sqlQuery.setDouble("endKm", endKm);
            sqlQuery.setDate("begin", start.getTime());
            sqlQuery.setDate("end", end.getTime());
            sqlQuery.setString("grain", "total");
            List<Object []> results = sqlQuery.list();
            SedimentLoad load = new SedimentLoad();
            Object[] row = results.get(0);
            load = new SedimentLoad(
                    (String) row[0],
                    (Date) row[1],
                    null,
                    false,
                    (String) row[4]);
            getValues("coarse", sqlQuery, load, floatStations);
            getValues("fine_middle", sqlQuery, load, floatStations);
            getValues("sand", sqlQuery, load, floatStations);
            getValues("suspended_sediment", sqlQuery, load, suspStations);
            getValues("susp_sand_bed", sqlQuery, load, floatStations);
            getValues("susp_sand", sqlQuery, load, floatStations);

            return load;
        }
        else if (type.equals("off_epoch")) {
            Calendar toStart = Calendar.getInstance();
            toStart.set(eyear - 1, 11, 31);
            Calendar toEnd = Calendar.getInstance();
            toEnd.set(eyear+1, 11, 31);
            sqlQuery = session.createSQLQuery(SQL_SELECT_EPOCHS_DATA)
                .addScalar("description", StandardBasicTypes.STRING)
                .addScalar("startYear", StandardBasicTypes.DATE)
                .addScalar("load", StandardBasicTypes.DOUBLE)
                .addScalar("km", StandardBasicTypes.DOUBLE)
                .addScalar("endYear", StandardBasicTypes.DATE)
                .addScalar("unit", StandardBasicTypes.STRING);
            sqlQuery.setString("name", river);
            sqlQuery.setDouble("startKm", startKm);
            sqlQuery.setDouble("endKm", endKm);
            sqlQuery.setDate("sbegin", start.getTime());
            sqlQuery.setDate("send", end.getTime());
            sqlQuery.setDate("ebegin",toStart.getTime());
            sqlQuery.setDate("eend", toEnd.getTime());
            sqlQuery.setString("grain", "total");

            List<Object[]> results = null;
            results = sqlQuery.list();

            SedimentLoad load = new SedimentLoad();
            Object[] row = results.get(0);
            load = new SedimentLoad(
                    (String) row[0],
                    (Date) row[1],
                    (Date) row[4],
                    true,
                    (String)row[5]);
            TDoubleArrayList kms = new TDoubleArrayList();
            for (int i = 0; i < results.size(); i++) {
                row = results.get(i);
                kms.add((Double)row[3]);
                load.setLoadTotal((Double)row[3], (Double)row[2]);
            }
            getValues("coarse", sqlQuery, load, floatStations);
            getValues("fine_middle", sqlQuery, load, floatStations);
            getValues("sand", sqlQuery, load, floatStations);
            getValues("suspended_sediment", sqlQuery, load, suspStations);
            getValues("susp_sand_bed", sqlQuery, load, floatStations);
            getValues("susp_sand", sqlQuery, load, floatStations);
            return load;
        }
        return new SedimentLoad();
    }


    /**
     * Run query with grain parameter set to fraction, feed result into
     * load.
     * @param fraction value to set 'grain' parameter in query to.
     * @param query query in which to set 'grain' parameter and run.
     * @param load[out] SedimentLoad which to populate with values.
     */
    protected static void getValues (
        String fraction,
        SQLQuery query,
        SedimentLoad load,
        TreeMap<Double, MeasurementStation> stations
    ) {
        query.setString("grain", fraction);
        List<Object[]> results = query.list();
        for (int i = 0; i < results.size(); i++) {
            Object[] row = results.get(i);
            double km = (Double)row[3];
            MeasurementStation station = stations.get(km);
            MeasurementStation nextStation = null;
            if (stations.ceilingEntry(km + 0.1d) != null) {
                nextStation = stations.ceilingEntry(km + 0.1d).getValue();
            }
            Range range = null;
            if (station == null) {
                log.warn("No measurement station for " + fraction + " km " + km);
                continue;
            }
            else {
                if (nextStation != null)
                    range = new Range(station.getRange().getA().doubleValue(),
                        nextStation.getRange().getA().doubleValue());
                else {
                    // TODO end-of-river instead of B.
                    range = new Range(station.getRange().getA().doubleValue(),
                        station.getRange().getB().doubleValue());
                }
            }
            double v = -1;
            if (row[2] != null) {
                v = ((Double)row[2]).doubleValue();
            }
            if (fraction.equals("coarse")) {
                load.setCoarse(km, v, range);
            }
            else if (fraction.equals("sand")) {
                load.setSand(km, v, range);
            }
            else if (fraction.equals("fine_middle")) {
                load.setFineMiddle(km, v, range);
            }
            else if (fraction.equals("suspended_sediment")) {
                load.setSuspSediment(km, v, range);
            }
            else if (fraction.equals("susp_sand")) {
                load.setSuspSand(km, v, range);
            }
            else if (fraction.equals("susp_sand_bed")) {
                load.setSuspSandBed(km, v, range);
            }
        }
    }

    public static SedimentLoad getLoadUnknown(
        String river,
        String description
    ) {
        log.debug("SedimentLoadFactory.getLoadWithData");
        Cache cache = CacheFactory.getCache(LOAD_DATA_CACHE_NAME);

        if (cache == null) {
            log.debug("Cache not configured.");
            return getSedimentLoadUnknownUncached(river, description);
        }

        StaticSedimentLoadCacheKey key =
            new StaticSedimentLoadCacheKey(river, 0d, 0d, 0, 0);

        Element element = cache.get(key);

        if (element != null) {
            log.debug("SedimentLoad found in cache");
            return (SedimentLoad)element.getValue();
        }

        SedimentLoad values = getSedimentLoadUnknownUncached(river, description);

        if (values != null && key != null) {
            log.debug("Store static bed height values in cache.");
            element = new Element(key, values);
            cache.put(element);
        }
        return values;
    }

    /**
     * Get sediment loads with fraction 'unknown' from db.
     * @param river the river
     * @param type the sediment load type (year or epoch)
     * @return according sediment loads.
     */
    public static SedimentLoad getSedimentLoadUnknownUncached(
        String river,
        String description
    ) {
        log.debug("SedimentLoadFactory.getSedimentLoadWithDataUncached");
        Session session = SessionHolder.HOLDER.get();
        SQLQuery sqlQuery = null;

        sqlQuery = session.createSQLQuery(SQL_SELECT_UNKNOWN_DATA)
            .addScalar("description", StandardBasicTypes.STRING)
            .addScalar("startYear", StandardBasicTypes.DATE)
            .addScalar("end", StandardBasicTypes.DATE)
            .addScalar("load", StandardBasicTypes.DOUBLE)
            .addScalar("km", StandardBasicTypes.DOUBLE)
            .addScalar("unit", StandardBasicTypes.STRING);
        sqlQuery.setString("name", river);
        sqlQuery.setString("descr", description);
        List<Object []> results = sqlQuery.list();
        SedimentLoad load = new SedimentLoad();
        if (results.isEmpty()) {
            return new SedimentLoad();
        }
        Object[] row = results.get(0);
        load = new SedimentLoad(
            (String) row[0],
            (Date) row[1],
            (Date) row[2],
            false,
            (String)row[5]);

        for (int i = 0; i < results.size(); i++) {
            row = results.get(i);
            SedimentLoadFraction fraction = new SedimentLoadFraction();
            fraction.setUnknown((Double)row[3]);
            load.addKm((Double)row[4], fraction);
        }
        return load;
    }

    /**
     * Return sediment loads with 'unknown' fraction type.
     * @param unit Restrict result set to those of given unit.
     */
    public static SedimentLoad[] getSedimentLoadUnknown(String river, String unit) {
        Session session = SessionHolder.HOLDER.get();
        SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_UNKNOWN)
            .addScalar("description", StandardBasicTypes.STRING)
            .addScalar("startYear", StandardBasicTypes.DATE)
            .addScalar("end", StandardBasicTypes.DATE);
        sqlQuery.setString("river", river);
        sqlQuery.setString("unit", unit);
        List<Object[]> results = sqlQuery.list();
        SedimentLoad[] loads = new SedimentLoad[results.size()];
        int counter = 0;
        for (Object[] row: results) {
            loads[counter] = new SedimentLoad(
                (String)row[0], (Date)row[1], (Date)row[2], false, "");
            counter++;
        }
        return loads;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org