QGIS/external/mdal/frmts/mdal_ascii_dat.cpp

312 lines
8.3 KiB
C++
Raw Normal View History

2018-05-16 11:20:25 +02:00
/*
MDAL - Mesh Data Abstraction Library (MIT License)
Copyright (C) 2018 Lutra Consulting Ltd.
*/
#include <stddef.h>
#include <iosfwd>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <cassert>
#include <memory>
#include "mdal_ascii_dat.hpp"
#include "mdal.h"
#include "mdal_utils.hpp"
2018-12-04 17:28:05 +01:00
#include "mdal_2dm.hpp"
2018-05-16 11:20:25 +02:00
#include <math.h>
#define EXIT_WITH_ERROR(error) { if (status) *status = (error); return; }
MDAL::LoaderAsciiDat::LoaderAsciiDat( const std::string &datFile ):
mDatFile( datFile )
{
}
/**
* The DAT format contains "datasets" and each dataset has N-outputs. One output
* represents data for all vertices/faces for one timestep
*
* In MDAL we convert one output to one MDAL dataset;
*
*/
void MDAL::LoaderAsciiDat::load( MDAL::Mesh *mesh, MDAL_Status *status )
{
if ( status ) *status = MDAL_Status::None;
if ( !MDAL::fileExists( mDatFile ) )
{
if ( status ) *status = MDAL_Status::Err_FileNotFound;
return;
}
std::ifstream in( mDatFile, std::ifstream::in );
std::string line;
if ( !std::getline( in, line ) )
{
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
return;
}
line = trim( line );
// http://www.xmswiki.com/xms/SMS:ASCII_Dataset_Files_*.dat
// Apart from the format specified above, there is an older supported format used in BASEMENT (and SMS?)
// which is simpler (has only one dataset in one file, no status flags etc)
bool oldFormat;
bool isVector = false;
2018-07-18 09:00:34 +02:00
std::shared_ptr<DatasetGroup> group; // DAT outputs data
std::string name( MDAL::baseName( mDatFile ) );
2018-05-16 11:20:25 +02:00
if ( line == "DATASET" )
oldFormat = false;
else if ( line == "SCALAR" || line == "VECTOR" )
{
oldFormat = true;
isVector = ( line == "VECTOR" );
2018-07-18 09:00:34 +02:00
2018-12-04 17:28:05 +01:00
group = std::make_shared< DatasetGroup >(
mesh,
mDatFile,
name
);
group->setIsScalar( !isVector );
2018-05-16 11:20:25 +02:00
}
else
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
2018-07-18 09:00:34 +02:00
// see if it contains face-centered results - supported by BASEMENT
bool faceCentered = false;
if ( !oldFormat && contains( name, "_els_" ) )
faceCentered = true;
if ( group )
2018-12-04 17:28:05 +01:00
group->setIsOnVertices( !faceCentered );
2018-05-16 11:20:25 +02:00
while ( std::getline( in, line ) )
{
2018-12-04 17:28:05 +01:00
// Replace tabs by spaces,
// since basement v.2.8 uses tabs instead of spaces (e.g. 'TS 0\t0.0')
line = replace( line, "\t", " " );
2018-05-16 11:20:25 +02:00
std::vector<std::string> items = split( line, " ", SplitBehaviour::SkipEmptyParts );
if ( items.size() < 1 )
continue; // empty line?? let's skip it
std::string cardType = items[0];
if ( cardType == "ND" && items.size() >= 2 )
{
size_t fileNodeCount = toSizeT( items[1] );
2018-12-04 17:28:05 +01:00
if ( mesh->verticesCount() != fileNodeCount )
2018-05-16 11:20:25 +02:00
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
}
else if ( !oldFormat && cardType == "NC" && items.size() >= 2 )
{
size_t fileElemCount = toSizeT( items[1] );
2018-12-04 17:28:05 +01:00
if ( mesh->facesCount() != fileElemCount )
2018-05-16 11:20:25 +02:00
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
}
else if ( !oldFormat && cardType == "OBJTYPE" )
{
if ( items[1] != "mesh2d" && items[1] != "\"mesh2d\"" )
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
else if ( !oldFormat && ( cardType == "BEGSCL" || cardType == "BEGVEC" ) )
{
2018-07-18 09:00:34 +02:00
if ( group )
2018-05-16 11:20:25 +02:00
{
debug( "New dataset while previous one is still active!" );
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
isVector = cardType == "BEGVEC";
2018-07-18 09:00:34 +02:00
2018-12-04 17:28:05 +01:00
group = std::make_shared< DatasetGroup >(
mesh,
mDatFile,
name
);
group->setIsScalar( !isVector );
group->setIsOnVertices( !faceCentered );
2018-05-16 11:20:25 +02:00
}
else if ( !oldFormat && cardType == "ENDDS" )
{
2018-07-18 09:00:34 +02:00
if ( !group )
2018-05-16 11:20:25 +02:00
{
debug( "ENDDS card for no active dataset!" );
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
2018-12-04 17:28:05 +01:00
group->setStatistics( MDAL::calculateStatistics( group ) );
2018-07-18 09:00:34 +02:00
mesh->datasetGroups.push_back( group );
group.reset();
2018-05-16 11:20:25 +02:00
}
else if ( !oldFormat && cardType == "NAME" && items.size() >= 2 )
{
2018-07-18 09:00:34 +02:00
if ( !group )
2018-05-16 11:20:25 +02:00
{
debug( "NAME card for no active dataset!" );
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
size_t quoteIdx1 = line.find( '\"' );
size_t quoteIdx2 = line.find( '\"', quoteIdx1 + 1 );
if ( quoteIdx1 != std::string::npos && quoteIdx2 != std::string::npos )
2018-07-18 09:00:34 +02:00
group->setName( line.substr( quoteIdx1 + 1, quoteIdx2 - quoteIdx1 - 1 ) );
2018-05-16 11:20:25 +02:00
}
else if ( oldFormat && ( cardType == "SCALAR" || cardType == "VECTOR" ) )
{
// just ignore - we know the type from earlier...
}
else if ( cardType == "TS" && items.size() >= ( oldFormat ? 2 : 3 ) )
{
double t = toDouble( items[oldFormat ? 1 : 2] );
2018-07-18 09:00:34 +02:00
if ( faceCentered )
2018-05-16 11:20:25 +02:00
{
2018-07-18 09:00:34 +02:00
readFaceTimestep( mesh, group, t, isVector, in );
2018-05-16 11:20:25 +02:00
}
else
{
bool hasStatus = ( oldFormat ? false : toBool( items[1] ) );
2018-07-18 09:00:34 +02:00
readVertexTimestep( mesh, group, t, isVector, hasStatus, in );
2018-05-16 11:20:25 +02:00
}
}
else
{
std::stringstream str;
str << " Unknown card:" << line;
debug( str.str() );
}
}
if ( oldFormat )
{
2018-07-18 09:00:34 +02:00
if ( !group || group->datasets.size() == 0 )
2018-05-16 11:20:25 +02:00
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
2018-12-04 17:28:05 +01:00
group->setStatistics( MDAL::calculateStatistics( group ) );
2018-07-18 09:00:34 +02:00
mesh->datasetGroups.push_back( group );
group.reset();
2018-05-16 11:20:25 +02:00
}
}
2018-07-18 09:00:34 +02:00
void MDAL::LoaderAsciiDat::readVertexTimestep(
const MDAL::Mesh *mesh,
std::shared_ptr<DatasetGroup> group,
double t,
bool isVector,
bool hasStatus,
std::ifstream &stream )
2018-05-16 11:20:25 +02:00
{
2018-07-18 09:00:34 +02:00
assert( group );
2018-12-04 17:28:05 +01:00
size_t faceCount = mesh->facesCount();
2018-05-16 11:20:25 +02:00
2018-12-04 17:28:05 +01:00
std::shared_ptr<MDAL::MemoryDataset> dataset = std::make_shared< MDAL::MemoryDataset >( group.get() );
dataset->setTime( t / 3600. ); // TODO read TIMEUNITS
2018-05-16 11:20:25 +02:00
2018-12-04 17:28:05 +01:00
int *active = dataset->active();
2018-05-16 11:20:25 +02:00
// only for new format
for ( size_t i = 0; i < faceCount; ++i )
{
if ( hasStatus )
{
std::string line;
std::getline( stream, line );
2018-12-04 17:28:05 +01:00
active[i] = toBool( line );
2018-05-16 11:20:25 +02:00
}
}
2018-12-04 17:28:05 +01:00
const Mesh2dm *m2dm = dynamic_cast<const Mesh2dm *>( mesh );
double *values = dataset->values();
for ( size_t i = 0; i < mesh->verticesCount(); ++i )
2018-05-16 11:20:25 +02:00
{
std::string line;
std::getline( stream, line );
std::vector<std::string> tsItems = split( line, " ", SplitBehaviour::SkipEmptyParts );
2018-12-04 17:28:05 +01:00
size_t index;
if ( m2dm )
index = m2dm->vertexIndex( i );
else
index = i;
2018-05-16 11:20:25 +02:00
if ( isVector )
{
if ( tsItems.size() >= 2 ) // BASEMENT files with vectors have 3 columns
{
2018-12-04 17:28:05 +01:00
values[2 * index] = toDouble( tsItems[0] );
values[2 * index + 1] = toDouble( tsItems[1] );
2018-05-16 11:20:25 +02:00
}
else
{
debug( "invalid timestep line" );
}
}
else
{
if ( tsItems.size() >= 1 )
2018-12-04 17:28:05 +01:00
values[index] = toDouble( tsItems[0] );
2018-05-16 11:20:25 +02:00
else
{
debug( "invalid timestep line" );
}
}
}
2018-12-04 17:28:05 +01:00
dataset->setStatistics( MDAL::calculateStatistics( dataset ) );
2018-07-18 09:00:34 +02:00
group->datasets.push_back( dataset );
2018-05-16 11:20:25 +02:00
}
2018-07-18 09:00:34 +02:00
void MDAL::LoaderAsciiDat::readFaceTimestep(
const MDAL::Mesh *mesh,
std::shared_ptr<DatasetGroup> group,
double t,
bool isVector,
std::ifstream &stream )
2018-05-16 11:20:25 +02:00
{
2018-07-18 09:00:34 +02:00
assert( group );
2018-12-04 17:28:05 +01:00
size_t faceCount = mesh->facesCount();
2018-05-16 11:20:25 +02:00
2018-12-04 17:28:05 +01:00
std::shared_ptr<MDAL::MemoryDataset> dataset = std::make_shared< MDAL::MemoryDataset >( group.get() );
dataset->setTime( t / 3600. );
double *values = dataset->values();
2018-05-16 11:20:25 +02:00
// TODO: hasStatus
for ( size_t index = 0; index < faceCount; ++index )
{
std::string line;
std::getline( stream, line );
std::vector<std::string> tsItems = split( line, " ", SplitBehaviour::SkipEmptyParts );
if ( isVector )
{
if ( tsItems.size() >= 2 ) // BASEMENT files with vectors have 3 columns
{
2018-12-04 17:28:05 +01:00
values[2 * index] = toDouble( tsItems[0] );
values[2 * index + 1] = toDouble( tsItems[1] );
2018-05-16 11:20:25 +02:00
}
else
{
debug( "invalid timestep line" );
}
}
else
{
if ( tsItems.size() >= 1 )
2018-12-04 17:28:05 +01:00
values[index] = toDouble( tsItems[0] );
2018-05-16 11:20:25 +02:00
else
{
debug( "invalid timestep line" );
}
}
}
2018-12-04 17:28:05 +01:00
dataset->setStatistics( MDAL::calculateStatistics( dataset ) );
2018-07-18 09:00:34 +02:00
group->datasets.push_back( dataset );
2018-05-16 11:20:25 +02:00
}