///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2025- Equinor ASA // // 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 "RifSurfio.h" #include "RifFileTools.h" #include "irap_export.h" #include "irap_import.h" #include //-------------------------------------------------------------------------------------------------- /// /// https://github.com/equinor/xtgeo/blob/main/src/xtgeo/surface/_regsurf_import.py /// https://xtgeo.readthedocs.io/en/latest/datamodels.html#description /// https://github.com/equinor/surfio /// //-------------------------------------------------------------------------------------------------- std::expected>, std::string> RifSurfio::importSurfaceData( const std::string& filename ) { auto extension = RifFileTools::extensionLowerCase( filename ); if ( extension != ".irap" && extension != ".gri" ) { return std::unexpected( "File is not a valid IRAP or GRI file: " + filename ); } // Check file permissions (best effort, may not be reliable on all platforms) auto isFileReadable = RifFileTools::isFileReadable( filename ); if ( !isFileReadable.has_value() ) { return std::unexpected( isFileReadable.error() ); } // Try to open the file to confirm readability std::ifstream file( filename ); if ( !file.is_open() ) { return std::unexpected( "Could not open file: " + filename ); } auto convertToRegularSurface = []( const surfio::irap::irap& fileData ) -> std::expected>, std::string> { RigRegularSurfaceData surfaceData; surfaceData.nx = fileData.header.ncol; surfaceData.ny = fileData.header.nrow; surfaceData.originX = fileData.header.xori; surfaceData.originY = fileData.header.yori; surfaceData.incrementX = fileData.header.xinc; surfaceData.incrementY = fileData.header.yinc; surfaceData.rotation = fileData.header.rot; // transpose the data to match the expected format std::vector transposedValues( fileData.values.size() ); for ( int row = 0; row < fileData.header.nrow; ++row ) { for ( int col = 0; col < fileData.header.ncol; ++col ) { transposedValues[row * fileData.header.ncol + col] = fileData.values[col * fileData.header.nrow + row]; } } return std::make_pair( surfaceData, transposedValues ); }; if ( extension == ".gri" ) { auto fileData = surfio::irap::from_binary_file( filename ); return convertToRegularSurface( fileData ); } else if ( extension == ".irap" ) { auto fileData = surfio::irap::from_ascii_file( filename ); return convertToRegularSurface( fileData ); } else { return std::unexpected( "File is not a valid IRAP or GRI file: " + filename ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RifSurfio::exportToGri( const std::string& filename, const RigRegularSurfaceData& surfaceData, const std::vector& values ) { return exportImpl( filename, surfaceData, values, true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RifSurfio::exportToIrap( const std::string& filename, const RigRegularSurfaceData& surfaceData, const std::vector& values ) { return exportImpl( filename, surfaceData, values, false ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RifSurfio::exportImpl( const std::string& filename, const RigRegularSurfaceData& surfaceData, const std::vector& values, bool binary ) { if ( static_cast( values.size() ) != surfaceData.nx * surfaceData.ny ) return false; surfio::irap::irap_header header; header.ncol = surfaceData.nx; header.nrow = surfaceData.ny; header.xori = surfaceData.originX; header.yori = surfaceData.originY; header.xmax = surfaceData.originX + ( surfaceData.nx - 1 ) * surfaceData.incrementX; header.ymax = surfaceData.originY + ( surfaceData.ny - 1 ) * surfaceData.incrementY; header.xinc = surfaceData.incrementX; header.yinc = surfaceData.incrementY; header.rot = surfaceData.rotation; header.xrot = surfaceData.originX; header.yrot = surfaceData.originY; // Transpose from row-major (ResInsight: values[j * nx + i]) to column-major (IRAP: values[i * ny + j]) std::vector irapValues( values.size() ); for ( int j = 0; j < surfaceData.ny; ++j ) { for ( int i = 0; i < surfaceData.nx; ++i ) { irapValues[i * surfaceData.ny + j] = values[j * surfaceData.nx + i]; } } const surfio::irap::surf_span span{ irapValues.data(), static_cast( surfaceData.nx ), static_cast( surfaceData.ny ) }; if ( binary ) surfio::irap::to_binary_file( filename, header, span ); else surfio::irap::to_ascii_file( filename, header, span ); return true; }