///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) Ceetron Solutions 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 // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimEmCase.h" #include "RiaDefines.h" #include "RiaLogging.h" #include "RiaPreferences.h" #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" #include "RigEclipseResultAddress.h" #include "RigMainGrid.h" #include "RigReservoirBuilder.h" #ifdef USE_HDF5 #include "H5Cpp.h" #endif #include "cafPdmObjectScriptingCapability.h" #include #include CAF_PDM_SOURCE_INIT( RimEmCase, "RimEmCase" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEmCase::RimEmCase() { CAF_PDM_InitScriptableObject( "RimEmCase", ":/EclipseInput48x48.png" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEmCase::~RimEmCase() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEmCase::openEclipseGridFile() { if ( eclipseCaseData() ) { // Early exit if reservoir data is created return true; } setReservoirData( new RigEclipseCaseData( this ) ); auto emDataFromFile = readDataFromFile(); auto emData = emDataFromFile; // Flip X and Y axis emData.cellSizes[0] = emDataFromFile.cellSizes[1]; emData.cellSizes[1] = emDataFromFile.cellSizes[0]; emData.ijkNumCells[0] = emDataFromFile.ijkNumCells[1]; emData.ijkNumCells[1] = emDataFromFile.ijkNumCells[0]; emData.originNED[0] = emDataFromFile.originNED[1]; emData.originNED[1] = emDataFromFile.originNED[0]; { RigReservoirBuilder builder; builder.setWorldCoordinates( cvf::Vec3d( emData.originNED[0], emData.originNED[1], emData.originNED[2] ), cvf::Vec3d( emData.originNED[0] + emData.cellSizes[0] * emData.ijkNumCells[0], emData.originNED[1] + emData.cellSizes[1] * emData.ijkNumCells[1], -( emData.originNED[2] + emData.cellSizes[2] * emData.ijkNumCells[2] ) ) ); builder.setIJKCount( cvf::Vec3st( emData.ijkNumCells[0], emData.ijkNumCells[1], emData.ijkNumCells[2] ) ); builder.createGridsAndCells( eclipseCaseData() ); } results( RiaDefines::PorosityModelType::MATRIX_MODEL )->createPlaceholderResultEntries(); if ( RiaPreferences::current()->autocomputeDepthRelatedProperties ) { results( RiaDefines::PorosityModelType::MATRIX_MODEL )->computeDepthRelatedResults(); results( RiaDefines::PorosityModelType::FRACTURE_MODEL )->computeDepthRelatedResults(); } results( RiaDefines::PorosityModelType::MATRIX_MODEL )->computeCellVolumes(); { // Compute resistivity as the inverted value for sigmaN and sigmaT std::map> additionalData; for ( auto [resultName, resultData] : emData.resultData ) { auto fullResultName = QString::fromStdString( resultName ); auto resultWords = fullResultName.split( "::" ); auto lastResultName = resultWords.last(); resultWords.removeLast(); auto resultNameSpace = resultWords.join( "::" ); std::map invertedResultNameMap = { { "Sigma", "Resistivity" }, { "SigmaN", "ResistivityN" }, { "SigmaT", "ResistivityT" } }; for ( auto [originalName, invertedName] : invertedResultNameMap ) { if ( lastResultName.compare( originalName, Qt::CaseInsensitive ) == 0 ) { std::vector inverted; inverted.resize( resultData.size() ); std::transform( resultData.begin(), resultData.end(), inverted.begin(), []( float val ) { return 1.0f / val; } ); additionalData[( resultNameSpace + "::" + invertedName ).toStdString()] = inverted; } } } for ( const auto& obj : additionalData ) { emData.resultData[obj.first] = obj.second; } } for ( auto [resultName, data] : emData.resultData ) { QString riResultName = eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->makeResultNameUnique( QString::fromStdString( resultName ) ); RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::ResultDataType::FLOAT, riResultName ); eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->createResultEntry( resAddr, false ); auto newPropertyData = eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->modifiableCellScalarResultTimesteps( resAddr ); std::vector reorganizedData; // Switch cell size ordering from IJK to KJI to make the data layout fit internal ResInsight result ordering auto kjiNumCells = emData.ijkNumCells; kjiNumCells[0] = emData.ijkNumCells[2]; kjiNumCells[2] = emData.ijkNumCells[0]; for ( int k = 0; k < kjiNumCells[0]; k++ ) { for ( int i = 0; i < kjiNumCells[2]; i++ ) { for ( int j = 0; j < kjiNumCells[1]; j++ ) { reorganizedData.push_back( data[k + j * kjiNumCells[0] + i * kjiNumCells[0] * kjiNumCells[1]] ); } } } newPropertyData->push_back( reorganizedData ); } computeCachedData(); return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEmCase::reloadEclipseGridFile() { setReservoirData( nullptr ); openReserviorCase(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEmCase::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { uiOrdering.add( &m_caseUserDescription ); uiOrdering.add( &m_displayNameOption ); uiOrdering.add( &m_caseId ); uiOrdering.add( &m_caseFileName ); auto group = uiOrdering.addNewGroup( "Case Options" ); group->add( &m_activeFormationNames ); group->add( &m_flipXAxis ); group->add( &m_flipYAxis ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEmData RimEmCase::readDataFromFile() { #ifndef USE_HDF5 return {}; #else QString fileName = gridFileName(); std::array originNED; std::array cellSizes; std::array ijkNumCells; std::map> resultData; try { H5::Exception::dontPrint(); // Turn off auto-printing of failures to handle the errors appropriately H5::H5File mainFile( fileName.toStdString().c_str(), H5F_ACC_RDONLY ); { auto attr = mainFile.openAttribute( "description::OriginNED" ); H5::DataType type = attr.getDataType(); attr.read( type, originNED.data() ); } { H5::Group group = mainFile.openGroup( "Mesh" ); { auto attr = group.openAttribute( "cell_sizes" ); H5::DataType type = attr.getDataType(); attr.read( type, cellSizes.data() ); } { auto attr = group.openAttribute( "num_cells" ); H5::DataType type = attr.getDataType(); attr.read( type, ijkNumCells.data() ); } } H5::Group group = mainFile.openGroup( "Data" ); auto numObj = group.getNumObjs(); for ( size_t i = 0; i < numObj; i++ ) { auto resultName = group.getObjnameByIdx( i ); std::vector resultValues; H5::DataSet dataset = H5::DataSet( group.openDataSet( resultName ) ); hsize_t dims[3]; H5::DataSpace dataspace = dataset.getSpace(); dataspace.getSimpleExtentDims( dims, nullptr ); resultValues.resize( dims[0] * dims[1] * dims[2] ); dataset.read( resultValues.data(), H5::PredType::NATIVE_FLOAT ); resultData[resultName] = resultValues; } } catch ( ... ) { } return { originNED, cellSizes, ijkNumCells, resultData }; #endif } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimEmCase::locationOnDisc() const { if ( gridFileName().isEmpty() ) return QString(); QFileInfo fi( gridFileName() ); return fi.absolutePath(); }