Support optimized surface export from grid model layers

* #7885 Update opm-common with optimized coordinate import
* #7885 Allow null as default result from a script method
* #7885 Propagate default parameter values to generated Python code
* #7885 Add CommandRouter as hub for worker methods
* #7885 Add support for use of CommadRouter from Python
This commit is contained in:
Magne Sjaastad
2021-08-23 11:58:32 +02:00
committed by GitHub
parent 2ef22f518c
commit 3a94078867
28 changed files with 1587 additions and 863 deletions

View File

@@ -0,0 +1,20 @@
set (SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimCommandRouter.h
${CMAKE_CURRENT_LIST_DIR}/RimcExtractSurfaces.h
)
set (SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimCommandRouter.cpp
${CMAKE_CURRENT_LIST_DIR}/RimcExtractSurfaces.cpp
)
list(APPEND CODE_HEADER_FILES
${SOURCE_GROUP_HEADER_FILES}
)
list(APPEND CODE_SOURCE_FILES
${SOURCE_GROUP_SOURCE_FILES}
)
source_group( "ProjectDataModelCommands\\CommandRouter" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )

View File

@@ -0,0 +1,74 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimCommandRouter.h"
#include "cafPdmObjectScriptingCapability.h"
CAF_PDM_SOURCE_INIT( RimCommandRouter, "RimCommandRouter" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimCommandRouter::RimCommandRouter()
{
CAF_PDM_InitScriptableObjectWithNameAndComment( "CommandRouter",
"",
"",
"",
"CommandRouter",
"The CommandRouter is used to call code independent to the "
"project" );
}
//--------------------------------------------------------------------------------------------------
///
/// RimCommandRouterMethod
///
///
///
///
//--------------------------------------------------------------------------------------------------
RimCommandRouterMethod::RimCommandRouterMethod( PdmObjectHandle* self )
: caf::PdmObjectMethod( self )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimCommandRouterMethod::isNullptrValidResult() const
{
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimCommandRouterMethod::resultIsPersistent() const
{
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::unique_ptr<caf::PdmObjectHandle> RimCommandRouterMethod::defaultResult() const
{
return nullptr;
}

View File

@@ -0,0 +1,62 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmObject.h"
#include "cafPdmObjectMethod.h"
//--------------------------------------------------------------------------------------------------
/// Usually, command router classes will require only the execute() method. Derive from RimCommandRouterMethod to get
/// default values for the other required virtual functions
//--------------------------------------------------------------------------------------------------
class RimCommandRouterMethod : public caf::PdmObjectMethod
{
public:
RimCommandRouterMethod( PdmObjectHandle* self );
bool isNullptrValidResult() const override;
bool resultIsPersistent() const override;
std::unique_ptr<PdmObjectHandle> defaultResult() const override;
};
//==================================================================================================
/// The command router object is used as a hub for data processing commands independent to a ResInsight project
/// (RimProject). The intention for this object is to have a hub to connect to when using ResInsight as a data
/// processing server. Avoid dependency on a GUI, and make sure the execute() commands works in headless mode.
///
/// The router object is made available from Python using
///
/// resinsight = rips.Instance.find()
/// command_router = resinsight.command_router
///
/// Steps to add a new processing function
/// 1) Create a new class deriving from RimCommandRouterMethod
/// 2) Add Pdm fields to this class. These fields will be made available as parameters from Python
/// 2) Implement data processing in execute() method using the input values specified in the Pdm fields
///
/// Example : RimcCommandRouter_extractSurfaces
///
//==================================================================================================
class RimCommandRouter : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RimCommandRouter();
};

View File

@@ -0,0 +1,134 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021- 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimcExtractSurfaces.h"
#include "RiaLogging.h"
#include "RifSurfaceExporter.h"
#include "RimCommandRouter.h"
#include "opm/io/eclipse/EGrid.hpp"
#include "cafPdmAbstractFieldScriptingCapability.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmObjectHandle.h"
#include <QDir>
#include <QFileInfo>
#include <memory>
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimCommandRouter, RimcCommandRouter_extractSurfaces, "ExtractSurfaces" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimcCommandRouter_extractSurfaces::RimcCommandRouter_extractSurfaces( caf::PdmObjectHandle* self )
: RimCommandRouterMethod( self )
{
CAF_PDM_InitObject( "Extract Layer Surface", "", "", "Extract Layer Surface" );
CAF_PDM_InitScriptableField( &m_gridModelFilename, "GridModelFilename", QString(), "Grid Model Case Filename", "", "", "" );
CAF_PDM_InitScriptableField( &m_layers, "Layers", std::vector<int>(), "Layers", "", "", "" );
CAF_PDM_InitScriptableField( &m_minimumI, "MinimumI", -1, "Minimum I", "", "", "" );
CAF_PDM_InitScriptableField( &m_maximumI, "MaximumI", -1, "Maximum I", "", "", "" );
CAF_PDM_InitScriptableField( &m_minimumJ, "MinimumJ", -1, "Minimum J", "", "", "" );
CAF_PDM_InitScriptableField( &m_maximumJ, "MaximumJ", -1, "Maximum J", "", "", "" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmObjectHandle* RimcCommandRouter_extractSurfaces::execute()
{
try
{
std::string filename = m_gridModelFilename().toStdString();
Opm::EclIO::EGrid grid1( filename );
auto dims = grid1.dimension();
int minI = m_minimumI() == -1 ? 0 : m_minimumI();
int maxI = m_maximumJ() == -1 ? dims[0] - 1 : m_maximumI();
int minJ = m_minimumI() == -1 ? 0 : m_minimumJ();
int maxJ = m_minimumI() == -1 ? dims[1] - 1 : m_maximumJ();
std::array<int, 4> range = { minI, maxI, minJ, maxJ };
for ( auto layer : m_layers() )
{
bool bottom = false;
auto xyz_data = grid1.getXYZ_layer( layer, range, bottom );
auto mapAxis = grid1.get_mapaxes();
// Create surface from coords
std::vector<unsigned> triangleIndices;
std::vector<cvf::Vec3d> vertices;
unsigned startOfCellCoordIndex = 0;
while ( startOfCellCoordIndex + 4 < xyz_data.size() )
{
for ( size_t cornerIdx = 0; cornerIdx < 4; cornerIdx++ )
{
auto coord1 = xyz_data[startOfCellCoordIndex + cornerIdx];
auto cvfCoord = cvf::Vec3d( coord1[0], coord1[1], -coord1[2] );
if ( !mapAxis.empty() )
{
cvfCoord[0] += mapAxis[2];
cvfCoord[1] += mapAxis[3];
}
vertices.push_back( cvfCoord );
}
triangleIndices.push_back( startOfCellCoordIndex );
triangleIndices.push_back( startOfCellCoordIndex + 3 );
triangleIndices.push_back( startOfCellCoordIndex + 2 );
triangleIndices.push_back( startOfCellCoordIndex );
triangleIndices.push_back( startOfCellCoordIndex + 1 );
triangleIndices.push_back( startOfCellCoordIndex + 3 );
// Coordinates are given for each four corners for each cell of the surface
startOfCellCoordIndex += 4;
}
// Write to TS file on disk
QFileInfo fi( m_gridModelFilename );
QString surfaceFilename = fi.absoluteDir().absolutePath() +
QString( "/surfaceexport/layer-%1.ts" ).arg( layer );
// TODO: Add more info in surface comment
if ( !RifSurfaceExporter::writeGocadTSurfFile( surfaceFilename, "Surface comment", vertices, triangleIndices ) )
{
RiaLogging::error( "Failed to export surface data to " + surfaceFilename );
}
else
{
RiaLogging::error( "Successfully exported surface data to " + surfaceFilename );
}
}
}
catch ( ... )
{
RiaLogging::error( "Error during creation of surface data for model " + m_gridModelFilename() );
}
return nullptr;
}

View File

@@ -0,0 +1,50 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021- 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimCommandRouter.h"
#include "cafPdmField.h"
#include "cvfVector3.h"
#include <QString>
#include <memory>
//==================================================================================================
///
//==================================================================================================
class RimcCommandRouter_extractSurfaces : public RimCommandRouterMethod
{
CAF_PDM_HEADER_INIT;
public:
RimcCommandRouter_extractSurfaces( caf::PdmObjectHandle* self );
caf::PdmObjectHandle* execute() override;
private:
caf::PdmField<QString> m_gridModelFilename;
caf::PdmField<std::vector<int>> m_layers;
caf::PdmField<int> m_minimumI;
caf::PdmField<int> m_maximumI;
caf::PdmField<int> m_minimumJ;
caf::PdmField<int> m_maximumJ;
};