Decouple Most of OPM-Common From LibECL

This commit takes a pass at the implementation files in opm-common
and removes references to libecl functions where practical.  In
particular we switch to using types from C++'s standard library (and
Boost.Filesystem) to achieve the effects of the interfaces being
replaced.

We also insert direct calls to Posix function fnmatch() to preserve
existing pattern matching behaviour (well lists and well templates).
This commit is contained in:
Bård Skaflestad
2019-10-11 01:10:56 -05:00
parent d84b7e19ee
commit bcfe700461
10 changed files with 110 additions and 62 deletions

View File

@@ -49,15 +49,14 @@
#include <cstdlib>
#include <cctype>
#include <memory> // unique_ptr
#include <stdexcept>
#include <sstream>
#include <unordered_map>
#include <utility> // move
#include <ert/ecl/EclFilename.hpp>
#include <ert/ecl/ecl_util.hpp>
#include <ert/util/util.h>
#include <boost/filesystem.hpp>
#include <boost/system/error_code.hpp>
// namespace start here since we don't want the ERT headers in it
namespace Opm {
namespace {
inline std::string uppercase( std::string x ) {
@@ -67,8 +66,34 @@ inline std::string uppercase( std::string x ) {
return x;
}
void ensure_directory_exists( const boost::filesystem::path& odir )
{
namespace fs = boost::filesystem;
if (fs::exists( odir ) && !fs::is_directory( odir ))
throw std::runtime_error {
"Filesystem element '" + odir.generic_string()
+ "' already exists but is not a directory"
};
boost::system::error_code ec{};
if (! fs::exists( odir ))
fs::create_directories( odir, ec );
if (ec != boost::system::errc::success) {
std::ostringstream msg;
msg << "Failed to create output directory '"
<< odir.generic_string()
<< "\nSystem reports: " << ec << '\n';
throw std::runtime_error { msg.str() };
}
}
}
namespace Opm {
class EclipseIO::Impl {
public:
Impl( const EclipseState&, EclipseGrid, const Schedule&, const SummaryConfig& );
@@ -113,14 +138,16 @@ void EclipseIO::Impl::writeINITFile(const data::Solution& simP
void EclipseIO::Impl::writeEGRIDFile( const NNC& nnc ) {
const auto& ioConfig = this->es.getIOConfig();
const auto formatted = this->es.cfg().io().getFMTOUT();
std::string egridFile( ERT::EclFilename( this->outputDir,
this->baseName,
ECL_EGRID_FILE,
ioConfig.getFMTOUT() ));
const auto ext = '.'
+ (formatted ? std::string{"F"} : std::string{})
+ "EGRID";
this->grid.save( egridFile, ioConfig.getFMTOUT(), nnc, this->es.getDeckUnitSystem());
const auto egridFile = (boost::filesystem::path{ this->outputDir }
/ (this->baseName + ext)).generic_string();
this->grid.save( egridFile, formatted, nnc, this->es.getDeckUnitSystem());
}
/*
@@ -236,19 +263,8 @@ EclipseIO::EclipseIO( const EclipseState& es,
{
if( !this->impl->output_enabled )
return;
{
const auto& outputDir = this->impl->outputDir;
// make sure that the output directory exists, if not try to create it
if ( !util_entry_exists( outputDir.c_str() ) ) {
util_make_path( outputDir.c_str() );
}
if( !util_is_directory( outputDir.c_str() ) ) {
throw std::runtime_error( "The path specified as output directory '"
+ outputDir + "' is not a directory");
}
}
ensure_directory_exists( this->impl->outputDir );
}
const out::Summary& EclipseIO::summary() {

View File

@@ -21,7 +21,7 @@
#include <stdexcept>
#include <vector>
#include <ert/ecl/ecl_grid_dims.hpp>
#include <opm/io/eclipse/EGrid.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
@@ -140,15 +140,11 @@ namespace Opm {
void GridDims::binary_init(const Deck& deck) {
const DeckKeyword& gdfile_kw = deck.getKeyword("GDFILE");
const std::string& gdfile_arg = gdfile_kw.getRecord(0).getItem("filename").get<std::string>(0);
std::string filename = deck.makeDeckPath(gdfile_arg);
ecl_grid_dims_type * grid_dims = ecl_grid_dims_alloc( filename.c_str(), nullptr );
if (grid_dims) {
const auto& dims = ecl_grid_dims_iget_dims(grid_dims, 0);
m_nx = dims->nx;
m_ny = dims->ny;
m_nz = dims->nz;
} else
throw std::invalid_argument("Could not determine grid dimensions from: " + filename);
const EclIO::EGrid egrid( deck.makeDeckPath(gdfile_arg) );
const auto& dimens = egrid.dimension();
m_nx = dimens[0];
m_ny = dimens[1];
m_nz = dimens[2];
}
}

View File

@@ -17,9 +17,10 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
@@ -32,9 +33,6 @@
#include <opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
#include <ert/ecl/EclFilename.hpp>
namespace Opm {
namespace {
@@ -190,9 +188,28 @@ namespace Opm {
std::string IOConfig::getRestartFileName(const std::string& restart_base, int report_step, bool output) const {
bool unified = output ? getUNIFOUT() : getUNIFIN();
bool fmt_file = output ? getFMTOUT() : getFMTIN();
ecl_file_enum file_type = (unified) ? ECL_UNIFIED_RESTART_FILE : ECL_RESTART_FILE;
return ERT::EclFilename( restart_base , file_type , report_step , fmt_file );
auto ext = std::string{};
if (unified) {
ext = fmt_file ? "FUNRST" : "UNRST";
}
else {
std::ostringstream os;
const char* fmt_prefix = "FGH";
const char* unfmt_prefix = "XYZ";
const int cycle = 10 * 1000;
const int p_ix = report_step / cycle;
const int n = report_step % cycle;
os << (fmt_file ? fmt_prefix[p_ix] : unfmt_prefix[p_ix])
<< std::setw(4) << std::setfill('0') << n;
ext = os.str();
}
return restart_base + '.' + ext;
}

View File

@@ -20,13 +20,13 @@
#include <algorithm>
#include <iostream>
#include <iterator>
#include <iomanip>
#include <sstream>
#include <boost/lexical_cast.hpp>
#include <opm/parser/eclipse/Utility/Functional.hpp>
#include <ert/ecl/ecl_util.h>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
@@ -708,12 +708,27 @@ void RestartConfig::handleScheduleSection(const SCHEDULESection& schedule, const
std::string RestartConfig::getRestartFileName(const std::string& restart_base, int report_step, bool unified , bool fmt_file) {
ecl_file_enum file_type = (unified) ? ECL_UNIFIED_RESTART_FILE : ECL_RESTART_FILE;
char * c_str = ecl_util_alloc_filename( NULL , restart_base.c_str() , file_type, fmt_file , report_step);
std::string restart_filename = c_str;
free( c_str );
auto ext = std::string{};
if (unified) {
ext = fmt_file ? "FUNRST" : "UNRST";
}
else {
std::ostringstream os;
return restart_filename;
const char* fmt_prefix = "FGH";
const char* unfmt_prefix = "XYZ";
const int cycle = 10 * 1000;
const int p_ix = report_step / cycle;
const int n = report_step % cycle;
os << (fmt_file ? fmt_prefix[p_ix] : unfmt_prefix[p_ix])
<< std::setw(4) << std::setfill('0') << n;
ext = os.str();
}
return restart_base + '.' + ext;
}

View File

@@ -19,8 +19,6 @@
#include <ostream>
#include <type_traits>
#include <ert/ecl/ecl_util.h>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/W.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
@@ -249,9 +247,13 @@ const EclHysterConfig& Runspec::hysterPar() const noexcept
available phases in Eclipse restart and init files.
*/
int Runspec::eclPhaseMask( ) const noexcept {
return ( active_phases.active( Phase::WATER ) ? ECL_WATER_PHASE : 0 )
| ( active_phases.active( Phase::OIL ) ? ECL_OIL_PHASE : 0 )
| ( active_phases.active( Phase::GAS ) ? ECL_GAS_PHASE : 0 );
const int water = 1 << 2;
const int oil = 1 << 0;
const int gas = 1 << 1;
return ( active_phases.active( Phase::WATER ) ? water : 0 )
| ( active_phases.active( Phase::OIL ) ? oil : 0 )
| ( active_phases.active( Phase::GAS ) ? gas : 0 );
}

View File

@@ -26,7 +26,7 @@
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellInjectionProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellProductionProperties.hpp>
#include <ert/util/util.h>
#include <fnmatch.h>
namespace Opm {
@@ -728,7 +728,7 @@ double Well2::injection_rate(const SummaryState& st, Phase phase_arg) const {
bool Well2::wellNameInWellNamePattern(const std::string& wellName, const std::string& wellNamePattern) {
bool wellNameInPattern = false;
if (util_fnmatch( wellNamePattern.c_str() , wellName.c_str()) == 0) {
if (fnmatch( wellNamePattern.c_str() , wellName.c_str() , 0 ) == 0) {
wellNameInPattern = true;
}
return wellNameInPattern;

View File

@@ -21,7 +21,8 @@
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <ert/util/util.h>
#include <fnmatch.h>
#include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
#include <opm/parser/eclipse/Parser/InputErrorAction.hpp>
@@ -266,7 +267,7 @@ namespace Opm {
const char * c_pattern = pattern.c_str();
for (const auto& pair : m_errorContexts) {
const std::string& key = pair.first;
if (util_fnmatch( c_pattern , key.c_str()) == 0)
if (fnmatch( c_pattern , key.c_str() , 0 ) == 0)
updateKey( key , action );
}
}

View File

@@ -143,13 +143,14 @@ namespace Opm {
m_count = 1;
}
else {
m_count = std::stoi( m_countString );
const auto cnt = std::stoi( m_countString );
if (m_count == 0)
if (cnt < 1)
// TODO: decorate the deck with a warning instead?
throw std::invalid_argument("Specifing zero repetitions is not allowed. Token: \'" + token + "\'.");
m_count = static_cast<std::size_t>(cnt);
}
}
}

View File

@@ -20,10 +20,10 @@
#ifndef STAR_TOKEN_HPP
#define STAR_TOKEN_HPP
#include <cctype>
#include <string>
#include <opm/parser/eclipse/Utility/Stringview.hpp>
#include <ert/util/ssize_t.h>
namespace Opm {
bool isStarToken(const string_view& token,
@@ -49,7 +49,7 @@ public:
init_(token);
}
size_t count() const {
std::size_t count() const {
return m_count;
}
@@ -78,7 +78,7 @@ private:
// must be set before calling this method.
void init_(const string_view& token);
ssize_t m_count;
std::size_t m_count;
std::string m_countString;
std::string m_valueString;
};