2012-05-18 09:45:23 +02:00
//
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
2013-03-22 16:12:00 +01:00
#include "RiaStdInclude.h"
2013-05-06 10:55:00 +02:00
#include "RiaSocketServer.h"
2012-05-18 09:45:23 +02:00
#include <QtGui>
#include <QtNetwork>
#include <stdlib.h>
2013-03-22 16:24:42 +01:00
#include "RiaApplication.h"
2013-03-22 17:30:50 +01:00
#include "RiuMainWindow.h"
2013-05-06 10:55:00 +02:00
#include "RimReservoirView.h"
#include "RimProject.h"
#include "RimReservoirCellResultsCacher.h"
2013-03-22 16:40:41 +01:00
#include "RimInputCase.h"
2013-05-06 10:55:00 +02:00
#include "RimInputProperty.h"
#include "RimInputPropertyCollection.h"
2012-06-26 16:10:41 +02:00
#include "RimUiTreeModelPdm.h"
2012-05-18 09:45:23 +02:00
2013-05-06 10:55:00 +02:00
#include "RimResultSlot.h"
#include "RimIdenticalGridCaseGroup.h"
#include "RimCellEdgeResultSlot.h"
#include "RimCellRangeFilterCollection.h"
#include "RimCellPropertyFilterCollection.h"
#include "Rim3dOverlayInfoConfig.h"
#include "RimWellCollection.h"
#include "RimScriptCollection.h"
#include "RimCaseCollection.h"
#include "cafPdmFieldCvfColor.h"
#include "cafPdmFieldCvfMat4d.h"
#include "RigCaseData.h"
#include "RigCaseCellResultsData.h"
2013-05-16 11:15:34 +02:00
#include "cafFactory.h"
class RiaSocketCommand
{
public :
virtual bool interpretCommand ( RiaSocketServer * server , const QList < QByteArray >& args , QDataStream & socketStream ) = 0 ;
2013-05-16 11:27:34 +02:00
virtual bool interpretMore ( QDataStream & stream ) { return true ; }
2013-05-16 11:15:34 +02:00
};
typedef caf :: Factory < RiaSocketCommand , QString > RiaSocketCommandFactory ;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void getCaseInfoFromCase ( RimCase * rimCase , qint64 & caseId , QString & caseName , QString & caseType , qint64 & caseGroupId )
{
CVF_ASSERT ( rimCase );
caseId = rimCase -> caseId ;
caseName = rimCase -> caseUserDescription ;
RimCaseCollection * caseCollection = rimCase -> parentCaseCollection ();
if ( caseCollection )
{
caseGroupId = caseCollection -> parentCaseGroup () -> groupId ;
if ( RimIdenticalGridCaseGroup :: isStatisticsCaseCollection ( caseCollection ))
{
caseType = "StatisticsCase" ;
}
else
{
caseType = "SourceCase" ;
}
}
else
{
caseGroupId = - 1 ;
if ( dynamic_cast < RimInputCase *> ( rimCase ))
{
caseType = "InputCase" ;
}
else
{
caseType = "ResultCase" ;
}
}
}
class RiaGetCurrentCase : public RiaSocketCommand
{
public :
static QString commandName () { return QString ( "GetCurrentCase" ); }
virtual bool interpretCommand ( RiaSocketServer * server , const QList < QByteArray >& args , QDataStream & socketStream )
{
qint64 caseId = - 1 ;
QString caseName ;
QString caseType ;
qint64 caseGroupId = - 1 ;
RimCase * rimCase = server -> findReservoir ( caseId );
if ( rimCase )
{
getCaseInfoFromCase ( rimCase , caseId , caseName , caseType , caseGroupId );
}
quint64 byteCount = 2 * sizeof ( qint64 );
byteCount += caseName . size () * sizeof ( QChar );
byteCount += caseType . size () * sizeof ( QChar );
socketStream << byteCount ;
socketStream << caseId ;
socketStream << caseName ;
socketStream << caseType ;
socketStream << caseGroupId ;
return true ;
}
};
static bool RiaGetCurrentCase_init = RiaSocketCommandFactory :: instance () -> registerCreator < RiaGetCurrentCase > ( RiaGetCurrentCase :: commandName ());
class RiaGetCaseGroups : public RiaSocketCommand
{
public :
static QString commandName () { return QString ( "GetCaseGroups" ); }
virtual bool interpretCommand ( RiaSocketServer * server , const QList < QByteArray >& args , QDataStream & socketStream )
{
if ( RiaApplication :: instance () -> project ())
{
std :: vector < QString > groupNames ;
std :: vector < qint64 > groupIds ;
size_t caseGroupCount = RiaApplication :: instance () -> project () -> caseGroups (). size ();
quint64 byteCount = 0 ;
for ( size_t i = 0 ; i < caseGroupCount ; i ++ )
{
RimIdenticalGridCaseGroup * cg = RiaApplication :: instance () -> project () -> caseGroups ()[ i ];
QString caseGroupName = cg -> name ;
qint64 caseGroupId = cg -> groupId ;
byteCount += caseGroupName . size () * sizeof ( QChar );
byteCount += sizeof ( qint64 );
groupNames . push_back ( caseGroupName );
groupIds . push_back ( caseGroupId );
}
socketStream << ( quint64 ) byteCount ;
socketStream << ( quint64 ) caseGroupCount ;
for ( size_t i = 0 ; i < caseGroupCount ; i ++ )
{
socketStream << groupNames [ i ];
socketStream << groupIds [ i ];
}
}
else
{
// ERROR
}
return true ;
}
};
static bool RiaGetCaseGroups_init = RiaSocketCommandFactory :: instance () -> registerCreator < RiaGetCaseGroups > ( RiaGetCaseGroups :: commandName ());
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void getCaseInfoFromCases ( std :: vector < RimCase *>& cases , std :: vector < qint64 >& caseIds , std :: vector < QString >& caseNames , std :: vector < QString > & caseTypes , std :: vector < qint64 >& caseGroupIds )
{
for ( size_t i = 0 ; i < cases . size (); i ++ )
{
RimCase * rimCase = cases [ i ];
qint64 caseId = - 1 ;
QString caseName ;
QString caseType ;
qint64 caseGroupId = - 1 ;
getCaseInfoFromCase ( rimCase , caseId , caseName , caseType , caseGroupId );
caseIds . push_back ( rimCase -> caseId );
caseNames . push_back ( rimCase -> caseUserDescription );
caseTypes . push_back ( caseType );
caseGroupIds . push_back ( caseGroupId );
}
}
class RiaGetSelectedCases : public RiaSocketCommand
{
public :
static QString commandName () { return QString ( "GetSelectedCases" ); }
virtual bool interpretCommand ( RiaSocketServer * server , const QList < QByteArray >& args , QDataStream & socketStream )
{
RiuMainWindow * ruiMainWindow = RiuMainWindow :: instance ();
if ( ruiMainWindow )
{
std :: vector < RimCase *> cases ;
ruiMainWindow -> selectedCases ( cases );
std :: vector < qint64 > caseIds ;
std :: vector < QString > caseNames ;
std :: vector < QString > caseTypes ;
std :: vector < qint64 > caseGroupIds ;
getCaseInfoFromCases ( cases , caseIds , caseNames , caseTypes , caseGroupIds );
quint64 byteCount = sizeof ( quint64 );
quint64 selectionCount = caseIds . size ();
for ( size_t i = 0 ; i < selectionCount ; i ++ )
{
byteCount += 2 * sizeof ( qint64 );
byteCount += caseNames [ i ]. size () * sizeof ( QChar );
byteCount += caseTypes [ i ]. size () * sizeof ( QChar );
}
socketStream << byteCount ;
socketStream << selectionCount ;
for ( size_t i = 0 ; i < selectionCount ; i ++ )
{
socketStream << caseIds [ i ];
socketStream << caseNames [ i ];
socketStream << caseTypes [ i ];
socketStream << caseGroupIds [ i ];
}
}
return true ;
}
};
static bool RiaGetSelectedCases_init = RiaSocketCommandFactory :: instance () -> registerCreator < RiaGetSelectedCases > ( RiaGetSelectedCases :: commandName ());
class RiaGetCases : public RiaSocketCommand
{
public :
static QString commandName () { return QString ( "GetCases" ); }
virtual bool interpretCommand ( RiaSocketServer * server , const QList < QByteArray >& args , QDataStream & socketStream )
{
quint64 argCaseGroupId = - 1 ;
if ( args . size () == 2 )
{
argCaseGroupId = args [ 1 ]. toInt ();
}
if ( RiaApplication :: instance () -> project ())
{
RimProject * proj = RiaApplication :: instance () -> project ();
std :: vector < RimCase *> cases ;
if ( argCaseGroupId == - 1 )
{
proj -> allCases ( cases );
}
else
{
RimIdenticalGridCaseGroup * caseGroup = NULL ;
for ( size_t i = 0 ; i < RiaApplication :: instance () -> project () -> caseGroups (). size (); i ++ )
{
RimIdenticalGridCaseGroup * cg = RiaApplication :: instance () -> project () -> caseGroups ()[ i ];
if ( argCaseGroupId == cg -> groupId ())
{
caseGroup = cg ;
}
}
if ( caseGroup )
{
for ( size_t i = 0 ; i < caseGroup -> statisticsCaseCollection () -> reservoirs . size (); i ++ )
{
cases . push_back ( caseGroup -> statisticsCaseCollection () -> reservoirs [ i ]);
}
for ( size_t i = 0 ; i < caseGroup -> caseCollection () -> reservoirs . size (); i ++ )
{
cases . push_back ( caseGroup -> caseCollection () -> reservoirs [ i ]);
}
}
}
std :: vector < qint64 > caseIds ;
std :: vector < QString > caseNames ;
std :: vector < QString > caseTypes ;
std :: vector < qint64 > caseGroupIds ;
getCaseInfoFromCases ( cases , caseIds , caseNames , caseTypes , caseGroupIds );
quint64 byteCount = sizeof ( quint64 );
quint64 caseCount = caseIds . size ();
for ( size_t i = 0 ; i < caseCount ; i ++ )
{
byteCount += 2 * sizeof ( qint64 );
byteCount += caseNames [ i ]. size () * sizeof ( QChar );
byteCount += caseTypes [ i ]. size () * sizeof ( QChar );
}
socketStream << byteCount ;
socketStream << caseCount ;
for ( size_t i = 0 ; i < caseCount ; i ++ )
{
socketStream << caseIds [ i ];
socketStream << caseNames [ i ];
socketStream << caseTypes [ i ];
socketStream << caseGroupIds [ i ];
}
}
return true ;
}
};
static bool RiaGetCases_init = RiaSocketCommandFactory :: instance () -> registerCreator < RiaGetCases > ( RiaGetCases :: commandName ());
2013-05-16 11:47:42 +02:00
class RiaGetMainGridDimensions : public RiaSocketCommand
{
public :
static QString commandName () { return QString ( "GetMainGridDimensions" ); }
virtual bool interpretCommand ( RiaSocketServer * server , const QList < QByteArray >& args , QDataStream & socketStream )
{
RimCase * rimCase = NULL ;
int caseId = - 1 ;
if ( args . size () > 1 )
{
caseId = args [ 1 ]. toInt ();
}
rimCase = server -> findReservoir ( caseId );
// Write data back to octave: I, J, K dimensions
size_t iCount = 0 ;
size_t jCount = 0 ;
size_t kCount = 0 ;
if ( rimCase && rimCase -> reservoirData () && rimCase -> reservoirData () -> mainGrid ())
{
iCount = rimCase -> reservoirData () -> mainGrid () -> cellCountI ();
jCount = rimCase -> reservoirData () -> mainGrid () -> cellCountJ ();
kCount = rimCase -> reservoirData () -> mainGrid () -> cellCountK ();
}
socketStream << ( quint64 ) iCount << ( quint64 ) jCount << ( quint64 ) kCount ;
return true ;
}
};
static bool RiaGetMainGridDimensions_init = RiaSocketCommandFactory :: instance () -> registerCreator < RiaGetMainGridDimensions > ( RiaGetMainGridDimensions :: commandName ());
2012-05-18 09:45:23 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaSocketServer :: RiaSocketServer ( QObject * parent )
: QObject ( parent ),
m_tcpServer ( NULL ),
m_currentClient ( NULL ),
m_currentCommandSize ( 0 ),
m_scalarResultsToAdd ( NULL ),
m_currentTimeStepToRead ( 0 ),
m_currentReservoir ( NULL ),
m_currentScalarIndex ( cvf :: UNDEFINED_SIZE_T ),
2012-10-15 15:13:41 +02:00
m_invalidActiveCellCountDetected ( false ),
2013-05-16 11:15:34 +02:00
m_readState ( ReadingCommand ),
m_currentCommand ( NULL )
2012-05-18 09:45:23 +02:00
{
2013-03-22 17:17:56 +01:00
m_errorMessageDialog = new QErrorMessage ( RiuMainWindow :: instance ());
2012-05-18 09:45:23 +02:00
// TCP server setup
m_tcpServer = new QTcpServer ( this );
if ( ! m_tcpServer -> listen ( QHostAddress :: LocalHost , 40001 ))
{
m_errorMessageDialog -> showMessage ( "Octave communication disabled : \n "
" \n "
2013-04-16 12:08:45 +02:00
"This instance of ResInsight could not start the Socket Server enabling octave to get and set data. \n "
2012-05-18 09:45:23 +02:00
"This is probably because you already have a running ResInsight process. \n "
"Octave can only communicate with one ResInsight process at a time, so the Octave \n "
"communication in this ResInsight instance will be disabled. \n "
" \n "
+ tr ( "The error from the socket system is: %1." ). arg ( m_tcpServer -> errorString ()));
return ;
}
2012-10-15 15:13:41 +02:00
connect ( m_tcpServer , SIGNAL ( newConnection ()), this , SLOT ( slotNewClientConnection ()));
2012-05-18 09:45:23 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaSocketServer ::~ RiaSocketServer ()
{
2013-05-16 11:15:34 +02:00
assert ( m_currentCommand == NULL );
2012-05-18 09:45:23 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
unsigned short RiaSocketServer :: serverPort ()
{
if ( m_tcpServer ) return m_tcpServer -> serverPort ();
else return 0 ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2012-10-15 15:13:41 +02:00
void RiaSocketServer :: slotNewClientConnection ()
2012-05-18 09:45:23 +02:00
{
// If we are currently handling a connection, just ignore the new one until the queue is empty.
2012-10-15 15:13:41 +02:00
if ( m_currentClient != NULL )
{
if ( m_currentClient -> state () == QAbstractSocket :: ConnectedState )
{
return ;
}
else
{
if ( m_readState == ReadingPropertyData )
{
readPropertyDataFromOctave ();
}
terminateCurrentConnection ();
}
}
2012-05-18 09:45:23 +02:00
// Get the first pending connection, and set it as the current Client to handle
QTcpSocket * newClient = m_tcpServer -> nextPendingConnection ();
this -> handleClientConnection ( newClient );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaSocketServer :: handleClientConnection ( QTcpSocket * clientToHandle )
{
CVF_ASSERT ( clientToHandle != NULL );
CVF_ASSERT ( m_currentClient == NULL );
m_currentClient = clientToHandle ;
// Initialize state varianbles
m_currentCommandSize = 0 ;
m_scalarResultsToAdd = NULL ;
m_timeStepCountToRead = 0 ;
m_bytesPerTimeStepToRead = 0 ;
m_currentTimeStepToRead = 0 ;
m_currentReservoir = NULL ;
m_currentScalarIndex = cvf :: UNDEFINED_SIZE_T ;
2012-06-26 16:10:41 +02:00
m_currentPropertyName = "" ;
2012-05-18 09:45:23 +02:00
connect ( m_currentClient , SIGNAL ( disconnected ()), this , SLOT ( slotCurrentClientDisconnected ()));
2012-10-15 15:13:41 +02:00
m_readState = ReadingCommand ;
2013-05-16 11:15:34 +02:00
m_currentCommand = NULL ;
2012-10-15 15:13:41 +02:00
2012-05-18 09:45:23 +02:00
if ( m_currentClient -> bytesAvailable ())
{
2012-10-15 15:13:41 +02:00
this -> readCommandFromOctave ();
2012-05-18 09:45:23 +02:00
}
2012-10-15 15:13:41 +02:00
connect ( m_currentClient , SIGNAL ( readyRead ()), this , SLOT ( slotReadyRead ()));
2012-05-18 09:45:23 +02:00
}
//--------------------------------------------------------------------------------------------------
2013-05-15 14:37:03 +02:00
/// Find the requested reservoir by caseId
2012-05-18 09:45:23 +02:00
//--------------------------------------------------------------------------------------------------
2013-05-15 14:37:03 +02:00
RimCase * RiaSocketServer :: findReservoir ( int caseId )
2012-05-18 09:45:23 +02:00
{
2013-05-15 14:37:03 +02:00
if ( caseId < 0 )
2012-05-18 09:45:23 +02:00
{
2013-03-22 15:50:44 +01:00
if ( RiaApplication :: instance () -> activeReservoirView ())
2012-05-18 09:45:23 +02:00
{
2013-03-22 15:50:44 +01:00
return RiaApplication :: instance () -> activeReservoirView () -> eclipseCase ();
2012-05-18 09:45:23 +02:00
}
}
else
{
2013-03-22 15:50:44 +01:00
RimProject * project = RiaApplication :: instance () -> project ();
2012-05-18 09:45:23 +02:00
if ( ! project ) return NULL ;
2013-05-15 14:37:03 +02:00
std :: vector < RimCase *> cases ;
project -> allCases ( cases );
for ( size_t i = 0 ; i < cases . size (); i ++ )
{
if ( cases [ i ] -> caseId == caseId )
{
return cases [ i ];
}
}
2012-05-18 09:45:23 +02:00
}
return NULL ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2012-10-15 15:13:41 +02:00
void RiaSocketServer :: readCommandFromOctave ()
2012-05-18 09:45:23 +02:00
{
QDataStream socketStream ( m_currentClient );
socketStream . setVersion ( QDataStream :: Qt_4_0 );
// If we have not read the currentCommandSize
// read the size of the command if all the data is available
if ( m_currentCommandSize == 0 )
{
if ( m_currentClient -> bytesAvailable () < ( int ) sizeof ( qint64 )) return ;
socketStream >> m_currentCommandSize ;
}
// Check if the complete command is available, return and whait for readyRead() if not
if ( m_currentClient -> bytesAvailable () < m_currentCommandSize ) return ;
// Now we can read the command
QByteArray command = m_currentClient -> read ( m_currentCommandSize );
QTextStream commandStream ( command );
QList < QByteArray > args ;
while ( ! commandStream . atEnd ())
{
QByteArray arg ;
commandStream >> arg ;
args . push_back ( arg );
}
CVF_ASSERT ( args . size () > 0 );
2013-05-16 11:15:34 +02:00
m_currentCommand = RiaSocketCommandFactory :: instance () -> create ( args [ 0 ]);
if ( m_currentCommand )
{
bool finished = m_currentCommand -> interpretCommand ( this , args , socketStream );
if ( finished )
{
delete m_currentCommand ;
m_currentCommand = NULL ;
}
}
else
{
// Todo: When all commands are into new shape, do the "unknown command" error output here.
2012-05-18 09:45:23 +02:00
2013-05-16 11:15:34 +02:00
bool isGetProperty = args [ 0 ] == "GetProperty" ; // GetProperty [casename/index] PropertyName
bool isSetProperty = args [ 0 ] == "SetProperty" ; // SetProperty [casename/index] PropertyName
bool isGetCellInfo = args [ 0 ] == "GetActiveCellInfo" ; // GetActiveCellInfo [casename/index]
2012-05-18 09:45:23 +02:00
2013-05-16 11:47:42 +02:00
if ( ! ( isGetProperty || isSetProperty || isGetCellInfo ))
2012-05-18 09:45:23 +02:00
{
m_errorMessageDialog -> showMessage ( tr ( "ResInsight SocketServer: \n " ) + tr ( "Unknown command: %1" ). arg ( args [ 0 ]. data ()));
2012-10-15 15:13:41 +02:00
terminateCurrentConnection ();
2012-05-18 09:45:23 +02:00
return ;
}
2013-05-15 14:37:03 +02:00
int caseId = - 1 ;
2012-05-18 09:45:23 +02:00
QString propertyName ;
2013-05-15 14:37:03 +02:00
RimCase * rimCase = NULL ;
2012-05-18 09:45:23 +02:00
// Find the correct arguments
if ( isGetProperty || isSetProperty )
{
if ( args . size () == 2 )
{
propertyName = args [ 1 ];
}
else if ( args . size () > 2 )
{
2013-05-15 14:37:03 +02:00
caseId = args [ 1 ]. toInt ();
2012-05-18 09:45:23 +02:00
propertyName = args [ 2 ];
}
}
2013-05-16 11:47:42 +02:00
else if ( isGetCellInfo )
2012-05-18 09:45:23 +02:00
{
if ( args . size () > 1 )
{
2013-05-15 14:37:03 +02:00
caseId = args [ 1 ]. toInt ();
2012-05-18 09:45:23 +02:00
}
}
2013-05-15 14:37:03 +02:00
rimCase = this -> findReservoir ( caseId );
2013-05-10 14:43:03 +02:00
2012-05-18 09:45:23 +02:00
2013-05-15 14:37:03 +02:00
if ( rimCase == NULL )
2012-05-18 09:45:23 +02:00
{
2013-05-15 14:37:03 +02:00
m_errorMessageDialog -> showMessage ( tr ( "ResInsight SocketServer: \n " ) + tr ( "Could not find the Case with CaseId : \" %1 \" " ). arg ( caseId ));
2012-05-18 09:45:23 +02:00
return ;
}
if ( isGetProperty || isSetProperty )
{
// Find the requested data, Or create a set if we are setting data and it is not found
size_t scalarResultIndex = cvf :: UNDEFINED_SIZE_T ;
std :: vector < std :: vector < double > >* scalarResultFrames = NULL ;
2013-05-15 14:37:03 +02:00
if ( rimCase && rimCase -> results ( RifReaderInterface :: MATRIX_RESULTS ))
2012-05-18 09:45:23 +02:00
{
2013-05-15 14:37:03 +02:00
scalarResultIndex = rimCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( propertyName );
2012-05-18 09:45:23 +02:00
if ( scalarResultIndex == cvf :: UNDEFINED_SIZE_T && isSetProperty )
{
2013-05-15 14:37:03 +02:00
scalarResultIndex = rimCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> cellResults () -> addEmptyScalarResult ( RimDefines :: GENERATED , propertyName , true );
2012-05-18 09:45:23 +02:00
}
if ( scalarResultIndex != cvf :: UNDEFINED_SIZE_T )
{
2013-05-15 14:37:03 +02:00
scalarResultFrames = & ( rimCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> cellResults () -> cellScalarResults ( scalarResultIndex ));
2012-05-18 09:45:23 +02:00
m_currentScalarIndex = scalarResultIndex ;
2012-06-26 16:10:41 +02:00
m_currentPropertyName = propertyName ;
2012-05-18 09:45:23 +02:00
}
}
if ( scalarResultFrames == NULL )
{
m_errorMessageDialog -> showMessage ( tr ( "ResInsight SocketServer: \n " ) + tr ( "Could not find the property named: \" %1 \" " ). arg ( propertyName ));
}
if ( isGetProperty )
{
// Write data back : timeStepCount, bytesPrTimestep, dataForTimestep0 ... dataForTimestepN
if ( scalarResultFrames == NULL )
{
// No data available
socketStream << ( quint64 ) 0 << ( quint64 ) 0 ;
}
else
{
// First write timestep count
quint64 timestepCount = ( quint64 ) scalarResultFrames -> size ();
socketStream << timestepCount ;
// then the byte-size of the result values in one timestep
size_t timestepResultCount = scalarResultFrames -> front (). size ();
quint64 timestepByteCount = ( quint64 )( timestepResultCount * sizeof ( double ));
socketStream << timestepByteCount ;
// Then write the data.
for ( size_t tIdx = 0 ; tIdx < scalarResultFrames -> size (); ++ tIdx )
{
#if 1 // Write data as raw bytes, fast but does not handle byteswapping
m_currentClient -> write (( const char * ) scalarResultFrames -> at ( tIdx ). data (), timestepByteCount ); // Raw print of data. Fast but no platform conversion
#else // Write data using QDataStream, does byteswapping for us. Must use QDataStream on client as well
for ( size_t cIdx = 0 ; cIdx < scalarResultFrames -> at ( tIdx ). size (); ++ cIdx )
{
socketStream << scalarResultFrames -> at ( tIdx )[ cIdx ];
}
#endif
}
}
}
else // Set property
{
2012-10-15 15:13:41 +02:00
m_readState = ReadingPropertyData ;
2012-05-18 09:45:23 +02:00
// Disconnect the socket from calling this slot again.
2013-05-15 14:37:03 +02:00
m_currentReservoir = rimCase ;
2012-05-18 09:45:23 +02:00
if ( scalarResultFrames != NULL )
{
m_scalarResultsToAdd = scalarResultFrames ;
if ( m_currentClient -> bytesAvailable ())
{
2012-10-15 15:13:41 +02:00
this -> readPropertyDataFromOctave ();
2012-05-18 09:45:23 +02:00
}
}
}
}
2013-05-15 14:37:03 +02:00
else if ( isGetCellInfo )
2012-05-18 09:45:23 +02:00
{
2013-05-15 14:37:03 +02:00
RifReaderInterface :: PorosityModelResultType porosityModel = RifReaderInterface :: MATRIX_RESULTS ;
if ( args . size () > 2 )
{
QString prorosityModelString = args [ 2 ];
if ( prorosityModelString . toUpper () == "FRACTURE" )
{
porosityModel = RifReaderInterface :: FRACTURE_RESULTS ;
}
}
// Write data back to octave: columnCount, bytesPrTimestep, GridNr I J K ParentGridNr PI PJ PK CoarseBoxIdx
2012-05-18 09:45:23 +02:00
2013-05-15 14:37:03 +02:00
caf :: FixedArray < std :: vector < qint32 > , 9 > activeCellInfo ;
if ( ! ( rimCase && rimCase -> reservoirData () && rimCase -> reservoirData () -> mainGrid ()) )
2012-05-18 09:45:23 +02:00
{
// No data available
socketStream << ( quint64 ) 0 << ( quint64 ) 0 ;
return ;
}
2013-05-15 14:37:03 +02:00
calculateMatrixModelActiveCellInfo ( rimCase , porosityModel ,
2013-04-16 12:08:45 +02:00
activeCellInfo [ 0 ],
2013-02-12 12:05:41 +01:00
activeCellInfo [ 1 ],
activeCellInfo [ 2 ],
activeCellInfo [ 3 ],
activeCellInfo [ 4 ],
activeCellInfo [ 5 ],
activeCellInfo [ 6 ],
2013-05-15 14:37:03 +02:00
activeCellInfo [ 7 ],
activeCellInfo [ 8 ]);
2012-05-18 09:45:23 +02:00
2013-05-15 14:37:03 +02:00
// First write column count
quint64 columnCount = ( quint64 ) 9 ;
socketStream << columnCount ;
2012-05-18 09:45:23 +02:00
2013-05-15 14:37:03 +02:00
// then the byte-size of the size of one column
2012-05-18 09:45:23 +02:00
size_t timestepResultCount = activeCellInfo [ 0 ]. size ();
quint64 timestepByteCount = ( quint64 )( timestepResultCount * sizeof ( qint32 ));
2013-05-15 14:37:03 +02:00
socketStream << timestepByteCount ;
2012-05-18 09:45:23 +02:00
// Then write the data.
2013-05-15 14:37:03 +02:00
for ( size_t tIdx = 0 ; tIdx < columnCount ; ++ tIdx )
2012-05-18 09:45:23 +02:00
{
#if 1 // Write data as raw bytes, fast but does not handle byteswapping
m_currentClient -> write (( const char * ) activeCellInfo [ tIdx ]. data (), timestepByteCount );
#else // Write data using QDataStream, does byteswapping for us. Must use QDataStream on client as well
for ( size_t cIdx = 0 ; cIdx < activeCellInfo [ tIdx ]. size (); ++ cIdx )
{
socketStream << activeCellInfo [ tIdx ][ cIdx ];
}
#endif
}
}
2012-06-26 16:10:41 +02:00
2013-05-16 11:15:34 +02:00
}
2012-05-18 09:45:23 +02:00
}
//--------------------------------------------------------------------------------------------------
/// This method reads data from octave and puts it into the resInsight Structures
//--------------------------------------------------------------------------------------------------
2012-10-15 15:13:41 +02:00
void RiaSocketServer :: readPropertyDataFromOctave ()
2012-05-18 09:45:23 +02:00
{
QDataStream socketStream ( m_currentClient );
socketStream . setVersion ( QDataStream :: Qt_4_0 );
// If we have not read the header and there are data enough: Read it.
// Do nothing if we have not enough data
if ( m_timeStepCountToRead == 0 || m_bytesPerTimeStepToRead == 0 )
{
if ( m_currentClient -> bytesAvailable () < ( int ) sizeof ( quint64 ) * 2 ) return ;
socketStream >> m_timeStepCountToRead ;
socketStream >> m_bytesPerTimeStepToRead ;
}
// If nothing should be read, or we already have read everything, do nothing
if (( m_timeStepCountToRead == 0 ) || ( m_currentTimeStepToRead >= m_timeStepCountToRead ) ) return ;
// Check if a complete timestep is available, return and whait for readyRead() if not
if ( m_currentClient -> bytesAvailable () < ( int ) m_bytesPerTimeStepToRead ) return ;
2012-06-26 16:10:41 +02:00
size_t cellCountFromOctave = m_bytesPerTimeStepToRead / sizeof ( double );
2012-05-18 09:45:23 +02:00
2013-03-22 09:32:42 +01:00
size_t gridActiveCellCount = m_currentReservoir -> reservoirData () -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS ) -> globalActiveCellCount ();
2012-06-26 16:10:41 +02:00
size_t gridTotalCellCount = m_currentReservoir -> reservoirData () -> mainGrid () -> cellCount ();
if ( cellCountFromOctave != gridActiveCellCount && cellCountFromOctave != gridTotalCellCount )
2012-05-18 09:45:23 +02:00
{
2012-06-26 16:10:41 +02:00
m_errorMessageDialog -> showMessage ( tr ( "ResInsight SocketServer: \n " ) +
2013-04-11 12:06:38 +02:00
tr ( "The number of cells in the data coming from octave does not match the case" ) + ": \" " + m_currentReservoir -> caseUserDescription () + " \"\n "
2012-06-26 16:10:41 +02:00
" Octave: " + QString :: number ( cellCountFromOctave ) + " \n "
2013-04-11 12:06:38 +02:00
" " + m_currentReservoir -> caseUserDescription () + ": Active cell count: " + QString :: number ( gridActiveCellCount ) + " Total cell count: " + QString :: number ( gridTotalCellCount )) ;
2012-05-18 09:45:23 +02:00
2012-06-26 16:10:41 +02:00
cellCountFromOctave = 0 ;
m_invalidActiveCellCountDetected = true ;
m_currentClient -> abort ();
2012-05-18 09:45:23 +02:00
2012-06-26 16:10:41 +02:00
return ;
2012-05-18 09:45:23 +02:00
}
// Make sure the size of the retreiving container is correct.
// If it is, this is noops
m_scalarResultsToAdd -> resize ( m_timeStepCountToRead );
for ( size_t tIdx = 0 ; tIdx < m_timeStepCountToRead ; ++ tIdx )
{
2012-06-26 16:10:41 +02:00
m_scalarResultsToAdd -> at ( tIdx ). resize ( cellCountFromOctave , HUGE_VAL );
2012-05-18 09:45:23 +02:00
}
// Read available complete timestepdata
while (( m_currentClient -> bytesAvailable () >= ( int ) m_bytesPerTimeStepToRead ) && ( m_currentTimeStepToRead < m_timeStepCountToRead ))
{
qint64 bytesRead = 0 ;
double * internalMatrixData = m_scalarResultsToAdd -> at ( m_currentTimeStepToRead ). data ();
#if 1 // Use raw data transfer. Faster.
bytesRead = m_currentClient -> read (( char * )( internalMatrixData ), m_bytesPerTimeStepToRead );
#else
2012-06-26 16:10:41 +02:00
for ( size_t cIdx = 0 ; cIdx < cellCountFromOctave ; ++ cIdx )
2012-05-18 09:45:23 +02:00
{
socketStream >> internalMatrixData [ cIdx ];
if ( socketStream . status () == QDataStream :: Ok ) bytesRead += sizeof ( double );
}
#endif
if (( int ) m_bytesPerTimeStepToRead != bytesRead )
{
m_errorMessageDialog -> showMessage ( tr ( "ResInsight SocketServer: \n " ) + tr ( "Could not read binary double data properly from socket" ));
}
++ m_currentTimeStepToRead ;
}
// If we have read all the data, refresh the views
if ( m_currentTimeStepToRead == m_timeStepCountToRead )
{
if ( m_currentReservoir != NULL )
{
2012-06-26 16:10:41 +02:00
// Create a new input property if we have an input reservoir
2013-03-22 15:43:42 +01:00
RimInputCase * inputRes = dynamic_cast < RimInputCase *> ( m_currentReservoir );
2012-06-26 16:10:41 +02:00
if ( inputRes )
{
RimInputProperty * inputProperty = NULL ;
inputProperty = inputRes -> m_inputPropertyCollection -> findInputProperty ( m_currentPropertyName );
if ( ! inputProperty )
{
inputProperty = new RimInputProperty ;
inputProperty -> resultName = m_currentPropertyName ;
inputProperty -> eclipseKeyword = "" ;
inputProperty -> fileName = "" ;
inputRes -> m_inputPropertyCollection -> inputProperties . push_back ( inputProperty );
2013-03-22 17:17:56 +01:00
RimUiTreeModelPdm * treeModel = RiuMainWindow :: instance () -> uiPdmModel ();
2013-05-13 12:00:52 +02:00
treeModel -> updateUiSubTree ( inputRes -> m_inputPropertyCollection ());
2012-06-26 16:10:41 +02:00
}
inputProperty -> resolvedState = RimInputProperty :: RESOLVED_NOT_SAVED ;
}
2012-05-18 09:45:23 +02:00
if ( m_currentScalarIndex != cvf :: UNDEFINED_SIZE_T &&
m_currentReservoir -> reservoirData () &&
2013-02-13 13:10:54 +01:00
m_currentReservoir -> reservoirData () -> results ( RifReaderInterface :: MATRIX_RESULTS ) )
2012-05-18 09:45:23 +02:00
{
2013-02-13 13:10:54 +01:00
m_currentReservoir -> reservoirData () -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> recalculateMinMax ( m_currentScalarIndex );
2012-05-18 09:45:23 +02:00
}
for ( size_t i = 0 ; i < m_currentReservoir -> reservoirViews . size (); ++ i )
{
if ( m_currentReservoir -> reservoirViews [ i ])
{
m_currentReservoir -> reservoirViews [ i ] -> updateCurrentTimeStepAndRedraw ();
}
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaSocketServer :: slotCurrentClientDisconnected ()
{
if ( m_timeStepCountToRead > 0
&& m_currentTimeStepToRead < m_timeStepCountToRead
&& m_currentClient -> bytesAvailable ()
&& ! m_invalidActiveCellCountDetected )
{
2012-10-15 15:13:41 +02:00
this -> readPropertyDataFromOctave ();
2012-05-18 09:45:23 +02:00
}
2012-10-15 15:13:41 +02:00
terminateCurrentConnection ();
QTcpSocket * newClient = m_tcpServer -> nextPendingConnection ();
if ( newClient )
{
this -> handleClientConnection ( newClient );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaSocketServer :: terminateCurrentConnection ()
{
if ( m_currentClient )
{
m_currentClient -> disconnect ( SIGNAL ( disconnected ()));
m_currentClient -> disconnect ( SIGNAL ( readyRead ()));
m_currentClient -> deleteLater ();
m_currentClient = NULL ;
}
2012-05-18 09:45:23 +02:00
// Clean up more state:
m_currentCommandSize = 0 ;
m_timeStepCountToRead = 0 ;
m_bytesPerTimeStepToRead = 0 ;
m_currentTimeStepToRead = 0 ;
2012-10-15 15:13:41 +02:00
m_scalarResultsToAdd = NULL ;
2012-05-18 09:45:23 +02:00
m_currentReservoir = NULL ;
m_currentScalarIndex = cvf :: UNDEFINED_SIZE_T ;
2012-06-26 16:10:41 +02:00
m_currentPropertyName = "" ;
2012-05-18 09:45:23 +02:00
m_invalidActiveCellCountDetected = false ;
2012-10-15 15:13:41 +02:00
m_readState = ReadingCommand ;
2012-05-18 09:45:23 +02:00
2012-10-15 15:13:41 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaSocketServer :: slotReadyRead ()
{
switch ( m_readState )
2012-05-18 09:45:23 +02:00
{
2012-10-15 15:13:41 +02:00
case ReadingCommand :
{
readCommandFromOctave ();
break ;
}
case ReadingPropertyData :
{
readPropertyDataFromOctave ();
break ;
}
default :
CVF_ASSERT ( false );
break ;
2012-05-18 09:45:23 +02:00
}
}
2012-10-19 10:05:55 +02:00
2013-02-12 12:05:41 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2013-05-15 14:37:03 +02:00
void RiaSocketServer :: calculateMatrixModelActiveCellInfo ( RimCase * reservoirCase , RifReaderInterface :: PorosityModelResultType porosityModel , std :: vector < qint32 >& gridNumber , std :: vector < qint32 >& cellI , std :: vector < qint32 >& cellJ , std :: vector < qint32 >& cellK , std :: vector < qint32 >& parentGridNumber , std :: vector < qint32 >& hostCellI , std :: vector < qint32 >& hostCellJ , std :: vector < qint32 >& hostCellK , std :: vector < qint32 >& coarseBoxIdx )
2013-02-12 12:05:41 +01:00
{
gridNumber . clear ();
cellI . clear ();
cellJ . clear ();
cellK . clear ();
parentGridNumber . clear ();
hostCellI . clear ();
hostCellJ . clear ();
hostCellK . clear ();
2013-05-15 14:37:03 +02:00
coarseBoxIdx . clear ();
2013-02-12 12:05:41 +01:00
2013-04-16 12:08:45 +02:00
if ( ! reservoirCase || ! reservoirCase -> reservoirData () || ! reservoirCase -> reservoirData () -> mainGrid ())
2013-02-12 12:05:41 +01:00
{
return ;
}
2013-05-15 14:37:03 +02:00
RigActiveCellInfo * actCellInfo = reservoirCase -> reservoirData () -> activeCellInfo ( porosityModel );
2013-03-22 09:32:42 +01:00
size_t numMatrixModelActiveCells = actCellInfo -> globalActiveCellCount ();
2013-02-12 12:05:41 +01:00
gridNumber . reserve ( numMatrixModelActiveCells );
cellI . reserve ( numMatrixModelActiveCells );
cellJ . reserve ( numMatrixModelActiveCells );
cellK . reserve ( numMatrixModelActiveCells );
parentGridNumber . reserve ( numMatrixModelActiveCells );
hostCellI . reserve ( numMatrixModelActiveCells );
hostCellJ . reserve ( numMatrixModelActiveCells );
hostCellK . reserve ( numMatrixModelActiveCells );
2013-05-15 14:37:03 +02:00
coarseBoxIdx . reserve ( numMatrixModelActiveCells );
2013-02-12 12:05:41 +01:00
2013-04-16 12:08:45 +02:00
const std :: vector < RigCell >& globalCells = reservoirCase -> reservoirData () -> mainGrid () -> cells ();
2013-02-12 12:05:41 +01:00
for ( size_t cIdx = 0 ; cIdx < globalCells . size (); ++ cIdx )
{
2013-03-22 09:32:42 +01:00
if ( actCellInfo -> isActive ( cIdx ))
2013-02-12 12:05:41 +01:00
{
RigGridBase * grid = globalCells [ cIdx ]. hostGrid ();
CVF_ASSERT ( grid != NULL );
size_t cellIndex = globalCells [ cIdx ]. cellIndex ();
size_t i , j , k ;
grid -> ijkFromCellIndex ( cellIndex , & i , & j , & k );
size_t pi , pj , pk ;
RigGridBase * parentGrid = NULL ;
if ( grid -> isMainGrid ())
{
pi = i ;
pj = j ;
pk = k ;
parentGrid = grid ;
}
else
{
size_t parentCellIdx = globalCells [ cIdx ]. parentCellIndex ();
parentGrid = ( static_cast < RigLocalGrid *> ( grid )) -> parentGrid ();
CVF_ASSERT ( parentGrid != NULL );
parentGrid -> ijkFromCellIndex ( parentCellIdx , & pi , & pj , & pk );
}
gridNumber . push_back ( static_cast < qint32 > ( grid -> gridIndex ()));
2013-05-15 14:37:03 +02:00
cellI . push_back ( static_cast < qint32 > ( i + 1 )); // NB: 1-based index in Octave
cellJ . push_back ( static_cast < qint32 > ( j + 1 )); // NB: 1-based index in Octave
cellK . push_back ( static_cast < qint32 > ( k + 1 )); // NB: 1-based index in Octave
2013-02-12 12:05:41 +01:00
parentGridNumber . push_back ( static_cast < qint32 > ( parentGrid -> gridIndex ()));
2013-05-15 14:37:03 +02:00
hostCellI . push_back ( static_cast < qint32 > ( pi + 1 )); // NB: 1-based index in Octave
hostCellJ . push_back ( static_cast < qint32 > ( pj + 1 )); // NB: 1-based index in Octave
hostCellK . push_back ( static_cast < qint32 > ( pk + 1 )); // NB: 1-based index in Octave
// TODO: Handle coarse box concept
coarseBoxIdx . push_back ( - 1 );
2013-02-12 12:05:41 +01:00
}
}
}