Skip to content

Commit 23a06cc

Browse files
magnesjkriben
andcommitted
Export zcorn/coord to grdecl.
Changes: - Refactors data writing to allow configurable row length - Adds documentation describing the Eclipse grid format (COORD and ZCORN) Co-Authored-By: Kristian Bendiksen <kristian.bendiksen@gmail.com>
1 parent 48ae7b2 commit 23a06cc

15 files changed

Lines changed: 2517 additions & 156 deletions

ApplicationLibCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ bool RicEclipseCellResultToFileImpl::writeResultToTextFile( const QString&
132132
resultData.push_back( resultValue );
133133
}
134134

135-
writeDataToTextFile( &file, writeEchoKeywords, eclipseKeyword, resultData );
135+
int valuesPerRow = 5;
136+
writeDataToTextFile( &file, writeEchoKeywords, eclipseKeyword, resultData, valuesPerRow );
136137

137138
return true;
138139
}
@@ -143,7 +144,8 @@ bool RicEclipseCellResultToFileImpl::writeResultToTextFile( const QString&
143144
void RicEclipseCellResultToFileImpl::writeDataToTextFile( QFile* file,
144145
bool writeEchoKeywords,
145146
const QString& eclipseKeyword,
146-
const std::vector<double>& resultData )
147+
const std::vector<double>& resultData,
148+
int valuesPerRow )
147149
{
148150
QTextStream textstream( file );
149151
textstream << "\n";
@@ -155,17 +157,41 @@ void RicEclipseCellResultToFileImpl::writeDataToTextFile( QFile*
155157
}
156158

157159
textstream << eclipseKeyword << "\n";
160+
161+
// Special formatting for MAPAXES to match Eclipse format exactly
162+
if ( eclipseKeyword == "MAPAXES" )
163+
{
164+
textstream.setFieldWidth( 0 );
165+
textstream.setRealNumberPrecision( 3 );
166+
textstream.setRealNumberNotation( QTextStream::FixedNotation );
167+
168+
// Write MAPAXES in proper Eclipse format: 2 values per line, 3 lines total
169+
for ( size_t i = 0; i < resultData.size(); i += 2 )
170+
{
171+
textstream << resultData[i] << " " << resultData[i + 1] << "\n";
172+
}
173+
textstream << "/\n";
174+
return; // Skip the normal loop for MAPAXES
175+
}
176+
158177
textstream.setFieldWidth( 16 );
159178
textstream.setFieldAlignment( QTextStream::AlignRight );
160179

180+
// Set higher precision for coordinate data
181+
if ( eclipseKeyword == "COORD" || eclipseKeyword == "ZCORN" )
182+
{
183+
textstream.setRealNumberPrecision( 3 );
184+
textstream.setRealNumberNotation( QTextStream::FixedNotation );
185+
}
186+
161187
caf::ProgressInfo pi( resultData.size(), QString( "Writing data to file %1" ).arg( file->fileName() ) );
162-
size_t progressSteps = resultData.size() / 20;
188+
size_t progressSteps = std::max( static_cast<size_t>( 1 ), resultData.size() / 20 );
163189

164190
for ( size_t i = 0; i < resultData.size(); i++ )
165191
{
166192
textstream << resultData[i];
167193

168-
if ( ( i + 1 ) % 5 == 0 )
194+
if ( ( i + 1 ) % valuesPerRow == 0 )
169195
{
170196
textstream << "\n";
171197
}

ApplicationLibCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,9 @@ class RicEclipseCellResultToFileImpl
6262
bool writeEchoKeywords,
6363
QString* errorMsg );
6464

65-
static void writeDataToTextFile( QFile* file, bool writeEchoKeywords, const QString& eclipseKeyword, const std::vector<double>& resultData );
65+
static void writeDataToTextFile( QFile* file,
66+
bool writeEchoKeywords,
67+
const QString& eclipseKeyword,
68+
const std::vector<double>& resultData,
69+
int valuesPerRow );
6670
};

ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,12 @@ void RicSaveEclipseInputVisibleCellsFeature::executeCommand( RimEclipseView*
100100
return;
101101
}
102102

103+
int valuesPerRow = 5;
103104
RicEclipseCellResultToFileImpl::writeDataToTextFile( &exportFile,
104105
exportSettings.writeEchoInGrdeclFiles,
105106
exportSettings.exportKeyword().text(),
106-
values );
107+
values,
108+
valuesPerRow );
107109
}
108110

109111
//--------------------------------------------------------------------------------------------------

ApplicationLibCode/FileInterface/RifEclipseInputFileTools.cpp

Lines changed: 7 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@
2929
#include "ExportCommands/RicEclipseCellResultToFileImpl.h"
3030

3131
#include "RifEclipseInputPropertyLoader.h"
32+
3233
#include "RifEclipseKeywordContent.h"
3334
#include "RifEclipseTextFileReader.h"
3435
#include "RifReaderEclipseOutput.h"
36+
#include "RigResdataGridConverter.h"
3537

3638
#include "RigActiveCellInfo.h"
3739
#include "RigCaseCellResultsData.h"
@@ -55,6 +57,7 @@
5557
#include <QFileInfo>
5658
#include <QTextStream>
5759

60+
#include "RigCellGeometryTools.h"
5861
#include "ert/ecl/ecl_box.hpp"
5962
#include "ert/ecl/ecl_grid.hpp"
6063
#include "ert/ecl/ecl_kw.h"
@@ -227,155 +230,8 @@ bool RifEclipseInputFileTools::exportGrid( const QString& fileName,
227230
const cvf::Vec3st& maxIn,
228231
const cvf::Vec3st& refinement )
229232
{
230-
if ( !eclipseCase )
231-
{
232-
return false;
233-
}
234-
235-
const RigActiveCellInfo* activeCellInfo = eclipseCase->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL );
236-
237-
CVF_ASSERT( activeCellInfo );
238-
239-
const RigMainGrid* mainGrid = eclipseCase->mainGrid();
240-
241-
cvf::Vec3st max = maxIn;
242-
if ( max == cvf::Vec3st::UNDEFINED )
243-
{
244-
max = cvf::Vec3st( mainGrid->cellCountI() - 1, mainGrid->cellCountJ() - 1, mainGrid->cellCountK() - 1 );
245-
}
246-
247-
int ecl_nx = static_cast<int>( ( max.x() - min.x() + 1 ) * refinement.x() );
248-
int ecl_ny = static_cast<int>( ( max.y() - min.y() + 1 ) * refinement.y() );
249-
int ecl_nz = static_cast<int>( ( max.z() - min.z() + 1 ) * refinement.z() );
250-
251-
CVF_ASSERT( ecl_nx > 0 && ecl_ny > 0 && ecl_nz > 0 );
252-
253-
size_t cellsPerOriginal = refinement.x() * refinement.y() * refinement.z();
254-
255-
caf::ProgressInfo progress( mainGrid->cellCount() * 2, "Save Eclipse Grid" );
256-
int cellProgressInterval = 1000;
257-
258-
std::vector<float*> ecl_corners;
259-
ecl_corners.reserve( mainGrid->cellCount() * cellsPerOriginal );
260-
std::vector<int*> ecl_coords;
261-
ecl_coords.reserve( mainGrid->cellCount() * cellsPerOriginal );
262-
263-
std::array<float, 6> mapAxes = mainGrid->mapAxesF();
264-
cvf::Mat4d mapAxisTrans = mainGrid->mapAxisTransform();
265-
if ( exportInLocalCoordinates )
266-
{
267-
cvf::Vec3d minPoint3d( mainGrid->boundingBox().min() );
268-
cvf::Vec2f minPoint2f( minPoint3d.x(), minPoint3d.y() );
269-
cvf::Vec2f origin( mapAxes[2] - minPoint2f.x(), mapAxes[3] - minPoint2f.y() );
270-
cvf::Vec2f xPoint = cvf::Vec2f( mapAxes[4], mapAxes[5] ) - minPoint2f;
271-
cvf::Vec2f yPoint = cvf::Vec2f( mapAxes[0], mapAxes[1] ) - minPoint2f;
272-
mapAxes = { yPoint.x(), yPoint.y(), origin.x(), origin.y(), xPoint.x(), xPoint.y() };
273-
274-
mapAxisTrans.setTranslation( mapAxisTrans.translation() - minPoint3d );
275-
}
276-
277-
const size_t* cellMappingECLRi = RifReaderEclipseOutput::eclipseCellIndexMapping();
278-
279-
int outputCellIndex = 0;
280-
281-
for ( size_t k = 0; k <= max.z() - min.z(); ++k )
282-
{
283-
for ( size_t j = 0; j <= max.y() - min.y(); ++j )
284-
{
285-
for ( size_t i = 0; i <= max.x() - min.x(); ++i )
286-
{
287-
size_t mainIndex = mainGrid->cellIndexFromIJK( min.x() + i, min.y() + j, min.z() + k );
288-
289-
int active = activeCellInfo->isActive( mainIndex ) ? 1 : 0;
290-
if ( active && cellVisibilityOverrideForActnum )
291-
{
292-
active = ( *cellVisibilityOverrideForActnum )[mainIndex];
293-
}
294-
std::array<cvf::Vec3d, 8> cellCorners = mainGrid->cellCornerVertices( mainIndex );
295-
296-
if ( mainGrid->useMapAxes() )
297-
{
298-
for ( cvf::Vec3d& corner : cellCorners )
299-
{
300-
corner.transformPoint( mapAxisTrans );
301-
}
302-
}
303-
304-
auto refinedCoords = RiaCellDividingTools::createHexCornerCoords( cellCorners, refinement.x(), refinement.y(), refinement.z() );
305-
306-
for ( size_t subK = 0; subK < refinement.z(); ++subK )
307-
{
308-
for ( size_t subJ = 0; subJ < refinement.y(); ++subJ )
309-
{
310-
for ( size_t subI = 0; subI < refinement.x(); ++subI )
311-
{
312-
int* ecl_cell_coords = new int[5];
313-
ecl_cell_coords[0] = static_cast<int>( i * refinement.x() + subI + 1 );
314-
ecl_cell_coords[1] = static_cast<int>( j * refinement.y() + subJ + 1 );
315-
ecl_cell_coords[2] = static_cast<int>( k * refinement.z() + subK + 1 );
316-
ecl_cell_coords[3] = outputCellIndex++;
317-
ecl_cell_coords[4] = active;
318-
ecl_coords.push_back( ecl_cell_coords );
319-
320-
size_t subIndex = subI + subJ * refinement.x() + subK * refinement.x() * refinement.y();
321-
322-
float* ecl_cell_corners = new float[24];
323-
for ( size_t cIdx = 0; cIdx < 8; ++cIdx )
324-
{
325-
const auto cellCorner = refinedCoords[subIndex * 8 + cIdx];
326-
ecl_cell_corners[cellMappingECLRi[cIdx] * 3] = cellCorner[0];
327-
ecl_cell_corners[cellMappingECLRi[cIdx] * 3 + 1] = cellCorner[1];
328-
ecl_cell_corners[cellMappingECLRi[cIdx] * 3 + 2] = -cellCorner[2];
329-
}
330-
ecl_corners.push_back( ecl_cell_corners );
331-
}
332-
}
333-
}
334-
}
335-
}
336-
337-
if ( outputCellIndex % cellProgressInterval == 0 )
338-
{
339-
progress.setProgress( outputCellIndex / cellsPerOriginal );
340-
}
341-
}
342-
343-
// Do not perform the transformation (applyMapaxes == false):
344-
// The coordinates have been transformed to the map axes coordinate system already.
345-
// However, send the map axes data in to resdata so that the coordinate system description is saved.
346-
bool applyMapaxes = false;
347-
ecl_grid_type* mainEclGrid =
348-
ecl_grid_alloc_GRID_data( (int)ecl_coords.size(), ecl_nx, ecl_ny, ecl_nz, 5, &ecl_coords[0], &ecl_corners[0], applyMapaxes, mapAxes.data() );
349-
progress.setProgress( mainGrid->cellCount() );
350-
351-
for ( float* floatArray : ecl_corners )
352-
{
353-
delete floatArray;
354-
}
355-
356-
for ( int* intArray : ecl_coords )
357-
{
358-
delete intArray;
359-
}
360-
361-
FILE* filePtr = util_fopen( RiaStringEncodingTools::toNativeEncoded( fileName ).data(), "w" );
362-
363-
if ( !filePtr )
364-
{
365-
return false;
366-
}
367-
368-
ert_ecl_unit_enum ecl_units = ECL_METRIC_UNITS;
369-
if ( eclipseCase->unitsType() == RiaDefines::EclipseUnitSystem::UNITS_FIELD )
370-
ecl_units = ECL_FIELD_UNITS;
371-
else if ( eclipseCase->unitsType() == RiaDefines::EclipseUnitSystem::UNITS_LAB )
372-
ecl_units = ECL_LAB_UNITS;
373-
374-
ecl_grid_fprintf_grdecl2( mainEclGrid, filePtr, ecl_units );
375-
ecl_grid_free( mainEclGrid );
376-
fclose( filePtr );
377-
378-
return true;
233+
// Use the new native implementation instead of resdata
234+
return RigResdataGridConverter::exportGrid( fileName, eclipseCase, exportInLocalCoordinates, cellVisibilityOverrideForActnum, min, maxIn, refinement );
379235
}
380236

381237
//--------------------------------------------------------------------------------------------------
@@ -481,7 +337,8 @@ bool RifEclipseInputFileTools::exportKeywords( const QString& resul
481337

482338
// Multiple keywords can be exported to same file, so write ECHO keywords outside the loop
483339
bool writeEchoKeywordsInExporterObject = false;
484-
RicEclipseCellResultToFileImpl::writeDataToTextFile( &exportFile, writeEchoKeywordsInExporterObject, keyword, filteredResults );
340+
int valuePerRow = 5;
341+
RicEclipseCellResultToFileImpl::writeDataToTextFile( &exportFile, writeEchoKeywordsInExporterObject, keyword, filteredResults, valuePerRow );
485342

486343
progress.incrementProgress();
487344
}

ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ set(SOURCE_GROUP_HEADER_FILES
8080
${CMAKE_CURRENT_LIST_DIR}/RigFloodingSettings.h
8181
${CMAKE_CURRENT_LIST_DIR}/RigHydrocarbonFlowTools.h
8282
${CMAKE_CURRENT_LIST_DIR}/RigDoglegTools.h
83+
${CMAKE_CURRENT_LIST_DIR}/RigResdataGridConverter.h
84+
${CMAKE_CURRENT_LIST_DIR}/RigGridExportAdapter.h
8385
)
8486

8587
set(SOURCE_GROUP_SOURCE_FILES
@@ -161,6 +163,8 @@ set(SOURCE_GROUP_SOURCE_FILES
161163
${CMAKE_CURRENT_LIST_DIR}/RigFloodingSettings.cpp
162164
${CMAKE_CURRENT_LIST_DIR}/RigHydrocarbonFlowTools.cpp
163165
${CMAKE_CURRENT_LIST_DIR}/RigDoglegTools.cpp
166+
${CMAKE_CURRENT_LIST_DIR}/RigResdataGridConverter.cpp
167+
${CMAKE_CURRENT_LIST_DIR}/RigGridExportAdapter.cpp
164168
)
165169

166170
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

0 commit comments

Comments
 (0)