#1662 Octave interface to push generated NNC values back into ResInsight

This commit is contained in:
Bjørnar Grip Fjær 2017-08-08 13:12:43 +02:00
parent fb158b29bd
commit 7e3e538a43
9 changed files with 697 additions and 19 deletions

View File

@ -164,6 +164,10 @@ void RivNNCGeometryGenerator::textureCoordinates(cvf::Vec2fArray* textureCoords,
{
nncResultVals = m_nncData->dynamicConnectionScalarResult(scalarResultIndex, timeStepIndex);
}
else if (resultType == RimDefines::GENERATED)
{
nncResultVals = m_nncData->generatedConnectionScalarResult(scalarResultIndex, timeStepIndex);
}
if (!nncResultVals)
{

View File

@ -110,6 +110,10 @@ bool RimDefines::isPerCellFaceResult(const QString& resultName)
{
return true;
}
else if (resultName.endsWith("IJK"))
{
return true;
}
return false;
}

View File

@ -350,6 +350,15 @@ size_t RigCaseCellResultsData::addEmptyScalarResult(RimDefines::ResultCatType ty
calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::DYNAMIC_NATIVE, "FLRGASK+"));
statisticsCalculator = calc;
}
else if (resultName.endsWith("IJK"))
{
cvf::ref<RigEclipseMultiPropertyStatCalc> calc = new RigEclipseMultiPropertyStatCalc();
QString baseName = resultName.left(resultName.size() - 3);
calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::GENERATED, QString("%1I").arg(baseName)));
calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::GENERATED, QString("%1J").arg(baseName)));
calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::GENERATED, QString("%1K").arg(baseName)));
statisticsCalculator = calc;
}
else
{
statisticsCalculator = new RigEclipseNativeStatCalc(this, scalarResultIndex);

View File

@ -293,6 +293,154 @@ const std::vector<double>* RigNNCData::dynamicConnectionScalarResultByName(const
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector< std::vector<double> >& RigNNCData::makeGeneratedConnectionScalarResult(QString nncDataType, size_t timeStepCount)
{
auto& results = m_connectionResults[nncDataType];
results.resize(timeStepCount);
return results;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector< std::vector<double> >* RigNNCData::generatedConnectionScalarResult(size_t scalarResultIndex) const
{
QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex);
if (nncDataType.isNull()) return nullptr;
auto it = m_connectionResults.find(nncDataType);
if (it != m_connectionResults.end())
{
return &(it->second);
}
else
{
return nullptr;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double>* RigNNCData::generatedConnectionScalarResult(size_t scalarResultIndex, size_t timeStep) const
{
QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex);
if (nncDataType.isNull()) return nullptr;
auto it = m_connectionResults.find(nncDataType);
if (it != m_connectionResults.end())
{
if (it->second.size() > timeStep)
{
return &(it->second[timeStep]);
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector< std::vector<double> >* RigNNCData::generatedConnectionScalarResult(size_t scalarResultIndex)
{
QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex);
if (nncDataType.isNull()) return nullptr;
auto it = m_connectionResults.find(nncDataType);
if (it != m_connectionResults.end())
{
return &(it->second);
}
else
{
return nullptr;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double>* RigNNCData::generatedConnectionScalarResult(size_t scalarResultIndex, size_t timeStep)
{
QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex);
if (nncDataType.isNull()) return nullptr;
auto it = m_connectionResults.find(nncDataType);
if (it != m_connectionResults.end())
{
if (it->second.size() > timeStep)
{
return &(it->second[timeStep]);
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<std::vector<double>>* RigNNCData::generatedConnectionScalarResultByName(const QString& nncDataType) const
{
auto it = m_connectionResults.find(nncDataType);
if (it != m_connectionResults.end())
{
return &(it->second);
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double>* RigNNCData::generatedConnectionScalarResultByName(const QString& nncDataType, size_t timeStep) const
{
auto it = m_connectionResults.find(nncDataType);
if (it != m_connectionResults.end())
{
if (it->second.size() > timeStep)
{
return &(it->second[timeStep]);
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<double>>* RigNNCData::generatedConnectionScalarResultByName(const QString& nncDataType)
{
auto it = m_connectionResults.find(nncDataType);
if (it != m_connectionResults.end())
{
return &(it->second);
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double>* RigNNCData::generatedConnectionScalarResultByName(const QString& nncDataType, size_t timeStep)
{
auto it = m_connectionResults.find(nncDataType);
if (it != m_connectionResults.end())
{
if (it->second.size() > timeStep)
{
return &(it->second[timeStep]);
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -302,11 +450,15 @@ std::vector<QString> RigNNCData::availableProperties(NNCResultType resultType) c
for (auto it : m_connectionResults)
{
if (resultType == NNC_STATIC && it.second.size() == 1 && it.second[0].size() > 0)
if (resultType == NNC_STATIC && it.second.size() == 1 && it.second[0].size() > 0 && isNative(it.first))
{
properties.push_back(it.first);
}
else if (resultType == NNC_DYNAMIC && it.second.size() > 1 && it.second[0].size() > 0)
else if (resultType == NNC_DYNAMIC && it.second.size() > 1 && it.second[0].size() > 0 && isNative(it.first))
{
properties.push_back(it.first);
}
else if (resultType == NNC_GENERATED && !isNative(it.first))
{
properties.push_back(it.first);
}
@ -348,21 +500,20 @@ const QString RigNNCData::getNNCDataTypeFromScalarResultIndex(size_t scalarResul
return QString();
}
/*
//--------------------------------------------------------------------------------------------------
/// TODO: Possibly not needed !
///
//--------------------------------------------------------------------------------------------------
const std::vector<size_t>& RigNNCData::findConnectionIndices( size_t reservoirCellIndex, cvf::StructGridInterface::FaceType face) const
bool RigNNCData::isNative(QString nncDataType) const
{
ConnectionSearchMap::const_iterator it;
static std::vector<size_t> empty;
it = m_cellIdxToFaceToConnectionIdxMap.find(reservoirCellIndex);
if (it != m_cellIdxToFaceToConnectionIdxMap.end())
if (nncDataType == RigNNCData::propertyNameCombTrans() ||
nncDataType == RigNNCData::propertyNameFluxGas() ||
nncDataType == RigNNCData::propertyNameFluxOil() ||
nncDataType == RigNNCData::propertyNameFluxWat() ||
nncDataType == RigNNCData::propertyNameRiCombMult() ||
nncDataType == RigNNCData::propertyNameRiCombTrans() ||
nncDataType == RigNNCData::propertyNameRiCombTransByArea())
{
return it->second[face];
return true;
}
return empty;
return false;
}
*/

View File

@ -83,24 +83,32 @@ public:
std::vector<double>& makeStaticConnectionScalarResult(QString nncDataType);
const std::vector<double>* staticConnectionScalarResult(size_t scalarResultIndex) const;
const std::vector<double>* staticConnectionScalarResultByName(const QString& nncDataType) const;
std::vector< std::vector<double> >& makeDynamicConnectionScalarResult(QString nncDataType, size_t timeStepCount);
const std::vector< std::vector<double> >* dynamicConnectionScalarResult(size_t scalarResultIndex) const;
const std::vector<double>* dynamicConnectionScalarResult(size_t scalarResultIndex, size_t timeStep) const;
const std::vector< std::vector<double> >* dynamicConnectionScalarResultByName(const QString& nncDataType) const;
const std::vector<double>* dynamicConnectionScalarResultByName(const QString& nncDataType, size_t timeStep) const;
std::vector< std::vector<double> >& makeGeneratedConnectionScalarResult(QString nncDataType, size_t timeStepCount);
const std::vector< std::vector<double> >* generatedConnectionScalarResult(size_t scalarResultIndex) const;
const std::vector<double>* generatedConnectionScalarResult(size_t scalarResultIndex, size_t timeStep) const;
std::vector< std::vector<double> >* generatedConnectionScalarResult(size_t scalarResultIndex);
std::vector<double>* generatedConnectionScalarResult(size_t scalarResultIndex, size_t timeStep);
const std::vector< std::vector<double> >* generatedConnectionScalarResultByName(const QString& nncDataType) const;
const std::vector<double>* generatedConnectionScalarResultByName(const QString& nncDataType, size_t timeStep) const;
std::vector< std::vector<double> >* generatedConnectionScalarResultByName(const QString& nncDataType);
std::vector<double>* generatedConnectionScalarResultByName(const QString& nncDataType, size_t timeStep);
std::vector<QString> availableProperties(NNCResultType resultType) const;
void setScalarResultIndex(const QString& nncDataType, size_t scalarResultIndex);
bool hasScalarValues(size_t scalarResultIndex);
private: // This section is possibly not needed
//const std::vector<size_t>& findConnectionIndices(size_t reservoirCellIndex, cvf::StructGridInterface::FaceType face) const;
//typedef std::map<size_t, caf::FixedArray<std::vector<size_t>, 7 > > ConnectionSearchMap;
//ConnectionSearchMap m_cellIdxToFaceToConnectionIdxMap;
private:
const QString getNNCDataTypeFromScalarResultIndex(size_t scalarResultIndex) const;
bool isNative(QString nncDataType) const;
private:
std::vector<RigConnection> m_connections;

View File

@ -161,6 +161,19 @@ cvf::ref<RigResultAccessor> RigResultAccessorFactory::createFromUiResultName(Rig
return cellFaceAccessObject;
}
else if (uiResultName.endsWith("IJK"))
{
cvf::ref<RigCombTransResultAccessor> cellFaceAccessObject = new RigCombTransResultAccessor(grid);
QString baseName = uiResultName.left(uiResultName.size() - 3);
cvf::ref<RigResultAccessor> iAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, QString("%1I").arg(baseName));
cvf::ref<RigResultAccessor> jAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, QString("%1J").arg(baseName));
cvf::ref<RigResultAccessor> kAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, QString("%1K").arg(baseName));
cellFaceAccessObject->setTransResultAccessors(iAccessor.p(), jAccessor.p(), kAccessor.p());
return cellFaceAccessObject;
}
return RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, uiResultName);
}

View File

@ -19,6 +19,7 @@
#include "RiaSocketCommand.h"
#include "RiaSocketServer.h"
#include "RiaSocketDataTransfer.h"
#include "RiaSocketTools.h"
#include "RiaApplication.h"
#include "RiaPreferences.h"
@ -37,6 +38,9 @@
#include "RimEclipseView.h"
#include "RimEclipseWellCollection.h"
#include "RimReservoirCellResultsStorage.h"
#include "RimEclipseInputCase.h"
#include "RimEclipseInputProperty.h"
#include "RimEclipseInputPropertyCollection.h"
#include <QTcpSocket>
#include <QErrorMessage>
@ -285,3 +289,291 @@ public:
};
static bool RiaGetNNCPropertyNames_init = RiaSocketCommandFactory::instance()->registerCreator<RiaGetNNCPropertyNames>(RiaGetNNCPropertyNames::commandName());
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
class RiaSetNNCProperty: public RiaSocketCommand
{
public:
RiaSetNNCProperty() :
m_currentReservoir(NULL),
m_currentScalarIndex(cvf::UNDEFINED_SIZE_T),
m_timeStepCountToRead(0),
m_bytesPerTimeStepToRead(0),
m_currentTimeStepNumberToRead(0),
m_invalidConnectionCountDetected(false),
m_porosityModelEnum(RifReaderInterface::MATRIX_RESULTS)
{}
static QString commandName () { return QString("SetNNCProperty"); }
virtual bool interpretCommand(RiaSocketServer* server, const QList<QByteArray>& args, QDataStream& socketStream)
{
RimEclipseCase* rimCase = RiaSocketTools::findCaseFromArgs(server, args);
QString propertyName = args[2];
// Find the requested data, or create a set if we are setting data and it is not found
if (!(rimCase && rimCase->eclipseCaseData() && rimCase->eclipseCaseData()->mainGrid()))
{
QString caseId = args[1];
server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find case with id %1").arg(caseId));
return true;
}
// 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 (server->currentClient()->bytesAvailable() < (int)sizeof(quint64)*2) return true;
socketStream >> m_timeStepCountToRead;
socketStream >> m_bytesPerTimeStepToRead;
}
RigNNCData* nncData = rimCase->eclipseCaseData()->mainGrid()->nncData();
auto nncResults = nncData->generatedConnectionScalarResultByName(propertyName);
if (nncResults == nullptr)
{
nncData->makeGeneratedConnectionScalarResult(propertyName, m_timeStepCountToRead);
}
if (rimCase && rimCase->results(m_porosityModelEnum))
{
bool ok = createIJKCellResults(rimCase->results(m_porosityModelEnum), propertyName);
if (!ok)
{
server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the property named: \"%2\"").arg(propertyName));
return true;
}
size_t scalarResultIndex = rimCase->results(m_porosityModelEnum)->findOrLoadScalarResult(QString("%1IJK").arg(propertyName));
nncData->setScalarResultIndex(propertyName, scalarResultIndex);
}
// Create a list of all the requested time steps
m_requestedTimesteps.clear();
if (args.size() <= 4)
{
// Select all
for (size_t tsIdx = 0; tsIdx < m_timeStepCountToRead; ++tsIdx)
{
m_requestedTimesteps.push_back(tsIdx);
}
}
else
{
bool timeStepReadError = false;
for (int argIdx = 4; argIdx < args.size(); ++argIdx)
{
bool conversionOk = false;
int tsIdx = args[argIdx].toInt(&conversionOk);
if (conversionOk)
{
m_requestedTimesteps.push_back(tsIdx);
}
else
{
timeStepReadError = true;
}
}
if (timeStepReadError)
{
server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: riSetNNCProperty : \n") +
RiaSocketServer::tr("An error occurred while interpreting the requested time steps."));
}
}
if (! m_requestedTimesteps.size())
{
server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("No time steps specified"));
return true;
}
m_currentReservoir = rimCase;
m_currentPropertyName = propertyName;
if (server->currentClient()->bytesAvailable())
{
return this->interpretMore(server, server->currentClient());
}
return false;
}
static bool createIJKCellResults(RimReservoirCellResultsStorage* results, QString propertyName)
{
bool ok;
ok = scalarResultExistsOrCreate(results, QString("%1IJK").arg(propertyName));
if (!ok) return false;
ok = scalarResultExistsOrCreate(results, QString("%1I").arg(propertyName));
if (!ok) return false;
ok = scalarResultExistsOrCreate(results, QString("%1J").arg(propertyName));
if (!ok) return false;
ok = scalarResultExistsOrCreate(results, QString("%1K").arg(propertyName));
return ok;
}
static bool scalarResultExistsOrCreate(RimReservoirCellResultsStorage* results, QString propertyName)
{
size_t scalarResultIndex = results->findOrLoadScalarResult(propertyName);
if (scalarResultIndex == cvf::UNDEFINED_SIZE_T)
{
scalarResultIndex = results->cellResults()->addEmptyScalarResult(RimDefines::GENERATED, propertyName, true);
}
if (scalarResultIndex != cvf::UNDEFINED_SIZE_T)
{
std::vector< std::vector<double> >* scalarResultFrames = nullptr;
scalarResultFrames = &(results->cellResults()->cellScalarResults(scalarResultIndex));
size_t timeStepCount = results->cellResults()->maxTimeStepCount();
scalarResultFrames->resize(timeStepCount);
return true;
}
return false;
}
virtual bool interpretMore(RiaSocketServer* server, QTcpSocket* currentClient)
{
if (m_invalidConnectionCountDetected) return true;
// If nothing should be read, or we already have read everything, do nothing
if ((m_timeStepCountToRead == 0) || (m_currentTimeStepNumberToRead >= m_timeStepCountToRead) ) return true;
if (!currentClient->bytesAvailable()) return false;
if (m_timeStepCountToRead != m_requestedTimesteps.size())
{
CVF_ASSERT(false);
}
// Check if a complete timestep is available, return and whait for readyRead() if not
if (currentClient->bytesAvailable() < (int)m_bytesPerTimeStepToRead) return false;
RigNNCData* nncData = m_currentReservoir->eclipseCaseData()->mainGrid()->nncData();
size_t connectionCountFromOctave = m_bytesPerTimeStepToRead / sizeof(double);
size_t connectionCount = nncData->connections().size();
std::vector< std::vector<double> >* resultsToAdd = nncData->generatedConnectionScalarResultByName(m_currentPropertyName);
if (connectionCountFromOctave != connectionCount)
{
server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") +
RiaSocketServer::tr("The number of connections in the data coming from octave does not match the case: '%1'\n").arg(m_currentReservoir->caseUserDescription()) +
RiaSocketServer::tr(" Octave: %1\n").arg(connectionCountFromOctave) +
RiaSocketServer::tr(" %1: Connection count: %2").arg(m_currentReservoir->caseUserDescription()).arg(connectionCount));
connectionCountFromOctave = 0;
m_invalidConnectionCountDetected = true;
currentClient->abort();
return true;
}
for (size_t tIdx = 0; tIdx < m_timeStepCountToRead; ++tIdx)
{
size_t tsId = m_requestedTimesteps[tIdx];
resultsToAdd->at(tsId).resize(connectionCount, HUGE_VAL);
}
std::vector<double> readBuffer;
double * internalMatrixData = nullptr;
QDataStream socketStream(currentClient);
socketStream.setVersion(riOctavePlugin::qtDataStreamVersion);
// Read available complete time step data
while ((currentClient->bytesAvailable() >= (int)m_bytesPerTimeStepToRead) && (m_currentTimeStepNumberToRead < m_timeStepCountToRead))
{
internalMatrixData = resultsToAdd->at(m_requestedTimesteps[m_currentTimeStepNumberToRead]).data();
QStringList errorMessages;
if (!RiaSocketDataTransfer::readBlockDataFromSocket(currentClient, (char*)(internalMatrixData), m_bytesPerTimeStepToRead, errorMessages))
{
for (int i = 0; i < errorMessages.size(); i++)
{
server->errorMessageDialog()->showMessage(errorMessages[i]);
}
currentClient->abort();
return true;
}
++m_currentTimeStepNumberToRead;
}
// If we have read all the data, refresh the views
if (m_currentTimeStepNumberToRead == m_timeStepCountToRead)
{
if (m_currentReservoir != nullptr)
{
// Create a new input property if we have an input reservoir
RimEclipseInputCase* inputRes = dynamic_cast<RimEclipseInputCase*>(m_currentReservoir);
if (inputRes)
{
RimEclipseInputProperty* inputProperty = inputRes->m_inputPropertyCollection->findInputProperty(m_currentPropertyName);
if (!inputProperty)
{
inputProperty = new RimEclipseInputProperty;
inputProperty->resultName = m_currentPropertyName;
inputProperty->eclipseKeyword = "";
inputProperty->fileName = "";
inputRes->m_inputPropertyCollection->inputProperties.push_back(inputProperty);
inputRes->m_inputPropertyCollection()->updateConnectedEditors();
}
inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED_NOT_SAVED;
}
if( m_currentScalarIndex != cvf::UNDEFINED_SIZE_T &&
m_currentReservoir->eclipseCaseData() &&
m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum) )
{
m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum)->recalculateStatistics(m_currentScalarIndex);
}
for (size_t i = 0; i < m_currentReservoir->reservoirViews.size(); ++i)
{
if (m_currentReservoir->reservoirViews[i])
{
// As new result might have been introduced, update all editors connected
m_currentReservoir->reservoirViews[i]->cellResult->updateConnectedEditors();
// It is usually not needed to create new display model, but if any derived geometry based on generated data (from Octave)
// a full display model rebuild is required
m_currentReservoir->reservoirViews[i]->scheduleCreateDisplayModelAndRedraw();
}
}
}
return true;
}
return false;
}
private:
RimEclipseCase* m_currentReservoir;
size_t m_currentScalarIndex;
QString m_currentPropertyName;
std::vector<size_t> m_requestedTimesteps;
RifReaderInterface::PorosityModelResultType m_porosityModelEnum;
quint64 m_timeStepCountToRead;
quint64 m_bytesPerTimeStepToRead;
size_t m_currentTimeStepNumberToRead;
bool m_invalidConnectionCountDetected;
};
static bool RiaSetNNCProperty_init = RiaSocketCommandFactory::instance()->registerCreator<RiaSetNNCProperty>(RiaSetNNCProperty::commandName());

View File

@ -32,6 +32,7 @@ set(CPP_SOURCES
riGetWellNames.cpp
riGetWellStatus.cpp
riGetWellCells.cpp
riSetNNCProperty.cpp
)
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
@ -202,6 +203,7 @@ if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE)
"${CMAKE_CURRENT_BINARY_DIR}/riGetWellNames.oct"
"${CMAKE_CURRENT_BINARY_DIR}/riGetWellStatus.oct"
"${CMAKE_CURRENT_BINARY_DIR}/riGetWellCells.oct"
"${CMAKE_CURRENT_BINARY_DIR}/riSetNNCProperty.oct"
SOURCES
${CPP_SOURCES}
riSettings.h

View File

@ -0,0 +1,195 @@
#include <QtNetwork>
#include <QStringList>
#include <octave/oct.h>
#include "riSettings.h"
#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration
void setNNCProperty(const Matrix& propertyFrames, const QString &hostName, quint16 port,
const qint64& caseId, QString propertyName, const int32NDArray& requestedTimeSteps)
{
QTcpSocket socket;
socket.connectToHost(hostName, port);
if (!socket.waitForConnected(riOctavePlugin::connectTimeOutMilliSecs))
{
error((("Connection: ") + socket.errorString()).toLatin1().data());
return;
}
QDataStream socketStream(&socket);
socketStream.setVersion(riOctavePlugin::qtDataStreamVersion);
// Create command as a string with arguments , and send it:
QString command;
command += "SetNNCProperty " + QString::number(caseId) + " " + propertyName;
for (int i = 0; i < requestedTimeSteps.length(); ++i)
{
if (i == 0) command += " ";
command += QString::number(static_cast<int>(requestedTimeSteps.elem(i)) - 1); // To make the index 0-based
if (i != requestedTimeSteps.length() -1) command += " ";
}
QByteArray cmdBytes = command.toLatin1();
socketStream << (qint64)(cmdBytes.size());
socket.write(cmdBytes);
// Write property data header
dim_vector mxDims = propertyFrames.dims();
qint64 connectionCount = mxDims.elem(0);
qint64 timeStepCount = mxDims.elem(1);
qint64 timeStepByteCount = connectionCount * sizeof(double);
socketStream << (qint64)(timeStepCount);
socketStream << (qint64)timeStepByteCount;
const double* internalData = propertyFrames.fortran_vec();
QStringList errorMessages;
if (!RiaSocketDataTransfer::writeBlockDataToSocket(&socket, (const char *)internalData, timeStepByteCount*timeStepCount, errorMessages))
{
for (int i = 0; i < errorMessages.size(); i++)
{
octave_stdout << errorMessages[i].toStdString();
}
return;
}
QString tmp = QString("riSetNNCProperty : Wrote %1").arg(propertyName);
if (caseId == -1)
{
tmp += QString(" to current case.");
}
else
{
tmp += QString(" to case with Id = %1.").arg(caseId);
}
octave_stdout << tmp.toStdString() << " NNC Connections : " << connectionCount << " Time steps : " << timeStepCount << std::endl;
while(socket.bytesToWrite() && socket.state() == QAbstractSocket::ConnectedState)
{
// octave_stdout << "Bytes to write: " << socket.bytesToWrite() << std::endl;
socket.waitForBytesWritten(riOctavePlugin::shortTimeOutMilliSecs);
OCTAVE_QUIT;
}
//octave_stdout << " Socket write completed" << std::endl;
if (socket.bytesToWrite() && socket.state() != QAbstractSocket::ConnectedState)
{
error("riSetNNCProperty : ResInsight refused to accept the data. Maybe the dimensions or porosity model is wrong");
}
#ifdef WIN32
// TODO: Due to synchronization issues seen on Windows 10, it is required to do a sleep here to be able to catch disconnect
// signals from the socket. No sleep causes the server to hang.
Sleep(100);
#endif //WIN32
return;
}
DEFUN_DLD (riSetNNCProperty, args, nargout,
"Usage:\n"
"\n"
"\triSetNNCProperty(Matrix[numNNCConnections][numTimeSteps], [CaseId], PropertyName, [TimeStepIndices]) \n"
"\n"
"Interprets the supplied matrix as a property set defined for the NNC connections in the case, "
"and puts the data into ResInsight as a \"Generated\" property with the name \"PropertyName\"."
"The \"TimeStepIndices\" argument is used to \"label\" all the time steps present in the supplied data matrix "
"and must thus be complete. The time step data will then be put into ResInsight at the time steps requested.\n"
"If the CaseId is not defined, ResInsight's Current Case is used."
)
{
int nargin = args.length ();
if (nargin < 2)
{
error("riSetNNCProperty: Too few arguments. The data matrix and the name of the property requested is necessary\n");
print_usage();
return octave_value_list ();
}
if (nargin > 4)
{
error("riSetNNCProperty: Too many arguments.\n");
print_usage();
return octave_value_list ();
}
Matrix propertyFrames = args(0).matrix_value();
if (error_state)
{
error("riSetNNCProperty: The supplied first argument is not a valid Matrix");
print_usage();
return octave_value_list ();
}
dim_vector mxDims = propertyFrames.dims();
if (mxDims.length() != 2)
{
error("riSetNNCProperty: The supplied Data Matrix must have two dimensions: numNNCConnections*numTimesteps");
print_usage();
return octave_value_list ();
}
std::vector<int> argIndices;
argIndices.push_back(0);
argIndices.push_back(1);
argIndices.push_back(2);
argIndices.push_back(3);
// Check if we have a CaseId:
if (!args(argIndices[1]).is_numeric_type())
{
argIndices[1] = -1;
for (size_t aIdx = 2; aIdx < argIndices.size(); ++aIdx)
--argIndices[aIdx];
}
// Check if we have a Requested TimeSteps
if (!(nargin > argIndices[3] && args(argIndices[3]).is_matrix_type() && !args(argIndices[3]).is_string()))
{
argIndices[3] = -1;
for (size_t aIdx = 4; aIdx < argIndices.size(); ++aIdx)
--argIndices[aIdx];
}
int caseId = -1;
std::string propertyName = "UNDEFINED";
int32NDArray requestedTimeSteps;
if (argIndices[1] >= 0) caseId = args(argIndices[1]).int_value();
if (argIndices[2] >= 0) propertyName = args(argIndices[2]).char_matrix_value().row_as_string(0);
if (argIndices[3] >= 0) requestedTimeSteps = args(argIndices[3]).int32_array_value();
if (requestedTimeSteps.length())
{
int timeStepCount = mxDims.elem(1);
if (requestedTimeSteps.length() != timeStepCount)
{
error("riSetNNCProperty: The number of time steps in the input matrix must match the number of time steps in the TimeStepIndices array.");
print_usage();
return octave_value_list ();
}
}
setNNCProperty(propertyFrames, "127.0.0.1", 40001, caseId, propertyName.c_str(), requestedTimeSteps);
return octave_value_list ();
}