org.kalypso.model.hydrology.internal.preprocessing.writer.TsFileWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.model.hydrology.internal.preprocessing.writer.TsFileWriter.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.model.hydrology.internal.preprocessing.writer;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.kalypso.contribs.java.net.UrlResolverSingleton;
import org.kalypso.contribs.java.util.FortranFormatHelper;
import org.kalypso.model.hydrology.NaModelConstants;
import org.kalypso.model.hydrology.binding.NAOptimize;
import org.kalypso.model.hydrology.binding.control.NAControl;
import org.kalypso.model.hydrology.binding.model.Catchment;
import org.kalypso.model.hydrology.binding.model.channels.Channel;
import org.kalypso.model.hydrology.internal.i18n.Messages;
import org.kalypso.model.hydrology.internal.preprocessing.NAPreprocessorException;
import org.kalypso.model.hydrology.internal.preprocessing.net.NetElement;
import org.kalypso.model.hydrology.internal.preprocessing.timeseries.GrapWriter;
import org.kalypso.model.hydrology.internal.preprocessing.timeseries.RangeFactor;
import org.kalypso.ogc.sensor.DateRange;
import org.kalypso.ogc.sensor.IAxis;
import org.kalypso.ogc.sensor.IObservation;
import org.kalypso.ogc.sensor.ITupleModel;
import org.kalypso.ogc.sensor.ObservationUtilities;
import org.kalypso.ogc.sensor.SensorException;
import org.kalypso.ogc.sensor.metadata.ITimeseriesConstants;
import org.kalypso.ogc.sensor.util.ZmlLink;
import org.kalypso.ogc.sensor.zml.ZmlFactory;
import org.kalypso.ogc.sensor.zml.ZmlURL;
import org.kalypsodeegree.model.feature.Feature;
import org.kalypsodeegree.model.feature.GMLWorkspace;
import org.kalypsodeegree.model.feature.IFeatureBindingCollection;
import org.kalypsodeegree_impl.model.feature.FeatureHelper;

/**
 * @author Gernot Belger
 */
public class TsFileWriter {
    private final Logger m_logger;

    private final URL m_zmlContext;

    private final NetElement[] m_channels;

    private final TimeseriesFileManager m_tsFileManager;

    private final GMLWorkspace m_synthNWorkspace;

    private final NAControl m_metaControl;

    private final NAOptimize m_naOptimize;

    public static enum TSFormat {
        GRAP, EX2
    }

    public TsFileWriter(final GMLWorkspace synthNWorkspace, final NAControl naControl, final NAOptimize naOptimize,
            final NetElement[] channels, final URL zmlContext, final TimeseriesFileManager tsFileManager,
            final Logger logger) {
        m_synthNWorkspace = synthNWorkspace;
        m_metaControl = naControl;
        m_naOptimize = naOptimize;
        m_channels = channels;
        m_zmlContext = zmlContext;
        m_tsFileManager = tsFileManager;
        m_logger = logger;
    }

    public void write(final File targetDir) throws NAPreprocessorException {
        for (final NetElement netElement : m_channels) {
            final Channel channel = netElement.getChannel();
            generateTimeSeries(channel, targetDir);
        }
    }

    private void generateTimeSeries(final Channel channel, final File klimaDir) throws NAPreprocessorException {
        final Date simulationStart = m_metaControl.getSimulationStart();
        final Date simulationEnd = m_metaControl.getSimulationEnd();
        final DateRange simulationRange = new DateRange(simulationStart, simulationEnd);

        final Catchment[] catchments = channel.findCatchments();

        for (final Catchment catchment : catchments) {
            try {
                writeCatchmentTimeseries(klimaDir, simulationRange, catchment);
            } catch (final Exception e) {
                e.printStackTrace();
                final String message = String.format(Messages.getString("TsFileWriter.0"), catchment.getName()); //$NON-NLS-1$
                throw new NAPreprocessorException(message, e);
            }
        }
    }

    private void writeCatchmentTimeseries(final File klimaDir, final DateRange simulationRange,
            final Catchment catchment) throws SensorException, IOException {
        final File targetFileN = m_tsFileManager.getNiederschlagEingabeDatei(catchment, klimaDir); //$NON-NLS-1$

        if (m_metaControl.isUsePrecipitationForm()) {
            if (!targetFileN.exists())
                writeSynthNFile(targetFileN, catchment);
        } else {
            if (!targetFileN.exists())
                writeNFile(targetFileN, catchment);

            final ZmlLink linkT = catchment.getTemperatureLink();
            final File targetFileT = m_tsFileManager.getTemperaturEingabeDatei(catchment, klimaDir); //$NON-NLS-1$
            writeExtTimeseries(targetFileT, linkT, m_zmlContext, ITimeseriesConstants.TYPE_MEAN_TEMPERATURE, "1.0", //$NON-NLS-1$
                    simulationRange);

            final ZmlLink linkV = catchment.getEvaporationLink();
            final File targetFileV = m_tsFileManager.getVerdunstungEingabeDatei(catchment, klimaDir); //$NON-NLS-1$
            writeExtTimeseries(targetFileV, linkV, m_zmlContext, ITimeseriesConstants.TYPE_EVAPORATION_LAND_BASED,
                    "0.5", simulationRange); //$NON-NLS-1$
        }
    }

    private void writeNFile(final File targetFileN, final Catchment catchment) throws SensorException, IOException {
        final ZmlLink linkN = catchment.getPrecipitationLink();

        final IObservation observation = loadObservationWithFilter(linkN, m_zmlContext, null);
        if (observation == null)
            return;

        final StringBuilder writer = new StringBuilder();

        final GrapWriter grapWriter = new GrapWriter(ITimeseriesConstants.TYPE_RAINFALL, observation);

        final RangeFactor forecastFactor = createForecastFactor(catchment);
        grapWriter.setRangeFactor(forecastFactor);

        grapWriter.write(writer);

        FileUtils.writeStringToFile(targetFileN, writer.toString());
    }

    /**
     * Very specialized: we have a special factor for precipitation in the forecast date range.<br/>
     * This makes actually only sense for highwater prediction.
     */
    private RangeFactor createForecastFactor(final Catchment catchment) {
        // FIXME: cannot work any more

        final Date startForecast = m_metaControl.getSimulationEnd();
        if (startForecast == null)
            return null;

        final Date simulationEnd = m_metaControl.getSimulationEnd();
        if (startForecast.equals(simulationEnd))
            return null;

        if (m_naOptimize == null)
            return null;

        final IFeatureBindingCollection<Catchment> catchmentCollection = m_naOptimize.getCatchmentCollection();
        if (!catchmentCollection.contains(catchment))
            return null;

        final double faktn = catchment.getFaktn();

        final double faktnPrognose = m_naOptimize.getFaktnPrognose();
        // THE BIG HACK: We always devide by the catchment factor, else we would get two factors: the catchment factor
        // (applied by kalypso-na.exe) AND the forecast factor. But we only want one factor.
        final double forcastFactorN = faktnPrognose / faktn;

        final DateRange forecastRange = new DateRange(startForecast, simulationEnd);
        return new RangeFactor(forecastRange, forcastFactorN);
    }

    public static final void writeGrapTimeseries(final File targetFile, final ZmlLink link, final URL zmlContext,
            final String valueAxisType, final String filter) throws SensorException, IOException {
        if (targetFile.exists())
            return;

        final IObservation observation = loadObservationWithFilter(link, zmlContext, filter);
        if (observation == null)
            return;

        final GrapWriter grapWriter = new GrapWriter(valueAxisType, observation);
        final StringBuilder writer = new StringBuilder();
        grapWriter.write(writer);
        FileUtils.writeStringToFile(targetFile, writer.toString());
    }

    public static final void writeExtTimeseries(final File targetFile, final ZmlLink link, final URL zmlContext,
            final String valueAxisType, final String defaultValue, final DateRange simulationRange)
            throws SensorException, IOException {
        if (targetFile.exists())
            return;

        final IObservation observation = loadObservationWithFilter(link, zmlContext, null);
        if (observation == null)
            return;

        // TODO: calculate start/end here
        final Ext2InterpolationWriter writer = new Ext2InterpolationWriter(observation, valueAxisType,
                defaultValue);
        writer.write(targetFile, simulationRange);
    }

    private static IObservation loadObservationWithFilter(final ZmlLink link, final URL zmlContext,
            final String filter) throws MalformedURLException, SensorException {
        if (link == null)
            return null;

        final String href = link.getHref();

        final String hrefWithFilter = filter == null ? href : ZmlURL.insertFilter(href, filter);

        final URL location = UrlResolverSingleton.getDefault().resolveURL(zmlContext, hrefWithFilter);

        return ZmlFactory.parseXML(location);
    }

    // FIXME: does not belong here -> move into own writer
    private void writeSynthNFile(final File targetFileN, final Catchment catchment)
            throws SensorException, IOException {
        final List<Feature> statNList = new ArrayList<>();

        final StringBuffer buffer = new StringBuffer();
        final Double annualityKey = m_metaControl.getAnnuality();
        // Kostra-Kachel/ synth. N gebietsabngig
        final String synthNKey = catchment.getSynthZR();

        statNList.addAll(Arrays
                .asList(FeatureHelper.getFeaturesWithName(m_synthNWorkspace, NaModelConstants.SYNTHN_STATN_FT)));

        // Performance & readability: linear search loop; first hash the synth-definitions; then write....

        for (final Feature statNFE : statNList) {
            if (statNFE.getName() != null) {
                if (statNFE.getName().equals(synthNKey)) {
                    final List<?> statNParameterList = (List<?>) statNFE
                            .getProperty(NaModelConstants.STATNPARA_MEMBER);
                    for (final Object object : statNParameterList) {
                        final Feature fe = (Feature) object;
                        final String annuality = Double
                                .toString(1d / (Double) fe.getProperty(NaModelConstants.STATN_PROP_XJAH));
                        if (annuality.equals(annualityKey.toString())) {
                            final IObservation tnProp = (IObservation) fe
                                    .getProperty(NaModelConstants.STATN_PROP_STATN_DIAG);
                            if (tnProp != null) {
                                final IObservation observation = tnProp;
                                final IAxis[] axisList = observation.getAxes();
                                final IAxis minutesAxis = ObservationUtilities.findAxisByType(axisList,
                                        ITimeseriesConstants.TYPE_MIN);
                                final IAxis precipitationAxis = ObservationUtilities.findAxisByType(axisList,
                                        ITimeseriesConstants.TYPE_RAINFALL);
                                buffer.append(FortranFormatHelper.printf(annualityKey, "f6.3") + " " + "1" + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
                                final ITupleModel values = observation.getValues(null);
                                final int count = values.size();
                                // if( count > 20 )
                                // throw new Exception( "Fehler!!! NA-Modell: Anzahl Wertepaare synth Niederschlag > maximale Anzahl
                                // (20) \n Niederschlag:" + synthNKey + "\n Wiederkehrwahrscheinlichkeit: "
                                // + annualityKey );
                                for (int row = 0; row < count; row++) {
                                    final Double minutesValue = (Double) values.get(row, minutesAxis);
                                    final Double hoursValue = minutesValue / 60d;
                                    if (hoursValue.equals(m_metaControl.getDurationHours())) {
                                        final Double precipitationValue = (Double) values.get(row,
                                                precipitationAxis);
                                        buffer.append(FortranFormatHelper.printf(hoursValue, "f9.3") + " " //$NON-NLS-1$//$NON-NLS-2$
                                                + FortranFormatHelper.printf(precipitationValue, "*") + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
                                    }
                                }

                                // FIXME: highly dubious: the same buffer is written again and again, but never cleared during the
                                // loop... is this correct?

                                final FileWriter writer = new FileWriter(targetFileN);
                                writer.write(buffer.toString());
                                IOUtils.closeQuietly(writer);
                            } else {
                                final String msg = Messages.getString(
                                        "org.kalypso.convert.namodel.manager.CatchmentManager.143", synthNKey, //$NON-NLS-1$
                                        annualityKey);
                                m_logger.log(Level.WARNING, msg);
                            }
                        }
                    }
                }
            }
        }
    }

}