org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.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.kalypsomodel1d2d.conv;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.regex.Pattern;

import javax.xml.datatype.XMLGregorianCalendar;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.kalypso.contribs.java.util.DateUtilities;
import org.kalypso.contribs.java.util.FormatterUtils;
import org.kalypso.core.KalypsoCorePlugin;
import org.kalypso.kalypsomodel1d2d.KalypsoModel1D2DPlugin;
import org.kalypso.kalypsomodel1d2d.conv.i18n.Messages;
import org.kalypso.kalypsomodel1d2d.schema.binding.discr.ICalculationUnit;
import org.kalypso.kalypsomodel1d2d.schema.binding.discr.ICalculationUnit.TYPE;
import org.kalypso.kalypsomodel1d2d.schema.binding.discr.ICalculationUnit1D2D;
import org.kalypso.kalypsomodel1d2d.schema.binding.discr.IFE1D2DComplexElement;
import org.kalypso.kalypsomodel1d2d.schema.binding.discr.IFE1D2DNode;
import org.kalypso.kalypsomodel1d2d.schema.binding.discr.IFELine;
import org.kalypso.kalypsomodel1d2d.schema.binding.flowrel.IBoundaryCondition;
import org.kalypso.kalypsomodel1d2d.schema.binding.flowrel.IBuildingFlowRelation;
import org.kalypso.kalypsomodel1d2d.schema.binding.flowrel.IBuildingFlowRelation.KIND;
import org.kalypso.kalypsomodel1d2d.schema.binding.flowrel.IBuildingFlowRelation2D;
import org.kalypso.kalypsomodel1d2d.schema.binding.flowrel.IBuildingFlowRelation2D.KIND2D;
import org.kalypso.kalypsomodel1d2d.schema.binding.model.IControlModel1D2D;
import org.kalypso.kalypsomodel1d2d.schema.dict.Kalypso1D2DDictConstants;
import org.kalypso.kalypsomodel1d2d.sim.ISimulation1D2DConstants;
import org.kalypso.kalypsomodel1d2d.ui.geolog.IGeoLog;
import org.kalypso.kalypsosimulationmodel.core.flowrel.IFlowRelationship;
import org.kalypso.kalypsosimulationmodel.core.flowrel.IFlowRelationshipModel;
import org.kalypso.kalypsosimulationmodel.core.roughness.IRoughnessCls;
import org.kalypso.kalypsosimulationmodel.core.roughness.IRoughnessClsCollection;
import org.kalypso.observation.IObservation;
import org.kalypso.observation.result.ComponentUtilities;
import org.kalypso.observation.result.IComponent;
import org.kalypso.observation.result.IRecord;
import org.kalypso.observation.result.TupleResult;
import org.kalypso.observation.result.TupleResultUtilities;
import org.kalypso.observation.util.TupleResultIndex;
import org.kalypsodeegree.model.feature.Feature;
import org.kalypsodeegree.model.feature.IFeatureBindingCollection;
import org.kalypsodeegree.model.geometry.GM_Object;
import org.kalypsodeegree.model.geometry.GM_Point;
import org.kalypsodeegree_impl.gml.binding.commons.IGeoStatus;

/**
 * @author huebsch <a href="mailto:j.huebsch@tuhh.de">Jessica Huebsch</a>
 * @author Gernot Belger
 * @author Dejan Antanaskovic, <a href="mailto:dejan.antanaskovic@tuhh.de">dejan.antanaskovic@tuhh.de</a>
 */
public class Control1D2DConverter {
    /** Directory name for RMAKalypso result files (Output...) files */
    public static final String RESULT_DIR_NAME = "./"; //$NON-NLS-1$

    /** Base filename name for RMAKalypso result files (Output...) files */
    public static final String RESULT_FILE_BASE = "Output"; //$NON-NLS-1$

    private final List<IBoundaryCondition> m_unitBoundaryConditions = new ArrayList<>();

    private final INativeIDProvider m_nativeIDProvider;

    private static IdMap m_staticInnerLinesIDProvider = null;

    private final LinkedHashMap<Integer, IBoundaryCondition> m_WQboundaryConditionsIDProvider = new LinkedHashMap<>();

    private final BuildingIDProvider m_buildingProvider;

    private final IControlModel1D2D m_controlModel;

    private final IRoughnessClsCollection m_roughnessModel;

    private final Map<String, TupleResultIndex> m_BCTupleResultIndexCache = new HashMap<>();

    private boolean m_isBCTupleResultIndexCached = false;

    private final IGeoLog m_log;

    private List<Date> m_listDateSteps = null;

    private final ICalculationUnit m_calculationUnit;

    private boolean m_boolPrintWindLineDone;

    public Control1D2DConverter(final IControlModel1D2D controlModel, final ICalculationUnit calculationUnit,
            final IFlowRelationshipModel flowModel, final IRoughnessClsCollection roughnessMmodel,
            final INativeIDProvider idProvider, final BuildingIDProvider buildingProvider, final IGeoLog log) {
        m_controlModel = controlModel;
        m_calculationUnit = calculationUnit;
        m_roughnessModel = roughnessMmodel;
        m_nativeIDProvider = idProvider;
        m_buildingProvider = buildingProvider;
        m_log = log;
        m_boolPrintWindLineDone = false;

        // only instantiate this provider once, we require global ids over several runs
        if (m_staticInnerLinesIDProvider == null)
            m_staticInnerLinesIDProvider = new IdMap();

        /* Initialize boundary conditions */
        final String calculationUnitID = m_calculationUnit.getId();
        for (final IFlowRelationship relationship : flowModel.getFlowRelationsShips()) {
            if (relationship instanceof IBoundaryCondition) {
                final IBoundaryCondition boundaryCondition = (IBoundaryCondition) relationship;
                if (boundaryCondition.isMemberOf(calculationUnitID))
                    m_unitBoundaryConditions.add(boundaryCondition);
            }
        }
        m_listDateSteps = new ArrayList<>();
    }

    public void writeR10File(final File outputFile) throws CoreException, IOException {
        try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputFile))) {
            writeR10File(outputStream);
        }
    }

    private void writeR10File(final OutputStream outputStream) throws CoreException, IOException {
        // REMARK: Made a central formatter with US locale (causing decimal point to be '.'),
        // so no local parameter for each format is needed any more .
        try (Formatter formatter = new Formatter(outputStream, Charset.defaultCharset().name(), Locale.US)) {
            writeR10File(formatter);
            FormatterUtils.checkIoException(formatter);
        }
    }

    private void writeR10File(final Formatter formatter) throws CoreException, IOException {
        writeR10ControlDataBlock(formatter);
        writeR10PropertiesDataBlock(formatter);
        writeR10ContinuityLineDataBlock(formatter);
        writeR10TimeStepDataBlock(formatter);
    }

    /**
     * Writes the Control Data Block of the RMAKalypso controlFile (*.R10) into the PrintWriter
     */
    private void writeR10ControlDataBlock(final Formatter formatter) throws CoreException, IOException {
        // This value is not used at all during the steady calculation,
        // so if user did not selected unsteady, instead of first time step we will take current date/time (see method
        // getFirstTimeStep())
        final Date firstDate = getFirstTimeStep();
        final Calendar calendarForFirstTimeStep = Calendar.getInstance();
        calendarForFirstTimeStep.setTime(firstDate);

        /* FILES DATA BLOCK */
        formatter.format("OUTFIL  %s%s%n", RESULT_DIR_NAME, RESULT_FILE_BASE); //$NON-NLS-1$
        formatter.format("INKALYPSmodel.2d%n"); //$NON-NLS-1$
        formatter.format("CONTROL A %4d 2d 0%n", m_controlModel.getIaccyc()); //$NON-NLS-1$
        if (m_controlModel.getRestart())
            formatter.format("RESTART%n"); //$NON-NLS-1$

        /* Write W/Q file, even if it is empty. */
        formatter.format("STFLFIL %s%n", ISimulation1D2DConstants.BC_WQ_File); //$NON-NLS-1$
        /* We always write a building file, even if it is empty. */
        formatter.format("INCSTR  %s%n", ISimulation1D2DConstants.BUILDING_File); //$NON-NLS-1$

        /* We only write a wind field, if we want to consider wind */
        if (m_controlModel.getHasWindDrag()) {
            formatter.format("AWINDIN3%s%n", ISimulation1D2DConstants.WIND_RMA10_File); //$NON-NLS-1$
            formatter.format("INSRCORD%s%n", ISimulation1D2DConstants.WIND_RMA10_COORDS_File); //$NON-NLS-1$
        }

        /* We always write a building file, even if it is empty. */
        //    formatter.format( "INSSTR  %s%n", ISimulation1D2DConstants.SURFACE_TRACTTION_File ); //$NON-NLS-1$

        formatter.format("ENDFIL%n"); //$NON-NLS-1$

        // TODO: @Nico -> hard coded defaults could be got from the schema, how?

        // default value: 1500
        if (m_controlModel.getMFW() != 1500)
            formatter.format("MAXFRONT %8d%n", m_controlModel.getMFW()); //$NON-NLS-1$

        // default value: 10.000.000
        if (m_controlModel.getBUFFSIZ() != 20000000)
            formatter.format("BUFFSIZL%16d%n", m_controlModel.getBUFFSIZ()); //$NON-NLS-1$

        /* CONTROL DATA BLOCK */
        final String controlModelName = m_controlModel.getName();
        final String projectName = controlModelName == null
                ? Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.8") //$NON-NLS-1$
                : controlModelName;
        formatter.format("TI      %30s%n", projectName); //$NON-NLS-1$

        // // C0
        Double tbfact = 0.0;
        if (m_controlModel.getIEDSW() == 2 || m_controlModel.getIEDSW() == 13 || m_controlModel.getIEDSW() == 14) {
            tbfact = m_controlModel.getTBFACT();
        } else {
            tbfact = m_controlModel.getTBFACT_ESCUDIER();
        }
        final Object[] c0Props = new Object[] { 0, m_controlModel.getIDNOPT(),
                calendarForFirstTimeStep.get(Calendar.YEAR), calendarForFirstTimeStep.get(Calendar.DAY_OF_YEAR),
                getTimeInPercentage(calendarForFirstTimeStep), m_controlModel.getIEDSW(), tbfact,
                m_controlModel.getTBMIN(), 1 };
        formatter.format("C0%14d%8d%8d%8d%8.2f%8d%8.3f%8.2f%8d%n", c0Props); //$NON-NLS-1$

        // C1
        formatter.format("C1%14d%8d%8d%8d%8d%8d%8d%8d%8d%n", 0, 1, 0, 0, 0, 0, 0, 0, 1); //$NON-NLS-1$

        // C2
        // TODO: P_BOTTOM still not implemented, ask Nico
        formatter.format("C2%14.2f%8.3f%8.1f%8.1f%8.1f%8d%8.2f%n", m_controlModel.getOMEGA(), //$NON-NLS-1$
                m_controlModel.getELEV(), 1.0, 1.0, 1.0, 1, m_controlModel.get_P_BOTTOM());

        // C3
        formatter.format("C3%14.3f%8.3f%8.3f%8.1f%8.3f%8.3f%8.3f%n", 1.0, 1.0, m_controlModel.getUNOM(), //$NON-NLS-1$
                m_controlModel.getUDIR(), m_controlModel.getHMIN(), m_controlModel.getDSET(),
                m_controlModel.getDSETD());

        // C4
        final boolean artImpulsstromBeiwert = m_controlModel.getBeient();
        formatter.format("C4%14.1f%8.1f%8.1f%40d%n", 0.0, 20.0, 0.0, artImpulsstromBeiwert ? 1 : 0); //$NON-NLS-1$

        // C5
        formatter.format("C5%14d%8d%16d%8d%8d%8d%8d%8d%8d%n", m_controlModel.getNITI(), m_controlModel.getNITN(), //$NON-NLS-1$
                m_controlModel.getNCYC(), 0, 0, 1, 0, 1, 1);

        // C6
        if (m_controlModel.getIcpu() != 0)
            formatter.format("C6%14d%8d%8d%8d%8.5f%8d%n", 0, 0, 0, m_controlModel.getIcpu(), //$NON-NLS-1$
                    m_controlModel.getHasWindDrag() ? m_controlModel.getChi() : 0.0,
                    m_controlModel.getMarshFrictionDistr());
        // C7
        formatter.format("C7%14d%8d%8d%n", 0, 0, m_controlModel.getPercentCheck() ? 1 : 0); //$NON-NLS-1$

        // CV
        formatter.format("CV%14.2g%8.2g%8.2g%8.2g%8.2g%16d%8.2f%n", m_controlModel.getCONV_1(), //$NON-NLS-1$
                m_controlModel.getCONV_2(), m_controlModel.getCONV_3(), 0.05, 0.05, m_controlModel.getIDRPT(),
                m_controlModel.getDRFACT());

        // IOP line deleted because Nico said that it is an ugly, baaad line... :)
        // (IOP has something to do with reordering, and this is not working properly with 1D-2D coupling)
        // formatter.format( "IOP%n" );

        // VEGETA
        if (m_controlModel.getVegeta())
            formatter.format("VEGETA%n"); //$NON-NLS-1$

        formatter.format("ENERGY%n"); //$NON-NLS-1$
        formatter.format("KAL_BC%n"); //$NON-NLS-1$

        FormatterUtils.checkIoException(formatter);
    }

    /**
     * writes the Properties Data Block of the RMAKalypso controlFile (*.R10) into the PrintWriter
     */
    private void writeR10PropertiesDataBlock(final Formatter formatter) throws CoreException, IOException {
        for (final IRoughnessCls rClass : m_roughnessModel.getRoughnessClasses()) {
            final int roughnessAsciiID = m_nativeIDProvider.getConversionID(rClass);

            final int iedsw = m_controlModel.getIEDSW();
            Double[] eddy = rClass.getViscosities(iedsw); // for empty tbmin* 1000 for all eddies
            eddy = checkViscosities(eddy);
            final Double ks = rClass.getKs();
            final Double axAy = rClass.getAxAy();
            final Double dp = rClass.getDp();

            if (ks == null || ks.isNaN()) {
                final String msg = Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.7", //$NON-NLS-1$
                        rClass.getName());
                throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, msg));
            }

            final Double axayCorrected = axAy == null ? 0.0 : axAy;
            final Double dpCorrected = dp == null ? 0.0 : dp;

            writeEDBlock(formatter, roughnessAsciiID, eddy, ks, axayCorrected, dpCorrected);
        }

        final Map<Integer, IFlowRelationship> buildingMap = m_buildingProvider.getBuildingData();
        for (final Integer buildingID : buildingMap.keySet())
            writeEDBlock(formatter, buildingID, 0.0, 0.0, 0.0, 0.0);
    }

    private Double[] checkViscosities(final Double[] eddy) {
        final Double[] eddyRes = new Double[eddy.length];
        final Double lDoubleDefaultViscosity = m_controlModel.getTBMIN();

        for (int i = 0; i < eddy.length; i++) {
            final Double double1 = eddy[i];
            if (double1.equals(0.0)) {
                eddyRes[i] = lDoubleDefaultViscosity * 1000;
            } else {
                eddyRes[i] = double1;
            }
        }
        return eddyRes;
    }

    private void writeEDBlock(final Formatter formatter, final int roughnessAsciiID, final Double[] eddy,
            final Double ks, final Double axayCorrected, final Double dpCorrected) throws IOException {
        if (eddy.length < 4)
            throw new IllegalArgumentException(
                    Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.17")); //$NON-NLS-1$
        formatter.format("ED1%13d%8.1f%8.1f%8.1f%8.1f%8.1f%8.3f%8.3f%n", roughnessAsciiID, eddy[0], eddy[1], //$NON-NLS-1$
                eddy[2], eddy[3], -1.0, 1.0, 1.0);
        formatter.format("ED2%21.1f%8.1f%8.3f%16.1f%n", 0.5, 0.5, 0.001, m_controlModel.getMarshFrictionFactor()); //$NON-NLS-1$
        formatter.format("ED4%21.5f%8.3f%8.3f%n", ks, axayCorrected, dpCorrected); //$NON-NLS-1$

        FormatterUtils.checkIoException(formatter);
    }

    private void writeEDBlock(final Formatter formatter, final int roughnessAsciiID, final double val,
            final Double ks, final Double axayCorrected, final Double dpCorrected) throws IOException {
        formatter.format("ED1%13d%8.1f%8.1f%8.1f%8.1f%8.1f%8.3f%8.3f%n", roughnessAsciiID, val, val, val, val, -1.0, //$NON-NLS-1$
                1.0, 1.0);
        formatter.format("ED2%21.1f%8.1f%8.3f%16.1f%n", 0.5, 0.5, 0.001, m_controlModel.getMarshFrictionFactor()); //$NON-NLS-1$
        formatter.format("ED4%21.5f%8.3f%8.3f%n", ks, axayCorrected, dpCorrected); //$NON-NLS-1$

        FormatterUtils.checkIoException(formatter);
    }

    /**
     * writes the Continuity Lines Data Block of the RMAKalypso controlFile (*.R10) into the PrintWriter
     */
    private void writeR10ContinuityLineDataBlock(final Formatter formatter) throws CoreException, IOException {
        final List<IFELine> continuityLines = m_calculationUnit.getContinuityLines();
        formatter.format("SCL%9d%n", continuityLines.size()); //$NON-NLS-1$
        for (final IFELine line : continuityLines) {
            final IFE1D2DNode[] nodes = line.getNodes();
            for (int i = 0; i < nodes.length; i++) {
                final IFE1D2DNode node = nodes[i];
                final int nodeID = m_nativeIDProvider.getConversionID(node);
                if (nodeID == 0) {
                    final GM_Point position = node.getPoint();
                    final String msg = Messages
                            .getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.11"); //$NON-NLS-1$
                    final IGeoStatus status = m_log.log(IStatus.ERROR, ISimulation1D2DConstants.CODE_PRE, msg,
                            position, null);
                    throw new CoreException(status);
                }

                if (i == 0)
                    formatter.format("CC1 %4d", m_nativeIDProvider.getConversionID(line)); //$NON-NLS-1$
                else if (i % 9 == 0) {
                    formatter.format("%nCC2     "); //$NON-NLS-1$
                }

                formatter.format("%8d", nodeID); //$NON-NLS-1$
            }

            // Why this "if" was here?
            // if( nodes.length % 9 != 0 )
            formatter.format("%n"); //$NON-NLS-1$

            // check if line is an inner boundary line (only for coupled 1d2d units and enabled coupled simulation)
            // this is the case if it is contained in two 2d calculation units of this coupled unit
            final ICalculationUnit parentCalculationUnit = m_controlModel.getCalculationUnit();
            if (parentCalculationUnit.getType() == TYPE.TYPE1D2D
                    && ((ICalculationUnit1D2D) parentCalculationUnit).isCoupledSimulation()) {
                final ICalculationUnit1D2D calculationUnit1D2D = (ICalculationUnit1D2D) parentCalculationUnit;
                final IFeatureBindingCollection<ICalculationUnit> changedSubUnits = calculationUnit1D2D
                        .getSubCalculationUnits();
                int in2DCalcUnitCount = 0;
                final IFE1D2DComplexElement<?>[] containers = line.getLinkedElements();
                for (final Feature calcUnit : containers) {
                    if (((ICalculationUnit) calcUnit).getType() == TYPE.TYPE2D
                            && changedSubUnits.contains(calcUnit)) {
                        in2DCalcUnitCount++;
                    }
                }
                if (in2DCalcUnitCount == 2)
                    formatter.format("ICL %4d %4d\n", m_staticInnerLinesIDProvider.getOrAdd(line.getId()), //$NON-NLS-1$
                            m_nativeIDProvider.getConversionID(line));
            }

            FormatterUtils.checkIoException(formatter);
        }
        formatter.format("ECL%n"); //$NON-NLS-1$

        if (m_controlModel.getIDNOPT() != 0 && m_controlModel.getIDNOPT() != -1)
            formatter.format("MP %21.3f%8.3f%8.5f%8.2f%n", //$NON-NLS-1$
                    m_controlModel.getFixedMarshBottom() ? 0.0 : m_controlModel.getAC1(), m_controlModel.getAC2(),
                    m_controlModel.getAC3(), m_controlModel.getFixedMarshBottom() ? m_controlModel.getAC4() : 0.0);

        formatter.format("ENDGEO%n"); //$NON-NLS-1$

        FormatterUtils.checkIoException(formatter);
    }

    /**
     * writes the Timestep Data Block of the RMAKalypso controlFile (*.R10) into the PrintWriter
     */
    private void writeR10TimeStepDataBlock(final Formatter formatter) throws CoreException, IOException {
        final IObservation<TupleResult> observation = m_controlModel.getTimeSteps();
        final TupleResult result = observation.getResult();
        final IComponent[] components = result.getComponents();

        final IComponent componentTime = ComponentUtilities.findComponentByID(components,
                Kalypso1D2DDictConstants.DICT_COMPONENT_TIME);
        final IComponent componentRelaxationsFaktor = ComponentUtilities.findComponentByID(components,
                Kalypso1D2DDictConstants.DICT_COMPONENT_UNDER_RELAXATION_FACTOR);

        /* Steady state, just one block for the Starting Date. */
        final int niti = m_controlModel.getNITI();

        final String msg = Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.33"); //$NON-NLS-1$

        // Double uRValSteady = m_controlModel.get_RelaxationsFactor();
        String uRValSteady = m_controlModel.get_RelaxationsFactor();
        if (uRValSteady == null || uRValSteady == "") //$NON-NLS-1$
        {
            if (m_controlModel.isSteadySelected()) {
                final String errMsg = Messages
                        .getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.34");//$NON-NLS-1$
                throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, errMsg));
            } else
                // Not used anyway (1.0 should be default value)
                uRValSteady = "1.0"; //$NON-NLS-1$
        }

        writeTimeStep(formatter, msg, null, null, uRValSteady, niti);

        if (m_controlModel.isUnsteadySelected()) {
            /* Sort records by time */
            final TupleResultIndex index = new TupleResultIndex(result, componentTime);
            final Iterator<IRecord> iterator = index.getIterator();
            if (!iterator.hasNext()) {
                final String errMsg = Messages
                        .getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.35");//$NON-NLS-1$
                throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, errMsg));
            }

            final IRecord firstRecord = iterator.next();

            final int nitn = m_controlModel.getNITN();

            if (nitn > 0) {
                /* Unsteady state: a block for each time step */

                // TODO: check for right time zone
                // // As we are using UTC for all our timeseries, this is the timezone that should be used here
                // final TimeZone DEFAULT_TIMEZONE = TimeZone.getTimeZone( "UTC" );
                final TupleResult owner = firstRecord.getOwner();
                final int indexTime = owner.indexOfComponent(componentTime);
                final int indexRelaxationsFaktor = owner.indexOfComponent(componentRelaxationsFaktor);

                final XMLGregorianCalendar cal = (XMLGregorianCalendar) firstRecord.getValue(indexTime);
                Calendar lastStepCal = cal.toGregorianCalendar();
                m_listDateSteps.add(DateUtilities.toDate(cal));

                int stepCount = 1;
                for (; iterator.hasNext(); stepCount++) {
                    final IRecord record = iterator.next();

                    // final float uRVal = ((BigDecimal) record.getValue( indexRelaxationsFaktor )).floatValue();
                    final String uRVal = ((String) record.getValue(indexRelaxationsFaktor));
                    final XMLGregorianCalendar stepXMLGrCal = (XMLGregorianCalendar) record.getValue(indexTime);
                    final Calendar stepCal = stepXMLGrCal.toGregorianCalendar();
                    m_listDateSteps.add(DateUtilities.toDate(stepXMLGrCal));

                    final String unsteadyMsg = Messages
                            .getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.36", stepCount); //$NON-NLS-1$
                    writeTimeStep(formatter, unsteadyMsg, stepCal, lastStepCal, uRVal, nitn);

                    lastStepCal = stepCal;

                }
                if (m_controlModel.getIaccyc() > stepCount) {
                    final String errMsg = Messages.getString(
                            "org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.12", stepCount, //$NON-NLS-1$
                            m_controlModel.getIaccyc());
                    throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, errMsg));
                }
            }
        }
    }

    /**
     * writes out the time steps. <BR>
     * IMPORTANT: we write the dates in the time zone according to the kalypso-preferences!
     */
    private void writeTimeStep(final Formatter formatter, final String message, final Calendar calculationStep,
            final Calendar lastStepCal, final String uRVal, final int niti) throws CoreException, IOException {
        final String dashes = StringUtils.repeat("-", message.length()); //$NON-NLS-1$
        formatter.format("com %s%n", dashes); //$NON-NLS-1$
        formatter.format("com %s%n", message); //$NON-NLS-1$
        formatter.format("com %s%n", dashes); //$NON-NLS-1$

        final long timeStepInterval;
        final double timeStepMinutes;
        final int year;
        final int dayOfYear;
        final double ihre;

        final TimeZone displayTimeZone = KalypsoCorePlugin.getDefault().getTimeZone();
        Calendar kalypsoCalendarStep = Calendar.getInstance(displayTimeZone);

        // unsteady
        if (calculationStep != null) {
            // REMARK: we write the date in the kalypso-preferences time zone!
            kalypsoCalendarStep.setTime(calculationStep.getTime());
            dayOfYear = kalypsoCalendarStep.get(Calendar.DAY_OF_YEAR);
            year = kalypsoCalendarStep.get(Calendar.YEAR);

            // REMARK: we write the date in the kalypso-preferences time zone!
            final Calendar kalypsoCallendarPreviousStep = Calendar.getInstance(displayTimeZone);
            kalypsoCallendarPreviousStep.setTime(lastStepCal.getTime());

            timeStepInterval = kalypsoCalendarStep.getTimeInMillis()
                    - kalypsoCallendarPreviousStep.getTimeInMillis();

            // FIXME: should never happen, kalypso does not allow summertime timezones any more
            // if timeStepInterval is zero, step will be ignored
            // (this will happen on summertime to wintertime transition)
            if (timeStepInterval == 0) {
                formatter.format(Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.14")); //$NON-NLS-1$
                return;
            }

            timeStepMinutes = (double) timeStepInterval / (60 * 1000);
            ihre = getTimeInPercentage(kalypsoCalendarStep);
        }
        // steady dont need startdate
        else {
            kalypsoCalendarStep = null;
            dayOfYear = 0;
            year = 0;
            timeStepMinutes = 0;
            ihre = 0;
        }

        formatter.format("DT MIN  %e%8d%8d%8.2f", timeStepMinutes, year, dayOfYear, ihre); //$NON-NLS-1$

        // BC lines
        if (niti == 0)
            formatter.format("%nBC%n"); //$NON-NLS-1$
        else
            formatBC(formatter, uRVal, niti);

        // order is important, first QC than HC, SQC and EFE
        formatBoundCondLines(formatter, kalypsoCalendarStep, Kalypso1D2DDictConstants.DICT_COMPONENT_TIME,
                Kalypso1D2DDictConstants.DICT_COMPONENT_DISCHARGE);
        formatBoundCondLines(formatter, kalypsoCalendarStep, Kalypso1D2DDictConstants.DICT_COMPONENT_TIME,
                Kalypso1D2DDictConstants.DICT_COMPONENT_WATERLEVEL);
        formatBoundCondLines(formatter, kalypsoCalendarStep, Kalypso1D2DDictConstants.DICT_COMPONENT_WATERLEVEL,
                Kalypso1D2DDictConstants.DICT_COMPONENT_DISCHARGE);

        FormatterUtils.checkIoException(formatter);

        for (final Map.Entry<Integer, IFlowRelationship> buildingData : m_buildingProvider.getBuildingData()
                .entrySet()) {
            final Integer buildingID = buildingData.getKey();
            final IFlowRelationship building = buildingData.getValue();
            final int buildingKind = 10;
            int lIntDirection = 0;
            if (building instanceof IBuildingFlowRelation) {
                if (((IBuildingFlowRelation) building).getKind() != KIND.TABULAR) {
                    final String msg = Messages.getString(
                            "org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.43", //$NON-NLS-1$
                            ((IBuildingFlowRelation) building).getKind());
                    throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, msg));
                }
                lIntDirection = ((IBuildingFlowRelation) building).getDirection();
            } else if (building instanceof IBuildingFlowRelation2D) {
                if (((IBuildingFlowRelation2D) building).getKind() != KIND2D.TABULAR) {
                    final String msg = Messages.getString(
                            "org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.43", //$NON-NLS-1$
                            ((IBuildingFlowRelation) building).getKind());
                    throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, msg));
                }
                lIntDirection = ((IBuildingFlowRelation2D) building).getDirection();
            }
            final double direction = Math.toRadians(lIntDirection);
            formatter.format("FC%14d%8d%8.3f%8.3f%8.3f%8.3f%8.3f%n", buildingID, buildingKind, 0.0, 0.0, 0.0, 0.0, //$NON-NLS-1$
                    direction);

            FormatterUtils.checkIoException(formatter);
        }

        formatBoundCondLines(formatter, kalypsoCalendarStep, Kalypso1D2DDictConstants.DICT_COMPONENT_TIME,
                Kalypso1D2DDictConstants.DICT_COMPONENT_SPECIFIC_DISCHARGE_1D);
        formatBoundCondLines(formatter, kalypsoCalendarStep, Kalypso1D2DDictConstants.DICT_COMPONENT_TIME,
                Kalypso1D2DDictConstants.DICT_COMPONENT_SPECIFIC_DISCHARGE_2D);

        // add other conti lines types as well (buildings)?
        if (m_controlModel.getHasWindDrag() && !m_boolPrintWindLineDone) {
            formatter.format("WVA          1.0     1.0       1%n"); //$NON-NLS-1$
            m_boolPrintWindLineDone = true;
        }
        formatter.format("ENDSTEP %s%n", message); //$NON-NLS-1$

        FormatterUtils.checkIoException(formatter);
    }

    /**
     * For big timeseries, creating TupleResultIndex for every time step is extremely slow. Cacheing those indexes for
     * performances reason is necessary.
     */
    private void cacheBCTupleResultIndexes() {
        m_BCTupleResultIndexCache.clear();
        for (final IBoundaryCondition boundaryCondition : m_unitBoundaryConditions) {
            if (boundaryCondition.getTypeByLocation().equals(IBoundaryCondition.PARENT_TYPE_ELEMENT1D2D)
                    || boundaryCondition.getTypeByLocation().equals(IBoundaryCondition.PARENT_TYPE_LINE1D2D)) {
                final IObservation<TupleResult> obs = boundaryCondition.getObservation();
                final TupleResult obsResult = obs.getResult();
                final IComponent timeComponent = TupleResultUtilities.findComponentById(obsResult,
                        Kalypso1D2DDictConstants.DICT_COMPONENT_TIME);

                // timeComponent is null for W/Q BCs
                if (timeComponent != null)
                    m_BCTupleResultIndexCache.put(boundaryCondition.getId(),
                            new TupleResultIndex(obsResult, timeComponent));
            }
        }
        m_isBCTupleResultIndexCached = true;
    }

    /**
     * Formats the lines for one type of boundary condition (QC or HC or ... ).
     */
    private void formatBoundCondLines(final Formatter formatter, final Calendar stepCal,
            final String bcAbscissaComponentType, final String bcOrdinateComponentType)
            throws IOException, CoreException {
        if (!m_isBCTupleResultIndexCached)
            cacheBCTupleResultIndexes();

        for (final IBoundaryCondition boundaryCondition : m_unitBoundaryConditions) {
            if (boundaryCondition.getTypeByLocation().equals(IBoundaryCondition.PARENT_TYPE_ELEMENT1D2D)
                    || boundaryCondition.getTypeByLocation().equals(IBoundaryCondition.PARENT_TYPE_LINE1D2D)) {
                final int ordinal = m_nativeIDProvider.getConversionID(boundaryCondition.getParentElementID());
                final IObservation<TupleResult> obs = boundaryCondition.getObservation();
                final TupleResult obsResult = obs.getResult();
                final IComponent abscissaComponent = TupleResultUtilities.findComponentById(obsResult,
                        bcAbscissaComponentType);
                IComponent ordinateComponent = TupleResultUtilities.findComponentById(obsResult,
                        bcOrdinateComponentType);

                // TODO: type of absolute element inflow must also become the type specificDischarge
                if (ordinateComponent == null
                        && (bcOrdinateComponentType
                                .equals(Kalypso1D2DDictConstants.DICT_COMPONENT_SPECIFIC_DISCHARGE_1D)
                                || bcOrdinateComponentType
                                        .equals(Kalypso1D2DDictConstants.DICT_COMPONENT_SPECIFIC_DISCHARGE_2D))
                        && (boundaryCondition.isAbsolute() != null))
                    ordinateComponent = TupleResultUtilities.findComponentById(obsResult,
                            Kalypso1D2DDictConstants.DICT_COMPONENT_DISCHARGE);

                if (abscissaComponent != null && ordinateComponent != null) {
                    final double stepValue = findStepValue(stepCal, bcAbscissaComponentType,
                            bcOrdinateComponentType, boundaryCondition, ordinateComponent);

                    if (bcAbscissaComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_TIME)
                            && bcOrdinateComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_DISCHARGE)
                            && (boundaryCondition.isAbsolute() == null)) {
                        // TODO: @Nico This is very ugly, but it works for the moment!! It should be introduced to GMLLoader checks
                        final Boolean hasDirectionProperty = boundaryCondition.hasDirection();
                        if (hasDirectionProperty == null)
                            boundaryCondition.setHasDirection(true);
                        else if (hasDirectionProperty == false)
                            boundaryCondition.setHasDirection(true);

                        final double theta = Math.toRadians(boundaryCondition.getDirection().doubleValue());
                        formatter.format("QC *%12d%8d%16.3f%8.3f%8.3f%8.3f%8.3f%n", ordinal, 0, stepValue, theta, //$NON-NLS-1$
                                0.000, 20.000, 0.000);
                    } else if (bcAbscissaComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_WATERLEVEL)
                            && bcOrdinateComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_DISCHARGE)) {
                        // TODO: @Nico This is very ugly, but it works for the moment!! It should be introduced to GMLLoader checks
                        final Boolean hasDirectionProperty = boundaryCondition.hasDirection();
                        if (hasDirectionProperty == false || hasDirectionProperty == null)
                            boundaryCondition.setHasDirection(true);
                        final double theta = Math.toRadians(boundaryCondition.getDirection().doubleValue());
                        formatter.format("SQC%13d%40.4f%8.3f%8.3f%8.3f%n", ordinal, theta, 0.000, 20.000, 0.000); //$NON-NLS-1$
                        m_WQboundaryConditionsIDProvider.put(ordinal, boundaryCondition);
                    } else if (bcAbscissaComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_TIME)
                            && bcOrdinateComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_WATERLEVEL)) {
                        formatter.format("HC%14d%8d%8.3f%8.3f%8.3f%8.3f%n", ordinal, 0, stepValue, 0.0, 20.000, //$NON-NLS-1$
                                0.0);
                    } else if (bcAbscissaComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_TIME)
                            && bcOrdinateComponentType
                                    .equals(Kalypso1D2DDictConstants.DICT_COMPONENT_SPECIFIC_DISCHARGE_1D)
                            && boundaryCondition.getParentElementID().startsWith("Element1D")) //$NON-NLS-1$
                    {
                        // 1D Element
                        final Boolean isAbsoluteProperty = boundaryCondition.isAbsolute();
                        final Boolean hasDirectionProperty = boundaryCondition.hasDirection();

                        // TODO: @Nico This is very ugly, but it works for the moment!! It should be introduced to GMLLoader checks
                        if (hasDirectionProperty == null) {
                            boundaryCondition.setHasDirection(false);
                            boundaryCondition.setDirection(new BigInteger("0")); //$NON-NLS-1$
                        }
                        if (boundaryCondition.hasDirection() && boundaryCondition.getDirection() == null)
                            boundaryCondition.setDirection(new BigInteger("0")); //$NON-NLS-1$

                        final int isAbsolute = (isAbsoluteProperty != null && isAbsoluteProperty.booleanValue()) ? 1
                                : 0;

                        if (boundaryCondition.hasDirection())
                            formatter.format("EFE%13d%8d%8d%8.3f%8.4f%8.4f%8.4f%8.4f%8.4f%n", ordinal, 0, //$NON-NLS-1$
                                    isAbsolute, stepValue, 0.0, 20.000, 0.0, boundaryCondition.getInflowVelocity(),
                                    Math.toRadians(boundaryCondition.getDirection().doubleValue()));
                        else
                            formatter.format("EFE%13d%8d%8d%8.3f%8.4f%8.4f%8.4f%n", ordinal, 0, isAbsolute, //$NON-NLS-1$
                                    stepValue, 0.0, 20.000, 0.0);
                    } else if (bcAbscissaComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_TIME)
                            && bcOrdinateComponentType
                                    .equals(Kalypso1D2DDictConstants.DICT_COMPONENT_SPECIFIC_DISCHARGE_2D)
                            && !boundaryCondition.getParentElementID().startsWith("Element1D")) //$NON-NLS-1$
                    {
                        // 2D Element
                        final Boolean isAbsoluteProperty = boundaryCondition.isAbsolute();
                        final Boolean hasDirectionProperty = boundaryCondition.hasDirection();

                        // TODO: @Nico This is very ugly, but it works for the moment!! It should be introduced to GMLLoader checks
                        if (hasDirectionProperty == null) {
                            boundaryCondition.setHasDirection(false);
                            boundaryCondition.setDirection(new BigInteger("0")); //$NON-NLS-1$
                        }
                        if (boundaryCondition.hasDirection() && boundaryCondition.getDirection() == null)
                            boundaryCondition.setDirection(new BigInteger("0")); //$NON-NLS-1$

                        final int isAbsolute = (isAbsoluteProperty != null && isAbsoluteProperty.booleanValue()) ? 1
                                : 0;
                        if (boundaryCondition.hasDirection()) {
                            double infVel = 0.001;
                            try {
                                infVel = boundaryCondition.getInflowVelocity();
                            } catch (final Exception e) {
                                // FIXME: grr, error handling -> we need to stop calculation in such a case!
                                m_log.log(IStatus.WARNING, ISimulation1D2DConstants.CODE_PRE,
                                        Messages.getString("Control1D2DConverter.1"), //$NON-NLS-1$
                                        boundaryCondition.getLocation(), e);
                            }
                            formatter.format("EFE%13d%8d%8d%8.3f%8.4f%8.4f%8.4f%8.4f%8.4f%n", ordinal, 0, //$NON-NLS-1$
                                    isAbsolute, stepValue, 0.0, 20.000, 0.0, infVel,
                                    Math.toRadians(boundaryCondition.getDirection().doubleValue()));
                        } else
                            formatter.format("EFE%13d%8d%8d%8.3f%8.4f%8.4f%8.4f%n", ordinal, 0, isAbsolute, //$NON-NLS-1$
                                    stepValue, 0.0, 20.000, 0.0);
                    }
                }
            }

            FormatterUtils.checkIoException(formatter);
        }
    }

    private double findStepValue(final Calendar stepCal, final String bcAbscissaComponentType,
            final String bcOrdinateComponentType, final IBoundaryCondition boundaryCondition,
            final IComponent ordinateComponent) throws CoreException {
        if (bcAbscissaComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_WATERLEVEL)
                && bcOrdinateComponentType.equals(Kalypso1D2DDictConstants.DICT_COMPONENT_DISCHARGE)) {
            // Its a w/Q Boundary Condition, we do not need a step value...
            return Double.NaN;
        }

        if (stepCal != null) {
            final TupleResultIndex tupleResultIndex = m_BCTupleResultIndexCache.get(boundaryCondition.getId());
            final Number result = (Number) tupleResultIndex.getValue(ordinateComponent, stepCal.getTime());
            if (result == null || Double.isNaN(result.doubleValue())) {
                final SimpleDateFormat df = new SimpleDateFormat(ISimulation1D2DConstants.TIMESTEP_DISPLAY_FORMAT);
                final String stepText = df.format(stepCal.getTime());
                final String bcLabel = boundaryCondition.getName();
                final String message = String.format(Messages.getString("Control1D2DConverter.0"), stepText, //$NON-NLS-1$
                        bcLabel);
                final GM_Object location = boundaryCondition.getPosition();
                final IGeoStatus error = m_log.log(IStatus.ERROR, ISimulation1D2DConstants.CODE_PRE, message,
                        location, null);
                throw new CoreException(error);
            }

            return result.doubleValue();
        } else {
            try {
                return Double.parseDouble(boundaryCondition.getStationaryCondition());
            } catch (final Exception e) {
                final String bcLabel = boundaryCondition.getName();
                final String message = String.format(Messages.getString("Control1D2DConverter.2"), bcLabel); //$NON-NLS-1$
                final GM_Object location = boundaryCondition.getPosition();
                final IGeoStatus error = m_log.log(IStatus.ERROR, ISimulation1D2DConstants.CODE_PRE, message,
                        location, null);

                throw new CoreException(error);
            }
        }
    }

    // private void formatBC( final Formatter formatter, final float uRVal, final int nitn ) throws CoreException,
    // IOException
    private void formatBC(final Formatter formatter, final String uRVal, final int nitn)
            throws CoreException, IOException {
        if (uRVal == null || uRVal == "") { //$NON-NLS-1$
            final String msg = Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.6");//$NON-NLS-1$
            throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, msg));
        }
        final List<Integer> lListFactors = getListParsedRelaxationFactor(uRVal, nitn);
        // final int buffVal = 10 - (int) (uRVal * 10);
        for (int j = 0; j < nitn; j++) {
            if (j % 9 == 0) {
                formatter.format("%nBC%6s", " "); //$NON-NLS-1$ //$NON-NLS-2$
            }
            formatter.format("%5d010", lListFactors.get(j)); //$NON-NLS-1$
        }
        formatter.format("%n"); //$NON-NLS-1$

        FormatterUtils.checkIoException(formatter);
    }

    private List<Integer> getListParsedRelaxationFactor(final String pStrVal, final int pIntNumberIterations)
            throws CoreException {
        final List<Integer> lListFactorsRes = new ArrayList<>();
        final List<Float> lListFactors = new ArrayList<>();
        if (!isLoopFomatedFactor(pStrVal.trim(), lListFactors, pIntNumberIterations)) {
            if (!isSeparatedValuesFormatedFactor(pStrVal.trim(), lListFactors, pIntNumberIterations)) {
                final String msg = Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.6");//$NON-NLS-1$
                throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, msg));
            }
        }

        for (int i = 0; i < pIntNumberIterations; ++i) {
            final int buffVal = 10 - (int) (lListFactors.get(i) * 10);
            lListFactorsRes.add(buffVal);
        }

        return lListFactorsRes;
    }

    /**
     * checks if the given string value contains string of form "0.1 to 0.5" and if it is, parses it and expands it into
     * according to amount of steps values and put them into pListFactors as floats
     */
    private boolean isLoopFomatedFactor(final String pStrValue, final List<Float> pListFactors,
            final int pIntNumberIterations) throws CoreException {
        final String lStrRegex = "[ \\t]*[0-9][.,][0-9][ \\t]*[tT][oO][ \\t]*[0-9][.,][0-9][ \\t]*"; //$NON-NLS-1$
        final String lStrToCheck = pStrValue.trim().toLowerCase();
        if (Pattern.matches(lStrRegex, lStrToCheck)) {
            final int lIntIndexSep = lStrToCheck.indexOf("to"); //$NON-NLS-1$
            final float lFloatStart = getFloatFromSimpleFloatString(lStrToCheck.substring(0, lIntIndexSep).trim());
            final float lFloatEnd = getFloatFromSimpleFloatString(lStrToCheck.substring(lIntIndexSep + 2).trim());
            if (lFloatStart < 0.0 || lFloatStart > 1.0 || lFloatEnd < 0.0 || lFloatEnd > 1.0) {
                final String msg = Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.6");//$NON-NLS-1$
                throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, msg));
            }
            final float lFloatInc = (float) ((lFloatEnd - lFloatStart) / 0.1);
            final int lIntPer = (int) (pIntNumberIterations / (Math.abs(lFloatInc) + 1));
            int lIntInc = 0;
            final float lFloatSignum = Math.signum(lFloatInc);
            for (int i = 1; i <= pIntNumberIterations; ++i) {
                pListFactors.add((float) (lFloatStart + 0.1 * lIntInc * lFloatSignum));
                if ((i) % lIntPer == 0 && pIntNumberIterations - i > Math.abs(lIntPer)
                        && lIntInc < Math.abs(lFloatInc)) {
                    lIntInc++;
                }
            }
            return true;
        }

        return false;
    }

    // /**
    // * checks if the given string value contains string of form "0.1 to 0.5" and if it is, parses it and expands it into
    // according to
    // * amount of steps values and put them into pListFactors as floats
    // *
    // * direct implementation of parsing the relaxation factor
    // */
    // private boolean isLoopFomatedFactor( String pStrValue, List<Float> pListFactors, int pIntNumberIterations ) throws
    // CoreException
    // {
    //    final String lStrRegex = "[ \\t]*[0-9][.,][0-9][ \\t]*[tT][oO][ \\t]*[0-9][.,][0-9][ \\t]*"; //$NON-NLS-1$
    // String lStrToCheck = pStrValue.trim().toLowerCase();
    // if( Pattern.matches( lStrRegex, lStrToCheck ) ){
    //      int lIntIndexSep = lStrToCheck.indexOf( "to" ); //$NON-NLS-1$
    // float lFloatStart = getFloatFromSimpleFloatString( lStrToCheck.substring( 0, lIntIndexSep ).trim() );
    // float lFloatEnd = getFloatFromSimpleFloatString( lStrToCheck.substring( lIntIndexSep + 2 ).trim() );
    // if( lFloatStart < 0.0 || lFloatStart > 1.0 || lFloatEnd < 0.0 || lFloatEnd > 1.0 ){
    //        final String msg = Messages.getString( "org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.6" );//$NON-NLS-1$
    // throw new CoreException( StatusUtilities.createErrorStatus( msg ) );
    // }
    // int lIntAllInc = Math.abs( ( int )( lFloatEnd * 10 ) - ( int )( lFloatStart * 10 ) );
    // int lIntPer = ( pIntNumberIterations / ( lIntAllInc ) );
    // int lIntIncDone = 0;
    // float lFloatSignum = Math.signum( lFloatEnd - lFloatStart );
    // for( int i = 1; i <= pIntNumberIterations; ++i ){
    // float lFloatRes = (float) ( lFloatStart + 0.1 * lIntIncDone * lFloatSignum );
    // pListFactors.add( lFloatRes ) ;
    // if( (i) % lIntPer == 0 && lIntIncDone < lIntAllInc ){
    // lIntAllInc++;
    // lIntIncDone++;
    // }
    // }
    // return true;
    // }
    //
    // return false;
    // }

    /**
     * checks if the given string value contains semicolon separated list of values and if it is parses it into
     * pListFactors as floats
     */
    private boolean isSeparatedValuesFormatedFactor(final String pStrValue, final List<Float> pListFactors,
            final int pIntNumberIterations) throws CoreException {
        final StringTokenizer lStringTokenizer = new StringTokenizer(pStrValue, ";"); //$NON-NLS-1$
        int lIntCounter = 0;
        float lFloatValAct = (float) 0.1;
        while (lIntCounter < pIntNumberIterations) {
            if (lStringTokenizer.hasMoreTokens()) {
                lFloatValAct = getFloatFromSimpleFloatString(lStringTokenizer.nextToken());
            }
            lIntCounter++;
            pListFactors.add(lFloatValAct);
        }
        return true;
    }

    private float getFloatFromSimpleFloatString(final String pStrFloat) throws CoreException {
        float lFloatValue = (float) 0.1;
        try {
            lFloatValue = Float.parseFloat(pStrFloat.trim());
        } catch (final Exception e) {
            try {
                lFloatValue = Float.parseFloat(pStrFloat.trim().replace(",", ".")); //$NON-NLS-1$ //$NON-NLS-2$
            } catch (final Exception e2) {
                final String msg = Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.6");//$NON-NLS-1$
                throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, msg));
            }
        }
        return lFloatValue;
    }

    private double getTimeInPercentage(final Calendar cal) {
        final int i = cal.get(Calendar.HOUR_OF_DAY);
        final int j2 = cal.get(Calendar.MINUTE);
        final float j = (float) (j2 / 60.0);
        return (double) i + j;
    }

    /**
     * @return If unsteady calculation is selected, returns date/time of the first timestep from the control model.
     *         <p>
     *         If unsteady calculation is not selected, returns current date/time (in the case of steady calculation, this value is not considered by RMAKalypso)
     */
    private Date getFirstTimeStep() throws CoreException {
        if (m_controlModel.isUnsteadySelected() == false) {
            m_listDateSteps.add(new Date());
            return m_listDateSteps.get(0);
        }

        m_controlModel.isUnsteadySelected();
        final IObservation<TupleResult> tupleSet = m_controlModel.getTimeSteps();
        final TupleResult result = tupleSet.getResult();
        final IComponent[] components = result.getComponents();
        final IComponent compTime = ComponentUtilities.findComponentByID(components,
                Kalypso1D2DDictConstants.DICT_COMPONENT_TIME);
        final TupleResultIndex index = new TupleResultIndex(result, compTime);
        final Iterator<IRecord> iterator = index.getIterator();
        if (!iterator.hasNext()) {
            final String msg = Messages.getString("org.kalypso.kalypsomodel1d2d.conv.Control1D2DConverter.52");//$NON-NLS-1$
            throw new CoreException(new Status(IStatus.ERROR, KalypsoModel1D2DPlugin.PLUGIN_ID, msg));
        }

        final IRecord firstRecord = iterator.next();

        final TupleResult owner = firstRecord.getOwner();
        final int indexTime = owner.indexOfComponent(compTime);
        return DateUtilities.toDate((XMLGregorianCalendar) firstRecord.getValue(indexTime));
    }

    public LinkedHashMap<Integer, IBoundaryCondition> getBoundaryConditionsIDProvider() {
        return m_WQboundaryConditionsIDProvider;
    }

    public final Date[] getListDateSteps() {
        return m_listDateSteps.toArray(new Date[m_listDateSteps.size()]);
    }
}