static NodeOutput* _readTimestep(float t, bool isVector, bool hasStatus, QTextStream& stream, int nodeCount, int elemCount, QVector<int>& nodeIDToIndex)
{
  NodeOutput* o = new NodeOutput;
  o->init(nodeCount, elemCount, isVector);
  o->time = t / 3600.;

  QRegExp reSpaces("\\s+");

  if (hasStatus)
  {
    // only for new format
    char* active = o->active.data();
    for (int i = 0; i < elemCount; ++i)
    {
      active[i] = stream.readLine().toInt();
    }
  }
  else
    memset(o->active.data(), 1, elemCount); // there is no status flag -> everything is active

  float* values = o->values.data();
  NodeOutput::float2D* valuesV = o->valuesV.data();
  for (int i = 0; i < nodeIDToIndex.count(); ++i)
  {
    QStringList tsItems = stream.readLine().split(reSpaces, QString::SkipEmptyParts);
    int index = nodeIDToIndex[i];
    if (index < 0)
      continue; // node ID that does not exist in the mesh

    if (isVector)
    {
      NodeOutput::float2D v;
      if (tsItems.count() >= 2) // BASEMENT files with vectors have 3 columns
      {
        v.x = tsItems[0].toFloat();
        v.y = tsItems[1].toFloat();
      }
      else
      {
        qDebug("Crayfish: invalid timestep line");
        v.x = v.y = 0;
      }
      valuesV[index] = v;
      values[index] = v.length(); // Determine the magnitude
    }
    else
    {
      if (tsItems.count() >= 1)
        values[index] = tsItems[0].toFloat();
      else
      {
        qDebug("Crayfish: invalid timestep line");
        values[index] = 0;
      }
    }
  }

  return o;
}
static void addStaticDataset(QVector<float>& vals, const QString& name, const DataSet::Type type, const QString& datFileName, Mesh* mesh) {
    int nelem = mesh->elements().size();
    int nnodes = mesh->nodes().size();

    NodeOutput* o = new NodeOutput;

    o->init(nnodes, nelem, false);
    o->time = 0.0;
    o->values = vals;

    if (type == DataSet::Bed) {
        memset(o->active.data(), 1, nelem); // All cells active
    } else {
        activateElements(o, mesh);
    }

    DataSet* ds = new DataSet(datFileName);
    ds->setType(type);
    ds->setName(name, false);
    ds->setIsTimeVarying(false);
    ds->addOutput(o);  // takes ownership of the Output
    ds->updateZRange();
    mesh->addDataSet(ds);
}
static void parseTIMDEPFile(const QString& datFileName, Mesh* mesh, const QVector<float>& elevations) {\
    // TIMDEP.OUT
    // this file is optional, so if not present, reading is skipped
    // time (separate line)
    // For every node:
    // FLO2D: node number (indexed from 1), depth, velocity, velocity x, velocity y
    // FLO2DPro: node number (indexed from 1), depth, velocity, velocity x, velocity y, water surface elevation
    QFileInfo fi(datFileName);
    QFile inFile(fi.dir().filePath("TIMDEP.OUT"));
    if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text)) return;
    QTextStream in(&inFile);

    int nnodes = mesh->nodes().size();
    int nelems = mesh->elements().size();
    int ntimes = 0;

    float time = 0.0;
    int node_inx = 0;

    DataSet* depthDs = new DataSet(datFileName);
    depthDs->setType(DataSet::Scalar);
    depthDs->setName("Depth");

    DataSet* waterLevelDs = new DataSet(datFileName);
    waterLevelDs->setType(DataSet::Scalar);
    waterLevelDs->setName("Water Level");

    DataSet* flowDs = new DataSet(datFileName);
    flowDs->setType(DataSet::Vector);
    flowDs->setName("Velocity");

    NodeOutput* flowOutput = 0;
    NodeOutput* depthOutput = 0;
    NodeOutput* waterLevelOutput = 0;


    while (!in.atEnd())
    {
        QString line = in.readLine();
        QStringList lineParts = line.split(" ", QString::SkipEmptyParts);
        if (lineParts.size() == 1) {
            time = line.toFloat();
            ntimes++;

            if (depthOutput) addOutput(depthDs, depthOutput, mesh);
            if (flowOutput) addOutput(flowDs, flowOutput, mesh);
            if (waterLevelOutput) addOutput(waterLevelDs, waterLevelOutput, mesh);

            depthOutput = new NodeOutput;
            flowOutput = new NodeOutput;
            waterLevelOutput = new NodeOutput;

            depthOutput->init(nnodes, nelems, false); //scalar
            flowOutput->init(nnodes, nelems, true); //vector
            waterLevelOutput->init(nnodes, nelems, false); //scalar

            depthOutput->time = time;
            flowOutput->time = time;
            waterLevelOutput->time = time;

            node_inx = 0;

        } else if ((lineParts.size() == 5) || (lineParts.size() == 6)) {
            // new node for time
            if (!depthOutput || !flowOutput || !waterLevelOutput) throw LoadStatus::Err_UnknownFormat;
            if (node_inx == nnodes) throw LoadStatus::Err_IncompatibleMesh;

            flowOutput->values[node_inx] = getFloat(lineParts[2]);
            flowOutput->valuesV[node_inx].x = getFloat(lineParts[3]);
            flowOutput->valuesV[node_inx].y = getFloat(lineParts[4]);

            float depth = getFloat(lineParts[1]);
            depthOutput->values[node_inx] = depth;

            if (!is_nodata(depth)) depth += elevations[node_inx];
            waterLevelOutput->values[node_inx] = depth;

            node_inx ++;

        } else {
            throw LoadStatus::Err_UnknownFormat;
        }
    }

    if (depthOutput) addOutput(depthDs, depthOutput, mesh);
    if (flowOutput) addOutput(flowDs, flowOutput, mesh);
    if (waterLevelOutput) addOutput(waterLevelDs, waterLevelOutput, mesh);

    depthDs->setIsTimeVarying(ntimes>1);
    flowDs->setIsTimeVarying(ntimes>1);
    waterLevelDs->setIsTimeVarying(ntimes>1);

    depthDs->updateZRange();
    flowDs->updateZRange();
    waterLevelDs->updateZRange();

    mesh->addDataSet(depthDs);
    mesh->addDataSet(flowDs);
    mesh->addDataSet(waterLevelDs);
}