Compare commits

..

13 Commits

Author SHA1 Message Date
Arne Morten Kvarving
8fa165c0d7 bump version to 2019.04 2019-05-08 08:29:45 +02:00
Arne Morten Kvarving
8ff950227f bump version to 2019.04-rc3 2019-05-03 10:42:48 +02:00
Joakim Hove
bc5aeaf4bf Internalize a global WHISTCTL setting in the Schedule object 2019-05-03 10:40:26 +02:00
Atgeirr Flø Rasmussen
0108437201 Bugfix: do not keep old control modes.
They will be treated as limits, and cause wrong behaviour.
2019-05-03 08:59:01 +02:00
Arne Morten Kvarving
828fe797f0 bump version to 2019.04 rc2 2019-04-29 08:50:42 +02:00
Jostein Alvestad
8f24032612 Added a improvement to the handling of MSW data for writing to restart file
Improvement to handle more general MSW data  for writing to
Eclipse compatible restart file
2019-04-26 09:40:50 +02:00
Joakim Hove
ee6bfbd76f Add configuration for keyword FLUXTYPE 2019-04-25 12:33:57 +02:00
Markus Blatt
54ee583112 Reintroduce overeagerly removed const qualifiers before function parameters.
Actually, the compiler does not complain about const in void func(const T type).
It just complains about const qualifiers before by-value return types.
2019-04-25 11:38:51 +02:00
Markus Blatt
b69010cfc9 reintroduce some const with elegance 2019-04-25 11:38:51 +02:00
Markus Blatt
2859980cb4 Removes nearly all warnings experienced with g++-8.3
Namely:
- unused parameter
- type qualifiers ignored ...
- catchinhg polymorphic type ... by value
2019-04-25 11:38:51 +02:00
Joakim Hove
3ffefd8098 Fix bug in WellSegments== 2019-04-25 08:31:32 +02:00
Joakim Hove
852fdd7ac4 Add "size" : 1 attribute to CARFIN keyword 2019-04-25 08:31:32 +02:00
Arne Morten Kvarving
47a43daeac bump versions to 2019.04-rc1 2019-04-12 10:29:12 +02:00
1083 changed files with 23961 additions and 636577 deletions

View File

@@ -1,20 +0,0 @@
{
BasedOnStyle: WebKit,
AlignAfterOpenBracket: AlwaysBreak,
AlignConsecutiveAssignments: false,
AlignConsecutiveDeclarations: false,
AlignAfterOpenBracket: Align,
AllowShortBlocksOnASingleLine: false,
AllowShortFunctionsOnASingleLine: None,
AlwaysBreakAfterReturnType: TopLevelDefinitions,
AlwaysBreakTemplateDeclarations: Yes,
BinPackArguments: false,
BinPackParameters: false,
BreakBeforeBraces: Linux,
BreakConstructorInitializers: BeforeComma,
ColumnLimit: 120,
Cpp11BracedListStyle: true,
FixNamespaceComments: true,
MaxEmptyLinesToKeep: 5,
NamespaceIndentation: Inner,
}

4
.gitignore vendored
View File

@@ -69,7 +69,3 @@ install
# emacs directory setting:
.dir-locals.el
*.pyc
*.eggs
*.egg-info

0
.gitmodules vendored
View File

View File

@@ -8,9 +8,11 @@ set(OPM_MACROS_ROOT ${PROJECT_SOURCE_DIR})
option(ENABLE_ECL_INPUT "Enable eclipse input support?" ON)
option(ENABLE_ECL_OUTPUT "Enable eclipse output support?" ON)
option(ENABLE_MOCKSIM "Build the mock simulator for io testing" ON)
option(OPM_ENABLE_PYTHON "Enable python bindings?" OFF)
option(OPM_ENABLE_EMBEDDED_PYTHON "Enable python bindings?" OFF)
option(ENABLE_WELL_TEST "Enable testing of well code when building Schedule object" OFF)
if (ENABLE_WELL_TEST)
add_definitions(-DWELL_TEST)
endif()
# Output implies input
if(ENABLE_ECL_OUTPUT)
@@ -112,8 +114,6 @@ macro (sources_hook)
# Append generated sources
list(APPEND opm-common_SOURCES ${PROJECT_BINARY_DIR}/ParserKeywords.cpp)
endif()
set_source_files_properties(src/opm/parser/eclipse/Python/Python.cpp
PROPERTIES COMPILE_FLAGS -Wno-shadow)
endmacro (sources_hook)
macro (fortran_hook)
@@ -149,7 +149,7 @@ if (ENABLE_MOCKSIM)
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
foreach( test test_msim test_msim_ACTIONX )
opm_add_test(${test} SOURCES tests/msim/${test}.cpp
opm_add_test(${test} SOURCES tests/msim/${test}
LIBRARIES ${_libs}
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/tests)
endforeach()
@@ -157,55 +157,25 @@ endif()
# Build the compare utilities
if(ENABLE_ECL_INPUT)
add_executable(compareECL
test_util/EclFilesComparator.cpp
test_util/EclRegressionTest.cpp
test_util/compareECL.cpp
)
add_executable(convertECL
test_util/convertECL.cpp
)
foreach(target compareECL convertECL)
target_link_libraries(${target} opmcommon)
install(TARGETS ${target} DESTINATION bin)
endforeach()
add_library(testutil STATIC
examples/test_util/EclFilesComparator.cpp
examples/test_util/EclIntegrationTest.cpp
examples/test_util/EclRegressionTest.cpp
examples/test_util/summaryComparator.cpp
examples/test_util/summaryIntegrationTest.cpp
examples/test_util/summaryRegressionTest.cpp)
target_link_libraries(testutil ecl)
add_executable(compareECL examples/test_util/compareECL.cpp)
target_link_libraries(compareECL testutil opmcommon)
# Add the tests
set(_libs opmcommon
set(_libs testutil opmcommon
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
opm_add_test(test_EclFilesComparator
CONDITION
ENABLE_ECL_INPUT
SOURCES
tests/test_EclFilesComparator.cpp
test_util/EclFilesComparator.cpp
LIBRARIES
${_libs}
WORKING_DIRECTORY
${PROJECT_BINARY_DIR}/tests
)
opm_add_test(test_EclRegressionTest
CONDITION
ENABLE_ECL_INPUT
SOURCES
tests/test_EclRegressionTest.cpp
test_util/EclFilesComparator.cpp
test_util/EclRegressionTest.cpp
LIBRARIES
${_libs}
WORKING_DIRECTORY
${PROJECT_BINARY_DIR}/tests
)
foreach(test test_EclIO test_EGrid test_ERft test_ERst test_ESmry)
foreach(test test_compareSummary test_EclFilesComparator)
opm_add_test(${test} CONDITION ENABLE_ECL_INPUT
LIBRARIES ${_libs}
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/tests)
LIBRARIES ${_libs})
endforeach()
install(TARGETS compareECL DESTINATION bin)
endif()
# Install build system files
@@ -213,93 +183,3 @@ install(DIRECTORY cmake DESTINATION share/opm)
# Install tab completion skeleton
install(FILES etc/opm_bash_completion.sh.in DESTINATION share/opm/etc)
if (OPM_ENABLE_PYTHON)
# -------------------------------------------------------------------------
# 1: Wrap C++ functionality in Python
find_package(PythonInterp REQUIRED)
include(FindPythonInterp)
make_directory(${CMAKE_BINARY_DIR}/python)
set(PYTHON_PACKAGE_PATH "site-packages")
set(PYTHON_INSTALL_PREFIX "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/${PYTHON_PACKAGE_PATH}" CACHE STRING "Subdirectory to install Python modules in")
get_target_property(_ecl_include_dirs ecl INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(_opmcommon_include_dirs opmcommon INCLUDE_DIRECTORIES)
list(APPEND _opmcommon_include_dirs ${_ecl_include_dirs})
string(REPLACE ";" ":" _setup_include_dirs "${_opmcommon_include_dirs}")
get_target_property(_ecl_lib ecl LOCATION)
get_filename_component(_ecl_lib_dir ${_ecl_lib} DIRECTORY)
set(_opmcommon_lib_dirs ${_ecl_lib_dir} ${CMAKE_BINARY_DIR}/lib ${CMAKE_PREFIX_PATH}/lib)
string(REPLACE ";" ":" _setup_lib_dirs "${_opmcommon_lib_dirs}")
add_custom_command(OUTPUT python/python/opm/libopmcommon_python.so
DEPENDS
python/cxx/connection.cpp
python/cxx/converters.hpp
python/cxx/deck.cpp
python/cxx/deck_keyword.cpp
python/cxx/eclipse_3d_properties.cpp
python/cxx/eclipse_config.cpp
python/cxx/eclipse_grid.cpp
python/cxx/eclipse_state.cpp
python/cxx/group.cpp
python/cxx/log.cpp
python/cxx/parsecontext.cpp
python/cxx/parser.cpp
python/cxx/schedule.cpp
python/cxx/export.cpp
python/cxx/export.hpp
python/cxx/common_state.cpp
python/cxx/common_state.hpp
python/cxx/table_manager.cpp
python/cxx/well.cpp
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/python/ ${CMAKE_BINARY_DIR}/python
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python/setup.py
build
build_ext
--build-lib=${CMAKE_BINARY_DIR}/python/python/opm
--library-dirs=${_setup_lib_dirs}
--include-dirs=${_setup_include_dirs}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/python
COMMENT "Building python bindings")
add_custom_target(opmcommon_python ALL DEPENDS python/python/opm/libopmcommon_python.so)
add_dependencies(opmcommon_python opmcommon)
install( CODE "execute_process(COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX} )" )
install( CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} python/setup.py build_ext --dry-run install --prefix=${CMAKE_INSTALL_PREFIX} )" )
add_test(NAME python_tests
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/python
COMMAND ${PYTHON_EXECUTABLE} setup.py build_ext --dry-run --build-lib ${CMAKE_BINARY_DIR}/python/python/opm test
)
set_target_properties(opmcommon PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/python/python)
# -------------------------------------------------------------------------
# Let cmake configure some small shell scripts which can be used to simplify
# building and testing of the Python extensions.
configure_file(python/setup-build.sh.in tmp/setup-build.sh)
file( COPY ${PROJECT_BINARY_DIR}/tmp/setup-build.sh
DESTINATION ${PROJECT_BINARY_DIR}
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE )
configure_file(python/setup-test.sh.in tmp/setup-test.sh)
file( COPY ${PROJECT_BINARY_DIR}/tmp/setup-test.sh
DESTINATION ${PROJECT_BINARY_DIR}
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE )
configure_file(python/enable-python.sh.in enable-python.sh)
# -------------------------------------------------------------------------
# 2: Embed the Python interpreter for keywords like PYACTION and PYINPUT
if (OPM_ENABLE_EMBEDDED_PYTHON)
add_subdirectory(python/pybind11)
target_include_directories(opmcommon PRIVATE "python/pybind11/include;${PYTHON_INCLUDE_DIRS}")
target_link_libraries(opmcommon PUBLIC ${PYTHON_LIBRARY})
add_definitions(-DEMBEDDED_PYTHON)
endif()
endif()

View File

@@ -1,5 +1,5 @@
# This file sets up five lists:
# MAIN_SOURCE_FILES List of compilation units which will be included in
# MAIN_SOURCE_FILES List of compilation units which will be included in
# the library. If it isn't on this list, it won't be
# part of the library. Please try to keep it sorted to
# maintain sanity.
@@ -21,6 +21,7 @@
# the library needs it.
list (APPEND MAIN_SOURCE_FILES
examples/test_util/EclFile.cpp
src/opm/common/data/SimulationDataContainer.cpp
src/opm/common/OpmLog/CounterLog.cpp
src/opm/common/OpmLog/EclipsePRTLog.cpp
@@ -41,13 +42,10 @@ if(ENABLE_ECL_INPUT)
src/opm/json/JsonObject.cpp
src/opm/parser/eclipse/Deck/Deck.cpp
src/opm/parser/eclipse/Deck/DeckItem.cpp
src/opm/parser/eclipse/Deck/DeckValue.cpp
src/opm/parser/eclipse/Deck/DeckKeyword.cpp
src/opm/parser/eclipse/Deck/DeckRecord.cpp
src/opm/parser/eclipse/Deck/DeckOutput.cpp
src/opm/parser/eclipse/Deck/Section.cpp
src/opm/parser/eclipse/Deck/UDAValue.cpp
src/opm/parser/eclipse/Python/Python.cpp
src/opm/parser/eclipse/EclipseState/AquiferCT.cpp
src/opm/parser/eclipse/EclipseState/Aquifetp.cpp
src/opm/parser/eclipse/EclipseState/Aquancon.cpp
@@ -74,29 +72,22 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/Grid/setKeywordBox.cpp
src/opm/parser/eclipse/EclipseState/Grid/TransMult.cpp
src/opm/parser/eclipse/EclipseState/InitConfig/Equil.cpp
src/opm/parser/eclipse/EclipseState/InitConfig/FoamConfig.cpp
src/opm/parser/eclipse/EclipseState/InitConfig/InitConfig.cpp
src/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp
src/opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.cpp
src/opm/parser/eclipse/EclipseState/Runspec.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionAST.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionContext.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionResult.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/Actdims.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/Actions.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionParser.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionValue.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/ASTNode.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Action/Condition.cpp
src/opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Events.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/Group2.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRate.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateModel.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/injection.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group.cpp
src/opm/parser/eclipse/EclipseState/Schedule/GroupTree.cpp
src/opm/parser/eclipse/EclipseState/Schedule/injection.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MessageLimits.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.cpp
@@ -105,17 +96,16 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/RFTConfig.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp
src/opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.cpp
src/opm/parser/eclipse/EclipseState/Schedule/SummaryState.cpp
src/opm/parser/eclipse/EclipseState/Schedule/TimeMap.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Tuning.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/Connection.cpp
src/opm/parser/eclipse/EclipseState/Schedule/eval_uda.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/Well2.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WList.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WListManager.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WellEconProductionLimits.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WellFoamProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WellInjectionProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WellPolymerProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WellTracerProperties.cpp
@@ -142,15 +132,14 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParams.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParser.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQWellSet.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQAssign.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQConfig.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQContext.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunction.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunctionTable.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.cpp
src/opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.cpp
src/opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.cpp
src/opm/parser/eclipse/Parser/ErrorGuard.cpp
@@ -160,68 +149,34 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/Parser/ParserItem.cpp
src/opm/parser/eclipse/Parser/ParserKeyword.cpp
src/opm/parser/eclipse/Parser/ParserRecord.cpp
src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp
src/opm/parser/eclipse/Parser/raw/RawRecord.cpp
src/opm/parser/eclipse/Parser/raw/StarToken.cpp
src/opm/parser/eclipse/RawDeck/RawKeyword.cpp
src/opm/parser/eclipse/RawDeck/RawRecord.cpp
src/opm/parser/eclipse/RawDeck/StarToken.cpp
src/opm/parser/eclipse/Units/Dimension.cpp
src/opm/parser/eclipse/Units/UnitSystem.cpp
src/opm/parser/eclipse/Utility/Functional.cpp
src/opm/parser/eclipse/Utility/Stringview.cpp
)
if (OPM_ENABLE_EMBEDDED_PYTHON)
list( APPEND PYTHON_SOURCE_FILES
src/opm/parser/eclipse/Python/PythonInterp.cpp
python/cxx/connection.cpp
python/cxx/deck.cpp
python/cxx/deck_keyword.cpp
python/cxx/eclipse_3d_properties.cpp
python/cxx/eclipse_config.cpp
python/cxx/eclipse_grid.cpp
python/cxx/eclipse_state.cpp
python/cxx/group.cpp
python/cxx/parsecontext.cpp
python/cxx/parser.cpp
python/cxx/schedule.cpp
python/cxx/export.cpp
python/cxx/common_state.cpp
python/cxx/table_manager.cpp
python/cxx/well.cpp
python/cxx/log.cpp
)
set_source_files_properties(${PYTHON_SOURCE_FILES} PROPERTIES COMPILE_FLAGS -Wno-shadow)
list( APPEND MAIN_SOURCE_FILES ${PYTHON_SOURCE_FILES})
endif()
if(NOT cjson_FOUND)
list(APPEND MAIN_SOURCE_FILES external/cjson/cJSON.c)
endif()
endif()
if(ENABLE_ECL_OUTPUT)
list( APPEND MAIN_SOURCE_FILES
src/opm/io/eclipse/EclFile.cpp
src/opm/io/eclipse/EclOutput.cpp
src/opm/io/eclipse/EclUtil.cpp
src/opm/io/eclipse/EGrid.cpp
src/opm/io/eclipse/ERft.cpp
src/opm/io/eclipse/ERst.cpp
src/opm/io/eclipse/ESmry.cpp
src/opm/io/eclipse/OutputStream.cpp
src/opm/output/eclipse/AggregateConnectionData.cpp
src/opm/output/eclipse/AggregateGroupData.cpp
src/opm/output/eclipse/AggregateMSWData.cpp
src/opm/output/eclipse/AggregateUDQData.cpp
src/opm/output/eclipse/AggregateWellData.cpp
src/opm/output/eclipse/CreateDoubHead.cpp
src/opm/output/eclipse/CreateInteHead.cpp
src/opm/output/eclipse/CreateLogiHead.cpp
src/opm/output/eclipse/CreateUdqDims.cpp
src/opm/output/eclipse/WellDataSerializers.cpp
src/opm/output/eclipse/DoubHEAD.cpp
src/opm/output/eclipse/EclipseGridInspector.cpp
src/opm/output/eclipse/EclipseIO.cpp
src/opm/output/eclipse/InteHEAD.cpp
src/opm/output/eclipse/libECLRestart.cpp
src/opm/output/eclipse/LinearisedOutputTable.cpp
src/opm/output/eclipse/LoadRestart.cpp
src/opm/output/eclipse/LogiHEAD.cpp
@@ -230,13 +185,12 @@ if(ENABLE_ECL_OUTPUT)
src/opm/output/eclipse/Tables.cpp
src/opm/output/eclipse/RegionCache.cpp
src/opm/output/eclipse/RestartValue.cpp
src/opm/output/eclipse/WriteInit.cpp
src/opm/output/eclipse/WriteRFT.cpp
src/opm/output/data/Solution.cpp
)
endif()
list (APPEND TEST_SOURCE_FILES
tests/test_EclFile.cpp
tests/test_calculateCellVol.cpp
tests/test_cmp.cpp
tests/test_cubic.cpp
@@ -261,18 +215,15 @@ if(ENABLE_ECL_INPUT)
tests/parser/ConnectionTests.cpp
tests/parser/COMPSEGUnits.cpp
tests/parser/CopyRegTests.cpp
tests/parser/DeckValueTests.cpp
tests/parser/DeckTests.cpp
tests/parser/DynamicStateTests.cpp
tests/parser/DynamicVectorTests.cpp
tests/parser/Eclipse3DPropertiesTests.cpp
tests/parser/EclipseGridTests.cpp
tests/parser/EmbeddedPython.cpp
tests/parser/EqualRegTests.cpp
tests/parser/EventTests.cpp
tests/parser/FaceDirTests.cpp
tests/parser/FaultTests.cpp
tests/parser/FoamTests.cpp
tests/parser/FunctionalTests.cpp
tests/parser/GeomodifierTests.cpp
tests/parser/GridPropertyTests.cpp
@@ -286,11 +237,8 @@ if(ENABLE_ECL_INPUT)
tests/parser/OrderedMapTests.cpp
tests/parser/ParseContextTests.cpp
tests/parser/ParseContext_EXIT1.cpp
tests/parser/ParseDATAWithDefault.cpp
tests/parser/PYACTION.cpp
tests/parser/PORVTests.cpp
tests/parser/RawKeywordTests.cpp
tests/parser/ResinsightTest.cpp
tests/parser/RestartConfigTests.cpp
tests/parser/RockTableTests.cpp
tests/parser/RunspecTests.cpp
@@ -326,16 +274,14 @@ if(ENABLE_ECL_OUTPUT)
tests/test_AggregateGroupData.cpp
tests/test_AggregateMSWData.cpp
tests/test_AggregateConnectionData.cpp
tests/test_AggregateUDQData.cpp
tests/test_ArrayDimChecker.cpp
tests/test_CharArrayNullTerm.cpp
tests/test_EclipseIO.cpp
tests/test_DoubHEAD.cpp
tests/test_InteHEAD.cpp
tests/test_LinearisedOutputTable.cpp
tests/test_LogiHEAD.cpp
tests/test_OutputStream.cpp
tests/test_regionCache.cpp
tests/test_PaddedOutputString.cpp
tests/test_Restart.cpp
tests/test_RFT.cpp
tests/test_Solution.cpp
@@ -343,7 +289,9 @@ if(ENABLE_ECL_OUTPUT)
tests/test_Tables.cpp
tests/test_Wells.cpp
tests/test_WindowedArray.cpp
tests/test_restartwellinfo.cpp
tests/test_writenumwells.cpp
tests/test_serialize_ICON.cpp
tests/test_serialize_SCON.cpp
)
endif()
@@ -352,7 +300,6 @@ list (APPEND TEST_DATA_FILES
)
if(ENABLE_ECL_OUTPUT)
list (APPEND TEST_DATA_FILES
tests/expect-wdims.chldg.err.out
tests/expect-wdims.err.out
tests/FIRST_SIM.DATA
tests/FIRST_SIM_THPRES.DATA
@@ -365,30 +312,14 @@ if(ENABLE_ECL_OUTPUT)
tests/SUMMARY_EFF_FAC.DATA
tests/SPE1CASE1.DATA
tests/SPE1CASE1.SMSPEC
tests/SPE1CASE1A.SMSPEC
tests/SPE9_CP_PACKED.DATA
tests/SOFR_TEST.DATA
tests/UDQ_TEST_WCONPROD_IUAD-2.DATA
)
endif()
list (APPEND EXAMPLE_SOURCE_FILES
)
if(ENABLE_ECL_INPUT)
list (APPEND TEST_DATA_FILES
tests/ECLFILE.INIT
tests/ECLFILE.FINIT
tests/SPE1CASE1.EGRID
tests/SPE1CASE1.RFT
tests/SPE1_TESTCASE.UNRST
tests/SPE1_TESTCASE.FUNRST
tests/SPE1_TESTCASE.F0025
tests/SPE1_TESTCASE.X0025
tests/SPE1CASE1.UNSMRY
tests/SPE1CASE1A.UNSMRY
tests/SPE1CASE1_RST60.SMSPEC
tests/SPE1CASE1_RST60.UNSMRY
)
list (APPEND EXAMPLE_SOURCE_FILES
examples/opmi.cpp
examples/opmpack.cpp
@@ -409,6 +340,8 @@ if(ENABLE_ECL_INPUT)
endif()
list( APPEND PUBLIC_HEADER_FILES
examples/test_util/EclFile.hpp
examples/test_util/data/EclIOdata.hpp
opm/common/ErrorMacros.hpp
opm/common/Exceptions.hpp
opm/common/data/SimulationDataContainer.hpp
@@ -465,9 +398,7 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/Parser/ParserConst.hpp
opm/parser/eclipse/EclipseState/InitConfig/InitConfig.hpp
opm/parser/eclipse/EclipseState/InitConfig/Equil.hpp
opm/parser/eclipse/EclipseState/InitConfig/FoamConfig.hpp
opm/parser/eclipse/EclipseState/Util/Value.hpp
opm/parser/eclipse/EclipseState/Util/IOrderSet.hpp
opm/parser/eclipse/EclipseState/Util/OrderedMap.hpp
opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp
opm/parser/eclipse/EclipseState/Edit/EDITNNC.hpp
@@ -529,8 +460,6 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Tables/TableContainer.hpp
opm/parser/eclipse/EclipseState/Tables/AqutabTable.hpp
opm/parser/eclipse/EclipseState/Tables/PlyadsTable.hpp
opm/parser/eclipse/EclipseState/Tables/FoamadsTable.hpp
opm/parser/eclipse/EclipseState/Tables/FoammobTable.hpp
opm/parser/eclipse/EclipseState/Tables/PbvdTable.hpp
opm/parser/eclipse/EclipseState/Tables/SorwmisTable.hpp
opm/parser/eclipse/EclipseState/Tables/PlymaxTable.hpp
@@ -563,27 +492,21 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Aquifetp.hpp
opm/parser/eclipse/EclipseState/Schedule/Action/ActionAST.hpp
opm/parser/eclipse/EclipseState/Schedule/Action/ActionContext.hpp
opm/parser/eclipse/EclipseState/Schedule/Action/ActionResult.hpp
opm/parser/eclipse/EclipseState/Schedule/Action/Actdims.hpp
opm/parser/eclipse/EclipseState/Schedule/Action/Actions.hpp
opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.hpp
opm/parser/eclipse/EclipseState/Schedule/Action/Condition.hpp
opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.hpp
opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp
opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.hpp
opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/Connection.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/ProductionControls.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/InjectionControls.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/Well2.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellInjectionProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WList.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WListManager.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellEconProductionLimits.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellFoamProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellInjectionProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellPolymerProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellProductionProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellTracerProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellProductionProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellTestConfig.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellTestState.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp
@@ -592,14 +515,12 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Schedule/RFTConfig.hpp
opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp
opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/GuideRate.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateModel.hpp
opm/parser/eclipse/EclipseState/Schedule/Group.hpp
opm/parser/eclipse/EclipseState/Schedule/MessageLimits.hpp
opm/parser/eclipse/EclipseState/Schedule/Events.hpp
opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp
opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/GroupTree.hpp
opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp
opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp
opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp
@@ -613,11 +534,11 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQAssign.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQContext.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQConfig.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParams.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQWellSet.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunction.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunctionTable.hpp
@@ -625,44 +546,35 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/Deck/Deck.hpp
opm/parser/eclipse/Deck/Section.hpp
opm/parser/eclipse/Deck/DeckOutput.hpp
opm/parser/eclipse/Deck/DeckValue.hpp
opm/parser/eclipse/Deck/DeckKeyword.hpp
opm/parser/eclipse/Deck/DeckRecord.hpp
opm/parser/eclipse/Deck/UDAValue.hpp
opm/parser/eclipse/Python/Python.hpp)
opm/parser/eclipse/RawDeck/StarToken.hpp
opm/parser/eclipse/RawDeck/RawEnums.hpp
opm/parser/eclipse/RawDeck/RawRecord.hpp
opm/parser/eclipse/RawDeck/RawKeyword.hpp
opm/parser/eclipse/RawDeck/RawConsts.hpp)
endif()
if(ENABLE_ECL_OUTPUT)
list(APPEND PUBLIC_HEADER_FILES
opm/io/eclipse/EclFile.hpp
opm/io/eclipse/EclIOdata.hpp
opm/io/eclipse/EclOutput.hpp
opm/io/eclipse/EclUtil.hpp
opm/io/eclipse/EGrid.hpp
opm/io/eclipse/ERft.hpp
opm/io/eclipse/ERst.hpp
opm/io/eclipse/ESmry.hpp
opm/io/eclipse/PaddedOutputString.hpp
opm/io/eclipse/OutputStream.hpp
opm/output/data/Cells.hpp
opm/output/data/Solution.hpp
opm/output/data/Wells.hpp
opm/output/eclipse/VectorItems/connection.hpp
opm/output/eclipse/VectorItems/group.hpp
opm/output/eclipse/VectorItems/intehead.hpp
opm/output/eclipse/VectorItems/logihead.hpp
opm/output/eclipse/VectorItems/msw.hpp
opm/output/eclipse/VectorItems/tabdims.hpp
opm/output/eclipse/VectorItems/well.hpp
opm/output/eclipse/AggregateGroupData.hpp
opm/output/eclipse/AggregateConnectionData.hpp
opm/output/eclipse/AggregateMSWData.hpp
opm/output/eclipse/AggregateUDQData.hpp
opm/output/eclipse/AggregateWellData.hpp
opm/output/eclipse/CharArrayNullTerm.hpp
opm/output/eclipse/DoubHEAD.hpp
opm/output/eclipse/EclipseGridInspector.hpp
opm/output/eclipse/EclipseIO.hpp
opm/output/eclipse/EclipseIOUtil.hpp
opm/output/eclipse/InteHEAD.hpp
opm/output/eclipse/libECLRestart.hpp
opm/output/eclipse/LinearisedOutputTable.hpp
opm/output/eclipse/LogiHEAD.hpp
opm/output/eclipse/RegionCache.hpp
@@ -671,8 +583,6 @@ if(ENABLE_ECL_OUTPUT)
opm/output/eclipse/Summary.hpp
opm/output/eclipse/Tables.hpp
opm/output/eclipse/WindowedArray.hpp
opm/output/eclipse/WriteInit.hpp
opm/output/eclipse/WriteRFT.hpp
opm/output/eclipse/WriteRestartHelpers.hpp
opm/output/OutputWriter.hpp
)

View File

@@ -49,13 +49,15 @@ list(APPEND EXTRA_TESTS EclipseStateTests)
foreach (test BoxTest
CheckDeckValidity
EclipseGridCreateFromDeck
EDITNNCTests
EDITNNCTests
IncludeTest
IntegrationTests
IOConfigIntegrationTest
NNCTests
ParseKEYWORD
ParseDATAWithDefault
Polymer
ResinsightTest
ScheduleCreateFromDeck
TransMultIntegrationTests)
@@ -85,8 +87,6 @@ if(HAVE_OPM_TESTS)
${OPM_TESTS_ROOT}/spe3/SPE3CASE2.DATA
${OPM_TESTS_ROOT}/spe9/SPE9_CP.DATA
${OPM_TESTS_ROOT}/spe9/SPE9_CP_GROUP.DATA
${OPM_TESTS_ROOT}/spe9/SPE9_CP_SHORT.DATA
${OPM_TESTS_ROOT}/spe9/SPE9_CP_SHORT_RESTART.DATA
${OPM_TESTS_ROOT}/spe9/SPE9.DATA
${OPM_TESTS_ROOT}/spe10model1/SPE10_MODEL1.DATA
${OPM_TESTS_ROOT}/spe10model2/SPE10_MODEL2.DATA
@@ -96,7 +96,6 @@ if(HAVE_OPM_TESTS)
EXE_NAME parse_write
TEST_ARGS ${deck})
endforeach()
opm_add_test("SPE9_CP_GROUP2" NO_COMPILE EXE_NAME parse_write TEST_ARGS "${OPM_TESTS_ROOT}/spe9group/SPE9_CP_GROUP.DATA")
set_property(TEST NORNE_ATW2013
PROPERTY ENVIRONMENT "OPM_ERRORS_IGNORE=PARSE_RANDOM_SLASH")
endif()

View File

@@ -1,7 +1,5 @@
set(genkw_SOURCES src/opm/json/JsonObject.cpp
src/opm/parser/eclipse/Parser/createDefaultKeywordList.cpp
src/opm/parser/eclipse/Deck/UDAValue.cpp
src/opm/parser/eclipse/Deck/DeckValue.cpp
src/opm/parser/eclipse/Deck/Deck.cpp
src/opm/parser/eclipse/Deck/DeckItem.cpp
src/opm/parser/eclipse/Deck/DeckKeyword.cpp
@@ -15,9 +13,9 @@ set(genkw_SOURCES src/opm/json/JsonObject.cpp
src/opm/parser/eclipse/Parser/ParserItem.cpp
src/opm/parser/eclipse/Parser/ParserKeyword.cpp
src/opm/parser/eclipse/Parser/ParserRecord.cpp
src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp
src/opm/parser/eclipse/Parser/raw/RawRecord.cpp
src/opm/parser/eclipse/Parser/raw/StarToken.cpp
src/opm/parser/eclipse/RawDeck/RawKeyword.cpp
src/opm/parser/eclipse/RawDeck/RawRecord.cpp
src/opm/parser/eclipse/RawDeck/StarToken.cpp
src/opm/parser/eclipse/Units/Dimension.cpp
src/opm/parser/eclipse/Units/UnitSystem.cpp
src/opm/parser/eclipse/Utility/Stringview.cpp

View File

@@ -66,6 +66,10 @@ set (_opm_proj_exemptions
dune-fem
)
# although a DUNE module, it is delivered in the OPM suite
set (opm-core_SUITE "opm")
set (ewoms_SUITE "opm")
# insert this boilerplate whenever we are going to find a new package
macro (find_and_append_package_to prefix name)
# special handling for Boost to avoid inadvertedly picking up system
@@ -152,6 +156,9 @@ macro (find_and_append_package_to prefix name)
if ( (NOT DEFINED ${name}_FOUND AND NOT DEFINED ${NAME}_FOUND )
OR _search_components GREATER -1)
string(REGEX MATCH "(dune|opm)-.*" _is_opm ${name})
if(NOT _is_opm)
string(REGEX MATCH "ewoms" _is_opm ${name})
endif()
if(${name} STREQUAL "ecl")
# Give us a chance to find ecl installed to CMAKE_INSTALL_PREFIX.
# We need to deactivate the package registry for this.

View File

@@ -20,7 +20,6 @@
# - CMP0026 to allow access to the LOCATION target property
# - CMP0048 to indicate that we want to deal with the *VERSION*
# variables ourselves
# - CMP0064 to indicate that we want TEST if conditions to be evaluated
if (POLICY CMP0026)
cmake_policy(SET CMP0026 OLD)
endif()
@@ -29,10 +28,6 @@ if (POLICY CMP0048)
cmake_policy(SET CMP0048 OLD)
endif()
if(POLICY CMP0064)
cmake_policy(SET CMP0064 NEW)
endif()
# set the behavior of the policy 0054 to NEW. (i.e. do not implicitly
# expand variables in if statements)
if (POLICY CMP0054)
@@ -261,13 +256,9 @@ macro (cond_disable_test name)
endif ((NOT DEFINED HAVE_${name}) OR (NOT HAVE_${name}))
endmacro (cond_disable_test name)
# use this target to run all tests, with parallel execution
cmake_host_system_information(RESULT TESTJOBS QUERY NUMBER_OF_PHYSICAL_CORES)
if(TESTJOBS EQUAL 0)
set(TESTJOBS 1)
endif()
# use this target to run all tests
add_custom_target (check
COMMAND ${CMAKE_CTEST_COMMAND} -j${TESTJOBS}
COMMAND ${CMAKE_CTEST_COMMAND}
DEPENDS test-suite
COMMENT "Checking if library is functional"
VERBATIM

View File

@@ -162,7 +162,7 @@ macro (find_package_deps module)
# (i.e. if an optional package requests a package to be required,
# the build will fail if it's not found)
string (REPLACE "REQUIRED" "${_${module}_required}" _args_req "${_${module}_args}")
if(_dep MATCHES "opm-")
if(_dep MATCHES "opm-" OR _dep MATCHES "ewoms")
set(deplist ${_dep})
string(STRIP "${_dep}" _dep)
string(REPLACE " " ";" deplist "${_dep}")

View File

@@ -1,5 +1,8 @@
# - Build satellites that are dependent of main library
option(ADD_DISABLED_CTESTS "Add the tests which are disabled due to failed preconditions to the ctest output (this makes ctest return an error if such a test is present)" ON)
mark_as_advanced(ADD_DISABLED_CTESTS)
#
# Enumerate all source code in a "satellite" directory such as tests/,
# compile each of them and optionally set them as a test for CTest to
@@ -8,136 +11,144 @@
# The following suffices must be defined for the opm prefix passed as
# parameter:
#
# _LINKER_FLAGS Necessary flags to link with this library
# _TARGET CMake target which creates the library
# _LIBRARIES Other dependencies that must also be linked
# _LINKER_FLAGS Necessary flags to link with this library
# _TARGET CMake target which creates the library
# _LIBRARIES Other dependencies that must also be linked
# Synopsis:
# opm_compile_satellites (opm satellite excl_all test_regexp)
# opm_compile_satellites (opm satellite excl_all test_regexp)
#
# Parameters:
# opm Prefix of the variable which contain information
# about the library these satellites depends on, e.g.
# pass "opm-core" if opm-core_TARGET is the name of
# the target the builds this library. Variables with
# suffixes _TARGET and _LIBRARIES must exist.
# opm Prefix of the variable which contain information
# about the library these satellites depends on, e.g.
# pass "opm-core" if opm-core_TARGET is the name of
# the target the builds this library. Variables with
# suffixes _TARGET and _LIBRARIES must exist.
#
# satellite Prefix of variable which contain the names of the
# files, e.g. pass "tests" if the files are in the
# variable tests_SOURCES. Variables with suffixes
# _DATAFILES, _SOURCES and _DIR should exist. This
# name is also used as name of the target that builds
# all these files.
# satellite Prefix of variable which contain the names of the
# files, e.g. pass "tests" if the files are in the
# variable tests_SOURCES. Variables with suffixes
# _DATAFILES, _SOURCES and _DIR should exist. This
# name is also used as name of the target that builds
# all these files.
#
# excl_all EXCLUDE_FROM_ALL if these targets should not be built by
# default, otherwise empty string.
# excl_all EXCLUDE_FROM_ALL if these targets should not be built by
# default, otherwise empty string.
#
# test_regexp Regular expression which picks the name of a test
# out of the filename, or blank if no test should be
# setup.
# test_regexp Regular expression which picks the name of a test
# out of the filename, or blank if no test should be
# setup.
#
# Example:
# opm_compile_satellites (opm-core test "" "^test_([^/]*)$")
# opm_compile_satellites (opm-core test "" "^test_([^/]*)$")
#
macro (opm_compile_satellites opm satellite excl_all test_regexp)
# if we are going to build the tests always, then make sure that
# the datafiles are present too
if (NOT (${excl_all} MATCHES "EXCLUDE_FROM_ALL"))
set (_incl_all "ALL")
set (_incl_all "ALL")
else (NOT (${excl_all} MATCHES "EXCLUDE_FROM_ALL"))
set (_incl_all "")
set (_incl_all "")
endif (NOT (${excl_all} MATCHES "EXCLUDE_FROM_ALL"))
# if a set of datafiles has been setup, pull those in
add_custom_target (${satellite} ${_incl_all})
if (${satellite}_DATAFILES)
add_dependencies (${satellite} ${${satellite}_DATAFILES})
add_dependencies (${satellite} ${${satellite}_DATAFILES})
endif (${satellite}_DATAFILES)
# compile each of these separately
foreach (_sat_FILE IN LISTS ${satellite}_SOURCES)
get_filename_component (_sat_NAME "${_sat_FILE}" NAME_WE)
add_executable (${_sat_NAME} ${excl_all} ${_sat_FILE})
add_dependencies (${satellite} ${_sat_NAME})
set_target_properties (${_sat_NAME} PROPERTIES
LINK_FLAGS "${${opm}_LINKER_FLAGS_STR}")
if(HAVE_DYNAMIC_BOOST_TEST)
set_target_properties (${_sat_NAME} PROPERTIES
COMPILE_DEFINITIONS BOOST_TEST_DYN_LINK)
endif()
# are we building a test? luckily, the testing framework doesn't
# require anything else, so we don't have to figure out where it
# should go in the library list
if (NOT "${test_regexp}" STREQUAL "")
set (_test_lib "${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}")
else (NOT "${test_regexp}" STREQUAL "")
set (_test_lib "")
add_static_analysis_tests(_sat_FILE ${opm}_INCLUDE_DIRS)
endif (NOT "${test_regexp}" STREQUAL "")
target_link_libraries (${_sat_NAME} ${${opm}_TARGET} ${${opm}_LIBRARIES} ${_test_lib})
if (STRIP_DEBUGGING_SYMBOLS)
strip_debug_symbols (${_sat_NAME} _sat_DEBUG)
list (APPEND ${satellite}_DEBUG ${_sat_DEBUG})
endif()
# variable with regular expression doubles as a flag for
# whether tests should be setup or not
set(_sat_FANCY)
if (NOT "${test_regexp}" STREQUAL "")
foreach (_regexp IN ITEMS ${test_regexp})
if ("${_sat_NAME}" MATCHES "${_regexp}")
string (REGEX REPLACE "${_regexp}" "\\1" _sat_FANCY "${_sat_NAME}")
elseif(NOT _sat_FANCY)
set(_sat_FANCY ${_sat_NAME})
get_filename_component (_sat_NAME "${_sat_FILE}" NAME_WE)
add_executable (${_sat_NAME} ${excl_all} ${_sat_FILE})
add_dependencies (${satellite} ${_sat_NAME})
set_target_properties (${_sat_NAME} PROPERTIES
LINK_FLAGS "${${opm}_LINKER_FLAGS_STR}"
)
if(HAVE_DYNAMIC_BOOST_TEST)
set_target_properties (${_sat_NAME} PROPERTIES
COMPILE_DEFINITIONS BOOST_TEST_DYN_LINK
)
endif()
# are we building a test? luckily, the testing framework doesn't
# require anything else, so we don't have to figure out where it
# should go in the library list
if (NOT "${test_regexp}" STREQUAL "")
set (_test_lib "${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}")
else (NOT "${test_regexp}" STREQUAL "")
set (_test_lib "")
add_static_analysis_tests(_sat_FILE ${opm}_INCLUDE_DIRS)
endif (NOT "${test_regexp}" STREQUAL "")
target_link_libraries (${_sat_NAME} ${${opm}_TARGET} ${${opm}_LIBRARIES} ${_test_lib})
if (STRIP_DEBUGGING_SYMBOLS)
strip_debug_symbols (${_sat_NAME} _sat_DEBUG)
list (APPEND ${satellite}_DEBUG ${_sat_DEBUG})
endif()
endforeach (_regexp)
get_target_property (_sat_LOC ${_sat_NAME} LOCATION)
# Run tests through mpi-run. Ubuntu 14.04 provided mpi libs will crash
# in the MPI_Finalize() call otherwise.
if(MPI_FOUND)
set(_sat_LOC ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${_sat_LOC})
endif()
if (CMAKE_VERSION VERSION_LESS "2.8.4")
add_test (NAME ${_sat_FANCY}
COMMAND ${CMAKE_COMMAND} -E chdir "${PROJECT_BINARY_DIR}/${${satellite}_DIR}" ${_sat_LOC})
else (CMAKE_VERSION VERSION_LESS "2.8.4")
add_test (${_sat_FANCY} ${_sat_LOC})
# run the test in the directory where the data files are
set_tests_properties (${_sat_FANCY} PROPERTIES
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/${${satellite}_DIR})
endif (CMAKE_VERSION VERSION_LESS "2.8.4")
if(NOT TARGET test-suite)
add_custom_target(test-suite)
endif()
add_dependencies(test-suite "${_sat_NAME}")
endif(NOT "${test_regexp}" STREQUAL "")
# if this program on the list of files that should be distributed?
# we check by the name of the source file
list (FIND ${satellite}_SOURCES_DIST "${_sat_FILE}" _is_util)
if (NOT (_is_util EQUAL -1))
install (TARGETS ${_sat_NAME} RUNTIME
DESTINATION bin${${opm}_VER_DIR}/)
endif (NOT (_is_util EQUAL -1))
# variable with regular expression doubles as a flag for
# whether tests should be setup or not
set(_sat_FANCY)
if (NOT "${test_regexp}" STREQUAL "")
foreach (_regexp IN ITEMS ${test_regexp})
if ("${_sat_NAME}" MATCHES "${_regexp}")
string (REGEX REPLACE "${_regexp}" "\\1" _sat_FANCY "${_sat_NAME}")
elseif(NOT _sat_FANCY)
set(_sat_FANCY ${_sat_NAME})
endif()
endforeach (_regexp)
get_target_property (_sat_LOC ${_sat_NAME} LOCATION)
# Run tests through mpi-run. Ubuntu 14.04 provided mpi libs will crash
# in the MPI_Finalize() call otherwise.
if(MPI_FOUND)
set(_sat_LOC ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${_sat_LOC})
endif()
if (CMAKE_VERSION VERSION_LESS "2.8.4")
add_test (
NAME ${_sat_FANCY}
COMMAND ${CMAKE_COMMAND} -E chdir "${PROJECT_BINARY_DIR}/${${satellite}_DIR}" ${_sat_LOC}
)
else (CMAKE_VERSION VERSION_LESS "2.8.4")
add_test (${_sat_FANCY} ${_sat_LOC})
# run the test in the directory where the data files are
set_tests_properties (${_sat_FANCY} PROPERTIES
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/${${satellite}_DIR}
)
endif (CMAKE_VERSION VERSION_LESS "2.8.4")
if(NOT TARGET test-suite)
add_custom_target(test-suite)
endif()
add_dependencies(test-suite "${_sat_NAME}")
endif(NOT "${test_regexp}" STREQUAL "")
# if this program on the list of files that should be distributed?
# we check by the name of the source file
list (FIND ${satellite}_SOURCES_DIST "${_sat_FILE}" _is_util)
if (NOT (_is_util EQUAL -1))
install (TARGETS ${_sat_NAME} RUNTIME
DESTINATION bin${${opm}_VER_DIR}/
)
endif (NOT (_is_util EQUAL -1))
endforeach (_sat_FILE)
endmacro (opm_compile_satellites opm prefix)
# Synopsis:
# opm_data (satellite target dirname files)
# opm_data (satellite target dirname files)
#
# provides these output variables:
#
# ${satellite}_INPUT_FILES List of all files that are copied
# ${satellite}_DATAFILES Name of target which copies these files
# ${satellite}_INPUT_FILES List of all files that are copied
# ${satellite}_DATAFILES Name of target which copies these files
#
# Example:
#
# opm_data (tests datafiles "tests/")
# opm_data (tests datafiles "tests/")
#
macro (opm_data satellite target dirname)
# even if there are no datafiles, create the directory so the
# satellite programs have a homedir to run in
execute_process (COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${dirname})
execute_process (
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${dirname}
)
# if ever huge test datafiles are necessary, then change this
# into "create_symlink" (on UNIX only, apparently)
@@ -147,27 +158,26 @@ macro (opm_data satellite target dirname)
# to a tests/ directory in the output tree (if different)
set (${satellite}_INPUT_FILES)
if (NOT PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
foreach (input_datafile IN LISTS ${satellite}_DATA)
if (IS_ABSOLUTE ${input_datafile})
file (RELATIVE_PATH rel_datafile "${PROJECT_SOURCE_DIR}" ${input_datafile})
else()
set(rel_datafile ${input_datafile})
endif()
set (output_datafile "${PROJECT_BINARY_DIR}/${rel_datafile}")
add_custom_command (OUTPUT ${output_datafile}
COMMAND ${CMAKE_COMMAND}
ARGS -E ${make_avail} ${input_datafile} ${output_datafile}
DEPENDS ${input_datafile}
VERBATIM)
list (APPEND ${satellite}_INPUT_FILES "${output_datafile}")
endforeach (input_datafile)
foreach (input_datafile IN LISTS ${satellite}_DATA)
file (RELATIVE_PATH rel_datafile "${PROJECT_SOURCE_DIR}" ${input_datafile})
set (output_datafile "${PROJECT_BINARY_DIR}/${rel_datafile}")
add_custom_command (
OUTPUT ${output_datafile}
COMMAND ${CMAKE_COMMAND}
ARGS -E ${make_avail} ${input_datafile} ${output_datafile}
DEPENDS ${input_datafile}
VERBATIM
)
list (APPEND ${satellite}_INPUT_FILES "${output_datafile}")
endforeach (input_datafile)
endif(NOT PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
# setup a target which does all the copying
set (${satellite}_DATAFILES "${target}")
add_custom_target (${${satellite}_DATAFILES}
DEPENDS ${${satellite}_INPUT_FILES}
COMMENT "Making \"${satellite}\" data available in output tree")
DEPENDS ${${satellite}_INPUT_FILES}
COMMENT "Making \"${satellite}\" data available in output tree"
)
if(NOT TARGET test-suite)
add_custom_target(test-suite)
endif()
@@ -299,8 +309,6 @@ macro(opm_add_test TestName)
# only compile the binary but do not run it as a test
add_executable("${CURTEST_EXE_NAME}" ${CURTEST_EXCLUDE_FROM_ALL} ${CURTEST_SOURCES})
target_link_libraries (${CURTEST_EXE_NAME} ${CURTEST_LIBRARIES})
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
add_static_analysis_tests(CURTEST_SOURCES dirs)
if(TARGET ${project}_prepare)
add_dependencies("${CURTEST_EXE_NAME}" ${project}_prepare)
@@ -316,11 +324,10 @@ macro(opm_add_test TestName)
add_executable("${CURTEST_EXE_NAME}" ${CURTEST_EXCLUDE_FROM_ALL} ${CURTEST_SOURCES})
if(HAVE_DYNAMIC_BOOST_TEST)
set_target_properties (${CURTEST_EXE_NAME} PROPERTIES
COMPILE_DEFINITIONS BOOST_TEST_DYN_LINK)
endif()
COMPILE_DEFINITIONS BOOST_TEST_DYN_LINK
)
endif()
target_link_libraries (${CURTEST_EXE_NAME} ${CURTEST_LIBRARIES})
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
add_static_analysis_tests(CURTEST_SOURCES dirs)
if(CURTEST_DEPENDS)
add_dependencies("${CURTEST_EXE_NAME}" ${CURTEST_DEPENDS})
@@ -363,6 +370,15 @@ macro(opm_add_test TestName)
endif()
add_dependencies(test-suite "${CURTEST_EXE_NAME}")
endif()
else() # test is skipped
# the following causes the test to appear as 'skipped' in the
# CDash dashboard. it this is removed, the test is just silently
# ignored.
if (NOT CURTEST_ONLY_COMPILE AND ADD_DISABLED_CTESTS)
add_test(${_FANCY} skip_test_dummy)
endif()
endif()
endmacro()

View File

@@ -34,29 +34,16 @@ function(add_static_analysis_tests sources includes)
list(APPEND IPATHS -I ${dep})
endforeach()
foreach(src ${${sources}})
if(src MATCHES "TARGET_OBJECTS:")
string(REGEX REPLACE "\\$<TARGET_OBJECTS:(.*)>" "\\1" TGT ${src})
get_target_property(src ${TGT} SOURCES)
endif()
if(IS_ABSOLUTE ${src})
file(RELATIVE_PATH name ${PROJECT_SOURCE_DIR} ${src})
else()
set(name ${src})
set(src ${PROJECT_SOURCE_DIR}/${src})
endif()
file(RELATIVE_PATH name ${PROJECT_SOURCE_DIR} ${src})
if(CPPCHECK_FOUND)
if(NOT TEST cppcheck+${name})
add_test(NAME cppcheck+${name}
COMMAND bin/cppcheck-test.sh ${CPPCHECK_PROGRAM} ${src} ${IPATHS}
CONFIGURATIONS analyze cppcheck)
endif()
add_test(NAME cppcheck+${name}
COMMAND bin/cppcheck-test.sh ${CPPCHECK_PROGRAM} ${src} ${IPATHS}
CONFIGURATIONS analyze cppcheck)
endif()
if(CLANGCHECK_FOUND AND CMAKE_EXPORT_COMPILE_COMMANDS)
if(NOT TEST clang-check+${name})
add_test(NAME clang-check+${name}
COMMAND bin/clang-check-test.sh ${CLANGCHECK_PROGRAM} ${src}
CONFIGURATIONS analyze clang-check)
endif()
add_test(NAME clang-check+${name}
COMMAND bin/clang-check-test.sh ${CLANGCHECK_PROGRAM} ${src}
CONFIGURATIONS analyze clang-check)
endif()
endforeach()
endif()

View File

@@ -6,7 +6,7 @@ is_compiler_gcc_compatible ()
if (CXX_COMPAT_GCC)
# default warnings flags, if not set by user
set_default_option (CXX _warn_flag "-Wall -Wextra -Wshadow" "(^|\ )-W")
set_default_option (CXX _warn_flag "-Wall" "(^|\ )-W")
if (_warn_flag)
message (STATUS "All warnings enabled: ${_warn_flag}")
add_options (ALL_LANGUAGES ALL_BUILDS "${_warn_flag}")

View File

@@ -31,15 +31,30 @@ if(NOT check_target)
endif()
# Build threads
include(ProcessorCount)
set(build_threads $ENV{CHECK_THREADS})
if(NOT build_threads)
ProcessorCount(build_threads)
if(build_threads EQUAL 0)
set(build_threads 1)
if(UNIX)
if(APPLE)
execute_process(COMMAND sysctl hw.ncpu
OUTPUT_VARIABLE build_threads)
string(REPLACE " " ";" build_threads_list ${build_threads)
list(GET build_threads_list 1 build_threads)
else()
find_program(NPROC_COMMAND nproc)
if(NPROC_COMMAND)
execute_process(COMMAND ${NPROC_COMMAND}
OUTPUT_VARIABLE build_threads)
string(REGEX REPLACE "(\r?\n)+$" "" build_threads "${build_threads}")
endif()
endif()
endif()
endif()
# If for some reason we could not find the info - e.g. centos5 where nproc is missing
if(NOT build_threads)
set(build_threads 1)
endif()
# Record current HEAD
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
OUTPUT_VARIABLE current_branch

2
debian/changelog vendored
View File

@@ -1,4 +1,4 @@
opm-common (2019.04-pre~xenial) xenial; urgency=medium
opm-common (2019.04-rfinal-1~xenial) xenial; urgency=medium
* New release

View File

@@ -5,8 +5,8 @@
Module: opm-common
Description: Open Porous Media Initiative shared infrastructure
Version: 2019.10-pre
Label: 2019.10-pre
Version: 2019.04
Label: 2019.04
Maintainer: opm@opm-project.org
MaintainerName: OPM community
Url: http://opm-project.org

View File

@@ -48,6 +48,6 @@ int main(int /* argc */, char** argv) {
Opm::msim msim(state);
Opm::EclipseIO io(state, state.getInputGrid(), schedule, summary_config);
msim.run(schedule, io, false);
msim.run(schedule, io);
}

View File

@@ -33,12 +33,11 @@
struct keyword {
keyword(const std::string& name_arg, const std::string& filename_arg,
std::size_t line_number_arg, std::size_t content_hash_arg) :
name(name_arg),
filename(filename_arg),
line_number(line_number_arg),
content_hash(content_hash_arg)
keyword(const std::string& name, const std::string& filename, std::size_t line_number, std::size_t content_hash) :
name(name),
filename(filename),
line_number(line_number),
content_hash(content_hash)
{}

View File

@@ -28,15 +28,6 @@
#include <opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/common/OpmLog/StreamLog.hpp>
#include <opm/common/OpmLog/LogUtil.hpp>
void initLogging() {
std::shared_ptr<Opm::StreamLog> cout_log = std::make_shared<Opm::StreamLog>(std::cout, Opm::Log::DefaultMessageTypes);
Opm::OpmLog::addBackend( "COUT" , cout_log);
}
inline void loadDeck( const char * deck_file) {
Opm::ParseContext parseContext;
@@ -54,7 +45,6 @@ inline void loadDeck( const char * deck_file) {
int main(int argc, char** argv) {
initLogging();
for (int iarg = 1; iarg < argc; iarg++)
loadDeck( argv[iarg] );
}

View File

@@ -0,0 +1,505 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string>
#include <string.h>
#include <sstream>
#include <iterator>
#include <iomanip>
#include <algorithm>
#include "EclFile.hpp"
// anonymous namespace for EclFile
namespace {
bool isEOF(std::fstream *fileH){
/* try to read 4 byte (integer), if passed eof of, return true.
if not, seek back to current file possition */
int num;
long int pos=fileH->tellg();
fileH->read((char *)&num, sizeof(num));
if (fileH->eof()){
return true;
} else {
fileH->seekg (pos);
return false;
}
}
int flipEndianInt(const int &num) {
unsigned int tmp=__builtin_bswap32(num);
return (int)tmp;
}
float flipEndianFloat(const float &num) {
float value=num;
char *floatToConvert = reinterpret_cast<char*>(&value);
std::reverse(floatToConvert, floatToConvert+4);
return value;
}
double flipEndianDouble(const double &num) {
double value=num;
char *doubleToConvert = reinterpret_cast<char*>(&value);
std::reverse(doubleToConvert, doubleToConvert+8);
return value;
}
std::tuple<const int, const int> block_size_data(EIOD::eclArrType arrType){
switch(arrType) {
case EIOD::INTE : return std::make_tuple(EIOD::sizeOfInte,EIOD::MaxBlockSizeInte); break;
case EIOD::REAL : return std::make_tuple(EIOD::sizeOfReal,EIOD::MaxBlockSizeReal); break;
case EIOD::DOUB : return std::make_tuple(EIOD::sizeOfDoub,EIOD::MaxBlockSizeDoub); break;
case EIOD::LOGI : return std::make_tuple(EIOD::sizeOfLogi,EIOD::MaxBlockSizeLogi); break;
case EIOD::CHAR : return std::make_tuple(EIOD::sizeOfChar,EIOD::MaxBlockSizeChar); break;
case EIOD::MESS : throw std::invalid_argument("Type 'MESS' have not assosiated data") ; break;
default : throw std::invalid_argument("Unknown type"); break;
}
}
std::string trimr(const std::string &str1) {
std::string tmpStr=str1;
while (tmpStr.back()==' '){
tmpStr.pop_back();
}
return std::move(tmpStr);
}
void readBinaryHeader(std::fstream &fileH, std::string &arrName, int &size, EIOD::eclArrType &arrType){
int bhead;
std::string tmpStrName(8,' ');
std::string tmpStrType(4,' ');
if (!fileH.is_open()){
std::string message="fstream fileH not open for reading";
throw std::runtime_error(message);
}
fileH.read((char *)&bhead, sizeof(bhead));
bhead=flipEndianInt(bhead);
if (bhead!=16){
std::string message="Error reading binary header. Expected 16 bytes of header data, found " + std::to_string(bhead);
throw std::runtime_error(message);
}
fileH.read(&tmpStrName[0], 8);
fileH.read((char *)&size, sizeof(size));
size=flipEndianInt(size);
fileH.read(&tmpStrType[0], 4);
fileH.read((char *)&bhead, sizeof(bhead));
bhead=flipEndianInt(bhead);
if (bhead!=16){
std::string message="Error reading binary header. Expected 16 bytes of header data, found " + std::to_string(bhead);
throw std::runtime_error(message);
}
arrName=tmpStrName;
if (tmpStrType=="INTE")
arrType=EIOD::INTE;
else if (tmpStrType=="REAL")
arrType=EIOD::REAL;
else if (tmpStrType=="DOUB")
arrType=EIOD::DOUB;
else if (tmpStrType=="CHAR")
arrType=EIOD::CHAR;
else if (tmpStrType=="LOGI")
arrType=EIOD::LOGI;
else if (tmpStrType=="MESS")
arrType=EIOD::MESS;
else
throw std::runtime_error("Error, unknown array type '" + tmpStrType +"'");
}
unsigned long int sizeOnDisk(const int num, const EIOD::eclArrType &arrType){
unsigned long int size=0;
if (arrType==EIOD::MESS){
if (num>0) {
std::string message="In routine calcSizeOfArray, type MESS can not have size > 0";
throw std::invalid_argument(message);
}
} else {
auto sizeData = block_size_data(arrType);
int sizeOfElement = std::get<0>(sizeData);
int maxBlockSize = std::get<1>(sizeData);
int maxNumberOfElements=maxBlockSize/sizeOfElement;
size=num*sizeOfElement;
size=size + ((num-1) / maxNumberOfElements)*2*EIOD::sizeOfInte; // 8 byte (two integers) every 1000 element
if (num>0){
size=size+2*EIOD::sizeOfInte;
}
}
return size;
}
std::vector<int> readBinaryInteArray(std::fstream &fileH, const int size){
std::vector<int> arr;
int rest=size;
auto sizeData = block_size_data(EIOD::INTE);
int sizeOfElement = std::get<0>(sizeData);
int maxBlockSize = std::get<1>(sizeData);
int maxNumberOfElements=maxBlockSize/sizeOfElement;
arr.reserve(size);
if (!fileH.is_open()){
std::string message="fstream fileH not open for reading";
throw std::runtime_error(message);
}
while (rest > 0) {
int num,dhead,dtail;
fileH.read((char *)&dhead, sizeof(dhead));
dhead=flipEndianInt(dhead);
num=dhead/sizeOfElement;
if ((num > maxNumberOfElements) || (num < 0)){
std::string message="Error reading binary inte data, inconsistent header data or incorrect number of elements";
throw std::runtime_error(message);
}
for (int i=0;i<num;i++){
int value;
fileH.read((char *)&value, sizeOfElement);
value=flipEndianInt(value);
arr.push_back(value);
}
rest=rest-num;
if (((num < maxNumberOfElements) && (rest!=0)) || ((num==maxNumberOfElements) && (rest < 0))) {
std::string message="Error reading binary integer data, incorrect number of elements";
throw std::runtime_error(message);
}
fileH.read((char *)&dtail, sizeof(dtail));
dtail=flipEndianInt(dtail);
if (dhead!=dtail){
std::string message="Error reading binary real data, tail not matching header.";
throw std::runtime_error(message);
}
}
return arr;
}
std::vector<float> readBinaryRealArray(std::fstream &fileH, const int size){
std::vector<float> arr;
arr.reserve(size);
auto sizeData = block_size_data(EIOD::REAL);
int sizeOfElement = std::get<0>(sizeData);
int maxBlockSize = std::get<1>(sizeData);
int maxNumberOfElements=maxBlockSize/sizeOfElement;
if (!fileH.is_open()){
std::string message="fstream fileH not open for reading";
throw std::runtime_error(message);
}
int rest=size;
while (rest > 0) {
int num,dhead,dtail;
fileH.read((char *)&dhead, sizeof(dhead));
dhead=flipEndianInt(dhead);
num=dhead/sizeOfElement;
if ((num > maxNumberOfElements) || (num < 0)){
std::string message="Error reading binary real data, inconsistent header data or incorrect number of elements";
throw std::runtime_error(message);
}
for (int i=0;i<num;i++){
float value;
fileH.read((char *)&value, sizeOfElement);
value=flipEndianFloat(value);
arr.push_back(value);
}
rest=rest-num;
if (((num < maxNumberOfElements) && (rest!=0)) || ((num==maxNumberOfElements) && (rest < 0))) {
std::string message="Error reading binary real data, incorrect number of elements";
throw std::runtime_error(message);
}
fileH.read((char *)&dtail, sizeof(dtail));
dtail=flipEndianInt(dtail);
if (dhead!=dtail){
std::string message="Error reading binary real data, tail not matching header.";
throw std::runtime_error(message);
}
}
return arr;
}
std::vector<double> readBinaryDoubArray(std::fstream &fileH, const int size){
std::vector<double> arr;
arr.reserve(size);
auto sizeData = block_size_data(EIOD::DOUB);
int sizeOfElement = std::get<0>(sizeData);
int maxBlockSize = std::get<1>(sizeData);
int maxNumberOfElements=maxBlockSize/sizeOfElement;
if (!fileH.is_open()){
std::string message="fstream fileH not open for reading";
throw std::runtime_error(message);
}
int rest=size;
while (rest > 0) {
int num,dhead,dtail;
fileH.read((char *)&dhead, sizeof(dhead));
dhead=flipEndianInt(dhead);
num=dhead/sizeOfElement;
if ((num > maxNumberOfElements) || (num < 0)){
std::string message="Error reading binary doub data, inconsistent header data or incorrect number of elements";
throw std::runtime_error(message);
}
for (int i=0;i<num;i++){
double value;
fileH.read((char *)&value, sizeOfElement);
value=flipEndianDouble(value);
arr.push_back(value);
}
rest=rest-num;
if (((num < maxNumberOfElements) && (rest!=0)) || ((num==maxNumberOfElements) && (rest < 0))) {
std::string message="Error reading binary doub data, incorrect number of elements";
throw std::runtime_error(message);
}
fileH.read((char *)&dtail, sizeof(dtail));
dtail=flipEndianInt(dtail);
if (dhead!=dtail){
std::string message="Error reading binary doub data, tail not matching header.";
throw std::runtime_error(message);
}
}
return arr;
}
std::vector<bool> readBinaryLogiArray(std::fstream &fileH, const int size){
std::vector<bool> arr;
arr.reserve(size);
int rest=size;
auto sizeData = block_size_data(EIOD::LOGI);
int sizeOfElement = std::get<0>(sizeData);
int maxBlockSize = std::get<1>(sizeData);
int maxNumberOfElements=maxBlockSize/sizeOfElement;
if (!fileH.is_open()){
std::string message="fstream fileH not open for reading";
throw std::runtime_error(message);
}
while (rest > 0) {
int num,dhead,dtail;
fileH.read((char *)&dhead, sizeof(dhead));
dhead=flipEndianInt(dhead);
num=dhead/sizeOfElement;
if ((num > maxNumberOfElements) || (num < 0)){
std::string message="This ?? Error reading binary logi data, inconsistent header data or incorrect number of elements";
throw std::runtime_error(message);
}
for (int i=0;i<num;i++){
bool value;
unsigned int intVal;
fileH.read((char *)&intVal, sizeOfElement);
if (intVal==EIOD::true_value){
value=true;
} else if (intVal==EIOD::false_value){
value=false;
} else {
std::string message="Error reading log value from element " + std::to_string(i);
throw std::runtime_error(message);
}
arr.push_back(value);
}
rest=rest-num;
if (((num < maxNumberOfElements) && (rest!=0)) || ((num==maxNumberOfElements) && (rest < 0))) {
std::string message="Error reading binary logi data, incorrect number of elements";
throw std::runtime_error(message);
}
fileH.read((char *)&dtail, sizeof(dtail));
dtail=flipEndianInt(dtail);
if (dhead!=dtail){
std::string message="Error reading binary logi data, tail not matching header.";
throw std::runtime_error(message);
}
}
return arr;
}
std::vector<std::string> readBinaryCharArray(std::fstream &fileH, const int size){
std::vector<std::string> arr;
arr.reserve(size);
int rest=size;
auto sizeData = block_size_data(EIOD::CHAR);
int sizeOfElement = std::get<0>(sizeData);
int maxBlockSize = std::get<1>(sizeData);
int maxNumberOfElements=maxBlockSize/sizeOfElement;
if (!fileH.is_open()){
std::string message="fstream fileH not open for reading";
throw std::runtime_error(message);
}
while (rest > 0) {
int num,dhead,dtail;
fileH.read((char *)&dhead, sizeof(dhead));
dhead=flipEndianInt(dhead);
num=dhead/sizeOfElement;
if ((num > maxNumberOfElements) || (num < 0)){
std::string message="Error reading binary char data, inconsistent header data or incorrect number of elements";
throw std::runtime_error(message);
}
for (int i=0;i<num;i++){
std::string str8(8,' ');
fileH.read(&str8[0], sizeOfElement);
arr.push_back(trimr(str8));
}
rest=rest-num;
if ((num < maxNumberOfElements) && (rest!=0)){
std::string message="Error reading binary char data, incorrect number of elements";
throw std::runtime_error(message);
}
fileH.read((char *)&dtail, sizeof(dtail));
dtail=flipEndianInt(dtail);
if (dhead!=dtail){
std::string message="Error reading binary char data, tail not matching header.";
throw std::runtime_error(message);
}
}
return arr;
}
} // anonymous namespace
EclFile::EclFile(const std::string& filename){
std::fstream fileH;
fileH.open(filename, std::ios::in | std::ios::binary);
if (!fileH.good()) {
std::string message="Could not open file";
throw std::runtime_error(message);
}
fileH.close();
}

View File

@@ -16,25 +16,26 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_ECLUTIL_HPP
#define OPM_IO_ECLUTIL_HPP
#include <opm/io/eclipse/EclIOdata.hpp>
//#include "EclIO.hpp"
#include <iostream>
#include <string>
#include <tuple>
#include <fstream>
#include <vector>
#include <ctime>
#include <map>
namespace Opm { namespace EclIO {
#include <examples/test_util/data/EclIOdata.hpp>
int flipEndianInt(int num);
float flipEndianFloat(float num);
double flipEndianDouble(double num);
namespace EIOD = Opm::ecl;
std::tuple<int, int> block_size_data_binary(eclArrType arrType);
std::tuple<int, int, int> block_size_data_formatted(eclArrType arrType);
class EclFile
{
std::string trimr(const std::string &str1);
public:
explicit EclFile(const std::string& filename);
};
}} // namespace Opm::EclIO
#endif // OPM_IO_ECLUTIL_HPP

View File

@@ -0,0 +1,300 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "EclFilesComparator.hpp"
#include <opm/common/ErrorMacros.hpp>
#include <opm/common/utility/numeric/calculateCellVol.hpp>
#include <stdio.h>
#include <set>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <numeric>
#include <ert/ecl/ecl_file.h>
#include <ert/ecl/ecl_grid.h>
#include <ert/ecl/ecl_type.h>
#include <ert/ecl_well/well_info.h>
// helper macro to handle error throws or not
#define HANDLE_ERROR(type, message) \
{ \
if (throwOnError) \
OPM_THROW(type, message); \
else { \
std::cerr << message << std::endl; \
++num_errors; \
} \
}
namespace {
/*
This is just a basic survival test; we verify that the ERT well
loader which is used in Resinsight can load the well description
from the restart file.
*/
void loadWells( const ecl_grid_type * grid , ecl_file_type * rst_file ) {
well_info_type * well_info = well_info_alloc( grid );
well_info_add_UNRST_wells2( well_info , ecl_file_get_global_view( rst_file ), true );
well_info_free( well_info );
}
}
void ECLFilesComparator::keywordValidForComparing(const std::string& keyword) const {
auto it = std::find(keywords1.begin(), keywords1.end(), keyword);
if (it == keywords1.end()) {
OPM_THROW(std::runtime_error, "Keyword " << keyword << " does not exist in first file.");
}
it = find(keywords2.begin(), keywords2.end(), keyword);
if (it == keywords2.end()) {
OPM_THROW(std::runtime_error, "Keyword " << keyword << " does not exist in second file.");
}
}
unsigned int ECLFilesComparator::getEclKeywordData(ecl_kw_type*& ecl_kw1, ecl_kw_type*& ecl_kw2, const std::string& keyword, int occurrence1, int occurrence2) const {
ecl_kw1 = ecl_file_iget_named_kw(ecl_file1, keyword.c_str(), occurrence1);
ecl_kw2 = ecl_file_iget_named_kw(ecl_file2, keyword.c_str(), occurrence2);
const unsigned int numCells1 = ecl_kw_get_size(ecl_kw1);
const unsigned int numCells2 = ecl_kw_get_size(ecl_kw2);
if (numCells1 != numCells2) {
OPM_THROW(std::runtime_error, "For keyword " << keyword << ":"
<< "\nOccurrence in first file " << occurrence1
<< "\nOccurrence in second file " << occurrence2
<< "\nCells in first file: " << numCells1
<< "\nCells in second file: " << numCells2
<< "\nThe number of cells differ.");
}
return numCells1;
}
template <typename T>
void ECLFilesComparator::printValuesForCell(const std::string& /*keyword*/, int occurrence1, int occurrence2, size_t kw_size, size_t cell, const T& value1, const T& value2) const {
if (kw_size == static_cast<size_t>(ecl_grid_get_active_size(ecl_grid1))) {
int i, j, k;
ecl_grid_get_ijk1A(ecl_grid1, cell, &i, &j, &k);
// Coordinates from this function are zero-based, hence incrementing
i++, j++, k++;
std::cout << std::endl
<< "Occurrence in first file = " << occurrence1 << "\n"
<< "Occurrence in second file = " << occurrence2 << "\n"
<< "Value index = " << cell << "\n"
<< "Grid coordinate = (" << i << ", " << j << ", " << k << ")" << "\n"
<< "(first value, second value) = (" << value1 << ", " << value2 << ")\n\n";
return;
}
if (kw_size == static_cast<size_t>(ecl_grid_get_global_size(ecl_grid1))) {
int i, j, k;
ecl_grid_get_ijk1(ecl_grid1, cell, &i, &j, &k);
// Coordinates from this function are zero-based, hence incrementing
i++, j++, k++;
std::cout << std::endl
<< "Occurrence in first file = " << occurrence1 << "\n"
<< "Occurrence in second file = " << occurrence2 << "\n"
<< "Value index = " << cell << "\n"
<< "Grid coordinate = (" << i << ", " << j << ", " << k << ")" << "\n"
<< "(first value, second value) = (" << value1 << ", " << value2 << ")\n\n";
return;
}
std::cout << std::endl
<< "Occurrence in first file = " << occurrence1 << "\n"
<< "Occurrence in second file = " << occurrence2 << "\n"
<< "Value index = " << cell << "\n"
<< "(first value, second value) = (" << value1 << ", " << value2 << ")\n\n";
}
template void ECLFilesComparator::printValuesForCell<bool> (const std::string& keyword, int occurrence1, int occurrence2, size_t kw_size, size_t cell, const bool& value1, const bool& value2) const;
template void ECLFilesComparator::printValuesForCell<int> (const std::string& keyword, int occurrence1, int occurrence2, size_t kw_size, size_t cell, const int& value1, const int& value2) const;
template void ECLFilesComparator::printValuesForCell<double> (const std::string& keyword, int occurrence1, int occurrence2, size_t kw_size, size_t cell, const double& value1, const double& value2) const;
template void ECLFilesComparator::printValuesForCell<std::string>(const std::string& keyword, int occurrence1, int occurrence2, size_t kw_size, size_t cell, const std::string& value1, const std::string& value2) const;
ECLFilesComparator::ECLFilesComparator(int file_type_arg, const std::string& basename1,
const std::string& basename2,
double absToleranceArg, double relToleranceArg) :
file_type(file_type_arg), absTolerance(absToleranceArg), relTolerance(relToleranceArg) {
std::string file1, file2;
if (file_type == ECL_UNIFIED_RESTART_FILE) {
file1 = basename1 + ".UNRST";
file2 = basename2 + ".UNRST";
}
else if (file_type == ECL_INIT_FILE) {
file1 = basename1 + ".INIT";
file2 = basename2 + ".INIT";
}
else if (file_type == ECL_RFT_FILE) {
file1 = basename1 + ".RFT";
file2 = basename2 + ".RFT";
}
else {
OPM_THROW(std::invalid_argument, "Unsupported filetype sent to ECLFilesComparator's constructor."
<< "Only unified restart (.UNRST), initial (.INIT) and .RFT files are supported.");
}
ecl_file1 = ecl_file_open(file1.c_str(), 0);
ecl_file2 = ecl_file_open(file2.c_str(), 0);
ecl_grid1 = ecl_grid_load_case(basename1.c_str());
ecl_grid2 = ecl_grid_load_case(basename2.c_str());
if (ecl_file1 == nullptr) {
OPM_THROW(std::invalid_argument, "Error opening first file: " << file1);
}
if (ecl_file2 == nullptr) {
OPM_THROW(std::invalid_argument, "Error opening second file: " << file2);
}
if (ecl_grid1 == nullptr) {
OPM_THROW(std::invalid_argument, "Error opening first grid file: " << basename1);
}
if (ecl_grid2 == nullptr) {
OPM_THROW(std::invalid_argument, "Error opening second grid file. " << basename2);
}
unsigned int numKeywords1 = ecl_file_get_num_distinct_kw(ecl_file1);
unsigned int numKeywords2 = ecl_file_get_num_distinct_kw(ecl_file2);
keywords1.reserve(numKeywords1);
keywords2.reserve(numKeywords2);
for (unsigned int i = 0; i < numKeywords1; ++i) {
std::string keyword(ecl_file_iget_distinct_kw(ecl_file1, i));
keywords1.push_back(keyword);
}
for (unsigned int i = 0; i < numKeywords2; ++i) {
std::string keyword(ecl_file_iget_distinct_kw(ecl_file2, i));
keywords2.push_back(keyword);
}
if (file_type == ECL_UNIFIED_RESTART_FILE) {
loadWells( ecl_grid1 , ecl_file1 );
loadWells( ecl_grid2 , ecl_file2 );
}
}
ECLFilesComparator::~ECLFilesComparator() {
ecl_file_close(ecl_file1);
ecl_file_close(ecl_file2);
ecl_grid_free(ecl_grid1);
ecl_grid_free(ecl_grid2);
}
void ECLFilesComparator::printKeywords() const {
std::cout << "\nKeywords in the first file:\n";
for (const auto& it : keywords1) {
std::cout << std::setw(15) << std::left << it << " of type " << ecl_type_get_name( ecl_file_iget_named_data_type(ecl_file1, it.c_str(), 0)) << std::endl;
}
std::cout << "\nKeywords in second file:\n";
for (const auto& it : keywords2) {
std::cout << std::setw(15) << std::left << it << " of type " << ecl_type_get_name( ecl_file_iget_named_data_type(ecl_file2, it.c_str(), 0)) << std::endl;
}
}
void ECLFilesComparator::printKeywordsDifference() const {
std::vector<std::string> common;
std::vector<std::string> uncommon;
const std::vector<std::string>* keywordsShort = &keywords1;
const std::vector<std::string>* keywordsLong = &keywords2;
if (keywords1.size() > keywords2.size()) {
keywordsLong = &keywords1;
keywordsShort = &keywords2;
}
for (const auto& it : *keywordsLong) {
const auto position = std::find(keywordsShort->begin(), keywordsShort->end(), it);
if (position != keywordsShort->end()) {
common.push_back(*position);
}
else {
uncommon.push_back(it);
}
}
std::cout << "\nCommon keywords for the two cases:\n";
for (const auto& it : common) std::cout << it << std::endl;
std::cout << "\nUncommon keywords for the two cases:\n";
for (const auto& it : uncommon) std::cout << it << std::endl;
}
Deviation ECLFilesComparator::calculateDeviations(double val1, double val2) {
val1 = std::abs(val1);
val2 = std::abs(val2);
Deviation deviation;
if (val1 != 0 || val2 != 0) {
deviation.abs = std::abs(val1 - val2);
if (val1 != 0 && val2 != 0) {
deviation.rel = deviation.abs/(std::max(val1, val2));
}
}
return deviation;
}
double ECLFilesComparator::median(std::vector<double> vec) {
if (vec.empty()) {
return 0;
}
else {
size_t n = vec.size()/2;
nth_element(vec.begin(), vec.begin() + n, vec.end());
if (vec.size() % 2 == 0) {
return 0.5*(vec[n-1]+vec[n]);
}
else {
return vec[n];
}
}
}
double ECLFilesComparator::average(const std::vector<double>& vec) {
if (vec.empty()) {
return 0;
}
double sum = std::accumulate(vec.begin(), vec.end(), 0.0);
return sum/vec.size();
}
double ECLFilesComparator::getCellVolume(const ecl_grid_type* ecl_grid,
const int globalIndex) {
std::vector<double> x(8, 0.0);
std::vector<double> y(8, 0.0);
std::vector<double> z(8, 0.0);
for (int i = 0; i < 8; i++) {
ecl_grid_get_cell_corner_xyz1(ecl_grid, globalIndex, i, &x.data()[i], &y.data()[i], &z.data()[i]);
}
return calculateCellVol(x,y,z);
}

View File

@@ -0,0 +1,127 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECLFILESCOMPARATOR_HPP
#define ECLFILESCOMPARATOR_HPP
#include "Deviation.hpp"
#include <map>
#include <vector>
#include <string>
struct ecl_file_struct; //!< Prototype for eclipse file struct, from ERT library.
typedef struct ecl_file_struct ecl_file_type;
struct ecl_grid_struct; //!< Prototype for eclipse grid struct, from ERT library.
typedef struct ecl_grid_struct ecl_grid_type;
struct ecl_kw_struct; //!< Prototype for eclipse keyword struct, from ERT library.
typedef struct ecl_kw_struct ecl_kw_type;
/*! \brief A class for comparing ECLIPSE files.
\details ECLFilesComparator opens ECLIPSE files
(unified restart, initial and RFT in addition to grid file)
from two simulations. This class has only the functions
printKeywords() and printKeywordsDifference(), in addition to a
couple of get-functions: the comparison logic is implemented in
the subclasses RegressionTest and IntegrationTest. */
class ECLFilesComparator {
private:
int file_type;
double absTolerance = 0;
double relTolerance = 0;
protected:
ecl_file_type* ecl_file1 = nullptr;
ecl_grid_type* ecl_grid1 = nullptr;
ecl_file_type* ecl_file2 = nullptr;
ecl_grid_type* ecl_grid2 = nullptr;
std::vector<std::string> keywords1, keywords2;
bool throwOnError = true; //!< Throw on first error
bool analysis = false; //!< Perform full error analysis
std::map<std::string, std::vector<Deviation>> deviations;
mutable size_t num_errors = 0;
//! \brief Checks if the keyword exists in both cases.
//! \param[in] keyword Keyword to check.
//! \details If the keyword does not exist in one of the cases, the function throws an exception.
void keywordValidForComparing(const std::string& keyword) const;
//! \brief Stores keyword data for a given occurrence
//! \param[out] ecl_kw1 Pointer to a ecl_kw_type, which stores keyword data for first case given the occurrence.
//! \param[out] ecl_kw2 Pointer to a ecl_kw_type, which stores keyword data for second case given the occurrence.
//! \param[in] keyword Which keyword to consider.
//! \param[in] occurrence Which keyword occurrence to consider.
//! \details This function stores keyword data for the given keyword and occurrence in #ecl_kw1 and #ecl_kw2, and returns the number of cells (for which the keyword has a value at the occurrence). If the number of cells differ for the two cases, an exception is thrown.
unsigned int getEclKeywordData(ecl_kw_type*& ecl_kw1, ecl_kw_type*& ecl_kw2, const std::string& keyword, int occurrence1, int occurrence2) const;
//! \brief Prints values for a given keyword, occurrence and cell
//! \param[in] keyword Which keyword to consider.
//! \param[in] occurrence Which keyword occurrence to consider.
//! \param[in] cell Which cell occurrence to consider (numbered by global index).
//! \param[in] value1 Value for first file, the data type can be bool, int, double or std::string.
//! \param[in] value2 Value for second file, the data type can be bool, int, double or std::string.
//! \details Templatefunction for printing values when exceptions are thrown. The function is defined for bool, int, double and std::string.
template <typename T>
void printValuesForCell(const std::string& keyword, int occurrence1, int occurrence2, size_t kw_size, size_t cell, const T& value1, const T& value2) const;
public:
//! \brief Open ECLIPSE files and set tolerances and keywords.
//! \param[in] file_type Specifies which filetype to be compared, possible inputs are UNRSTFILE, INITFILE and RFTFILE.
//! \param[in] basename1 Full path without file extension to the first case.
//! \param[in] basename2 Full path without file extension to the second case.
//! \param[in] absTolerance Tolerance for absolute deviation.
//! \param[in] relTolerance Tolerance for relative deviation.
//! \details The content of the ECLIPSE files specified in the input is stored in the ecl_file_type and ecl_grid_type member variables. In addition the keywords and absolute and relative tolerances (member variables) are set. If the constructor is unable to open one of the ECLIPSE files, an exception will be thrown.
ECLFilesComparator(int file_type, const std::string& basename1, const std::string& basename2, double absTolerance, double relTolerance);
//! \brief Closing the ECLIPSE files.
~ECLFilesComparator();
//! \brief Set whether to throw on errors or not.
void throwOnErrors(bool dothrow) { throwOnError = dothrow; }
//! \brief Set whether to perform a full error analysis.
void doAnalysis(bool analize) { analysis = analize; }
//! \brief Returns the number of errors encountered in the performed comparisons.
size_t getNoErrors() const { return num_errors; }
//! \brief Returns the ECLIPSE filetype of this
int getFileType() const {return file_type;}
//! \brief Returns the absolute tolerance stored as a private member variable in the class
double getAbsTolerance() const {return absTolerance;}
//! \brief Returns the relative tolerance stored as a private member variable in the class
double getRelTolerance() const {return relTolerance;}
//! \brief Print all keywords and their respective Eclipse type for the two input cases.
void printKeywords() const;
//! \brief Print common and uncommon keywords for the two input cases.
void printKeywordsDifference() const;
//! \brief Calculate deviations for two values.
//! \details Using absolute values of the input arguments: If one of the values are non-zero, the Deviation::abs returned is the difference between the two input values. In addition, if both values are non-zero, the Deviation::rel returned is the absolute deviation divided by the largest value.
static Deviation calculateDeviations(double val1, double val2);
//! \brief Calculate median of a vector.
//! \details Returning the median of the input vector, i.e. the middle value of the sorted vector if the number of elements is odd or the mean of the two middle values if the number of elements are even.
static double median(std::vector<double> vec);
//! \brief Calculate average of a vector.
//! \details Returning the average of the input vector, i.e. the sum of all values divided by the number of elements.
static double average(const std::vector<double>& vec);
//! \brief Obtain the volume of a cell.
static double getCellVolume(const ecl_grid_type* ecl_grid, const int globalIndex);
};
#endif

View File

@@ -0,0 +1,199 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "EclIntegrationTest.hpp"
#include <opm/common/ErrorMacros.hpp>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <set>
#include <ert/ecl/ecl_file.h>
#include <ert/ecl/ecl_grid.h>
#include <ert/ecl/ecl_type.h>
#include <ert/ecl_well/well_info.h>
// helper macro to handle error throws or not
#define HANDLE_ERROR(type, message) \
{ \
if (throwOnError) \
OPM_THROW(type, message); \
else { \
std::cerr << message << std::endl; \
++num_errors; \
} \
}
void ECLIntegrationTest::setCellVolumes() {
double absTolerance = getAbsTolerance();
double relTolerance = getRelTolerance();
const unsigned int globalGridCount1 = ecl_grid_get_global_size(ecl_grid1);
const unsigned int activeGridCount1 = ecl_grid_get_active_size(ecl_grid1);
const unsigned int globalGridCount2 = ecl_grid_get_global_size(ecl_grid2);
const unsigned int activeGridCount2 = ecl_grid_get_active_size(ecl_grid2);
if (globalGridCount1 != globalGridCount2) {
OPM_THROW(std::runtime_error, "In grid file:"
<< "\nCells in first file: " << globalGridCount1
<< "\nCells in second file: " << globalGridCount2
<< "\nThe number of global cells differ.");
}
if (activeGridCount1 != activeGridCount2) {
OPM_THROW(std::runtime_error, "In grid file:"
<< "\nCells in first file: " << activeGridCount1
<< "\nCells in second file: " << activeGridCount2
<< "\nThe number of active cells differ.");
}
for (unsigned int cell = 0; cell < globalGridCount1; ++cell) {
const double cellVolume1 = getCellVolume(ecl_grid1, cell);
const double cellVolume2 = getCellVolume(ecl_grid2, cell);
Deviation dev = calculateDeviations(cellVolume1, cellVolume2);
if (dev.abs > absTolerance && dev.rel > relTolerance) {
int i, j, k;
ecl_grid_get_ijk1(ecl_grid1, cell, &i, &j, &k);
// Coordinates from this function are zero-based, hence incrementing
i++, j++, k++;
OPM_THROW(std::runtime_error, "In grid file: Deviations of cell volume exceed tolerances. "
<< "\nFor cell with coordinate (" << i << ", " << j << ", " << k << "):"
<< "\nCell volume in first file: " << cellVolume1
<< "\nCell volume in second file: " << cellVolume2
<< "\nThe absolute deviation is " << dev.abs << ", and the tolerance limit is " << absTolerance << "."
<< "\nThe relative deviation is " << dev.rel << ", and the tolerance limit is " << relTolerance << ".");
} // The second input case is used as reference.
cellVolumes.push_back(cellVolume2);
}
}
void ECLIntegrationTest::initialOccurrenceCompare(const std::string& keyword) {
ecl_kw_type* ecl_kw1 = nullptr;
ecl_kw_type* ecl_kw2 = nullptr;
const unsigned int numCells = getEclKeywordData(ecl_kw1, ecl_kw2, keyword, 0, 0);
std::vector<double> values1(numCells);
initialCellValues.resize(numCells);
ecl_kw_get_data_as_double(ecl_kw1, values1.data());
ecl_kw_get_data_as_double(ecl_kw2, initialCellValues.data());
// This variable sums up the difference between the keyword value for the first case and the keyword value for the second case, for each cell. The sum is weighted with respect to the cell volume of each cell.
double weightedDifference = 0;
// This variable sums up the keyword value for the first case for each cell. The sum is weighted with respect to the cell volume of each cell.
double weightedTotal = 0;
for (size_t cell = 0; cell < initialCellValues.size(); ++cell) {
weightedTotal += initialCellValues[cell]*cellVolumes[cell];
weightedDifference += std::abs(values1[cell] - initialCellValues[cell])*cellVolumes[cell];
}
if (weightedTotal != 0) {
double ratioValue = weightedDifference/weightedTotal;
if ((ratioValue) > getRelTolerance()) {
OPM_THROW(std::runtime_error, "\nFor keyword " << keyword << " and occurrence 0:"
<< "\nThe ratio of the deviation and the total value is " << ratioValue
<< ", which exceeds the relative tolerance of " << getRelTolerance() << "."
<< "\nSee the docs for more information about how the ratio is computed.");
}
}
}
void ECLIntegrationTest::occurrenceCompare(const std::string& keyword, int occurrence) const {
ecl_kw_type* ecl_kw1 = nullptr;
ecl_kw_type* ecl_kw2 = nullptr;
const unsigned int numCells = getEclKeywordData(ecl_kw1, ecl_kw2, keyword, occurrence, occurrence);
std::vector<double> values1(numCells), values2(numCells);
ecl_kw_get_data_as_double(ecl_kw1, values1.data());
ecl_kw_get_data_as_double(ecl_kw2, values2.data());
// This variable sums up the difference between the keyword value for the first case and the keyword value for the second case, for each cell. The sum is weighted with respect to the cell volume of each cell.
double weightedDifference = 0;
// This variable sums up the difference between the keyword value for the occurrence and the initial keyword value for each cell. The sum is weighted with respect to the cell volume of each cell.
double relativeWeightedTotal = 0;
for (size_t cell = 0; cell < values1.size(); ++cell) {
relativeWeightedTotal += std::abs(values1[cell] - initialCellValues[cell])*cellVolumes[cell];
weightedDifference += std::abs(values1[cell] - values2[cell])*cellVolumes[cell];
}
if (relativeWeightedTotal != 0) {
double ratioValue = weightedDifference/relativeWeightedTotal;
if ((ratioValue) > getRelTolerance()) {
OPM_THROW(std::runtime_error, "\nFor keyword " << keyword << " and occurrence " << occurrence << ":"
<< "\nThe ratio of the deviation and the total value is " << ratioValue
<< ", which exceeds the relative tolerance of " << getRelTolerance() << "."
<< "\nSee the docs for more information about how the ratio is computed.");
}
}
}
ECLIntegrationTest::ECLIntegrationTest(const std::string& basename1,
const std::string& basename2,
double absTolerance, double relTolerance) :
ECLFilesComparator(ECL_UNIFIED_RESTART_FILE, basename1, basename2, absTolerance, relTolerance) {
std::cout << "\nUsing cell volumes and keyword values from case " << basename2
<< " as reference." << std::endl << std::endl;
setCellVolumes();
}
bool ECLIntegrationTest::elementInWhitelist(const std::string& keyword) const {
auto it = std::find(keywordWhitelist.begin(), keywordWhitelist.end(), keyword);
return it != keywordWhitelist.end();
}
void ECLIntegrationTest::equalNumKeywords() const {
if (keywords1.size() != keywords2.size()) {
OPM_THROW(std::runtime_error, "\nKeywords in first file: " << keywords1.size()
<< "\nKeywords in second file: " << keywords2.size()
<< "\nThe number of keywords differ.");
}
}
void ECLIntegrationTest::results() {
for (const auto& it : keywordWhitelist)
resultsForKeyword(it);
}
void ECLIntegrationTest::resultsForKeyword(const std::string& keyword) {
std::cout << "Comparing " << keyword << "...";
keywordValidForComparing(keyword);
const unsigned int occurrences1 = ecl_file_get_num_named_kw(ecl_file1, keyword.c_str());
const unsigned int occurrences2 = ecl_file_get_num_named_kw(ecl_file2, keyword.c_str());
if (occurrences1 != occurrences2) {
OPM_THROW(std::runtime_error, "For keyword " << keyword << ":"
<< "\nKeyword occurrences in first file: " << occurrences1
<< "\nKeyword occurrences in second file: " << occurrences2
<< "\nThe number of occurrences differ.");
}
initialOccurrenceCompare(keyword);
for (unsigned int occurrence = 1; occurrence < occurrences1; ++occurrence) {
occurrenceCompare(keyword, occurrence);
}
std::cout << "done." << std::endl;
}

View File

@@ -0,0 +1,78 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECLINTEGRATIONTEST_HPP
#define ECLINTEGRATIONTEST_HPP
#include "EclFilesComparator.hpp"
/*! \brief A class for executing a integration test for two ECLIPSE files.
\details This class inherits from ECLFilesComparator, which opens and closes
the input cases and stores keywordnames. The three public functions
equalNumKeywords(), results() and resultsForKeyword() can be invoked
to compare griddata or keyworddata for all keywords or a given
keyword (resultsForKeyword()).
*/
class ECLIntegrationTest: public ECLFilesComparator {
private:
std::vector<double> cellVolumes; //!< Vector of cell volumes in second input case (indexed by global index)
std::vector<double> initialCellValues; //!< Keyword values for all cells at first occurrence (index by global index)
// These are the only keywords which are compared, since SWAT should be "1 - SOIL - SGAS", this keyword is omitted.
const std::vector<std::string> keywordWhitelist = {"SGAS", "SWAT", "PRESSURE"};
void setCellVolumes();
void initialOccurrenceCompare(const std::string& keyword);
void occurrenceCompare(const std::string& keyword, int occurrence) const;
public:
//! \brief Sets up the integration test.
//! \param[in] basename1 Full path without file extension to the first case.
//! \param[in] basename2 Full path without file extension to the second case.
//! \param[in] absTolerance Tolerance for absolute deviation.
//! \param[in] relTolerance Tolerance for relative deviation.
//! \details This constructor calls the constructor of the superclass, with input filetype unified restart. See the docs for ECLFilesComparator for more information.
ECLIntegrationTest(const std::string& basename1, const std::string& basename2, double absTolerance, double relTolerance);
//! \brief Checks if a keyword is supported for comparison.
//! \param[in] keyword Keyword to check.
bool elementInWhitelist(const std::string& keyword) const;
//! \brief Checks if the number of keywords equal in the two input cases.
//! \param[in] keyword Keyword to check.
void equalNumKeywords() const;
//! \brief Finds deviations for all supported keywords.
//! \details results() loops through all supported keywords for integration test (defined in keywordWhitelist -- this is SGAS, SWAT and PRESSURE) and calls resultsForKeyword() for each keyword.
void results();
//! \brief Finds deviations for a specific keyword.
//! \param[in] keyword Keyword to check.
/*! \details First, resultsForKeyword() checks if the keyword exits in both cases, and if the number of keyword occurrences in the two cases differ. If these tests fail, an exception is thrown. Then deviaitons are calculated as described below for each occurrence, and an exception is thrown if the relative error ratio \f$E\f$ is larger than the relative tolerance.
* Calculation:\n
* Let the keyword values for occurrence \f$n\f$ and cell \f$i\f$ be \f$p_{n,i}\f$ and \f$q_{n,i}\f$ for input case 1 and 2, respectively.
* Consider first the initial occurrence (\f$n=0\f$). The function uses the second cases as reference, and calculates the volume weighted sum of \f$q_{0,i}\f$ over all cells \f$i\f$:
* \f[ S_0 = \sum_{i} q_{0,i} v_i \f]
* where \f$v_{i}\f$ is the volume of cell \f$i\f$ in case 2. Then, the deviations between the cases for each cell are calculated:
* \f[ \Delta = \sum_{i} |p_{0,i} - q_{0,i}| v_i.\f]
* The error ratio is then \f$E = \Delta/S_0\f$.\n
* For all other occurrences \f$n\f$, the deviation value \f$\Delta\f$ is calculated the same way, but the total value \f$S\f$ is calculated relative to the initial occurrence total \f$S_0\f$:
* \f[ S = \sum_{i} |q_{n,i} - q_{0,i}| v_i. \f]
* The error ratio is \f$ E = \Delta/S\f$. */
void resultsForKeyword(const std::string& keyword);
};
#endif

View File

@@ -0,0 +1,352 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "EclRegressionTest.hpp"
#include <opm/common/ErrorMacros.hpp>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <set>
#include <ert/ecl/ecl_file.h>
#include <ert/ecl/ecl_grid.h>
#include <ert/ecl/ecl_type.h>
#include <ert/ecl_well/well_info.h>
// helper macro to handle error throws or not
#define HANDLE_ERROR(type, message) \
{ \
if (throwOnError) \
OPM_THROW(type, message); \
else { \
std::cerr << message << std::endl; \
++num_errors; \
} \
}
void ECLRegressionTest::printResultsForKeyword(const std::string& keyword) const {
std::cout << "Deviation results for keyword " << keyword << " of type "
<< ecl_type_get_name(ecl_file_iget_named_data_type(ecl_file1, keyword.c_str(), 0))
<< ":\n";
const double absDeviationAverage = average(absDeviation);
const double relDeviationAverage = average(relDeviation);
std::cout << "Average absolute deviation = " << absDeviationAverage << std::endl;
std::cout << "Median absolute deviation = " << median(absDeviation) << std::endl;
std::cout << "Average relative deviation = " << relDeviationAverage << std::endl;
std::cout << "Median relative deviation = " << median(relDeviation) << "\n\n";
}
void ECLRegressionTest::boolComparisonForOccurrence(const std::string& keyword,
int occurrence1, int occurrence2) const {
ecl_kw_type* ecl_kw1 = nullptr;
ecl_kw_type* ecl_kw2 = nullptr;
const unsigned int numCells = getEclKeywordData(ecl_kw1, ecl_kw2, keyword, occurrence1, occurrence2);
for (size_t cell = 0; cell < numCells; cell++) {
bool data1 = ecl_kw_iget_bool(ecl_kw1, cell);
bool data2 = ecl_kw_iget_bool(ecl_kw2, cell);
if (data1 != data2) {
printValuesForCell(keyword, occurrence1, occurrence2, numCells, cell, data1, data2);
HANDLE_ERROR(std::runtime_error, "Values of bool type differ.");
}
}
}
void ECLRegressionTest::charComparisonForOccurrence(const std::string& keyword,
int occurrence1, int occurrence2) const {
ecl_kw_type* ecl_kw1 = nullptr;
ecl_kw_type* ecl_kw2 = nullptr;
const unsigned int numCells = getEclKeywordData(ecl_kw1, ecl_kw2, keyword, occurrence1, occurrence2);
for (size_t cell = 0; cell < numCells; cell++) {
std::string data1(ecl_kw_iget_char_ptr(ecl_kw1, cell));
std::string data2(ecl_kw_iget_char_ptr(ecl_kw2, cell));
if (data1.compare(data2) != 0) {
printValuesForCell(keyword, occurrence1, occurrence2, numCells, cell, data1, data2);
HANDLE_ERROR(std::runtime_error, "Values of char type differ.");
}
}
}
void ECLRegressionTest::intComparisonForOccurrence(const std::string& keyword,
int occurrence1, int occurrence2) const {
ecl_kw_type* ecl_kw1 = nullptr;
ecl_kw_type* ecl_kw2 = nullptr;
const unsigned int numCells = getEclKeywordData(ecl_kw1, ecl_kw2, keyword, occurrence1, occurrence2);
std::vector<int> values1(numCells), values2(numCells);
ecl_kw_get_memcpy_int_data(ecl_kw1, values1.data());
ecl_kw_get_memcpy_int_data(ecl_kw2, values2.data());
for (size_t cell = 0; cell < values1.size(); cell++) {
if (values1[cell] != values2[cell]) {
printValuesForCell(keyword, occurrence1, occurrence2, values1.size(), cell, values1[cell], values2[cell]);
HANDLE_ERROR(std::runtime_error, "Values of int type differ.");
}
}
}
void ECLRegressionTest::doubleComparisonForOccurrence(const std::string& keyword,
int occurrence1, int occurrence2) {
ecl_kw_type* ecl_kw1 = nullptr;
ecl_kw_type* ecl_kw2 = nullptr;
const unsigned int numCells = getEclKeywordData(ecl_kw1, ecl_kw2, keyword, occurrence1, occurrence2);
std::vector<double> values1(numCells), values2(numCells);
ecl_kw_get_data_as_double(ecl_kw1, values1.data());
ecl_kw_get_data_as_double(ecl_kw2, values2.data());
auto it = std::find(keywordDisallowNegatives.begin(), keywordDisallowNegatives.end(), keyword);
for (size_t cell = 0; cell < values1.size(); cell++) {
deviationsForCell(values1[cell], values2[cell], keyword, occurrence1, occurrence2, cell, it == keywordDisallowNegatives.end());
}
}
void ECLRegressionTest::deviationsForCell(double val1, double val2,
const std::string& keyword,
int occurrence1, int occurrence2,
size_t kw_size, size_t cell,
bool allowNegativeValues) {
double absTolerance = getAbsTolerance();
double relTolerance = getRelTolerance();
if (!allowNegativeValues) {
if (val1 < 0) {
if (std::abs(val1) > absTolerance) {
printValuesForCell(keyword, occurrence1, occurrence2, kw_size, cell, val1, val2);
HANDLE_ERROR(std::runtime_error, "Negative value in first file, "
<< "which in absolute value exceeds the absolute tolerance of " << absTolerance << ".");
}
val1 = 0;
}
if (val2 < 0) {
if (std::abs(val2) > absTolerance) {
printValuesForCell(keyword, occurrence1, occurrence2, kw_size, cell, val1, val2);
HANDLE_ERROR(std::runtime_error, "Negative value in second file, "
<< "which in absolute value exceeds the absolute tolerance of " << absTolerance << ".");
}
val2 = 0;
}
}
Deviation dev = calculateDeviations(val1, val2);
if (dev.abs > absTolerance && dev.rel > relTolerance) {
if (analysis) {
deviations[keyword].push_back(dev);
} else {
printValuesForCell(keyword, occurrence1, occurrence2, kw_size, cell, val1, val2);
HANDLE_ERROR(std::runtime_error, "Deviations exceed tolerances."
<< "\nThe absolute deviation is " << dev.abs << ", and the tolerance limit is " << absTolerance << "."
<< "\nThe relative deviation is " << dev.rel << ", and the tolerance limit is " << relTolerance << ".");
}
}
if (dev.abs != -1) {
absDeviation.push_back(dev.abs);
}
if (dev.rel != -1) {
relDeviation.push_back(dev.rel);
}
}
void ECLRegressionTest::gridCompare(const bool volumecheck) const {
double absTolerance = getAbsTolerance();
double relTolerance = getRelTolerance();
const unsigned int globalGridCount1 = ecl_grid_get_global_size(ecl_grid1);
const unsigned int activeGridCount1 = ecl_grid_get_active_size(ecl_grid1);
const unsigned int globalGridCount2 = ecl_grid_get_global_size(ecl_grid2);
const unsigned int activeGridCount2 = ecl_grid_get_active_size(ecl_grid2);
if (globalGridCount1 != globalGridCount2) {
OPM_THROW(std::runtime_error, "In grid file:"
<< "\nCells in first file: " << globalGridCount1
<< "\nCells in second file: " << globalGridCount2
<< "\nThe number of global cells differ.");
}
if (activeGridCount1 != activeGridCount2) {
OPM_THROW(std::runtime_error, "In grid file:"
<< "\nCells in first file: " << activeGridCount1
<< "\nCells in second file: " << activeGridCount2
<< "\nThe number of active cells differ.");
}
if (!volumecheck) {
return;
}
for (unsigned int cell = 0; cell < globalGridCount1; ++cell) {
const bool active1 = ecl_grid_cell_active1(ecl_grid1, cell);
const bool active2 = ecl_grid_cell_active1(ecl_grid2, cell);
if (active1 != active2) {
int i, j, k;
ecl_grid_get_ijk1(ecl_grid1, cell, &i, &j, &k);
// Coordinates from this function are zero-based, hence incrementing
i++, j++, k++;
HANDLE_ERROR(std::runtime_error, "Grid cell with one-based indices ( "
<< i << ", " << j << ", " << k << " ) is "
<< (active1 ? "active" : "inactive") << " in first grid, but "
<< (active2 ? "active" : "inactive") << " in second grid.");
}
const double cellVolume1 = getCellVolume(ecl_grid1, cell);
const double cellVolume2 = getCellVolume(ecl_grid2, cell);
Deviation dev = calculateDeviations(cellVolume1, cellVolume2);
if (dev.abs > absTolerance && dev.rel > relTolerance) {
int i, j, k;
ecl_grid_get_ijk1(ecl_grid1, cell, &i, &j, &k);
// Coordinates from this function are zero-based, hence incrementing
i++, j++, k++;
HANDLE_ERROR(std::runtime_error, "In grid file: Deviations of cell volume exceed tolerances. "
<< "\nFor cell with one-based indices (" << i << ", " << j << ", " << k << "):"
<< "\nCell volume in first file: " << cellVolume1
<< "\nCell volume in second file: " << cellVolume2
<< "\nThe absolute deviation is " << dev.abs << ", and the tolerance limit is " << absTolerance << "."
<< "\nThe relative deviation is " << dev.rel << ", and the tolerance limit is " << relTolerance << "."
<< "\nCell 1 active: " << active1
<< "\nCell 2 active: " << active2);
}
}
}
void ECLRegressionTest::results() {
if (!this->acceptExtraKeywords) {
if (keywords1.size() != keywords2.size()) {
std::set<std::string> keys(keywords1.begin() , keywords1.end());
for (const auto& key2: keywords2)
keys.insert( key2 );
for (const auto& key : keys)
fprintf(stderr," %8s:%3d %8s:%3d \n",key.c_str() , ecl_file_get_num_named_kw( ecl_file1 , key.c_str()),
key.c_str() , ecl_file_get_num_named_kw( ecl_file2 , key.c_str()));
OPM_THROW(std::runtime_error, "\nKeywords in first file: " << keywords1.size()
<< "\nKeywords in second file: " << keywords2.size()
<< "\nThe number of keywords differ.");
}
}
for (const auto& it : keywords1)
resultsForKeyword(it);
if (analysis) {
std::cout << deviations.size() << " keyword"
<< (deviations.size() > 1 ? "s":"") << " exhibit failures" << std::endl;
for (const auto& iter : deviations) {
std::cout << "\t" << iter.first << std::endl;
std::cout << "\t\tFails for " << iter.second.size() << " entries" << std::endl;
std::cout.precision(7);
double absErr = std::max_element(iter.second.begin(), iter.second.end(),
[](const Deviation& a, const Deviation& b)
{
return a.abs < b.abs;
})->abs;
double relErr = std::max_element(iter.second.begin(), iter.second.end(),
[](const Deviation& a, const Deviation& b)
{
return a.rel < b.rel;
})->rel;
std::cout << "\t\tLargest absolute error: "
<< std::scientific << absErr << std::endl;
std::cout << "\t\tLargest relative error: "
<< std::scientific << relErr << std::endl;
}
}
}
void ECLRegressionTest::resultsForKeyword(const std::string& keyword) {
keywordValidForComparing(keyword);
const unsigned int occurrences1 = ecl_file_get_num_named_kw(ecl_file1, keyword.c_str());
const unsigned int occurrences2 = ecl_file_get_num_named_kw(ecl_file2, keyword.c_str());
if (!onlyLastOccurrence && occurrences1 != occurrences2) {
OPM_THROW(std::runtime_error, "For keyword " << keyword << ":"
<< "\nKeyword occurrences in first file: " << occurrences1
<< "\nKeyword occurrences in second file: " << occurrences2
<< "\nThe number of occurrences differ.");
}
// Assuming keyword type is constant for every occurrence:
const ecl_type_enum kw_type = ecl_type_get_type( ecl_file_iget_named_data_type(ecl_file1, keyword.c_str(), 0) );
switch(kw_type) {
case ECL_DOUBLE_TYPE:
case ECL_FLOAT_TYPE:
std::cout << "Comparing " << keyword << "...";
if (onlyLastOccurrence) {
doubleComparisonForOccurrence(keyword, occurrences1 - 1, occurrences2 - 1);
}
else {
for (unsigned int occurrence = 0; occurrence < occurrences1; ++occurrence) {
doubleComparisonForOccurrence(keyword, occurrence, occurrence);
}
}
std::cout << "done." << std::endl;
printResultsForKeyword(keyword);
absDeviation.clear();
relDeviation.clear();
return;
case ECL_INT_TYPE:
std::cout << "Comparing " << keyword << "...";
if (onlyLastOccurrence) {
intComparisonForOccurrence(keyword, occurrences1 - 1, occurrences2 - 1);
}
else {
for (unsigned int occurrence = 0; occurrence < occurrences1; ++occurrence) {
intComparisonForOccurrence(keyword, occurrence, occurrence);
}
}
break;
case ECL_CHAR_TYPE:
std::cout << "Comparing " << keyword << "...";
if (onlyLastOccurrence) {
charComparisonForOccurrence(keyword, occurrences1 - 1, occurrences2 - 1);
}
else {
for (unsigned int occurrence = 0; occurrence < occurrences1; ++occurrence) {
charComparisonForOccurrence(keyword, occurrence, occurrence);
}
}
break;
case ECL_BOOL_TYPE:
std::cout << "Comparing " << keyword << "...";
if (onlyLastOccurrence) {
boolComparisonForOccurrence(keyword, occurrences1 - 1, occurrences2 - 1);
}
else {
for (unsigned int occurrence = 0; occurrence < occurrences1; ++occurrence) {
boolComparisonForOccurrence(keyword, occurrence, occurrence);
}
}
break;
case ECL_MESS_TYPE:
std::cout << "\nKeyword " << keyword << " is of type MESS"
<< ", which is not supported in regression test." << "\n\n";
return;
default:
std::cout << "\nKeyword " << keyword << "has undefined type." << std::endl;
return;
}
std::cout << "done." << std::endl;
}

View File

@@ -0,0 +1,93 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECLREGRESSIONTEST_HPP
#define ECLREGRESSIONTEST_HPP
#include "EclFilesComparator.hpp"
/*! \brief A class for executing a regression test for two ECLIPSE files.
\details This class inherits from ECLFilesComparator, which opens and
closes the input cases and stores keywordnames.
The three public functions gridCompare(), results() and
resultsForKeyword() can be invoked to compare griddata
or keyworddata for all keywords or a given keyword (resultsForKeyword()).
*/
class ECLRegressionTest: public ECLFilesComparator {
private:
// These vectors store absolute and relative deviations, respecively. Note that they are whiped clean for every new keyword comparison.
std::vector<double> absDeviation, relDeviation;
// Keywords which should not contain negative values, i.e. uses allowNegativeValues = false in deviationsForCell():
const std::vector<std::string> keywordDisallowNegatives = {"SGAS", "SWAT", "PRESSURE"};
// Only compare last occurrence
bool onlyLastOccurrence = false;
// Accept extra keywords in the restart file of the 'new' simulation.
bool acceptExtraKeywords = false;
// Prints results stored in absDeviation and relDeviation.
void printResultsForKeyword(const std::string& keyword) const;
// Function which compares data at specific occurrences and for a specific keyword type. The functions takes two occurrence inputs to also be able to
// compare keywords which are shifted relative to each other in the two files. This is for instance handy when running flow with restart from different timesteps,
// and comparing the last timestep from the two runs.
void boolComparisonForOccurrence(const std::string& keyword, int occurrence1, int occurrence2) const;
void charComparisonForOccurrence(const std::string& keyword, int occurrence1, int occurrence2) const;
void intComparisonForOccurrence(const std::string& keyword, int occurrence1, int occurrence2) const;
void doubleComparisonForOccurrence(const std::string& keyword, int occurrence1, int occurrence2);
// deviationsForCell throws an exception if both the absolute deviation AND the relative deviation
// are larger than absTolerance and relTolerance, respectively. In addition,
// if allowNegativeValues is passed as false, an exception will be thrown when the absolute value
// of a negative value exceeds absTolerance. If no exceptions are thrown, the absolute and relative deviations are added to absDeviation and relDeviation.
void deviationsForCell(double val1, double val2, const std::string& keyword, int occurrence1, int occurrence2, size_t kw_size, size_t cell, bool allowNegativeValues = true);
public:
//! \brief Sets up the regression test.
//! \param[in] file_type Specifies which filetype to be compared, possible inputs are UNRSTFILE, INITFILE and RFTFILE.
//! \param[in] basename1 Full path without file extension to the first case.
//! \param[in] basename2 Full path without file extension to the second case.
//! \param[in] absTolerance Tolerance for absolute deviation.
//! \param[in] relTolerance Tolerance for relative deviation.
//! \details This constructor only calls the constructor of the superclass, see the docs for ECLFilesComparator for more information.
ECLRegressionTest(int file_type, const std::string& basename1, const std::string& basename2, double absTolerance, double relTolerance):
ECLFilesComparator(file_type, basename1, basename2, absTolerance, relTolerance) {}
//! \brief Option to only compare last occurrence
void setOnlyLastOccurrence(bool onlyLastOccurrenceArg) {this->onlyLastOccurrence = onlyLastOccurrenceArg;}
// Accept extra keywords: If this switch is set to true the comparison
// of restart files will ignore extra keywords which are only present
// in the new simulation.
void setAcceptExtraKeywords(bool acceptExtraKeywordsArg) { this->acceptExtraKeywords = acceptExtraKeywordsArg; }
//! \brief Compares grid properties of the two cases.
// gridCompare() checks if both the number of active and global cells in the two cases are the same. If they are, and volumecheck is true, all cells are looped over to calculate the cell volume deviation for the two cases. If the both the relative and absolute deviation exceeds the tolerances, an exception is thrown.
void gridCompare(const bool volumecheck) const;
//! \brief Calculates deviations for all keywords.
// This function checks if the number of keywords of the two cases are equal, and if it is, resultsForKeyword() is called for every keyword. If not, an exception is thrown.
void results();
//! \brief Calculates deviations for a specific keyword.
//! \param[in] keyword Keyword which should be compared, if this keyword is absent in one of the cases, an exception will be thrown.
//! \details This function loops through every report step and every cell and compares the values for the given keyword from the two input cases. If the absolute or relative deviation between the two values for each step exceeds both the absolute tolerance and the relative tolerance (stored in ECLFilesComparator), an exception is thrown. In addition, some keywords are marked for "disallow negative values" -- these are SGAS, SWAT and PRESSURE. An exception is thrown if a value of one of these keywords is both negative and has an absolute value larger than the absolute tolerance. If no exceptions are thrown, resultsForKeyword() uses the private member funtion printResultsForKeyword to print the average and median deviations.
void resultsForKeyword(const std::string& keyword);
};
#endif

View File

@@ -0,0 +1,381 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "EclIntegrationTest.hpp"
#include "EclRegressionTest.hpp"
#include "summaryIntegrationTest.hpp"
#include "summaryRegressionTest.hpp"
#include <opm/common/ErrorMacros.hpp>
#include <ert/util/util.h>
#include <ert/util/stringlist.h>
#include <ert/ecl/ecl_endian_flip.h>
#include <ert/ecl/ecl_file.h>
#include <iostream>
#include <string>
#include <getopt.h>
static void printHelp() {
std::cout << "\ncompareECL compares ECLIPSE files (restart (.RST), unified restart (.UNRST), initial (.INIT), summary (.SMRY), unified summary (.UNSMRY) or .RFT) and gridsizes (from .EGRID or .GRID file) from two simulations.\n"
<< "The program takes four arguments:\n\n"
<< "1. Case number 1 (full path without extension)\n"
<< "2. Case number 2 (full path without extension)\n"
<< "3. Absolute tolerance\n"
<< "4. Relative tolerance (between 0 and 1)\n\n"
<< "In addition, the program takes these options (which must be given before the arguments):\n\n"
<< "-a Run a full analysis of errors.\n"
<< "-g Will print the vector with the greatest error ratio.\n"
<< "-h Print help and exit.\n"
<< "-i Execute integration test (regression test is default).\n"
<< " The integration test compares SGAS, SWAT and PRESSURE in unified restart files, so this option can not be used in combination with -t.\n"
<< "-I Same as -i, but throws an exception when the number of keywords in the two cases differ. Can not be used in combination with -t.\n"
<< "-k Specify specific keyword to compare (capitalized), for example -k PRESSURE.\n"
<< "-K Will not allow different amount of keywords in the two files. Throws an exception if the amount are different.\n"
<< "-l Only do comparison for the last occurrence. This option is only for the regression test, and can therefore not be used in combination with -i or -I.\n"
<< "-m mainVar. Will calculate the error ratio for one main variable. Valid input is WOPR, WWPR, WGPR or WBHP.\n"
<< "-n Do not throw on errors.\n"
<< "-p Print keywords in both cases and exit. Can not be used in combination with -P.\n"
<< "-P Print common and uncommon keywords in both cases and exit. Can not be used in combination with -p.\n"
<< "-R Will allow comparison between a restarted simulation and a normal simulation for summary regression tests. The files must end at the same time.\n"
<< "-s int Sets the number of spikes that are allowed for each keyword in summary integration tests.\n"
<< "-t Specify ECLIPSE filetype to compare (unified restart is default). Can not be used in combination with -i or -I. Different possible arguments are:\n"
<< " -t UNRST \t Compare two unified restart files (.UNRST). This the default value, so it is the same as not passing option -t.\n"
<< " -t INIT \t Compare two initial files (.INIT).\n"
<< " -t RFT \t Compare two RFT files (.RFT).\n"
<< " -t RST \t Compare two cases consisting of restart files (.Xnnnn).\n"
<< " -t SMRY \t Compare two cases consistent of (unified) summary files.\n"
<< " -t RST1 \t Compare two cases where the first case consists of restart files (.Xnnnn), and the second case consists of a unified restart file (.UNRST).\n"
<< " -t RST2 \t Compare two cases where the first case consists of a unified restart file (.UNRST), and the second case consists of restart files (.Xnnnn).\n"
<< " Note that when dealing with restart files (.Xnnnn), the program concatenates all of them into one unified restart file, which is used for comparison and stored in the same directory as the restart files.\n"
<< " This will overwrite any existing unified restart file in that directory.\n\n"
<< "-v For the rate keywords WOPR, WGPR, WWPR and WBHP. Calculates the error volume of the two summary files. This is printed to screen.\n"
<< "\nExample usage of the program: \n\n"
<< "compareECL -k PRESSURE <path to first casefile> <path to second casefile> 1e-3 1e-5\n"
<< "compareECL -t INIT -k PORO <path to first casefile> <path to second casefile> 1e-3 1e-5\n"
<< "compareECL -i <path to first casefile> <path to second casefile> 0.01 1e-6\n\n"
<< "Exceptions are thrown (and hence program exits) when deviations are larger than the specified "
<< "tolerances, or when the number of cells does not match -- either in the grid file or for a "
<< "specific keyword. Information about the keyword, keyword occurrence (zero based) and cell "
<< "coordinate is printed when an exception is thrown. For more information about how the cases "
<< "are compared, see the documentation of the EclFilesComparator class.\n\n";
}
void splitBasename(const std::string& basename, std::string& path, std::string& filename) {
const size_t lastSlashIndex = basename.find_last_of("/\\");
path = basename.substr(0,lastSlashIndex);
filename = basename.substr(lastSlashIndex+1);
}
// Inspired by the ecl_pack application in the ERT library
void concatenateRestart(const std::string& basename) {
std::string inputPath, inputBase;
splitBasename(basename, inputPath, inputBase);
stringlist_type* inputFiles = stringlist_alloc_new();
const int numFiles = ecl_util_select_filelist(inputPath.c_str(), inputBase.c_str(), ECL_RESTART_FILE, false, inputFiles);
const char* target_file_name = ecl_util_alloc_filename(inputPath.c_str(), inputBase.c_str(), ECL_UNIFIED_RESTART_FILE, false, -1);
fortio_type* target = fortio_open_writer(target_file_name, false, ECL_ENDIAN_FLIP);
int dummy;
ecl_kw_type* seqnum_kw = ecl_kw_alloc_new("SEQNUM", 1, ECL_INT, &dummy);
int reportStep = 0;
for (int i = 0; i < numFiles; ++i) {
ecl_util_get_file_type(stringlist_iget(inputFiles, i), nullptr, &reportStep);
ecl_file_type* src_file = ecl_file_open(stringlist_iget(inputFiles, i), 0);
ecl_kw_iset_int(seqnum_kw, 0, reportStep);
ecl_kw_fwrite(seqnum_kw, target);
ecl_file_fwrite_fortio(src_file, target, 0);
ecl_file_close(src_file);
}
fortio_fclose(target);
stringlist_free(inputFiles);
}
//------------------------------------------------//
int main(int argc, char** argv) {
// Restart is default
ecl_file_enum file_type = ECL_UNIFIED_RESTART_FILE;
// RegressionTest is default
bool integrationTest = false;
bool allowDifferentAmount = true;
bool checkNumKeywords = false;
bool findGreatestErrorRatio = false;
bool findVolumeError = false;
bool onlyLastOccurrence = false;
bool printKeywords = false;
bool printKeywordsDifference = false;
bool restartFile = false;
bool specificKeyword = false;
bool specificFileType = false;
bool allowSpikes = false;
bool throwOnError = true;
bool throwTooGreatErrorRatio = true;
bool acceptExtraKeywords = false;
bool analysis = false;
bool volumecheck = true;
char* keyword = nullptr;
char* fileTypeCstr = nullptr;
const char* mainVariable = nullptr;
int c = 0;
int spikeLimit = -1;
while ((c = getopt(argc, argv, "hiIk:alnpPt:VRgs:m:vKx")) != -1) {
switch (c) {
case 'a':
analysis = true;
break;
case 'g':
findGreatestErrorRatio = true;
throwTooGreatErrorRatio = false;
break;
case 'h':
printHelp();
return 0;
case 'i':
integrationTest = true;
break;
case 'I':
integrationTest = true;
checkNumKeywords = true;
break;
case 'k':
specificKeyword = true;
keyword = optarg;
break;
case 'K':
allowDifferentAmount = false;
break;
case 'l':
onlyLastOccurrence = true;
break;
case 'm':
mainVariable = optarg;
break;
case 'n':
throwOnError = false;
break;
case 'p':
printKeywords = true;
break;
case 'P':
printKeywordsDifference = true;
break;
case 'R':
restartFile = true;
break;
case 's':
allowSpikes = true;
spikeLimit = atof(optarg);
break;
case 't':
specificFileType = true;
fileTypeCstr = optarg;
break;
case 'v':
findVolumeError = true;
break;
case 'V':
volumecheck = false;
break;
case 'x':
acceptExtraKeywords = true;
break;
case '?':
if (optopt == 'k' || optopt == 'm' || optopt == 's') {
std::cerr << "Option " << optopt << " requires a keyword as argument, see manual (-h) for more information." << std::endl;
return EXIT_FAILURE;
}
else if (optopt == 't') {
std::cerr << "Option t requires an ECLIPSE filetype as argument, see manual (-h) for more information." << std::endl;
return EXIT_FAILURE;
}
else {
std::cerr << "Unknown option." << std::endl;
return EXIT_FAILURE;
}
default:
return EXIT_FAILURE;
}
}
int argOffset = optind;
if ((printKeywords && printKeywordsDifference) ||
(integrationTest && specificFileType) ||
(integrationTest && onlyLastOccurrence)) {
std::cerr << "Error: Options given which can not be combined. "
<< "Please see the manual (-h) for more information." << std::endl;
return EXIT_FAILURE;
}
if (argc != argOffset + 4) {
std::cerr << "Error: The number of options and arguments given is not correct. "
<< "Please run compareECL -h to see manual." << std::endl;
return EXIT_FAILURE;
}
std::string basename1 = argv[argOffset];
std::string basename2 = argv[argOffset + 1];
double absTolerance = strtod(argv[argOffset + 2], nullptr);
double relTolerance = strtod(argv[argOffset + 3], nullptr);
if (specificFileType) {
std::string fileTypeString(fileTypeCstr);
for (auto& ch: fileTypeString) ch = toupper(ch);
if (fileTypeString== "UNRST") {} //Do nothing
else if (fileTypeString == "RST") {
concatenateRestart(basename1);
concatenateRestart(basename2);
}
else if (fileTypeString == "RST1") {
concatenateRestart(basename1);
}
else if (fileTypeString == "RST2") {
concatenateRestart(basename2);
}
else if (fileTypeString == "INIT") {
file_type = ECL_INIT_FILE;
}
else if (fileTypeString == "RFT") {
file_type = ECL_RFT_FILE;
}
else if (fileTypeString == "SMRY")
file_type = ECL_SUMMARY_FILE;
else {
std::cerr << "Unknown ECLIPSE filetype specified with option -t. Please run compareECL -h to see manual." << std::endl;
return EXIT_FAILURE;
}
}
if (restartFile && (file_type != ECL_SUMMARY_FILE || integrationTest)) {
std::cerr << "Error: -R can only be used in for summary regression tests." << std::endl;
return EXIT_FAILURE;
}
std::cout << "Comparing '" << basename1 << "' to '" << basename2 << "'." << std::endl;
try {
if (file_type == ECL_SUMMARY_FILE) {
if(!integrationTest){
SummaryRegressionTest compare(basename1,basename2,absTolerance,relTolerance);
compare.throwOnErrors(throwOnError);
compare.doAnalysis(analysis);
compare.setPrintKeywords(printKeywords);
compare.setIsRestartFile(restartFile);
compare.setAllowDifferentNumberOfKeywords(acceptExtraKeywords);
if(specificKeyword){
compare.getRegressionTest(keyword);
}
else{
compare.setPrintKeywords(printKeywords);
compare.getRegressionTest();
}
} else {
SummaryIntegrationTest compare(basename1,basename2,absTolerance,relTolerance);
compare.throwOnErrors(throwOnError);
compare.setFindVectorWithGreatestErrorRatio(findGreatestErrorRatio);
compare.setAllowSpikes(allowSpikes);
if (mainVariable) {
compare.setOneOfTheMainVariables(true);
std::string str(mainVariable);
std::transform(str.begin(), str.end(),str.begin(), ::toupper);
if(str == "WOPR" ||str=="WWPR" ||str=="WGPR" || str == "WBHP"){
compare.setMainVariable(str);
}else{
throw std::invalid_argument("The input is not a main variable. -m option requires a valid main variable.");
}
}
compare.setFindVolumeError(findVolumeError);
if (spikeLimit != -1) {
compare.setSpikeLimit(spikeLimit);
}
compare.setAllowDifferentAmountOfKeywords(allowDifferentAmount);
compare.setPrintKeywords(printKeywords);
compare.setThrowExceptionForTooGreatErrorRatio(throwTooGreatErrorRatio);
if(specificKeyword){
compare.setPrintSpecificKeyword(specificKeyword);
compare.getIntegrationTest(keyword);
return 0;
}
compare.getIntegrationTest();
}
}
else if (integrationTest) {
ECLIntegrationTest comparator(basename1, basename2, absTolerance, relTolerance);
if (printKeywords) {
comparator.printKeywords();
return 0;
}
if (printKeywordsDifference) {
comparator.printKeywordsDifference();
return 0;
}
if (checkNumKeywords) {
comparator.equalNumKeywords();
}
if (specificKeyword) {
if (comparator.elementInWhitelist(keyword)) {
comparator.resultsForKeyword(keyword);
}
else {
std::cerr << "Keyword " << keyword << " is not supported for the integration test. Use SGAS, SWAT or PRESSURE." << std::endl;
return EXIT_FAILURE;
}
}
else {
comparator.results();
}
}
else {
ECLRegressionTest comparator(file_type, basename1, basename2, absTolerance, relTolerance);
comparator.throwOnErrors(throwOnError);
comparator.doAnalysis(analysis);
comparator.setAcceptExtraKeywords(acceptExtraKeywords);
if (printKeywords) {
comparator.printKeywords();
return 0;
}
if (printKeywordsDifference) {
comparator.printKeywordsDifference();
return 0;
}
if (onlyLastOccurrence) {
comparator.setOnlyLastOccurrence(true);
}
if (specificKeyword) {
comparator.gridCompare(volumecheck);
comparator.resultsForKeyword(keyword);
}
else {
comparator.gridCompare(volumecheck);
comparator.results();
}
if (comparator.getNoErrors() > 0)
OPM_THROW(std::runtime_error, comparator.getNoErrors() << " errors encountered in comparisons.");
}
}
catch (const std::exception& e) {
std::cerr << "Program threw an exception: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return 0;
}

View File

@@ -17,19 +17,22 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_ECLIODATA_HPP
#define OPM_IO_ECLIODATA_HPP
#ifndef OPM_ECLIO_DATA_HPP
#define OPM_ECLIO_DATA_HPP
#include <tuple>
namespace Opm { namespace EclIO {
namespace Opm {
namespace ecl {
// type MESS have no assisiated data
enum eclArrType {
INTE, REAL, DOUB, CHAR, LOGI, MESS
};
// named constants related to binary file format
const unsigned int true_value = 0xffffffff;
const unsigned int false_value = 0x00000000;
@@ -45,25 +48,7 @@ namespace Opm { namespace EclIO {
const int MaxBlockSizeLogi = 4000; // Maximum block size for LOGI arrays in binary files
const int MaxBlockSizeChar = 840; // Maximum block size for CHAR arrays in binary files
// named constants related to formatted file file format
const int MaxNumBlockInte = 1000; // maximum number of Inte values in block => hard line shift
const int MaxNumBlockReal = 1000; // maximum number of Real values in block => hard line shift
const int MaxNumBlockDoub = 1000; // maximum number of Doub values in block => hard line shift
const int MaxNumBlockLogi = 1000; // maximum number of Logi values in block => hard line shift
const int MaxNumBlockChar = 105; // maximum number of Char values in block => hard line shift
} // ecl
} // Opm
const int numColumnsInte = 6; // number of columns for Inte values
const int numColumnsReal = 4; // number of columns for Real values
const int numColumnsDoub = 3; // number of columns for Doub values
const int numColumnsLogi = 25; // number of columns for Logi values
const int numColumnsChar = 7; // number of columns for Char values
const int columnWidthInte = 12; // number of characters fore each Inte Element
const int columnWidthReal = 17; // number of characters fore each Inte Element
const int columnWidthDoub = 23; // number of characters fore each Inte Element
const int columnWidthLogi = 3; // number of characters fore each Inte Element
const int columnWidthChar = 11; // number of characters fore each Inte Element
}} // namespace Opm::EclIO
#endif // OPM_IO_ECLIODATA_HPP
#endif // OPM_ECLIO_DATA_HPP

View File

@@ -0,0 +1,240 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "summaryComparator.hpp"
#include <ert/ecl/ecl_sum.hpp>
#include <ert/util/stringlist.hpp>
#include <ert/util/int_vector.hpp>
#include <ert/util/bool_vector.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <cmath>
#include <numeric>
SummaryComparator::SummaryComparator(const std::string& basename1,
const std::string& basename2,
double absoluteTol, double relativeTol){
ecl_sum1 = ecl_sum_fread_alloc_case(basename1.c_str(), ":");
ecl_sum2 = ecl_sum_fread_alloc_case(basename2.c_str(), ":");
if (ecl_sum1 == nullptr || ecl_sum2 == nullptr) {
OPM_THROW(std::runtime_error, "Not able to open files");
}
absoluteTolerance = absoluteTol;
relativeTolerance = relativeTol;
keys1 = stringlist_alloc_new();
keys2 = stringlist_alloc_new();
ecl_sum_select_matching_general_var_list( ecl_sum1 , "*" , this->keys1);
stringlist_sort(this->keys1 , nullptr );
ecl_sum_select_matching_general_var_list( ecl_sum2 , "*" , this->keys2);
stringlist_sort(this->keys2 , nullptr );
if(stringlist_get_size(keys1) <= stringlist_get_size(keys2)){
this->keysShort = this->keys1;
this->keysLong = this->keys2;
}else{
this->keysShort = this->keys2;
this->keysLong = this->keys1;
}
}
SummaryComparator::~SummaryComparator(){
ecl_sum_free(ecl_sum1);
ecl_sum_free(ecl_sum2);
stringlist_free(keys1);
stringlist_free(keys2);
}
Deviation SummaryComparator::calculateDeviations(double val1, double val2){
double absDev;
Deviation deviation;
absDev = std::abs(val1 - val2);
deviation.abs = absDev;
if (val1 != 0 || val2 != 0) {
deviation.rel = absDev/double(std::max(std::abs(val1), std::abs(val2)));
}
return deviation;
}
void SummaryComparator::setTimeVecs(std::vector<double> &timeVec1,
std::vector<double> &timeVec2){
timeVec1.reserve(ecl_sum_get_data_length(ecl_sum1));
for (int time_index = 0; time_index < ecl_sum_get_data_length(ecl_sum1); time_index++){
timeVec1.push_back(ecl_sum_iget_sim_days(ecl_sum1 , time_index ));
}
timeVec2.reserve(ecl_sum_get_data_length(ecl_sum2));
for (int time_index = 0; time_index < ecl_sum_get_data_length(ecl_sum2); time_index++){
timeVec2.push_back(ecl_sum_iget_sim_days(ecl_sum2 , time_index ));
}
}
void SummaryComparator::getDataVecs(std::vector<double> &dataVec1,
std::vector<double> &dataVec2,
const char* keyword){
dataVec1.reserve(ecl_sum_get_data_length(ecl_sum1));
for (int time_index = 0; time_index < ecl_sum_get_data_length(ecl_sum1); time_index++){
dataVec1.push_back(ecl_sum_iget(ecl_sum1, time_index, ecl_sum_get_general_var_params_index( ecl_sum1 , keyword )));
}
dataVec2.reserve(ecl_sum_get_data_length(ecl_sum2));
for (int time_index = 0; time_index < ecl_sum_get_data_length(ecl_sum2); time_index++){
dataVec2.push_back(ecl_sum_iget(ecl_sum2, time_index, ecl_sum_get_general_var_params_index( ecl_sum2 , keyword )));
}
}
void SummaryComparator::setDataSets(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2){
if(timeVec1.size() < timeVec2.size()){
ecl_sum_fileShort = this->ecl_sum1;
ecl_sum_fileLong = this->ecl_sum2;
}
else{
ecl_sum_fileShort = this->ecl_sum2;
ecl_sum_fileLong = this->ecl_sum1;
}
}
void SummaryComparator::chooseReference(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const std::vector<double>& dataVec1,
const std::vector<double>& dataVec2){
if(timeVec1.size() <= timeVec2.size()){
referenceVec = &timeVec1; // time vector
referenceDataVec = &dataVec1; //data vector
checkVec = &timeVec2;
checkDataVec = &dataVec2;
}
else{
referenceVec = &timeVec2;
referenceDataVec = &dataVec2;
checkVec = &timeVec1;
checkDataVec = &dataVec1;
}
}
void SummaryComparator::getDeviation(size_t refIndex, size_t &checkIndex, Deviation &dev){
if((*referenceVec)[refIndex] == (*checkVec)[checkIndex]){
dev = SummaryComparator::calculateDeviations((*referenceDataVec)[refIndex], (*checkDataVec)[checkIndex]);
checkIndex++;
return;
}
else if((*referenceVec)[refIndex]<(*checkVec)[checkIndex]){
double value = SummaryComparator::unitStep((*checkDataVec)[checkIndex]);
/*Must be a little careful here. Flow writes out old value first,
than changes value. Say there should be a change in production rate from A to B at timestep 300.
Then the data of time step 300 is A and the next timestep will have value B. Must use the upper limit. */
dev = SummaryComparator::calculateDeviations((*referenceDataVec)[refIndex], value);
checkIndex++;
return;
}
else{
checkIndex++;
getDeviation(refIndex, checkIndex , dev);
}
if(checkIndex == checkVec->size() -1 ){
return;
}
}
void SummaryComparator::printUnits(){
std::vector<double> timeVec1, timeVec2;
setTimeVecs(timeVec1, timeVec2); // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
setDataSets(timeVec1, timeVec2);
for (int jvar = 0; jvar < stringlist_get_size(keysLong); jvar++){
std::cout << stringlist_iget(keysLong, jvar) << " unit: " << ecl_sum_get_unit(ecl_sum_fileShort, stringlist_iget(keysLong, jvar)) << std::endl;
}
}
//Called only when the keywords are equal in the getDeviations()-function
const char* SummaryComparator::getUnit(const char* keyword){
return ecl_sum_get_unit(ecl_sum_fileShort, keyword);
}
void SummaryComparator::printKeywords(){
int ivar = 0;
std::vector<std::string> noMatchString;
std::cout << "Keywords that are common for the files:" << std::endl;
while(ivar < stringlist_get_size(keysLong)){
const char* keyword = stringlist_iget(keysLong, ivar);
if (stringlist_contains(keysLong, keyword) && stringlist_contains(keysShort, keyword)){
std::cout << keyword << std::endl;
ivar++;
}
else{
noMatchString.push_back(keyword);
ivar++;
}
}
if(noMatchString.size() == 0){
std::cout << "No keywords were different" << std::endl;
return;
}
std::cout << "Keywords that are different: " << std::endl;
for (const auto& it : noMatchString) std::cout << it << std::endl;
std::cout << "\nOf the " << stringlist_get_size(keysLong) << " keywords " << stringlist_get_size(keysLong)-noMatchString.size() << " were equal and " << noMatchString.size() << " were different" << std::endl;
}
void SummaryComparator::printDataOfSpecificKeyword(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const char* keyword){
std::vector<double> dataVec1, dataVec2;
getDataVecs(dataVec1,dataVec2,keyword);
chooseReference(timeVec1, timeVec2,dataVec1,dataVec2);
size_t ivar = 0;
size_t jvar = 0;
const char separator = ' ';
const int numWidth = 14;
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << "Time";
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << "Ref data";
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << "Check data" << std::endl;
while(ivar < referenceVec->size()){
if(ivar == referenceVec->size() || jvar == checkVec->size() ){
break;
}
if((*referenceVec)[ivar] == (*checkVec)[jvar]){
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << (*referenceVec)[ivar];
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << (*referenceDataVec)[ivar];
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << (*checkDataVec)[jvar] << std::endl;
ivar++;
jvar++;
}else if((*referenceVec)[ivar] < (*checkVec)[jvar]){
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << (*referenceVec)[ivar];
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << (*referenceDataVec)[ivar];
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << "" << std::endl;
ivar++;
}
else{
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << (*checkVec)[jvar];
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << "";
std::cout << std::left << std::setw(numWidth) << std::setfill(separator) << (*checkDataVec)[jvar] << std::endl;
jvar++;
}
}
}

View File

@@ -0,0 +1,182 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SUMMARYCOMPARATOR_HPP
#define SUMMARYCOMPARATOR_HPP
#include "Deviation.hpp"
#include <iostream>
#include <iomanip>
#include <map>
#include <vector>
#include <algorithm>
#include <string>
// helper macro to handle error throws or not
#define HANDLE_ERROR(type, message) \
{ \
if (throwOnError) \
OPM_THROW(type, message); \
else \
std::cerr << message << std::endl; \
}
//! \brief Prototyping struct, encapsuling the stringlist libraries.
struct stringlist_struct;
typedef struct stringlist_struct stringlist_type;
//! \brief Prototyping struct, encapsuling the ert libraries.
struct ecl_sum_struct;
typedef struct ecl_sum_struct ecl_sum_type;
class SummaryComparator {
private:
double absoluteTolerance = 0; //!< The maximum absolute deviation that is allowed between two values.
double relativeTolerance = 0; //!< The maximum relative deviation that is allowed between twi values.
protected:
ecl_sum_type * ecl_sum1 = nullptr; //!< Struct that contains file1
ecl_sum_type * ecl_sum2 = nullptr; //!< Struct that contains file2
ecl_sum_type * ecl_sum_fileShort = nullptr; //!< For keeping track of the file with most/fewest timesteps
ecl_sum_type * ecl_sum_fileLong = nullptr; //!< For keeping track of the file with most/fewest timesteps
stringlist_type* keys1 = nullptr; //!< For storing all the keywords of file1
stringlist_type* keys2 = nullptr; //!< For storing all the keywords of file2
stringlist_type * keysShort = nullptr; //!< For keeping track of the file with most/fewest keywords
stringlist_type * keysLong = nullptr; //!< For keeping track of the file with most/fewest keywords
const std::vector<double> * referenceVec = nullptr; //!< For storing the values of each time step for the file containing the fewer time steps.
const std::vector<double> * referenceDataVec = nullptr; //!< For storing the data corresponding to each time step for the file containing the fewer time steps.
const std::vector<double> * checkVec = nullptr; //!< For storing the values of each time step for the file containing the more time steps.
const std::vector<double> * checkDataVec = nullptr; //!< For storing the data values corresponding to each time step for the file containing the more time steps.
bool printKeyword = false; //!< Boolean value for choosing whether to print the keywords or not
bool printSpecificKeyword = false; //!< Boolean value for choosing whether to print the vectors of a keyword or not
bool throwOnError = true; //!< Throw on first error
bool analysis = false; //!< Perform error analysis
std::map<std::string, std::vector<Deviation>> deviations;
//! \brief Calculate deviation between two data values and stores it in a Deviation struct.
//! \param[in] refIndex Index in reference data
//! \param[in] checkindex Index in data to be checked.
//! \param[out] dev Holds the result from the comparison on return.
//! \details Uses the #referenceVec as basis, and checks its values against the values in #checkDataVec. The function is reccursive, and will update the iterative index j of the #checkVec until #checkVec[j] >= #referenceVec[i]. \n When #referenceVec and #checkVec have the same time value (i.e. #referenceVec[i] == #checkVec[j]) a direct comparison is used, \n when this is not the case, when #referenceVec[i] do not excist as an element in #checkVec, a value is generated, either by the principle of unit step or by interpolation.
void getDeviation(size_t refIndex, size_t &checkIndex, Deviation &dev);
//! \brief Figure out which data file contains the most / less timesteps and assign member variable pointers accordingly.
//! \param[in] timeVec1 Data from first file
//! \param[in] timeVec2 Data from second file
//! \details Figure out which data file that contains the more/fewer time steps and assigns the private member variable pointers #ecl_sum_fileShort / #ecl_sum_fileLong to the correct data sets #ecl_sum1 / #ecl_sum2.
void setDataSets(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2);
//! \brief Reads in the time values of each time step.
//! \param[in] timeVec1 Vector for storing the time steps from file1
//! \param[in] timeVec2 Vector for storing the time steps from file2
void setTimeVecs(std::vector<double> &timeVec1,std::vector<double> &timeVec2);
//! \brief Read the data for one specific keyword into two separate vectors.
//! \param[in] dataVec1 Vector for storing the data for one specific keyword from file1
//! \param[in] dataVec2 Vector for storing the data for one specific keyword from file2
//! \details The two data files do not necessarily have the same amount of data values, but the values must correspond to the same interval in time. Thus possible to interpolate values.
void getDataVecs(std::vector<double> &dataVec1,
std::vector<double> &dataVec2, const char* keyword);
//! \brief Sets one data set as a basis and the other as values to check against.
//! \param[in] timeVec1 Used to figure out which dataset that have the more/fewer time steps.
//! \param[in] timeVec2 Used to figure out which dataset that have the more/fewer time steps.
//! \param[in] dataVec1 For assiging the the correct pointer to the data vector.
//! \param[in] dataVec2 For assiging the the correct pointer to the data vector.
//! \details Figures out which time vector that contains the fewer elements. Sets this as #referenceVec and its corresponding data as #referenceDataVec. \n The remaining data set is set as #checkVec (the time vector) and #checkDataVec.
void chooseReference(const std::vector<double> &timeVec1,
const std::vector<double> &timeVec2,
const std::vector<double> &dataVec1,
const std::vector<double> &dataVec2);
//! \brief Returns the relative tolerance.
double getRelTolerance(){return this->relativeTolerance;}
//! \brief Returns the absolute tolerance.
double getAbsTolerance(){return this->absoluteTolerance;}
//! \brief Returns the unit of the values of a keyword
//! \param[in] keyword The keyword of interest.
//! \param[out] ret The unit of the keyword as a const char*.
const char* getUnit(const char* keyword);
//! \brief Prints the units of the files.
void printUnits();
//! \brief Prints the keywords of the files.
//! \details The function prints first the common keywords, than the keywords that are different.
void printKeywords();
//! \brief Prints the summary vectors from the two files.
//! \details The function requires that the summary vectors of the specific file have been read into the member variables referenceVec etc.
void printDataOfSpecificKeyword(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const char* keyword);
public:
//! \brief Creates an SummaryComparator class object
//! \param[in] basename1 Path to file1 without extension.
//! \param[in] basename1 Path to file2 without extension.
//! \param[in] absoluteTolerance The absolute tolerance which is to be used in the test.
//! \param[in] relativeTolerance The relative tolerance which is to be used in the test.
//! \details The constructor creates an object of the class, and openes the files, an exception is thrown if the opening of the files fails. \n It creates stringlists, in which keywords are to be stored, and figures out which keylist that contains the more/less keywords. \n Also the private member variables aboluteTolerance and relativeTolerance are set.
SummaryComparator(const std::string& basename1,
const std::string& basename2,
double absoluteTolerance, double relativeTolerance);
//! \brief Destructor
//! \details The destructor takes care of the allocated memory in which data has been stored.
~SummaryComparator();
//! \brief Calculates the deviation between two values
//! \param[in] val1 The first value of interest.
//! \param[in] val2 The second value if interest.
//! \param[out] ret Returns a Deviation struct.
//! \details The function takes two values, calculates the absolute and relative deviation and returns the result as a Deviation struct.
static Deviation calculateDeviations( double val1, double val2);
//! \brief Sets the private member variable printKeywords
//! \param[in] boolean Boolean value
//! \details The function sets the private member variable printKeywords. When it is true the function printKeywords will be called.
void setPrintKeywords(bool boolean){this->printKeyword = boolean;}
//! \brief Sets the private member variable printSpecificKeyword
//! \param[in] boolean Boolean value
//! \details The function sets the private member variable printSpecificKeyword. When true, the summary vector of the keyword for both files will be printed.
void setPrintSpecificKeyword(bool boolean){this->printSpecificKeyword = boolean;}
//! \brief Unit step function
//! \param[in] value The input value should be the last know value
//! \param[out] ret Return the unit-step-function value.
//! \details In this case: The unit step function is used when the data from the two data set, which is to be compared, don't match in time. \n The unit step function is then to be called on the #checkDataVec 's value at the last time step which is before the time of comparison.
//! \brief Returns a value based on the unit step principle.
static double unitStep(double value){return value;}
//! \brief Set whether to throw on errors or not.
void throwOnErrors(bool dothrow) { throwOnError = dothrow; }
//! \brief Set whether or not to perform error analysis.
void doAnalysis(bool analyse) { analysis = analyse; }
};
#endif

View File

@@ -0,0 +1,386 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "summaryIntegrationTest.hpp"
#include <opm/common/ErrorMacros.hpp>
#include <ert/ecl/ecl_sum.hpp>
#include <ert/util/stringlist.hpp>
#include <cmath>
void SummaryIntegrationTest::getIntegrationTest(){
std::vector<double> timeVec1, timeVec2;
setTimeVecs(timeVec1, timeVec2); // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
setDataSets(timeVec1, timeVec2);
int ivar = 0;
if(!allowDifferentAmountOfKeywords){
if(stringlist_get_size(keysShort) != stringlist_get_size(keysLong)){
OPM_THROW(std::invalid_argument, "Different ammont of keywords in the two summary files.");
}
}
if(printKeyword){
printKeywords();
return;
}
std::string keywordWithGreatestErrorRatio;
double greatestRatio = 0;
//Iterates over all keywords from the restricted file, use iterator "ivar". Searches for a match in the file with more keywords, use the itarator "jvar".
while(ivar < stringlist_get_size(keysShort)){
const char* keyword = stringlist_iget(keysShort, ivar);
if(oneOfTheMainVariables){
std::string keywordString(keyword);
std::string substr = keywordString.substr(0,4);
if(substr!= mainVariable){
ivar++;
continue;
}
}
for (int jvar = 0; jvar < stringlist_get_size(keysLong); jvar++){
if (strcmp(keyword, stringlist_iget(keysLong, jvar)) == 0){ //When the keywords are equal, proceed in comparing summary files.
/* if(!checkUnits(keyword)){
OPM_THROW(std::runtime_error, "For keyword " << keyword << " the unit of the two files is not equal. Not possible to compare.");
} //Comparing the unit of the two vectors.*/
checkForKeyword(timeVec1, timeVec2, keyword);
if(findVectorWithGreatestErrorRatio){
WellProductionVolume volume = getSpecificWellVolume(timeVec1,timeVec2, keyword);
findGreatestErrorRatio(volume,greatestRatio, keyword, keywordWithGreatestErrorRatio);
}
break;
}
//will only enter here if no keyword match
if(jvar == stringlist_get_size(keysLong)-1){
if(!allowDifferentAmountOfKeywords){
OPM_THROW(std::invalid_argument, "No match on keyword");
}
}
}
ivar++;
}
if(findVectorWithGreatestErrorRatio){
std::cout << "The keyword " << keywordWithGreatestErrorRatio << " had the greatest error ratio, which was " << greatestRatio << std::endl;
}
if((findVolumeError || oneOfTheMainVariables) && !findVectorWithGreatestErrorRatio){
evaluateWellProductionVolume();
}
if(allowSpikes){
std::cout << "checkWithSpikes succeeded." << std::endl;
}
}
void SummaryIntegrationTest::getIntegrationTest(const char* keyword){
if(stringlist_contains(keysShort,keyword) && stringlist_contains(keysLong, keyword)){
std::vector<double> timeVec1, timeVec2;
setTimeVecs(timeVec1, timeVec2); // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
setDataSets(timeVec1, timeVec2);
if(printSpecificKeyword){
printDataOfSpecificKeyword(timeVec1, timeVec2, keyword);
}
if(findVolumeError){
WellProductionVolume volume = getSpecificWellVolume(timeVec1, timeVec2, keyword);
if(volume.error == 0){
std::cout << "For keyword " << keyword << " the total production volume is 0" << std::endl;
}
else{
std::cout << "For keyword " << keyword << " the total production volume is "<< volume.total;
std::cout << ", the error volume is " << volume.error << " the error ratio is " << volume.error/volume.total << std::endl;
}
}
checkForKeyword(timeVec1, timeVec2, keyword);
return;
}
OPM_THROW(std::invalid_argument, "The keyword used is not common for the two files.");
}
void SummaryIntegrationTest::checkForKeyword(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const char* keyword){
std::vector<double> dataVec1, dataVec2;
getDataVecs(dataVec1,dataVec2,keyword);
chooseReference(timeVec1, timeVec2,dataVec1,dataVec2);
if(allowSpikes){
checkWithSpikes(keyword);
}
if(findVolumeError ||oneOfTheMainVariables ){
volumeErrorCheck(keyword);
}
}
int SummaryIntegrationTest::checkDeviation(const Deviation& deviation){
double absTol = getAbsTolerance();
double relTol = getRelTolerance();
if (deviation.rel> relTol && deviation.abs > absTol){
return 1;
}
return 0;
}
void SummaryIntegrationTest::findGreatestErrorRatio(const WellProductionVolume& volume,
double &greatestRatio,
const char* currentKeyword,
std::string &greatestErrorRatio){
if (volume.total != 0 && (volume.total - volume.error > getAbsTolerance()) ){
if(volume.error/volume.total > greatestRatio){
greatestRatio = volume.error/volume.total;
std::string currentKeywordStr(currentKeyword);
greatestErrorRatio = currentKeywordStr;
}
}
}
void SummaryIntegrationTest::volumeErrorCheck(const char* keyword){
const ecl::smspec_node * node = ecl_sum_get_general_var_node (ecl_sum_fileShort ,keyword);//doesn't matter which ecl_sum_file one uses, the kewyord SHOULD be equal in terms of smspec data.
if (node->is_historical())
return;
if (!mainVariable.empty()){
std::string keywordString(keyword);
std::string firstFour = keywordString.substr(0,4);
if(mainVariable == firstFour && firstFour == "WOPR"){
if(firstFour == "WOPR"){
WellProductionVolume result = getWellProductionVolume(keyword);
WOP += result;
return;
}
}
if(mainVariable == firstFour && firstFour == "WWPR"){
if(firstFour == "WWPR"){
WellProductionVolume result = getWellProductionVolume(keyword);
WWP += result;
return;
}
}
if(mainVariable == firstFour && firstFour == "WGPR"){
if(firstFour == "WGPR"){
WellProductionVolume result = getWellProductionVolume(keyword);
WGP += result;
return;
}
}
if(mainVariable == firstFour && firstFour == "WBHP"){
if(firstFour == "WBHP"){
WellProductionVolume result = getWellProductionVolume(keyword);
WBHP += result;
return;
}
}
}
updateVolumeError(keyword);
}
void SummaryIntegrationTest::updateVolumeError(const char* keyword){
std::string keywordString(keyword);
std::string firstFour = keywordString.substr(0,4);
if(firstFour == "WOPR"){
WellProductionVolume result = getWellProductionVolume(keyword);
WOP += result;
}
if(firstFour == "WWPR"){
WellProductionVolume result = getWellProductionVolume(keyword);
WWP += result;
}
if(firstFour == "WGPR"){
WellProductionVolume result = getWellProductionVolume(keyword);
WGP += result;
}
if(firstFour == "WBHP"){
WellProductionVolume result = getWellProductionVolume(keyword);
WBHP += result;
}
}
WellProductionVolume SummaryIntegrationTest::getWellProductionVolume(const char * keyword){
double total = integrate(*referenceVec, *referenceDataVec);
double error = integrateError(*referenceVec, *referenceDataVec,
*checkVec, *checkDataVec);
WellProductionVolume wPV;
wPV.total = total;
wPV.error = error;
if(wPV.total != 0 && wPV.total-wPV.error > getAbsTolerance()){
if( (wPV.error/wPV.total > getRelTolerance()) && throwExceptionForTooGreatErrorRatio){
OPM_THROW(std::runtime_error, "For the keyword "<< keyword << " the error ratio was " << wPV.error/wPV.total << " which is greater than the tolerance " << getRelTolerance());
}
}
return wPV;
}
void SummaryIntegrationTest::evaluateWellProductionVolume(){
if(mainVariable.empty()){
double ratioWOP, ratioWWP, ratioWGP, ratioWBHP;
ratioWOP = WOP.error/WOP.total;
ratioWWP = WWP.error/WWP.total;
ratioWGP = WGP.error/WGP.total;
ratioWBHP = WBHP.error/WBHP.total;
std::cout << "\n The total oil volume is " << WOP.total << ". The error volume is "<< WOP.error << ". The error ratio is " << ratioWOP << std::endl;
std::cout << "\n The total water volume is " << WWP.total << ". The error volume is "<< WWP.error << ". The error ratio is " << ratioWWP << std::endl;
std::cout << "\n The total gas volume is " << WGP.total <<". The error volume is "<< WGP.error << ". The error ratio is " << ratioWGP << std::endl;
std::cout << "\n The total area under the WBHP curve is " << WBHP.total << ". The area under the error curve is "<< WBHP.error << ". The error ratio is " << ratioWBHP << std::endl << std::endl;
}
if(mainVariable == "WOPR"){
std::cout << "\nThe total oil volume is " << WOP.total << ". The error volume is "<< WOP.error << ". The error ratio is " << WOP.error/WOP.total << std::endl<< std::endl;
}
if(mainVariable == "WWPR"){
std::cout << "\nThe total water volume is " << WWP.total << ". The error volume is "<< WWP.error << ". The error ratio is " << WWP.error/WWP.total << std::endl<< std::endl;
}
if(mainVariable == "WGPR"){
std::cout << "\nThe total gas volume is " << WGP.total <<". The error volume is "<< WGP.error << ". The error ratio is " << WGP.error/WGP.total << std::endl<< std::endl;
}
if(mainVariable == "WBHP"){
std::cout << "\nThe total area under the WBHP curve " << WBHP.total << ". The area under the error curve is "<< WBHP.error << ". The error ratio is " << WBHP.error/WBHP.total << std::endl << std::endl;
}
}
void SummaryIntegrationTest::checkWithSpikes(const char* keyword){
int errorOccurrences = 0;
size_t jvar = 0 ;
bool spikeCurrent = false;
Deviation deviation;
for (size_t ivar = 0; ivar < referenceVec->size(); ivar++){
int errorOccurrencesPrev = errorOccurrences;
bool spikePrev = spikeCurrent;
getDeviation(ivar,jvar, deviation);
errorOccurrences += checkDeviation(deviation);
if (errorOccurrences != errorOccurrencesPrev){
spikeCurrent = true;
} else{
spikeCurrent = false;
}
if(spikePrev&&spikeCurrent){
std::cout << "For keyword " << keyword << " at time step " << (*referenceVec)[ivar] <<std::endl;
OPM_THROW(std::invalid_argument, "For keyword " << keyword << " at time step " << (*referenceVec)[ivar] << ", wwo deviations in a row exceed the limit. Not a spike value. Integration test fails." );
}
if(errorOccurrences > this->spikeLimit){
std::cout << "For keyword " << keyword << std::endl;
OPM_THROW(std::invalid_argument, "For keyword " << keyword << " too many spikes in the vector. Integration test fails.");
}
}
}
WellProductionVolume
SummaryIntegrationTest::getSpecificWellVolume(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const char* keyword){
std::vector<double> dataVec1, dataVec2;
getDataVecs(dataVec1,dataVec2,keyword);
chooseReference(timeVec1, timeVec2,dataVec1,dataVec2);
return getWellProductionVolume(keyword);
}
double SummaryIntegrationTest::integrate(const std::vector<double>& timeVec,
const std::vector<double>& dataVec){
double totalSum = 0;
if(timeVec.size() != dataVec.size()){
OPM_THROW(std::runtime_error, "The size of the time vector does not match the size of the data vector.");
}
for(size_t i = 0; i < timeVec.size()-1; i++){
double width = timeVec[i+1] - timeVec[i];
double height = dataVec[i+1];
totalSum += getRectangleArea(height, width);
}
return totalSum;
}
double SummaryIntegrationTest::integrateError(const std::vector<double>& timeVec1,
const std::vector<double>& dataVec1,
const std::vector<double>& timeVec2,
const std::vector<double>& dataVec2){
// When the data corresponds to a rate the integration will become a Riemann
// sum. This function calculates the Riemann sum of the error. The reason why
// a Riemann sum is used is because of the way the data is written to file.
// When a change occur (e.g. change of a rate), the data (value and time) is
// written to file, THEN the change happens in the simulator, i.e., we will
// notice the change at the next step.
//
// Keep in mind that the summary vector is NOT a continuous curve, only points
// of data (time, value). We have to guess what happens between the data
// points, we do this by saying: "There are no change, the only change happens
// at the data points." As stated above, the value of this constant "height" of
// the rectangle corresponds to the value of the last time step. Thus we have
// to use the "right hand side value of the rectangle as height
//
// someDataVector[ivar] instead of someDataVector[ivar-1]
//
// (which intuition is saying is the correct value to use).
if(timeVec1.size() != dataVec1.size() || timeVec2.size() != dataVec2.size() ){
OPM_THROW(std::runtime_error, "The size of the time vector does not match the size of the data vector.");
}
double errorSum = 0;
double rightEdge, leftEdge, width;
size_t i = 1;
size_t j = 1;
leftEdge = timeVec1[0];
while(i < timeVec1.size()){
if(j == timeVec2.size() ){
break;
}
if(timeVec1[i] == timeVec2[j]){
rightEdge = timeVec1[i];
width = rightEdge - leftEdge;
double dev = std::fabs(dataVec1[i] - dataVec2[j]);
errorSum += getRectangleArea(dev, width);
leftEdge = rightEdge;
i++;
j++;
continue;
}
if(timeVec1[i] < timeVec2[j]){
rightEdge = timeVec1[i];
width = rightEdge - leftEdge;
double value = unitStep(dataVec2[j]);
double dev = std::fabs(dataVec1[i]-value);
errorSum += getRectangleArea(dev, width);
leftEdge = rightEdge;
i++;
continue;
}
if(timeVec2[j] < timeVec1[i]){
rightEdge = timeVec2[j];
width = rightEdge - leftEdge;
double value = unitStep(dataVec1[i]);
double dev = std::fabs(dataVec2[j]-value);
errorSum += getRectangleArea(dev, width);
leftEdge = rightEdge;
j++;
continue;
}
}
return errorSum;
}

View File

@@ -0,0 +1,217 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "summaryComparator.hpp"
//! \brief Struct for storing the total area under a graph.
//! \details Used when plotting summary vector against time. In most cases this represents a volume.
struct WellProductionVolume{
double total=0; //!< The total area under the graph when plotting the summary vector against time. In most cases the total production volume.
double error=0; //!< The total area under the graph when plotting the deviation vector against time. In most cases the total error volume.
//! \brief Overloaded operator
//! \param[in] rhs WellProductionVolume struct
WellProductionVolume& operator+=(const WellProductionVolume& rhs){
this->total += rhs.total;
this->error += rhs.error;
return *this;
}
};
//! \details The class inherits from the SummaryComparator class, which takes care of all file reading. \n The IntegrationTest class compares values from the two different files and throws exceptions when the deviation is unsatisfying.
class SummaryIntegrationTest: public SummaryComparator {
private:
bool allowSpikes = false; //!< Boolean value, when true checkForSpikes is included as a sub test in the integration test. By default: false.
bool findVolumeError = false; //!< Boolean value, when true volumeErrorCheck() is included as a sub test in the integration test. By default: false.
bool allowDifferentAmountOfKeywords = true; //!< Boolean value, when false the integration test will check wheter the two files have the same amount of keywords. \nIf they don't, an exception will be thrown. By default: true.
bool findVectorWithGreatestErrorRatio = false; //!< Boolean value, when true the integration test will find the vector that has the greatest error ratio. By default: false.
bool oneOfTheMainVariables = false; //!< Boolean value, when true the integration test will only check for one of the primary variables (WOPR, WGPR, WWPR. WBHP), which will be specified by user. By default: false.
bool throwExceptionForTooGreatErrorRatio = true; //!< Boolean value, when true any volume error ratio that exceeds the relativeTolerance will cause an exception to be thrown. By default: true.
std::string mainVariable; //!< String variable, where the name of the main variable of interest (one of WOPR, WBHP, WWPR, WGPR) is stored. Can be empty.
int spikeLimit = 13370; //!< The limit for how many spikes to allow in the data set of a certain keyword. By default: Set to a high number, \n should not trig the (if spikeOccurrences > spikeLimit){ // throw exception }.
WellProductionVolume WOP; //!< WellProductionVolume struct for storing the total production volume and total error volume of all the keywords which start with WOPR
WellProductionVolume WWP; //!< WellProductionVolume struct for storing the total production volume and total error volume of all the keywords which start with WWPR
WellProductionVolume WGP;//!< WellProductionVolume struct for storing the total production volume and total error volume of all the keywords which start with WGPR
WellProductionVolume WBHP; //!< WellProductionVolume struct for storing the value of the area under the graph when plotting summary vector/deviation vector against time.This is for keywords starting with WBHP. \nNote: the name of the struct may be misleading, this is not an actual volume.
//! \brief The function gathers the correct data for comparison for a specific keyword
//! \param[in] timeVec1 A std::vector<double> that contains the time steps of file 1.
//! \param[in] timeVec2 A std::vector<double> that contains the time steps of file 2.
//! \param[in] keyword The keyword of interest
//! \details The function requires an outer loop which iterates over the keywords of the files. It prepares an integration test by gathering the data, stroing it into two vectors, \n deciding which is to be used as a reference/basis and calling the test function.
void checkForKeyword(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2, const char* keyword);
//! \brief The function compares the volume error to the total production volume of a certain type of keyword.
//! param[in] keyword The keyword of interest.
//! \details The function takes in a keyword and checks if it is of interest. Only keywords which say something about the well oil production, well water production, \n well gas production and the well BHP are of interest. The function sums up the total production in the cases where it is possible, \n and sums up the error volumes by a trapezoid integration method. The resulting values are stored in member variable structs of type WellProductionVolume, and double variables. For proper use of the function all the keywords of the file should be checked. This is satisfied if it is called by checkForKeyword.
void volumeErrorCheck(const char* keyword);
//! \brief The function calculates the total production volume and total error volume of a specific keyword
//! \param[in] timeVec1 A std::vector<double> that contains the time steps of file 1.
//! \param[in] timeVec2 A std::vector<double> that contains the time steps of file 2.
//! \param[in] keyword The keyword of interest
//! \param[out] ret Returns a WellProductionWolume struct
//! \details The function reads the data from the two files into the member variable vectors (of the super class). It returns a WellProductionVolume struct calculated from the vectors corresponding to the keyword.
WellProductionVolume getSpecificWellVolume(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const char* keyword);
//! \brief The function is a regression test which allows spikes.
//! \param[in] keyword The keyword of interest, the keyword the summary vectors "belong" to.
//! \details The function requires the protected member variables referenceVec, referenceDataVec, checkVec and checkDataVec to be stored with data, which is staisfied if it is called by checkForKeyword. \n It compares the two vectors value by value, and if the deviation is unsatisfying, the errorOccurrenceCounter is incremented. If the errorOccurrenceCounter becomes greater than the errorOccurrenceLimit, \n a exception is thrown. The function will allow spike values, however, if two values in a row exceed the deviation limit, they are no longer spikes, and an exception is thrown.
void checkWithSpikes(const char* keyword);
//! \brief Caluculates a deviation, throws exceptions and writes and error message.
//! \param[in] deviation Deviation struct
//! \param[out] int Returns 0/1, depending on wheter the deviation exceeded the limit or not.
//! \details The function checks the values of the Deviation struct against the absolute and relative tolerance, which are private member values of the super class. \n When comparing against the relative tolerance an additional term is added, the absolute deviation has to be greater than 1e-6 for the function to throw an exception. \n When the deviations are too great, the function returns 1.
int checkDeviation(const Deviation& deviation);
//! \brief Calculates the keyword's total production volume and error volume
//! \param[in] keyword The keyword of interest.
//! \param[out] wellProductionVolume A struct containing the total production volume and the total error volume.
//! \details The function calculates the total production volume and total error volume of a keyword, by the trapezoid integral method. \n The function throws and exception if the total error volume is negative. The function returns the results as a struct.
WellProductionVolume getWellProductionVolume(const char* keyword);
//! \brief The function function works properly when the private member variables are set (after running the integration test which findVolumeError = true). \n It prints out the total production volume, the total error volume and the error ratio.
void evaluateWellProductionVolume();
//! \brief The function calculates the total production volume and total error volume
//! \param keyword The keyword of interest
//! \details The function uses the data that is stored in the member variable vectors. It calculates the total production volume \n and the total error volume of the specified keyword, and adds the result to the private member WellProductionVolume variables of the class.
void updateVolumeError(const char* keyword);
//! \brief Finds the keyword which has the greates error volume ratio
//! \param[in] volume WellProductionVolume struct which contains the data used for comparison
//! \param[in] greatestRatio Double value taken in by reference. Stores the greatest error ratio value.
//! \param[in] currentKeyword The keyword that is under evaluation
//! \param[in] greatestErrorRatio String which contains the name of the keyword which has the greatest error ratio
//! \details The function requires an outer loop which iterates over the keywords in the files, and calls the function for each keyword. \nThe valiables double greatestRatio and std::string keywordWithTheGreatestErrorRatio must be declared outside the loop. \nWhen the current error ratio is greater than the value stored in greatestRatio, the gratestRatio value is updated with the current error ratio.
void findGreatestErrorRatio(const WellProductionVolume& volume,
double &greatestRatio,
const char* currentKeyword,
std::string &greatestErrorRatio);
#if 0
//! \brief Checks whether the unit of the two data vectors is the same
//! \param[in] keyword The keyword of interest
//! \param[out] boolean True/false, depending on whether the units are equal or not
bool checkUnits(const char* keyword);
#endif
public:
//! \brief Constructor, creates an object of IntegrationTest class.
//! \param[in] basename1 Path to file1 without extension.
//! \param[in] basename1 Path to file2 without extension.
//! \param[in] atol The absolute tolerance which is to be used in the test.
//! \param[in] rtol The relative tolerance which is to be used in the test.
//! \details The constructor calls the constructor of the super class.
SummaryIntegrationTest(const std::string& basename1,
const std::string& basename2,
double atol, double rtol) :
SummaryComparator(basename1, basename2, atol, rtol) {}
//! \brief This function sets the private member variable allowSpikes.
//! \param[in] allowSpikes Boolean value
//! \details When allowSpikes is true, the integration test checkWithSpikes is excecuted.
void setAllowSpikes(bool allowSpikesArg){this->allowSpikes = allowSpikesArg;}
//! \brief This function sets the private member variable findVolumeError.
//! \param[in] findVolumeError Boolean value
//! \details When findVolumeError is true, the integration test volumeErrorCheck and the function evaluateWellProductionVolume are excecuted.
void setFindVolumeError(bool findVolumeErrorArg){this->findVolumeError = findVolumeErrorArg;}
//! \brief This function sets the private member variable oneOfTheMainVariables
//! \param[in] oneOfTheMainVariables Boolean value
//! \details When oneOfTheMainVariables is true, the integration test runs the substest volumeErrorCheckForOneSpecificVariable.
void setOneOfTheMainVariables(bool oneOfTheMainVariablesArg){this->oneOfTheMainVariables = oneOfTheMainVariablesArg;}
//! \brief This function sets the member variable string #mainVariable
//! \param[in] mainVar This is the string should contain one of the main variables. e.g. WOPR
void setMainVariable(std::string mainVar){this->mainVariable = mainVar;}
//! \brief This function sets the private member variable spikeLimit.
//! \param[in] lim The value which the spike limit is to be given.
void setSpikeLimit(int lim){this->spikeLimit = lim;}
//! \brief This function sets the private member variable findVectorWithGreatestErrorRatio
//! \param[in] findVolumeError Boolean value
//! \details When findVectorWithGreatestErrorRatio is true, the integration test will print the vector with the greatest error ratio.
void setFindVectorWithGreatestErrorRatio(bool boolean){this->findVectorWithGreatestErrorRatio = boolean;}
//! \brief This function sets the private member variable allowDifferentAmountsOfKeywords
//! \param[in] boolean Boolean value
//! \details When allowDifferentAmountOfKeywords is false, the amount of kewyord in the two files will be compared. \nIf the number of keywords are different an exception will be thrown.
void setAllowDifferentAmountOfKeywords(bool boolean){this->allowDifferentAmountOfKeywords = boolean;}
//! \brief This function sets the private member variable throwExceptionForTooGreatErrorRatio
//! \param[in] boolean Boolean value
//! \details When throwExceptionForTooGreatErrorRatio is false, the function getWellProductionVolume will throw an exception.
void setThrowExceptionForTooGreatErrorRatio(bool boolean){this->throwExceptionForTooGreatErrorRatio = boolean;}
//! \brief This function executes a integration test for all the keywords. If the two files do not match in amount of keywords, an exception is thrown. \n Uses the boolean member variables to know which tests to execute.
void getIntegrationTest();
//! \brief This function executes a integration test for one specific keyword. If one or both of the files do not have the keyword, an exception is thorwn. \n Uses the boolean member variables to know which tests to execute.
void getIntegrationTest(const char* keyword);
//! \brief This function calculates the area of an rectangle of height height and width time-timePrev
//! \param[in] height The height of the rectangle. See important statement of use below.
//! \param[in] width The width of the rectangle
//! \param[out] area Returns the area of the rectangle
//! \details This function is simple. When using it on a summary vector (data values plotted againt time), calculating the area between the two points i and i+1 note this:\nThe width is time_of_i+1 - time_of_i, the height is data_of_i+1 NOT data_of_i. The upper limit must be used.
static double getRectangleArea(double height, double width){return height*width;}
//! \brief This function calculates the area under a graph by doing a Riemann sum
//! \param[in] timeVec Contains the time values
//! \param[in] dataVec Contains the data values
//! \details The function does a Riemann sum integration of the graph formed
//! by the points (timeVec[i] , dataVec[i]).
//! In the case of a summary vector, the summary vector of quantity
//! corresponding to a rate, is a piecewise continus function consisting
//! of unit step functions. Thus the Riemann sum will become an
//! exact expression for the integral of the graph.
//! Important: For the data values correspoding to time i and i-1,
//! the fixed value of the height of the rectangles in the Riemann sum
//! is set by the data value i. The upper limit must be used.
static double integrate(const std::vector<double>& timeVec,
const std::vector<double>& dataVec);
//! \brief This function calculates the Riemann sum of the error between two graphs.
//! \param[in] timeVec1 Contains the time values of graph 1
//! \param[in] dataVec1 Contains the data values of graph 1
//! \param[in] timeVec2 Contains the time values of graph 2
//! \param[in] dataVec2 Contains the data values of graph 2
//! \details This function takes in two graphs and returns the integrated error.
//! In case of ecl summary vectors: if the vectors correspond to a
//! quantity which is a rate, the vectors will be piecewise
//! continous unit step functions. In this case the error will also
//! be a piecewise continous unit step function. The function uses
//! a Riemann sum when calculating the integral. Thus the integral
//! will become exact. Important: For the data values corresponding
//! to time i and i-1, the fixed value of the height of the rectangles
//! in the Riemann sum is set by the data value i.
//! The upper limit must be used.
static double integrateError(const std::vector<double>& timeVec1,
const std::vector<double>& dataVec1,
const std::vector<double>& timeVec2,
const std::vector<double>& dataVec2);
};

View File

@@ -0,0 +1,178 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "summaryRegressionTest.hpp"
#include <opm/common/ErrorMacros.hpp>
#include <ert/ecl/ecl_sum.hpp>
#include <ert/util/stringlist.h>
#include <string>
void SummaryRegressionTest::getRegressionTest(){
std::vector<double> timeVec1, timeVec2;
setTimeVecs(timeVec1, timeVec2); // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
setDataSets(timeVec1, timeVec2); //Figures which dataset that contains more/less values pr keyword vector.
std::cout << "Comparing " << timeVec1.size() << " steps." << std::endl;
int ivar = 0;
if((! this->allowDifferentNumberOfKeywords) &&
(stringlist_get_size(keysShort) != stringlist_get_size(keysLong)))
{
int missing_count = 0;
std::cout << "Keywords missing from one case: " << std::endl;
for (int i=0; i < stringlist_get_size( keysLong); i++) {
const char * key = stringlist_iget( keysLong , i );
if (!stringlist_contains( keysShort , key)) {
std::cout << key << " ";
missing_count++;
if ((missing_count % 8) == 0)
std::cout << std::endl;
}
}
std::cout << std::endl;
HANDLE_ERROR(std::runtime_error, "Different amount of keywords in the two summary files.");
}
if(printKeyword){
printKeywords();
}
//Iterates over all keywords from the restricted file, use iterator "ivar". Searches for a match in the file with more keywords, use the iterator "jvar".
bool throwAtEnd = false;
while(ivar < stringlist_get_size(keysShort)){
const char* keyword = stringlist_iget(keysShort, ivar);
std::string keywordString(keyword);
for (int jvar = 0; jvar < stringlist_get_size(keysLong); jvar++){
if (strcmp(keyword, stringlist_iget(keysLong, jvar)) == 0){ //When the keywords are equal, proceed in comparing summary files.
if (isRestartFile && keywordString.substr(3,1)=="T"){
break;
}
throwAtEnd |= !checkForKeyword(timeVec1, timeVec2, keyword);
break;
}
//will only enter here if no keyword match
if(jvar == stringlist_get_size(keysLong)-1){
std::cout << "Could not find keyword: " << stringlist_iget(keysShort, ivar) << std::endl;
OPM_THROW(std::runtime_error, "No match on keyword");
}
}
ivar++;
}
if (analysis) {
std::cout << deviations.size() << " summary keyword"
<< (deviations.size() > 1 ? "s":"") << " exhibit failures" << std::endl;
size_t len = ecl_sum_get_data_length(ecl_sum1);
for (const auto& iter : deviations) {
std::cout << "\t" << iter.first << std::endl;
std::cout << "\t\tFails for " << iter.second.size() << " / " << len << " steps." << std::endl;
std::cout.precision(7);
double absErr = std::max_element(iter.second.begin(), iter.second.end(),
[](const Deviation& a, const Deviation& b)
{
return a.abs < b.abs;
})->abs;
double relErr = std::max_element(iter.second.begin(), iter.second.end(),
[](const Deviation& a, const Deviation& b)
{
return a.rel < b.rel;
})->rel;
std::cout << "\t\tLargest absolute error: "
<< std::scientific << absErr << std::endl;
std::cout << "\t\tLargest relative error: "
<< std::scientific << relErr << std::endl;
}
}
if (throwAtEnd)
OPM_THROW(std::runtime_error, "Regression test failed.");
else if (deviations.empty())
std::cout << "Regression test succeeded." << std::endl;
}
void SummaryRegressionTest::getRegressionTest(const char* keyword){
std::vector<double> timeVec1, timeVec2;
setTimeVecs(timeVec1, timeVec2); // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
setDataSets(timeVec1, timeVec2); //Figures which dataset that contains more/less values pr keyword vector.
std::string keywordString(keyword);
if(stringlist_contains(keysShort,keyword) && stringlist_contains(keysLong, keyword)){
if (isRestartFile && keywordString.substr(3,1)=="T"){
return;
}
if (checkForKeyword(timeVec1, timeVec2, keyword))
std::cout << "Regression test succeeded." << std::endl;
else
OPM_THROW(std::runtime_error, "Regression test failed");
return;
}
std::cout << "The keyword suggested, " << keyword << ", is not supported by one or both of the summary files. Please use a different keyword." << std::endl;
OPM_THROW(std::runtime_error, "Input keyword from user does not exist in/is not common for the two summary files.");
}
bool SummaryRegressionTest::checkDeviation(Deviation deviation, const char* keyword, int refIndex, int checkIndex){
double absTol = getAbsTolerance();
double relTol = getRelTolerance();
if (deviation.rel > relTol && deviation.abs > absTol){
if (analysis) {
deviations[keyword].push_back(deviation);
} else {
std::cout << "For keyword " << keyword << std::endl;
std::cout << "(days, reference value) and (days, check value) = (" << (*referenceVec)[refIndex] << ", " << (*referenceDataVec)[refIndex]
<< ") and (" << (*checkVec)[checkIndex-1] << ", " << (*checkDataVec)[checkIndex-1] << ")\n";
// -1 in [checkIndex -1] because checkIndex is updated after leaving getDeviation function
std::cout << "The absolute deviation is " << deviation.abs << ". The tolerance limit is " << absTol << std::endl;
std::cout << "The relative deviation is " << deviation.rel << ". The tolerance limit is " << relTol << std::endl;
HANDLE_ERROR(std::runtime_error, "Deviation exceed the limit.");
}
return false;
}
return true;
}
bool SummaryRegressionTest::checkForKeyword(std::vector<double>& timeVec1, std::vector<double>& timeVec2, const char* keyword){
std::vector<double> dataVec1, dataVec2;
getDataVecs(dataVec1,dataVec2,keyword);
chooseReference(timeVec1, timeVec2,dataVec1,dataVec2);
return startTest(keyword);
}
bool SummaryRegressionTest::startTest(const char* keyword){
size_t jvar = 0;
Deviation deviation;
bool result = true;
for (size_t ivar = 0; ivar < referenceVec->size(); ivar++){
getDeviation(ivar, jvar, deviation);//Reads from the protected member variables in the super class.
result = checkDeviation(deviation, keyword,ivar, jvar);
}
return result;
}
void SummaryRegressionTest::setAllowDifferentNumberOfKeywords(const bool allow)
{
this->allowDifferentNumberOfKeywords = allow;
}

View File

@@ -0,0 +1,87 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SUMMARYREGRESSIONTEST_HPP
#define SUMMARYREGRESSIONTEST_HPP
#include "summaryComparator.hpp"
//! \details The class inherits from the SummaryComparator class, which takes care of all file reading. \n The RegressionTest class compares the values from the two different files and throws exceptions when the deviation is unsatisfying.
class SummaryRegressionTest: public SummaryComparator {
private:
//! \brief Gathers the correct data for comparison for a specific keyword
//! \param[in] timeVec1 The time steps of file 1.
//! \param[in] timeVec2 The time steps of file 2.
//! \param[in] keyword The keyword of interest
//! \details The function prepares a regression test by gathering the data, stroing it into two vectors, \n deciding which is to be used as a reference/basis and calling the test function.
//! \return True if check passed, false otherwise.
bool checkForKeyword(std::vector<double>& timeVec1, std::vector<double>& timeVec2, const char* keyword);
//! \brief The regression test
//! \param[in] keyword The keyword common for both the files. The vectors associated with the keyword are used for comparison.
//! \details Start test uses the private member variables, pointers of std::vector<double> type, which are set to point to the correct vectors in SummaryComparison::chooseReference(...). \n The function iterates over the referenceVev/basis and for each iteration it calculates the deviation with SummaryComparison::getDeviation(..) and stors it in a Deviation struct. \n SummaryComparison::getDeviation takes the int jvar as an reference input, and using it as an iterative index for the values which are to be compared with the basis. \n Thus, by updating the jvar variable every time a deviation is calculated, one keep track jvar and do not have to iterate over already checked values.
bool startTest(const char* keyword);
//! \brief Caluculates a deviation, throws exceptions and writes and error message.
//! \param[in] deviation Deviation struct
//! \param[in] keyword The keyword that the data that are being compared belongs to.
//! \param[in] refIndex The report step of which the deviation originates from in #referenceDataVec.
//! \param[in] checkIndex The report step of which the deviation originates from in #checkDataVec.
//! \details The function checks the values of the Deviation struct against the absolute and relative tolerance, which are private member values of the super class. \n When comparing against the relative tolerance an additional term is added, the absolute deviation has to be greater than 1e-6 for the function to throw an exception. \n When the deviations are too great, the function writes out which keyword, and at what report step the deviation is too great before optionally throwing an exception.
//! \return True if check passed, false otherwise.
bool checkDeviation(Deviation deviation, const char* keyword, int refIndex, int checkIndex);
bool isRestartFile = false; //!< Private member variable, when true the files that are being compared is a restart file vs a normal file
/// Whether or not to require that the two files have the same
/// number of keywords. Throw exception if not.
/// Default value: false (don't allow different number of keywords).
bool allowDifferentNumberOfKeywords = false;
public:
//! \brief Constructor, creates an object of RefressionTest class.
//! \param[in] basename1 Path to file1 without extension.
//! \param[in] basename1 Path to file2 without extension.
//! \param[in] relativeTol The relative tolerance which is to be used in the test.
//! \param[in] absoluteTol The absolute tolerance which is to be used in the test.
//! \details The constructor calls the constructor of the super class.
SummaryRegressionTest(const std::string& basename1,
const std::string& basename2,
double relativeTol, double absoluteTol) :
SummaryComparator(basename1, basename2, relativeTol, absoluteTol) {}
//! \details The function executes a regression test for all the keywords. If the two files do not match in amount of keywords, an exception is thrown.
void getRegressionTest();
//! \details The function executes a regression test for one specific keyword. If one or both of the files do not have the keyword, an exception is thrown.
void getRegressionTest(const char* keyword);///< Regression test for a certain keyword of the files.
//! \brief This function sets the private member variable isRestartFiles
//! \param[in] boolean Boolean value
void setIsRestartFile(bool boolean){this->isRestartFile = boolean;}
/// \brief Dynamically control whether or not to require equal
/// number of keywords (vectors) in the two result sets.
///
/// \param[in] allow Whether or not to allow different number of
/// summary keywords in the two result sets.
void setAllowDifferentNumberOfKeywords(const bool allow);
};
#endif

View File

@@ -3,9 +3,8 @@
declare -A configurations
declare -A EXTRA_MODULE_FLAGS
EXTRA_MODULE_FLAGS[opm-common]="-DENABLE_WELL_TEST=ON"
EXTRA_MODULE_FLAGS[opm-simulators]="-DBUILD_EBOS_EXTENSIONS=ON -DBUILD_EBOS_DEBUG_EXTENSIONS=ON"
EXTRA_MODULE_FLAGS[opm-common]="-DOPM_ENABLE_PYTHON=ON -DOPM_ENABLE_EMBEDDED_PYTHON=ON"
EXTRA_MODULE_FLAGS[libecl]="-DCMAKE_POSITION_INDEPENDENT_CODE=1"
# Parse revisions from trigger comment and setup arrays
# Depends on: 'upstreams', upstreamRev',
@@ -13,7 +12,6 @@ EXTRA_MODULE_FLAGS[libecl]="-DCMAKE_POSITION_INDEPENDENT_CODE=1"
# 'ghprbCommentBody',
# 'CONFIGURATIONS', 'TOOLCHAINS'
function parseRevisions {
# Set default for libecl to be last known good commit.
for upstream in ${upstreams[*]}
do
if grep -qi "$upstream=" <<< $ghprbCommentBody
@@ -112,12 +110,11 @@ function build_module {
cmake --build .
fi
test $? -eq 0 || exit 2
TESTTHREADS=${TESTTHREADS:-1}
if test -z "$CTEST_CONFIGURATION"
then
ctest -T Test --no-compress-output -j$TESTTHREADS
ctest -T Test --no-compress-output
else
ctest -j$TESTTHREADS -C $CTEST_CONFIGURATION --timeout 5000 -T Test --no-compress-output
ctest -C $CTEST_CONFIGURATION --timeout 5000 -T Test --no-compress-output
fi
# Convert to junit format
@@ -150,7 +147,7 @@ function clone_module {
git init .
if [ "$1" == "libecl" ]
then
git remote add origin https://github.com/equinor/$1
git remote add origin https://github.com/Statoil/$1
else
git remote add origin https://github.com/OPM/$1
fi

View File

@@ -16,7 +16,7 @@ upstreamRev[libecl]=master
declare -a downstreams
downstreams=(opm-material
opm-grid
opm-models
ewoms
opm-simulators
opm-upscaling
)
@@ -24,7 +24,7 @@ downstreams=(opm-material
declare -A downstreamRev
downstreamRev[opm-material]=master
downstreamRev[opm-grid]=master
downstreamRev[opm-models]=master
downstreamRev[ewoms]=master
downstreamRev[opm-simulators]=master
downstreamRev[opm-upscaling]=master

View File

@@ -9,7 +9,7 @@ upstreams=(libecl
opm-common
opm-material
opm-grid
opm-models
ewoms
opm-simulators
opm-upscaling
)
@@ -19,7 +19,7 @@ upstreamRev[libecl]=master
upstreamRev[opm-common]=master
upstreamRev[opm-material]=master
upstreamRev[opm-grid]=master
upstreamRev[opm-models]=master
upstreamRev[ewoms]=master
upstreamRev[opm-simulators]=master
upstreamRev[opm-upscaling]=master

View File

@@ -21,27 +21,28 @@ namespace Opm {
class EclipseIO;
class ParseContext;
class Parser;
class SummaryState;
class msim {
public:
using well_rate_function = double(const EclipseState&, const Schedule&, const SummaryState& st, const data::Solution&, size_t report_step, double seconds_elapsed);
using well_rate_function = double(const EclipseState&, const Schedule&, const data::Solution&, size_t report_step, double seconds_elapsed);
using solution_function = void(const EclipseState&, const Schedule&, data::Solution&, size_t report_step, double seconds_elapsed);
msim(const EclipseState& state);
void well_rate(const std::string& well, data::Rates::opt rate, std::function<well_rate_function> func);
void solution(const std::string& field, std::function<solution_function> func);
void run(Schedule& schedule, EclipseIO& io, bool report_only);
void post_step(Schedule& schedule, const SummaryState& st, data::Solution& sol, data::Wells& well_data, size_t report_step) const;
void run(Schedule& schedule, EclipseIO& io);
void post_step(Schedule& schedule, data::Solution& sol, data::Wells& well_data, size_t report_step, EclipseIO& io) const;
private:
void run_step(const Schedule& schedule, SummaryState& st, data::Solution& sol, data::Wells& well_data, size_t report_step, EclipseIO& io) const;
void run_step(const Schedule& schedule, SummaryState& st, data::Solution& sol, data::Wells& well_data, size_t report_step, double dt, EclipseIO& io) const;
void output(SummaryState& st, size_t report_step, bool substep, double seconds_elapsed, const data::Solution& sol, const data::Wells& well_data, EclipseIO& io) const;
void simulate(const Schedule& schedule, const SummaryState& st, data::Solution& sol, data::Wells& well_data, size_t report_step, double seconds_elapsed, double time_step) const;
void run_step(const Schedule& schedule, data::Solution& sol, data::Wells& well_data, size_t report_step, EclipseIO& io) const;
void run_step(const Schedule& schedule, data::Solution& sol, data::Wells& well_data, size_t report_step, double dt, EclipseIO& io) const;
void output(size_t report_step, bool substep, double seconds_elapsed, const data::Solution& sol, const data::Wells& well_data, EclipseIO& io) const;
void simulate(const Schedule& schedule, data::Solution& sol, data::Wells& well_data, size_t report_step, double seconds_elapsed, double time_step) const;
EclipseState state;
std::map<std::string, std::map<data::Rates::opt, std::function<well_rate_function>>> well_rates;
std::map<std::string, std::function<solution_function>> solutions;
};

View File

@@ -21,7 +21,6 @@
#include <opm/output/eclipse/EclipseIO.hpp>
#include <opm/output/eclipse/RestartValue.hpp>
#include <opm/output/eclipse/Summary.hpp>
#include <opm/output/data/Solution.hpp>
#include <opm/output/data/Wells.hpp>
@@ -34,52 +33,48 @@
namespace Opm {
msim::msim(const EclipseState& state_arg) :
state(state_arg)
msim::msim(const EclipseState& state) :
state(state)
{}
void msim::run(Schedule& schedule, EclipseIO& io, bool report_only) {
void msim::run(Schedule& schedule, EclipseIO& io) {
const double week = 7 * 86400;
data::Solution sol;
data::Wells well_data;
SummaryState st(std::chrono::system_clock::from_time_t(schedule.getStartTime()));
io.writeInitial();
for (size_t report_step = 1; report_step < schedule.size(); report_step++) {
if (report_only)
run_step(schedule, st, sol, well_data, report_step, io);
else {
double time_step = std::min(week, 0.5*schedule.stepLength(report_step - 1));
run_step(schedule, st, sol, well_data, report_step, time_step, io);
}
post_step(schedule, st, sol, well_data, report_step);
double time_step = std::min(week, 0.5*schedule.stepLength(report_step - 1));
run_step(schedule, sol, well_data, report_step, time_step, io);
post_step(schedule, sol, well_data, report_step, io);
}
}
void msim::post_step(Schedule& schedule, const SummaryState& st, data::Solution& /* sol */, data::Wells& /* well_data */, size_t report_step) const {
const auto& actions = schedule.actions(report_step);
void msim::post_step(Schedule& schedule, data::Solution& /* sol */, data::Wells& /* well_data */, size_t report_step, EclipseIO& io) const {
const auto& actions = schedule.actions();
if (actions.empty())
return;
Action::Context context( st );
const SummaryState& summary_state = io.summaryState();
ActionContext context( summary_state );
std::vector<std::string> matching_wells;
auto sim_time = schedule.simTime(report_step);
for (const auto& action : actions.pending(sim_time)) {
auto result = action->eval(sim_time, context);
if (result)
schedule.applyAction(report_step, *action, result);
if (action->eval(sim_time, context, matching_wells))
schedule.applyAction(report_step, *action, matching_wells);
}
}
void msim::run_step(const Schedule& schedule, SummaryState& st, data::Solution& sol, data::Wells& well_data, size_t report_step, EclipseIO& io) const {
this->run_step(schedule, st, sol, well_data, report_step, schedule.stepLength(report_step - 1), io);
void msim::run_step(const Schedule& schedule, data::Solution& sol, data::Wells& well_data, size_t report_step, EclipseIO& io) const {
this->run_step(schedule, sol, well_data, report_step, schedule.stepLength(report_step - 1), io);
}
void msim::run_step(const Schedule& schedule, SummaryState& st, data::Solution& sol, data::Wells& well_data, size_t report_step, double dt, EclipseIO& io) const {
void msim::run_step(const Schedule& schedule, data::Solution& sol, data::Wells& well_data, size_t report_step, double dt, EclipseIO& io) const {
double start_time = schedule.seconds(report_step - 1);
double end_time = schedule.seconds(report_step);
double seconds_elapsed = start_time;
@@ -89,20 +84,10 @@ void msim::run_step(const Schedule& schedule, SummaryState& st, data::Solution&
if ((seconds_elapsed + time_step) > end_time)
time_step = end_time - seconds_elapsed;
this->simulate(schedule, st, sol, well_data, report_step, seconds_elapsed, time_step);
this->simulate(schedule, sol, well_data, report_step, seconds_elapsed, time_step);
seconds_elapsed += time_step;
io.summary().eval(st,
report_step,
seconds_elapsed,
this->state,
schedule,
well_data,
{});
this->output(st,
report_step,
this->output(report_step,
(seconds_elapsed < end_time),
seconds_elapsed,
sol,
@@ -113,17 +98,19 @@ void msim::run_step(const Schedule& schedule, SummaryState& st, data::Solution&
void msim::output(SummaryState& st, size_t report_step, bool /* substep */, double seconds_elapsed, const data::Solution& sol, const data::Wells& well_data, EclipseIO& io) const {
void msim::output(size_t report_step, bool /* substep */, double seconds_elapsed, const data::Solution& sol, const data::Wells& well_data, EclipseIO& io) const {
RestartValue value(sol, well_data);
io.writeTimeStep(st,
report_step,
io.writeTimeStep(report_step,
false,
seconds_elapsed,
value);
value,
{},
{},
{});
}
void msim::simulate(const Schedule& schedule, const SummaryState& st, data::Solution& sol, data::Wells& well_data, size_t report_step, double seconds_elapsed, double time_step) const {
void msim::simulate(const Schedule& schedule, data::Solution& sol, data::Wells& well_data, size_t report_step, double seconds_elapsed, double time_step) const {
for (const auto& sol_pair : this->solutions) {
auto func = sol_pair.second;
func(this->state, schedule, sol, report_step, seconds_elapsed + time_step);
@@ -136,7 +123,7 @@ void msim::simulate(const Schedule& schedule, const SummaryState& st, data::Solu
auto rate = rate_pair.first;
auto func = rate_pair.second;
well.rates.set(rate, func(this->state, schedule, st, sol, report_step, seconds_elapsed + time_step));
well.rates.set(rate, func(this->state, schedule, sol, report_step, seconds_elapsed + time_step));
}
// This is complete bogus; a temporary fix to pass an assert() in the

View File

@@ -16,10 +16,9 @@
*/
#include <vector>
#include <array>
#include <math.h>
double calculateCellVol(const std::array<double,8>& X, const std::array<double,8>& Y, const std::array<double,8>& Z);
double calculateCellVol(const std::vector<double>& X, const std::vector<double>& Y, const std::vector<double>& Z);

View File

@@ -1,65 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_EGRID_HPP
#define OPM_IO_EGRID_HPP
#include <opm/io/eclipse/EclFile.hpp>
#include <array>
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <ctime>
#include <map>
namespace Opm { namespace EclIO {
class EGrid : public EclFile
{
public:
explicit EGrid(const std::string& filename);
int global_index(int i, int j, int k) const;
int active_index(int i, int j, int k) const;
const std::array<int, 3>& dimension() const { return nijk; }
std::array<int, 3> ijk_from_active_index(int actInd) const;
std::array<int, 3> ijk_from_global_index(int globInd) const;
void getCellCorners(int globindex, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z) const;
void getCellCorners(const std::array<int, 3>& ijk, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z) const;
int activeCells() const { return nactive; }
int totalNumberOfCells() const { return nijk[0] * nijk[1] * nijk[2]; }
private:
std::array<int, 3> nijk;
int nactive;
std::vector<int> act_index;
std::vector<int> glob_index;
std::vector<float> coord_array;
std::vector<float> zcorn_array;
};
}} // namespace Opm::EclIO
#endif // OPM_IO_EGRID_HPP

View File

@@ -1,84 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_ERFT_HPP
#define OPM_IO_ERFT_HPP
#include <opm/io/eclipse/EclFile.hpp>
#include <ctime>
#include <map>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
namespace Opm { namespace EclIO {
class ERft : public EclFile
{
public:
explicit ERft(const std::string &filename);
using RftDate = std::tuple<int,int,int>;
template <typename T>
const std::vector<T>& getRft(const std::string& name, const std::string& wellName,
const RftDate& date) const;
template <typename T>
const std::vector<T>& getRft(const std::string& name, const std::string& wellName,
int year, int month, int day) const;
std::vector<std::string> listOfWells() const;
std::vector<RftDate> listOfdates() const;
using RftReportList = std::vector<std::pair<std::string, RftDate>>;
const RftReportList& listOfRftReports() const { return rftReportList; }
bool hasRft(const std::string& wellName, const RftDate& date) const;
bool hasRft(const std::string& wellName, int year, int month, int day) const;
std::vector<EclEntry> listOfRftArrays(const std::string& wellName,
const RftDate& date) const;
std::vector<EclEntry> listOfRftArrays(const std::string& wellName,
int year, int month, int day) const;
bool hasArray(const std::string& arrayName, const std::string& wellName,
const RftDate& date) const;
private:
std::map<int, std::pair<int,int>> arrIndexRange;
int numReports;
std::vector<float> timeList;
std::set<std::string> wellList;
std::set<RftDate> dateList;
RftReportList rftReportList;
std::map<std::pair<std::string,RftDate>,int> reportIndex; // mapping report index to wellName and date (tupe)
int getReportIndex(const std::string& wellName, const RftDate& date) const;
int getArrayIndex(const std::string& name, const std::string& wellName,
const RftDate& date) const;
};
}} // namespace Opm::EclIO
#endif // OPM_IO_ERFT_HPP

View File

@@ -1,70 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_ERST_HPP
#define OPM_IO_ERST_HPP
#include <opm/io/eclipse/EclFile.hpp>
#include <ios>
#include <map>
#include <string>
#include <unordered_map>
#include <vector>
namespace Opm { namespace EclIO { namespace OutputStream {
class Restart;
}}}
namespace Opm { namespace EclIO {
class ERst : public EclFile
{
public:
explicit ERst(const std::string& filename);
bool hasReportStepNumber(int number) const;
void loadReportStepNumber(int number);
template <typename T>
const std::vector<T>& getRst(const std::string& name, int reportStepNumber);
const std::vector<int>& listOfReportStepNumbers() const { return seqnum; }
std::vector<EclEntry> listOfRstArrays(int reportStepNumber);
friend class OutputStream::Restart;
private:
int nReports;
std::vector<int> seqnum; // report step numbers, from SEQNUM array in restart file
std::unordered_map<int,bool> reportLoaded;
std::map<int, std::pair<int,int>> arrIndexRange; // mapping report step number to array indeces (start and end)
void initUnified();
void initSeparate(const int number);
int getArrayIndex(const std::string& name, int seqnum) const;
std::streampos
restartStepWritePosition(const int seqnumValue) const;
};
}} // namespace Opm::EclIO
#endif // OPM_IO_ERST_HPP

View File

@@ -1,61 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_ESMRY_HPP
#define OPM_IO_ESMRY_HPP
#include <string>
#include <vector>
namespace Opm { namespace EclIO {
class ESmry
{
public:
explicit ESmry(const std::string& filename, bool loadBaseRunData=false); // filename (smspec file) or file root name
int numberOfVectors() const { return nVect; }
bool hasKey(const std::string& key) const;
const std::vector<float>& get(const std::string& name) const;
std::vector<float> get_at_rstep(const std::string& name) const;
const std::vector<std::string>& keywordList() const { return keyword; }
private:
int nVect, nI, nJ, nK;
std::string path="";
void ijk_from_global_index(int glob, int &i, int &j, int &k) const;
std::vector<std::vector<float>> param;
std::vector<std::string> keyword;
std::vector<int> seqIndex;
std::vector<float> seqTime;
void getRstString(const std::vector<std::string> &restartArray, std::string &path, std::string &rootN) const;
void updatePathAndRootName(std::string &path, std::string &rootN) const;
std::string makeKeyString(const std::string& keyword, const std::string& wgname, int num) const;
};
}} // namespace Opm::EclIO
#endif // OPM_IO_ESMRY_HPP

View File

@@ -1,116 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_ECLFILE_HPP
#define OPM_IO_ECLFILE_HPP
#include <opm/common/ErrorMacros.hpp>
#include <opm/io/eclipse/EclIOdata.hpp>
#include <ios>
#include <string>
#include <stdexcept>
#include <tuple>
#include <unordered_map>
#include <vector>
namespace Opm { namespace EclIO {
class EclFile
{
public:
explicit EclFile(const std::string& filename);
bool formattedInput() { return formatted; }
void loadData(); // load all data
void loadData(const std::string& arrName); // load all arrays with array name equal to arrName
void loadData(int arrIndex); // load data based on array indices in vector arrIndex
void loadData(const std::vector<int>& arrIndex); // load data based on array indices in vector arrIndex
void clearData()
{
inte_array.clear();
real_array.clear();
doub_array.clear();
logi_array.clear();
char_array.clear();
}
using EclEntry = std::tuple<std::string, eclArrType, int>;
std::vector<EclEntry> getList() const;
template <typename T>
const std::vector<T>& get(int arrIndex);
template <typename T>
const std::vector<T>& get(const std::string& name);
bool hasKey(const std::string &name) const;
const std::vector<std::string>& arrayNames() const { return array_name; }
protected:
bool formatted;
std::string inputFilename;
std::unordered_map<int, std::vector<int>> inte_array;
std::unordered_map<int, std::vector<bool>> logi_array;
std::unordered_map<int, std::vector<double>> doub_array;
std::unordered_map<int, std::vector<float>> real_array;
std::unordered_map<int, std::vector<std::string>> char_array;
std::vector<std::string> array_name;
std::vector<eclArrType> array_type;
std::vector<int> array_size;
std::vector<unsigned long int> ifStreamPos;
std::map<std::string, int> array_index;
template<class T>
const std::vector<T>& getImpl(int arrIndex, eclArrType type,
const std::unordered_map<int, std::vector<T>>& array,
const std::string& typeStr)
{
if (array_type[arrIndex] != type) {
std::string message = "Array with index " + std::to_string(arrIndex) + " is not of type " + typeStr;
OPM_THROW(std::runtime_error, message);
}
if (!arrayLoaded[arrIndex]) {
loadData(arrIndex);
}
return array.at(arrIndex);
}
std::streampos
seekPosition(const std::vector<std::string>::size_type arrIndex) const;
private:
std::vector<bool> arrayLoaded;
void loadBinaryArray(std::fstream& fileH, std::size_t arrIndex);
void loadFormattedArray(const std::string& fileStr, std::size_t arrIndex, long int fromPos);
};
}} // namespace Opm::EclIO
#endif // OPM_IO_ECLFILE_HPP

View File

@@ -1,116 +0,0 @@
/*
Copyright 2019 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_ECLOUTPUT_HPP
#define OPM_IO_ECLOUTPUT_HPP
#include <fstream>
#include <ios>
#include <string>
#include <typeinfo>
#include <vector>
#include <opm/io/eclipse/EclIOdata.hpp>
#include <opm/io/eclipse/PaddedOutputString.hpp>
namespace Opm { namespace EclIO { namespace OutputStream {
class Restart;
class SummarySpecification;
}}}
namespace Opm { namespace EclIO {
class EclOutput
{
public:
EclOutput(const std::string& filename,
const bool formatted,
const std::ios_base::openmode mode = std::ios::out);
template<typename T>
void write(const std::string& name,
const std::vector<T>& data)
{
eclArrType arrType = MESS;
if (typeid(T) == typeid(int))
arrType = INTE;
else if (typeid(T) == typeid(float))
arrType = REAL;
else if (typeid(T) == typeid(double))
arrType = DOUB;
else if (typeid(T) == typeid(bool))
arrType = LOGI;
else if (typeid(T) == typeid(char))
arrType = MESS;
if (isFormatted)
{
writeFormattedHeader(name, data.size(), arrType);
if (arrType != MESS)
writeFormattedArray(data);
}
else
{
writeBinaryHeader(name, data.size(), arrType);
if (arrType != MESS)
writeBinaryArray(data);
}
}
void message(const std::string& msg);
void flushStream();
friend class OutputStream::Restart;
friend class OutputStream::SummarySpecification;
private:
void writeBinaryHeader(const std::string& arrName, int size, eclArrType arrType);
template <typename T>
void writeBinaryArray(const std::vector<T>& data);
void writeBinaryCharArray(const std::vector<std::string>& data);
void writeBinaryCharArray(const std::vector<PaddedOutputString<8>>& data);
void writeFormattedHeader(const std::string& arrName, int size, eclArrType arrType);
template <typename T>
void writeFormattedArray(const std::vector<T>& data);
void writeFormattedCharArray(const std::vector<std::string>& data);
void writeFormattedCharArray(const std::vector<PaddedOutputString<8>>& data);
std::string make_real_string(float value) const;
std::string make_doub_string(double value) const;
bool isFormatted;
std::ofstream ofileH;
};
template<>
void EclOutput::write<std::string>(const std::string& name,
const std::vector<std::string>& data);
template <>
void EclOutput::write<PaddedOutputString<8>>
(const std::string& name,
const std::vector<PaddedOutputString<8>>& data);
}} // namespace Opm::EclIO
#endif // OPM_IO_ECLOUTPUT_HPP

View File

@@ -1,455 +0,0 @@
/*
Copyright (c) 2019 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_OUTPUTSTREAM_HPP_INCLUDED
#define OPM_IO_OUTPUTSTREAM_HPP_INCLUDED
#include <opm/io/eclipse/PaddedOutputString.hpp>
#include <array>
#include <chrono>
#include <ios>
#include <memory>
#include <string>
#include <vector>
namespace Opm { namespace EclIO {
class EclOutput;
}} // namespace Opm::EclIO
namespace Opm { namespace EclIO { namespace OutputStream {
struct Formatted { bool set; };
struct Unified { bool set; };
/// Abstract representation of an ECLIPSE-style result set.
struct ResultSet
{
/// Output directory. Commonly "." or location of run's .DATA file.
std::string outputDir;
/// Base name of simulation run.
std::string baseName;
};
/// File manager for "init" output streams.
class Init
{
public:
/// Constructor.
///
/// Opens file stream for writing.
///
/// \param[in] rset Output directory and base name of output stream.
///
/// \param[in] fmt Whether or not to create formatted output files.
explicit Init(const ResultSet& rset,
const Formatted& fmt);
~Init();
Init(const Init& rhs) = delete;
Init(Init&& rhs);
Init& operator=(const Init& rhs) = delete;
Init& operator=(Init&& rhs);
/// Write integer data to underlying output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<int>& data);
/// Write boolean data to underlying output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<bool>& data);
/// Write single precision floating point data to underlying
/// output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<float>& data);
/// Write double precision floating point data to underlying
/// output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<double>& data);
private:
/// Init file output stream.
std::unique_ptr<EclOutput> stream_;
/// Open output stream.
///
/// Writes to \c stream_.
///
/// \param[in] fname Filename of new output stream.
///
/// \param[in] formatted Whether or not to create a
/// formatted output file.
void open(const std::string& fname,
const bool formatted);
/// Access writable output stream.
EclOutput& stream();
/// Implementation function for public \c write overload set.
template <typename T>
void writeImpl(const std::string& kw,
const std::vector<T>& data);
};
/// File manager for restart output streams.
class Restart
{
public:
/// Constructor.
///
/// Opens file stream pertaining to restart of particular report
/// step and also outputs a SEQNUM record in the case of a unified
/// output stream.
///
/// Must be called before accessing the stream object through the
/// stream() member function.
///
/// \param[in] rset Output directory and base name of output stream.
///
/// \param[in] seqnum Sequence number of new report. One-based
/// report step ID.
///
/// \param[in] fmt Whether or not to create formatted output files.
///
/// \param[in] unif Whether or not to create unified output files.
explicit Restart(const ResultSet& rset,
const int seqnum,
const Formatted& fmt,
const Unified& unif);
~Restart();
Restart(const Restart& rhs) = delete;
Restart(Restart&& rhs);
Restart& operator=(const Restart& rhs) = delete;
Restart& operator=(Restart&& rhs);
/// Generate a message string (keyword type 'MESS') in underlying
/// output stream.
///
/// \param[in] msg Message string (e.g., "STARTSOL").
void message(const std::string& msg);
/// Write integer data to underlying output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<int>& data);
/// Write boolean data to underlying output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<bool>& data);
/// Write single precision floating point data to underlying
/// output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<float>& data);
/// Write double precision floating point data to underlying
/// output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<double>& data);
/// Write unpadded string data to underlying output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<std::string>& data);
/// Write padded character data (8 characters per string)
/// to underlying output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<PaddedOutputString<8>>& data);
private:
/// Restart output stream.
std::unique_ptr<EclOutput> stream_;
/// Open unified output file and place stream's output indicator
/// in appropriate location.
///
/// Writes to \c stream_.
///
/// \param[in] fname Filename of output stream.
///
/// \param[in] formatted Whether or not to create a
/// formatted output file.
///
/// \param[in] seqnum Sequence number of new report. One-based
/// report step ID.
void openUnified(const std::string& fname,
const bool formatted,
const int seqnum);
/// Open new output stream.
///
/// Handles the case of separate output files or unified output file
/// that does not already exist. Writes to \c stream_.
///
/// \param[in] fname Filename of new output stream.
///
/// \param[in] formatted Whether or not to create a
/// formatted output file.
void openNew(const std::string& fname,
const bool formatted);
/// Open existing output file and place stream's output indicator
/// in appropriate location.
///
/// Writes to \c stream_.
///
/// \param[in] fname Filename of output stream.
///
/// \param[in] writePos Position at which to place stream's output
/// indicator. Use \code streampos{ streamoff{-1} } \endcode to
/// place output indicator at end of file (i.e, simple append).
void openExisting(const std::string& fname,
const bool formatted,
const std::streampos writePos);
/// Access writable output stream.
///
/// Must not be called prior to \c prepareStep.
EclOutput& stream();
/// Implementation function for public \c write overload set.
template <typename T>
void writeImpl(const std::string& kw,
const std::vector<T>& data);
};
/// File manager for RFT output streams
class RFT
{
public:
struct OpenExisting { bool set; };
/// Constructor.
///
/// Opens file stream for writing.
///
/// \param[in] rset Output directory and base name of output stream.
///
/// \param[in] fmt Whether or not to create formatted output files.
///
/// \param[in] existing Whether or not to open an existing output file.
explicit RFT(const ResultSet& rset,
const Formatted& fmt,
const OpenExisting& existing);
~RFT();
RFT(const RFT& rhs) = delete;
RFT(RFT&& rhs);
RFT& operator=(const RFT& rhs) = delete;
RFT& operator=(RFT&& rhs);
/// Write integer data to underlying output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<int>& data);
/// Write single precision floating point data to underlying
/// output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<float>& data);
/// Write padded character data (8 characters per string)
/// to underlying output stream.
///
/// \param[in] kw Name of output vector (keyword).
///
/// \param[in] data Output values.
void write(const std::string& kw,
const std::vector<PaddedOutputString<8>>& data);
private:
/// Init file output stream.
std::unique_ptr<EclOutput> stream_;
/// Open output stream.
///
/// Writes to \c stream_.
///
/// \param[in] fname Filename of new output stream.
///
/// \param[in] formatted Whether or not to create a
/// formatted output file.
///
/// \param[in] existing Whether or not to open an
/// existing output file (mode ios_base::app).
void open(const std::string& fname,
const bool formatted,
const bool existing);
/// Access writable output stream.
EclOutput& stream();
/// Implementation function for public \c write overload set.
template <typename T>
void writeImpl(const std::string& kw,
const std::vector<T>& data);
};
class SummarySpecification
{
public:
using StartTime = std::chrono::system_clock::time_point;
enum class UnitConvention
{
Metric = 1,
Field = 2,
Lab = 3,
Pvt_M = 4,
};
struct RestartSpecification
{
std::string root;
int step;
};
class Parameters
{
public:
void add(const std::string& keyword,
const std::string& wgname,
const int num,
const std::string& unit);
friend class SummarySpecification;
private:
std::vector<PaddedOutputString<8>> keywords{};
std::vector<PaddedOutputString<8>> wgnames{};
std::vector<int> nums{};
std::vector<PaddedOutputString<8>> units{};
};
explicit SummarySpecification(const ResultSet& rset,
const Formatted& fmt,
const UnitConvention uconv,
const std::array<int,3>& cartDims,
const RestartSpecification& restart,
const StartTime start);
~SummarySpecification();
SummarySpecification(const SummarySpecification& rhs) = delete;
SummarySpecification(SummarySpecification&& rhs);
SummarySpecification& operator=(const SummarySpecification& rhs) = delete;
SummarySpecification& operator=(SummarySpecification&& rhs);
void write(const Parameters& params);
private:
int unit_;
int restartStep_;
std::array<int,3> cartDims_;
StartTime startDate_;
std::vector<PaddedOutputString<8>> restart_;
/// Summary specification (SMSPEC) file output stream.
std::unique_ptr<EclOutput> stream_;
void rewindStream();
void flushStream();
EclOutput& stream();
};
std::unique_ptr<EclOutput>
createSummaryFile(const ResultSet& rset,
const int seqnum,
const Formatted& fmt,
const Unified& unif);
/// Derive filename corresponding to output stream of particular result
/// set, with user-specified file extension.
///
/// Low-level string concatenation routine that does not know specific
/// relations between base names and file extensions. Handles details
/// of base name ending in a period (full stop) or having a name that
/// might otherwise appear to contain a file extension (e.g., CASE.01).
///
/// \param[in] rsetDescriptor Output directory and base name of result set.
///
/// \param[in] ext Filename extension.
///
/// \return outputDir/baseName.ext
std::string outputFileName(const ResultSet& rsetDescriptor,
const std::string& ext);
}}} // namespace Opm::EclIO::OutputStream
#endif // OPM_IO_OUTPUTSTREAM_HPP_INCLUDED

View File

@@ -20,135 +20,154 @@
#ifndef OPM_AGGREGATE_GROUP_DATA_HPP
#define OPM_AGGREGATE_GROUP_DATA_HPP
#include <opm/output/eclipse/CharArrayNullTerm.hpp>
#include <opm/output/eclipse/WindowedArray.hpp>
#include <opm/io/eclipse/PaddedOutputString.hpp>
#include <cstddef>
#include <string>
#include <vector>
#include <map>
namespace Opm {
class Schedule;
class SummaryState;
class Group2;
class Schedule;
class SummaryState;
class Group;
} // Opm
namespace Opm { namespace RestartIO { namespace Helpers {
class AggregateGroupData
{
public:
explicit AggregateGroupData(const std::vector<int>& inteHead);
class groupMaps {
public:
const std::map <size_t, const Opm::Group*>& indexGroupMap() const;
const std::map <const std::string, size_t>& groupNameIndexMap() const;
void captureDeclaredGroupData(const Opm::Schedule& sched,
const std::size_t simStep,
const Opm::SummaryState& sumState,
const std::vector<int>& inteHead);
void currentGrpTreeNameSeqIndMap(const Opm::Schedule& sched,
const size_t simStep,
const std::map<const std::string , size_t>& GnIMap,
const std::map<size_t, const Opm::Group*>& IGMap);
const std::vector<int>& getIGroup() const
{
return this->iGroup_.data();
}
const std::vector<float>& getSGroup() const
{
return this->sGroup_.data();
}
const std::vector<double>& getXGroup() const
{
return this->xGroup_.data();
}
const std::vector<EclIO::PaddedOutputString<8>>& getZGroup() const
{
return this->zGroup_.data();
}
const std::vector<std::string> restart_group_keys = {"GOPP", "GWPP", "GOPR", "GWPR", "GGPR",
"GVPR", "GWIR", "GGIR", "GWCT", "GGOR",
"GOPT", "GWPT", "GGPT", "GVPT", "GWIT",
"GGIT",
"GOPTH", "GWPTH", "GGPTH",
"GWITH", "GGITH"};
const std::vector<std::string> restart_field_keys = {"FOPP", "FWPP", "FOPR", "FWPR", "FGPR",
"FVPR", "FWIR", "FGIR", "FWCT", "FGOR",
"FOPT", "FWPT", "FGPT", "FVPT", "FWIT",
"FGIT",
"FOPTH", "FWPTH", "FGPTH",
"FWITH", "FGITH"};
const std::map<std::string, size_t> groupKeyToIndex = {
{"GOPR", 0},
{"GWPR", 1},
{"GGPR", 2},
{"GVPR", 3},
{"GWIR", 5},
{"GGIR", 6},
{"GWCT", 8},
{"GGOR", 9},
{"GOPT", 10},
{"GWPT", 11},
{"GGPT", 12},
{"GVPT", 13},
{"GWIT", 15},
{"GGIT", 16},
{"GOPP", 22},
{"GWPP", 23},
{"GOPTH", 135},
{"GWPTH", 139},
{"GWITH", 140},
{"GGPTH", 143},
{"GGITH", 144},
private:
std::map <size_t, const Opm::Group*> m_indexGroupMap;
std::map <const std::string, size_t> m_groupNameIndexMap;
};
const std::map<std::string, size_t> fieldKeyToIndex = {
{"FOPR", 0},
{"FWPR", 1},
{"FGPR", 2},
{"FVPR", 3},
{"FWIR", 5},
{"FGIR", 6},
{"FWCT", 8},
{"FGOR", 9},
{"FOPT", 10},
{"FWPT", 11},
{"FGPT", 12},
{"FVPT", 13},
{"FWIT", 15},
{"FGIT", 16},
{"FOPP", 22},
{"FWPP", 23},
{"FOPTH", 135},
{"FWPTH", 139},
{"FWITH", 140},
{"FGPTH", 143},
{"FGITH", 144},
class AggregateGroupData
{
public:
explicit AggregateGroupData(const std::vector<int>& inteHead);
void captureDeclaredGroupData(const Opm::Schedule& sched,
const std::vector<std::string>& restart_group_keys,
const std::vector<std::string>& restart_field_keys,
const std::map<std::string, size_t>& groupKeyToIndex,
const std::map<std::string, size_t>& fieldKeyToIndex,
const bool ecl_compatible_rst,
const std::size_t simStep,
const Opm::SummaryState& sumState,
const std::vector<int>& inteHead);
const std::vector<int>& getIGroup() const
{
return this->iGroup_.data();
}
const std::vector<float>& getSGroup() const
{
return this->sGroup_.data();
}
const std::vector<double>& getXGroup() const
{
return this->xGroup_.data();
}
const std::vector<CharArrayNullTerm<8>>& getZGroup() const
{
return this->zGroup_.data();
}
const std::vector<std::string> restart_group_keys = {"GOPP", "GWPP", "GOPR", "GWPR", "GGPR",
"GVPR", "GWIR", "GGIR", "GWCT", "GGOR",
"GOPT", "GWPT", "GGPT", "GVPT", "GWIT",
"GGIT",
"GOPTH", "GWPTH", "GGPTH",
"GWITH", "GGITH"};
const std::vector<std::string> restart_field_keys = {"FOPP", "FWPP", "FOPR", "FWPR", "FGPR",
"FVPR", "FWIR", "FGIR", "FWCT", "FGOR",
"FOPT", "FWPT", "FGPT", "FVPT", "FWIT",
"FGIT",
"FOPTH", "FWPTH", "FGPTH",
"FWITH", "FGITH"};
const std::map<std::string, size_t> groupKeyToIndex = {
{"GOPR", 0},
{"GWPR", 1},
{"GGPR", 2},
{"GVPR", 3},
{"GWIR", 5},
{"GGIR", 6},
{"GWCT", 8},
{"GGOR", 9},
{"GOPT", 10},
{"GWPT", 11},
{"GGPT", 12},
{"GVPT", 13},
{"GWIT", 15},
{"GGIT", 16},
{"GOPP", 22},
{"GWPP", 23},
{"GOPTH", 135},
{"GWPTH", 139},
{"GWITH", 140},
{"GGPTH", 143},
{"GGITH", 144},
};
const std::map<std::string, size_t> fieldKeyToIndex = {
{"FOPR", 0},
{"FWPR", 1},
{"FGPR", 2},
{"FVPR", 3},
{"FWIR", 5},
{"FGIR", 6},
{"FWCT", 8},
{"FGOR", 9},
{"FOPT", 10},
{"FWPT", 11},
{"FGPT", 12},
{"FVPT", 13},
{"FWIT", 15},
{"FGIT", 16},
{"FOPP", 22},
{"FWPP", 23},
{"FOPTH", 135},
{"FWPTH", 139},
{"FWITH", 140},
{"FGPTH", 143},
{"FGITH", 144},
};
private:
/// Aggregate 'IWEL' array (Integer) for all wells.
WindowedArray<int> iGroup_;
/// Aggregate 'SWEL' array (Real) for all wells.
WindowedArray<float> sGroup_;
/// Aggregate 'XWEL' array (Double Precision) for all wells.
WindowedArray<double> xGroup_;
/// Aggregate 'ZWEL' array (Character) for all wells.
WindowedArray<CharArrayNullTerm<8>> zGroup_;
/// Maximum number of wells in a group.
int nWGMax_;
/// Maximum number of groups
int nGMaxz_;
};
private:
/// Aggregate 'IWEL' array (Integer) for all wells.
WindowedArray<int> iGroup_;
/// Aggregate 'SWEL' array (Real) for all wells.
WindowedArray<float> sGroup_;
/// Aggregate 'XWEL' array (Double Precision) for all wells.
WindowedArray<double> xGroup_;
/// Aggregate 'ZWEL' array (Character) for all wells.
WindowedArray<EclIO::PaddedOutputString<8>> zGroup_;
/// Maximum number of wells in a group.
int nWGMax_;
/// Maximum number of groups
int nGMaxz_;
};
}}} // Opm::RestartIO::Helpers
#endif // OPM_AGGREGATE_WELL_DATA_HPP

View File

@@ -21,6 +21,7 @@
#define OPM_AGGREGATE_MSW_DATA_HPP
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/CharArrayNullTerm.hpp>
#include <opm/output/eclipse/WindowedArray.hpp>
#include <string>
@@ -54,13 +55,13 @@ namespace Opm { namespace RestartIO { namespace Helpers {
std::vector<double> sofr;
std::vector<double> swfr;
std::vector<double> sgfr;
};
};
class AggregateMSWData
{
public:
explicit AggregateMSWData(const std::vector<int>& inteHead);
void captureDeclaredMSWData(const Opm::Schedule& sched,
const std::size_t rptStep,
const Opm::UnitSystem& units,

View File

@@ -1,142 +0,0 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_AGGREGATE_UDQ_DATA_HPP
#define OPM_AGGREGATE_UDQ_DATA_HPP
#include <opm/output/eclipse/WindowedArray.hpp>
#include <opm/io/eclipse/PaddedOutputString.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQAssign.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParams.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <cstddef>
#include <string>
#include <vector>
#include <map>
namespace Opm {
class Schedule;
class UDQInput;
class UDQActive;
} // Opm
namespace Opm { namespace RestartIO { namespace Helpers {
class igphData {
public:
const std::vector<int> ig_phase(const Opm::Schedule& sched, const std::size_t simStep, const std::vector<int>& inteHead);
};
class AggregateUDQData
{
public:
explicit AggregateUDQData(const std::vector<int>& udqDims);
void captureDeclaredUDQData(const Opm::Schedule& sched,
const std::size_t simStep,
const Opm::SummaryState& st,
const std::vector<int>& inteHead);
const std::vector<int>& getIUDQ() const
{
return this->iUDQ_.data();
}
const std::vector<int>& getIUAD() const
{
return this->iUAD_.data();
}
const std::vector<EclIO::PaddedOutputString<8>>& getZUDN() const
{
return this->zUDN_.data();
}
const std::vector<EclIO::PaddedOutputString<8>>& getZUDL() const
{
return this->zUDL_.data();
}
const std::vector<int>& getIGPH() const
{
return this->iGPH_.data();
}
const std::vector<int>& getIUAP() const
{
return this->iUAP_.data();
}
const std::vector<double>& getDUDW() const
{
return this->dUDW_.data();
}
const std::vector<double>& getDUDG() const
{
return this->dUDG_.data();
}
const std::vector<double>& getDUDF() const
{
return this->dUDF_.data();
}
private:
/// Aggregate 'IUDQ' array (Integer) for all UDQ data (3 integers pr UDQ)
WindowedArray<int> iUDQ_;
/// Aggregate 'IUAD' array (Integer) for all UDQ data (5 integers pr UDQ that is used for various well and group controls)
WindowedArray<int> iUAD_;
/// Aggregate 'ZUDN' array (Character) for all UDQ data. (2 * 8 chars pr UDQ -> UNIT keyword)
WindowedArray<EclIO::PaddedOutputString<8>> zUDN_;
/// Aggregate 'ZUDL' array (Character) for all UDQ data. (16 * 8 chars pr UDQ DEFINE "Data for operation - Msth Expression)
WindowedArray<EclIO::PaddedOutputString<8>> zUDL_;
/// Aggregate 'IGPH' array (Integer) for all UDQ data (3 - zeroes - as of current understanding)
WindowedArray<int> iGPH_;
/// Aggregate 'IUAP' array (ICharArrayNullTermnteger) for all UDQ data (1 integer pr UDQ constraint used)
WindowedArray<int> iUAP_;
/// Aggregate 'DUDW' array (Double Precision) for all UDQ data. (Dimension = max no wells * noOfUDQ's)
WindowedArray<double> dUDW_;
/// Aggregate 'DUDG' array (Double Precision) for all UDQ data. (Dimension = (max no groups + 1) * noOfUDQ's)
WindowedArray<double> dUDG_;
/// Aggregate 'DUDF' array (Double Precision) for all UDQ data. (Dimension = Number of FU - UDQ's, with value equal to the actual constraint)
WindowedArray<double> dUDF_;
};
}}} // Opm::RestartIO::Helpers
#endif //OPM_AGGREGATE_WELL_DATA_HPP

View File

@@ -20,10 +20,9 @@
#ifndef OPM_AGGREGATE_WELL_DATA_HPP
#define OPM_AGGREGATE_WELL_DATA_HPP
#include <opm/output/eclipse/CharArrayNullTerm.hpp>
#include <opm/output/eclipse/WindowedArray.hpp>
#include <opm/io/eclipse/PaddedOutputString.hpp>
#include <cstddef>
#include <string>
#include <vector>
@@ -53,6 +52,7 @@ namespace Opm { namespace RestartIO { namespace Helpers {
void captureDynamicWellData(const Opm::Schedule& sched,
const std::size_t sim_step,
const bool ecl_compatible_rst,
const Opm::data::WellRates& xw,
const Opm::SummaryState& smry);
@@ -75,7 +75,7 @@ namespace Opm { namespace RestartIO { namespace Helpers {
}
/// Retrieve Character Well Data Array.
const std::vector<EclIO::PaddedOutputString<8>>& getZWell() const
const std::vector<CharArrayNullTerm<8>>& getZWell() const
{
return this->zWell_.data();
}
@@ -93,7 +93,7 @@ namespace Opm { namespace RestartIO { namespace Helpers {
WindowedArray<double> xWell_;
/// Aggregate 'ZWEL' array (Character) for all wells.
WindowedArray<EclIO::PaddedOutputString<8>> zWell_;
WindowedArray<CharArrayNullTerm<8>> zWell_;
/// Maximum number of groups in model.
int nWGMax_;

View File

@@ -17,8 +17,8 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_PADDEDOUTPUTSTRING_HEADER_HPP
#define OPM_PADDEDOUTPUTSTRING_HEADER_HPP
#ifndef OPM_CHARARRAY_HEADER_HPP
#define OPM_CHARARRAY_HEADER_HPP
#include <algorithm>
#include <array>
@@ -26,7 +26,7 @@
#include <cstddef>
#include <string>
namespace Opm { namespace EclIO {
namespace Opm { namespace RestartIO { namespace Helpers {
/// Null-terminated, left adjusted, space padded array of N characters.
///
@@ -36,30 +36,30 @@ namespace Opm { namespace EclIO {
///
/// \tparam N Number of characters.
template <std::size_t N>
class PaddedOutputString
class CharArrayNullTerm
{
public:
PaddedOutputString()
CharArrayNullTerm()
{
this->clear();
}
explicit PaddedOutputString(const std::string& s)
: PaddedOutputString()
explicit CharArrayNullTerm(const std::string& s)
: CharArrayNullTerm()
{
this->copy_in(s.c_str(), s.size());
}
~PaddedOutputString() = default;
~CharArrayNullTerm() = default;
PaddedOutputString(const PaddedOutputString& rhs) = default;
PaddedOutputString(PaddedOutputString&& rhs) = default;
CharArrayNullTerm(const CharArrayNullTerm& rhs) = default;
CharArrayNullTerm(CharArrayNullTerm&& rhs) = default;
PaddedOutputString& operator=(const PaddedOutputString& rhs) = default;
PaddedOutputString& operator=(PaddedOutputString&& rhs) = default;
CharArrayNullTerm& operator=(const CharArrayNullTerm& rhs) = default;
CharArrayNullTerm& operator=(CharArrayNullTerm&& rhs) = default;
/// Assign from \code std::string \endcode.
PaddedOutputString& operator=(const std::string& s)
CharArrayNullTerm& operator=(const std::string& s)
{
this->clear();
this->copy_in(s.data(), s.size());
@@ -99,5 +99,5 @@ namespace Opm { namespace EclIO {
}
};
}} // Opm::EclIO
#endif // OPM_PADDEDOUTPUTSTRING_HEADER_HPP
}}} // Opm::RestartIO::Helpers
#endif // CHARARRAY_HEADER

View File

@@ -27,7 +27,6 @@
namespace Opm {
class Tuning;
class Schedule;
class UDQParams;
}
namespace Opm { namespace RestartIO {
@@ -39,7 +38,7 @@ namespace Opm { namespace RestartIO {
std::chrono::time_point<std::chrono::system_clock> start;
std::chrono::duration<double, std::chrono::seconds::period> elapsed;
};
DoubHEAD();
~DoubHEAD() = default;
@@ -58,9 +57,7 @@ namespace Opm { namespace RestartIO {
DoubHEAD& drsdt(const Schedule& sched,
const std::size_t lookup_step,
const double cnvT);
DoubHEAD& udq_param(const UDQParams& udqPar);
const double cnvT);
const std::vector<double>& data() const
{

View File

@@ -23,9 +23,10 @@
#define OPM_ECLIPSE_WRITER_HPP
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <array>
#include <memory>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/NNC.hpp>
@@ -35,15 +36,11 @@
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/RestartValue.hpp>
namespace Opm { namespace out {
class Summary;
}} // namespace Opm::out
namespace Opm {
class EclipseState;
class Schedule;
class SummaryConfig;
class Schedule;
class SummaryState;
/*!
@@ -174,11 +171,13 @@ public:
* hardcoded static map misc_units in Summary.cpp.
*/
void writeTimeStep( const SummaryState& st,
int report_step,
void writeTimeStep( int report_step,
bool isSubstep,
double seconds_elapsed,
RestartValue value,
const std::map<std::string, double>& single_summary_values,
const std::map<std::string, std::vector<double>>& region_summary_values,
const std::map<std::pair<std::string, int>, double>& block_summary_values,
const bool write_double = false);
@@ -220,12 +219,14 @@ public:
missing, if the bool is false missing keywords will be ignored
(there will *not* be an empty vector in the return value).
*/
RestartValue loadRestart(SummaryState& summary_state, const std::vector<RestartKey>& solution_keys, const std::vector<RestartKey>& extra_keys = {}) const;
const out::Summary& summary();
RestartValue loadRestart(const std::vector<RestartKey>& solution_keys, const std::vector<RestartKey>& extra_keys = {}) const;
EclipseIO( const EclipseIO& ) = delete;
~EclipseIO();
const SummaryState& summaryState() const;
private:
class Impl;
std::unique_ptr< Impl > impl;

View File

@@ -39,7 +39,6 @@ namespace Opm { namespace RestartIO {
int maxPerf;
int maxWellInGroup;
int maxGroupInField;
int maxWellsInField;
};
struct WellSegDims {
@@ -90,10 +89,6 @@ namespace Opm { namespace RestartIO {
struct Group {
int ngroups;
};
struct UdqParam {
int udqParam_1;
};
InteHEAD();
~InteHEAD() = default;
@@ -122,7 +117,6 @@ namespace Opm { namespace RestartIO {
InteHEAD& wellSegDimensions(const WellSegDims& wsdim);
InteHEAD& regionDimensions(const RegDims& rdim);
InteHEAD& ngroups(const Group& gr);
InteHEAD& udqParam_1(const UdqParam& udqpar);
const std::vector<int>& data() const
{

View File

@@ -1,5 +1,4 @@
/*
Copyright 2019 Equinor ASA.
Copyright 2016, 2017 Statoil ASA.
This file is part of the Open Porous Media Project (OPM).
@@ -28,49 +27,6 @@ namespace Opm { namespace RestartIO {
class LogiHEAD
{
public:
/// Key characteristics of simulation run's PVT model.
struct PVTModel
{
/// Whether or not simulation run uses a live oil model (with
/// dissolved gas).
bool isLiveOil { false };
/// Whether or not simulation run uses a wet gas model (with
/// vaporised oil).
bool isWetGas { false };
/// Whether or not simulation run uses a constant
/// compressibility oil model (keyword PVCDO).
bool constComprOil { false };
};
/// Key characteristics of simulation model's saturation functions.
struct SatfuncFlags
{
/// Whether or not simulation run uses directionally dependent
/// relative permeability.
bool useDirectionalRelPerm { false };
/// Whether or not simulation run uses reversible relative
/// permeability functions.
bool useReversibleRelPerm { true };
/// Whether or not simulation run uses end-point scaling.
bool useEndScale { false };
/// Whether or not simulation run uses directionally dependent
/// end-point scaling.
bool useDirectionalEPS { false };
/// Whether or not simulation run uses reversible end-point
/// scaling.
bool useReversibleEPS { true };
/// Whether or not simulation run activates the alternative
/// (three-point) end-point scaling feature.
bool useAlternateEPS { false };
};
LogiHEAD();
~LogiHEAD() = default;
@@ -86,21 +42,6 @@ namespace Opm { namespace RestartIO {
const bool enableHyster
);
/// Assign PVT model characteristics.
///
/// \param[in] pvt Current run's PVT model characteristics.
///
/// \return \code *this \endcode.
LogiHEAD& pvtModel(const PVTModel& pvt);
/// Assign saturation function characteristics.
///
/// \param[in] satfunc Current run's saturation function
/// characteristics.
///
/// \return \code *this \endcode.
LogiHEAD& saturationFunction(const SatfuncFlags& satfunc);
const std::vector<bool>& data() const
{
return this->data_;

View File

@@ -24,11 +24,23 @@
#ifndef RESTART_IO_HPP
#define RESTART_IO_HPP
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
#include <opm/output/data/Cells.hpp>
#include <opm/output/data/Solution.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/RestartValue.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
#include <string>
#include <ert/ecl/EclKW.hpp>
#include <ert/ecl/ecl_rsthead.h>
#include <ert/ecl/ecl_rst_file.h>
#include <ert/util/util.h>
#include <map>
#include <utility>
#include <vector>
@@ -36,15 +48,11 @@ namespace Opm {
class EclipseGrid;
class EclipseState;
class Phases;
class Schedule;
} // namespace Opm
namespace Opm { namespace EclIO { namespace OutputStream {
class Restart;
}}}
/*
The two free functions RestartIO::save() and RestartIO::load() can
@@ -69,25 +77,24 @@ namespace Opm { namespace EclIO { namespace OutputStream {
*/
namespace Opm { namespace RestartIO {
void save(EclIO::OutputStream::Restart& rstFile,
int report_step,
double seconds_elapsed,
RestartValue value,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const SummaryState& sumState,
bool write_double = false);
void save(const std::string& filename,
int report_step,
double seconds_elapsed,
RestartValue value,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const SummaryState& sumState,
bool write_double = false);
RestartValue load(const std::string& filename,
int report_step,
SummaryState& summary_state,
const std::vector<RestartKey>& solution_keys,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const std::vector<RestartKey>& extra_keys = {});
std::pair<RestartValue, SummaryState>
load(const std::string& filename,
int report_step,
const std::vector<RestartKey>& solution_keys,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const std::vector<RestartKey>& extra_keys = {});
}} // namespace Opm::RestartIO

View File

@@ -25,7 +25,6 @@
#include <vector>
#include <ert/ecl/ecl_sum.h>
#include <ert/util/ert_unique_ptr.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
@@ -44,40 +43,37 @@ namespace Opm {
namespace out {
class Summary {
public:
Summary( const EclipseState&, const SummaryConfig&, const EclipseGrid&, const Schedule& );
Summary( const EclipseState&, const SummaryConfig&, const EclipseGrid&, const Schedule&, const std::string& );
Summary( const EclipseState&, const SummaryConfig&, const EclipseGrid&, const Schedule&, const char* basename );
public:
Summary( const EclipseState&, const SummaryConfig&, const EclipseGrid&, const Schedule& );
Summary( const EclipseState&, const SummaryConfig&, const EclipseGrid&, const Schedule&, const std::string& );
Summary( const EclipseState&, const SummaryConfig&, const EclipseGrid&, const Schedule&, const char* basename );
void add_timestep(const SummaryState& st,
int report_step);
void add_timestep(int report_step,
double secs_elapsed,
const EclipseState& es,
const Schedule& schedule,
const data::Wells&,
const std::map<std::string, double>& single_values,
const std::map<std::string, std::vector<double>>& region_values = {},
const std::map<std::pair<std::string, int>, double>& block_values = {});
void write();
void eval(SummaryState& summary_state,
int report_step,
double secs_elapsed,
const EclipseState& es,
const Schedule& schedule,
const data::Wells&,
const std::map<std::string, double>& single_values,
const std::map<std::string, std::vector<double>>& region_values = {},
const std::map<std::pair<std::string, int>, double>& block_values = {}) const;
~Summary();
const SummaryState& get_restart_vectors() const;
void reset_cumulative_quantities(const SummaryState& rstrt);
~Summary();
void write() const;
private:
class keyword_handlers;
private:
void internal_store(const SummaryState& summary_state, int report_step);
class keyword_handlers;
const EclipseGrid& grid;
out::RegionCache regionCache;
ERT::ert_unique_ptr< ecl_sum_type, ecl_sum_free > ecl_sum;
std::unique_ptr< keyword_handlers > handlers;
const EclipseGrid& grid;
out::RegionCache regionCache;
ERT::ert_unique_ptr< ecl_sum_type, ecl_sum_free > ecl_sum;
std::unique_ptr< keyword_handlers > handlers;
double prev_time_elapsed = 0;
SummaryState prev_state;
};
}

View File

@@ -24,6 +24,11 @@
#include <vector>
#include <ert/ecl/FortIO.hpp>
#include <ert/ecl/EclKW.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/PvtoTable.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/PvtgTable.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/FlatTable.hpp>
namespace Opm {
@@ -34,6 +39,9 @@ namespace Opm {
public:
explicit Tables( const UnitSystem& units);
void addPVTO(const std::vector<PvtoTable>& pvtoTables);
void addPVTG(const std::vector<PvtgTable>& pvtgTables);
void addPVTW(const PvtwTable& pvtwTable);
void addDensity(const DensityTable& density);
/// Add normalised PVT function tables to INIT file's TAB vector.
@@ -129,6 +137,20 @@ namespace Opm {
/// TableManager sub-object.
void addWaterPVTTables(const EclipseState& es);
};
/// Emit normalised tabular information (TABDIMS and TAB vectors) to
/// ECL-like result set file (typically INIT file).
///
/// \param[in] tables Collection of normalised tables. Its \code
/// tabdims() \endcode and \code tab() \endcode vectors will be
/// emitted to \p fortio as ECL keywords "TABDIMS" and "TAB",
/// respectively.
///
/// \param[in,out] fortio ECL-like result set file. Typically
/// corresponds to a preopened stream attached to the INIT file.
void fwrite(const Tables& tables,
ERT::FortIO& fortio);
}
#endif // OUTPUT_TABLES_HPP
#endif

View File

@@ -30,9 +30,6 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
TsInit = 1, // Maximum Length of Next Timestep
TsMaxz = 2, // Maximum Length of Timestep After Next
TsMinz = 3, // Minumum Length of All Timesteps
UdqPar_2 = 212, // UDQPARAM item number 2 (Permitted range (+/-) of user-defined quantities)
UdqPar_3 = 213, // UDQPARAM item number 3 (Value given to undefined elements when outputting data)
UdqPar_4 = 214, // UDQPARAM item number 4 (fractional equality tolerance used in ==, <= etc. functions)
};
}}}} // Opm::RestartIO::Helpers::VectorItems

View File

@@ -76,8 +76,6 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
NSCAQZ = 46, // Number of data elements per aquifer connection in SCAQ array
NACAQZ = 47, // Number of data elements per aquifer connection in ACAQ array
NWMAXZ = 163, // Maximum number of wells in the model
NSEGWL = 174, // Number of multisegment wells defined with WELSEG
NSWLMX = 175, // Maximum number of segmented wells (item 1 ofWSEGDIMS)
NSEGMX = 176, // Maximum number of segments per well (item 2 of WSEGDIMS)
@@ -86,7 +84,6 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
NISEGZ = 178, // Number of entries per segment in ISEG array
NRSEGZ = 179, // Number of entries per segment in RSEG array
NILBRZ = 180, // Number of entries per segment in ILBR array
UDQPAR_1 = 267, // Integer seed value for the RAND /
};
}}}} // Opm::RestartIO::Helpers::VectorItems

View File

@@ -1,48 +0,0 @@
/*
Copyright (c) 2019 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_OUTPUT_ECLIPSE_VECTOR_LOGIHEAD_HPP
#define OPM_OUTPUT_ECLIPSE_VECTOR_LOGIHEAD_HPP
#include <vector>
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
// This is a subset of the items in src/opm/output/eclipse/LogiHEAD.cpp .
// Promote items from that list to this in order to make them public.
enum logihead : std::vector<bool>::size_type {
IsLiveOil = 0, // Oil phase w/dissolved gas
IsWetGas = 1, // Gas phase w/vaporised oil
DirKr = 2, // Directional relative permeability
E100RevKr = 3, // Reversible rel. perm. (E100)
E100Radial = 4, // Radial model (E100)
E300Radial = 3, // Radial model (E300, others)
E300RevKr = 4, // Reversible rel. perm. (E300, others)
Hyster = 6, // Enable hysteresis
DualPoro = 14, // Enable dual porosity
EndScale = 16, // Enable end-point scaling
DirEPS = 17, // Directional end-point scaling
RevEPS = 18, // Reversible end-point scaling
AltEPS = 19, // Alternative (3-pt) end-point scaling
ConstCo = 38, // Constant oil compressibility (PVCDO)
HasMSWells = 75, // Whether or not model has MS Wells.
};
}}}} // Opm::RestartIO::Helpers::VectorItems
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_LOGIHEAD_HPP

View File

@@ -1,76 +0,0 @@
/*
Copyright (c) 2019 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_OUTPUT_ECLIPSE_VECTOR_TABDIMS_HPP
#define OPM_OUTPUT_ECLIPSE_VECTOR_TABDIMS_HPP
#include <vector>
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
namespace TabDims {
enum index : std::vector<int>::size_type {
// Number of elements in 'TAB' array
TabSize = 0,
// Oil PVT table
PvtoMainStart = 6,
PvtoCompStart = 7,
NumPvtoCompNodes = 8,
NumPvtoPressNodes = 9,
NumPvtoTables = 10,
// Water PVT table
PvtwStart = 11,
NumPvtwTables = 12,
// Gas PVT tables
PvtgMainStart = 13,
PvtgPressStart = 14,
NumPvtgCompNodes = 15,
NumPvtgPressNodes = 16,
NumPvtgTables = 17,
// Density tables
DensityTableStart = 18,
DensityNumTables = 19,
// SWFN tables
SwfnTableStart = 20,
SwfnNumSatNodes = 21,
SwfnNumTables = 22,
// SGFN tables
SgfnTableStart = 23,
SgfnNumSatNodes = 24,
SgfnNumTables = 25,
// SOFN tables
SofnTableStart = 26,
SofnNumSatNodes = 28,
SofnNumTables = 29,
// Size of TABDIMS array
TabDimsNumElems = 100,
};
} // namespace TabDims
}}}} // namespace Opm::RestartIO::Helpers::VectorItems
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_TABDIMS_HPP

View File

@@ -21,9 +21,7 @@
#define OPM_WINDOWED_ARRAY_HPP
#include <cassert>
#include <exception>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include <vector>
@@ -74,10 +72,7 @@ namespace Opm { namespace RestartIO { namespace Helpers {
explicit WindowedArray(const NumWindows n, const WindowSize sz)
: x_ (n.value * sz.value)
, windowSize_(sz.value)
{
if (sz.value == 0)
throw std::invalid_argument("Window array with windowsize==0 is not permitted");
}
{}
/// Retrieve number of windows allocated for this array.
Idx numWindows() const
@@ -184,10 +179,7 @@ namespace Opm { namespace RestartIO { namespace Helpers {
const WindowSize& sz)
: data_ (NumWindows{ nRows.value * nCols.value }, sz)
, numCols_(nCols.value)
{
if (nCols.value == 0)
throw std::invalid_argument("Window matrix with columns==0 is not permitted");
}
{}
/// Retrieve number of columns allocated for this matrix.
Idx numCols() const

View File

@@ -1,60 +0,0 @@
/*
Copyright (c) 2019 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_WRITE_INIT_HPP
#define OPM_WRITE_INIT_HPP
#include <map>
#include <string>
#include <vector>
namespace Opm {
class EclipseGrid;
class EclipseState;
class NNC;
class Schedule;
} // namespace Opm
namespace Opm { namespace data {
class Solution;
}} // namespace Opm::data
namespace Opm { namespace EclIO { namespace OutputStream {
class Init;
}}} // namespace Opm::EclIO::OutputStream
namespace Opm { namespace InitIO {
void write(const ::Opm::EclipseState& es,
const ::Opm::EclipseGrid& grid,
const ::Opm::Schedule& schedule,
const ::Opm::data::Solution& simProps,
std::map<std::string, std::vector<int>> int_data,
const ::Opm::NNC& nnc,
::Opm::EclIO::OutputStream::Init& initFile);
}} // namespace Opm::InitIO
#endif // OPM_WRITE_INIT_HPP

View File

@@ -1,89 +0,0 @@
/*
Copyright (c) 2019 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_WRITE_RFT_HPP
#define OPM_WRITE_RFT_HPP
namespace Opm {
class EclipseGrid;
class Schedule;
class UnitSystem;
} // namespace Opm
namespace Opm { namespace data {
class WellRates;
}} // namespace Opm::data
namespace Opm { namespace EclIO { namespace OutputStream {
class RFT;
}}} // namespace Opm::EclIO::OutputStream
namespace Opm { namespace RftIO {
/// Collect RFT data and output to pre-opened output stream.
///
/// RFT data is output for all affected wells at a given timestep,
/// and consists of
///
/// 1) Time stamp (elapsed and date)
/// 2) Metadata about the output (units of measure, well types,
/// data type identifier)
/// 3) Depth, pressure, Sw, Sg, (I,J,K), and hostgrid for each
/// reservoir connection of the affected well.
///
/// If no RFT output is requested at given timestep, then this
/// function returns with no output written to the RFT file.
///
/// \param[in] reportStep Report step time point for which to output
/// RFT data.
///
/// \param[in] elapsed Number of seconds of simulated time until
/// this report step (\p reportStep).
///
/// \param[in] usys Unit system conventions for output. Typically
/// corresponds to run's active unit system (i.e., \code
/// EclipseState::getUnits() \endcode).
///
/// \param[in] grid Run's active grid. Used to determine which
/// reservoir connections are in active grid cells.
///
/// \param[in] schedule Run's SCHEDULE section from which to access
/// the active wells and the RFT configuration.
///
/// \param[in,out] rftFile RFT output stream. On input, appropriately
/// positioned for new content (i.e., at end-of-file). On output,
/// containing new RFT output (if applicable) and positioned after
/// new contents.
void write(const int reportStep,
const double elapsed,
const ::Opm::UnitSystem& usys,
const ::Opm::EclipseGrid& grid,
const ::Opm::Schedule& schedule,
const ::Opm::data::WellRates& wellSol,
::Opm::EclIO::OutputStream::RFT& rftFile);
}} // namespace Opm::RftIO
#endif // OPM_WRITE_RFT_HPP

View File

@@ -36,7 +36,6 @@ namespace Opm {
class Schedule;
class Well;
class UnitSystem;
class UDQActive;
} // Opm
@@ -64,11 +63,17 @@ namespace Opm { namespace RestartIO { namespace Helpers {
std::vector<bool>
createLogiHead(const EclipseState& es);
std::vector<int>
createUdqDims(const Schedule& sched,
const std::size_t lookup_step,
const std::vector<int>& inteHead);
std::vector<int> serialize_ICON(int lookup_step, // The integer index used to look up dynamic properties, e.g. the number of well.
int ncwmax, // Max number of completions per well, should be entry 17 from createInteHead.
int niconz, // Number of elements per completion in ICON, should be entry 32 from createInteHead.
const std::vector<const Well*>& sched_wells);
std::vector<double> serialize_SCON(int lookup_step, // The integer index used to look up dynamic properties, e.g. the number of well.
int ncwmax, // Max number of completions per well, should be entry 17 from createInteHead.
int nsconz, // Number of elements per completion in SCON, should be entry 33 from createInteHead.
const std::vector<const Well*>& sched_wells,
const UnitSystem& units);
}}} // Opm::RestartIO::Helpers

File diff suppressed because it is too large Load Diff

View File

@@ -124,6 +124,10 @@ namespace Opm {
using iterator = std::vector< DeckKeyword >::iterator;
Deck();
// cppcheck-suppress noExplicitConstructor
Deck( std::initializer_list< DeckKeyword > );
// cppcheck-suppress noExplicitConstructor
Deck( std::initializer_list< std::string > );
Deck( const Deck& );

View File

@@ -27,7 +27,6 @@
#include <opm/parser/eclipse/Units/Dimension.hpp>
#include <opm/parser/eclipse/Utility/Typetools.hpp>
#include <opm/parser/eclipse/Deck/UDAValue.hpp>
namespace Opm {
class DeckOutput;
@@ -35,10 +34,11 @@ namespace Opm {
class DeckItem {
public:
DeckItem() = default;
DeckItem( const std::string&, int);
DeckItem( const std::string&, double);
DeckItem( const std::string&, std::string);
DeckItem( const std::string&, UDAValue);
explicit DeckItem( const std::string& );
DeckItem( const std::string&, int, size_t size_hint = 8 );
DeckItem( const std::string&, double, size_t size_hint = 8 );
DeckItem( const std::string&, std::string, size_t size_hint = 8 );
const std::string& name() const;
@@ -58,23 +58,19 @@ namespace Opm {
size_t size() const;
size_t out_size() const;
//template< typename T > T& get( size_t ) ;
template< typename T > T get( size_t ) const;
template< typename T > const T& get( size_t ) const;
double getSIDouble( size_t ) const;
std::string getTrimmedString( size_t ) const;
template< typename T > const std::vector< T >& getData() const;
const std::vector< double >& getSIDoubleData() const;
void push_back( UDAValue );
void push_back( int );
void push_back( double );
void push_back( std::string );
void push_back( UDAValue, size_t );
void push_back( int, size_t );
void push_back( double, size_t );
void push_back( std::string, size_t );
void push_backDefault( UDAValue );
void push_backDefault( int );
void push_backDefault( double );
void push_backDefault( std::string );
@@ -111,22 +107,17 @@ namespace Opm {
bool operator!=(const DeckItem& other) const;
static bool to_bool(std::string string_value);
private:
mutable std::vector< double > dval;
std::vector< double > dval;
std::vector< int > ival;
std::vector< std::string > sval;
std::vector< UDAValue > uval;
type_tag type = type_tag::unknown;
std::string item_name;
std::vector< bool > defaulted;
std::vector< Dimension > dimensions;
/*
To save space we mutate the dval object in place when asking for SI
data; the current state of of the dval member is tracked with the
raw_data bool member.
*/
mutable bool raw_data = true;
mutable std::vector< double > SIdata;
template< typename T > std::vector< T >& value_ref();
template< typename T > const std::vector< T >& value_ref() const;
template< typename T > void push( T );

View File

@@ -23,36 +23,25 @@
#include <string>
#include <vector>
#include <memory>
#include <utility>
#include <opm/parser/eclipse/Parser/ParserKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckValue.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
namespace Opm {
class DeckOutput;
class ParserKeyword;
class DeckOutput;
class DeckKeyword {
public:
typedef std::vector< DeckRecord >::const_iterator const_iterator;
explicit DeckKeyword(const ParserKeyword& parserKeyword);
DeckKeyword(const ParserKeyword& parserKeyword, const std::string& keywordName);
DeckKeyword(const ParserKeyword& parserKeyword, const std::vector<std::vector<DeckValue>>& record_list);
DeckKeyword(const ParserKeyword& parserKeyword, const std::vector<int>& data);
DeckKeyword(const ParserKeyword& parserKeyword, const std::vector<double>& data);
explicit DeckKeyword(const std::string& keywordName);
DeckKeyword(const std::string& keywordName, bool knownKeyword);
const std::string& name() const;
void setFixedSize();
void setLocation(const std::pair<const std::string&, std::size_t>& location);
void setLocation(const std::string& fileName, int lineNumber);
const std::string& getFileName() const;
int getLineNumber() const;
std::pair<std::string, std::size_t> location() const;
size_t size() const;
void addRecord(DeckRecord&& record);
@@ -60,13 +49,13 @@ namespace Opm {
DeckRecord& getRecord(size_t index);
const DeckRecord& getDataRecord() const;
void setDataKeyword(bool isDataKeyword = true);
bool isKnown() const;
bool isDataKeyword() const;
const std::vector<int>& getIntData() const;
const std::vector<double>& getRawDoubleData() const;
const std::vector<double>& getSIDoubleData() const;
const std::vector<std::string>& getStringData() const;
const ParserKeyword& parserKeyword() const;
size_t getDataSize() const;
void write( DeckOutput& output ) const;
void write_data( DeckOutput& output ) const;
@@ -94,9 +83,9 @@ namespace Opm {
int m_lineNumber;
std::vector< DeckRecord > m_recordList;
bool m_knownKeyword;
bool m_isDataKeyword;
bool m_slashTerminated;
ParserKeyword parser_keyword;
};
}

View File

@@ -1,58 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DECK_VALUE_HPP
#define DECK_VALUE_HPP
#include <string>
#include <opm/parser/eclipse/Utility/Typetools.hpp>
namespace Opm {
class DeckValue {
public:
DeckValue();
explicit DeckValue(int);
explicit DeckValue(double);
explicit DeckValue(const std::string&);
bool is_default() const;
template<typename T>
T get() const;
template<typename T>
bool is_compatible() const;
private:
bool default_value;
type_tag value_enum;
int int_value;
double double_value;
std::string string_value;
};
}
#endif

View File

@@ -1,69 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UDA_VALUE_HPP
#define UDA_VALUE_HPP
#include <stdexcept>
#include <vector>
#include <string>
#include <iosfwd>
#include <opm/parser/eclipse/Units/Dimension.hpp>
namespace Opm {
class UDAValue {
public:
UDAValue();
explicit UDAValue(double);
explicit UDAValue(const std::string&);
template<typename T>
T get() const;
template<typename T>
bool is() const;
void reset(double value);
void reset(const std::string& value);
void assert_numeric() const;
void assert_numeric(const std::string& error_msg) const;
void set_dim(const Dimension& dim) const;
const Dimension& get_dim() const;
bool operator==(const UDAValue& other) const;
bool operator!=(const UDAValue& other) const;
private:
bool numeric_value;
double double_value;
std::string string_value;
/* This 'mutable' modifier is a hack to avoid tampering with the overall
const-ness of the data in a deck item. */
mutable Dimension dim;
};
std::ostream& operator<<( std::ostream& stream, const UDAValue& uda_value );
}
#endif

View File

@@ -98,8 +98,6 @@ namespace Opm {
void loadGridPropertyFromDeckKeyword(const Box& inputBox,
const DeckKeyword& deckKeyword);
void adjustSOGCRwithSWL();
std::string m_defaultRegion;
UnitSystem m_deckUnitSystem;
GridProperties<int> m_intGridProperties;

View File

@@ -25,24 +25,23 @@
#include <cstddef>
namespace Opm {
class EclipseGrid;
class Box {
public:
struct index_pair {
std::size_t global;
std::size_t active;
};
Box(const EclipseGrid& grid);
Box(const EclipseGrid& grid , int i1 , int i2 , int j1 , int j2 , int k1 , int k2);
Box() = default;
Box(int nx , int ny , int nz);
Box(const Box& globalBox , int i1 , int i2 , int j1 , int j2 , int k1 , int k2); // Zero offset coordinates.
Box(int nx, int ny, int nz, int i1 , int i2 , int j1 , int j2 , int k1 , int k2);
size_t size() const;
bool isGlobal() const;
size_t getDim(size_t idim) const;
const std::vector<index_pair>& index_list() const;
const std::vector<size_t>& getIndexList() const;
bool equal(const Box& other) const;
explicit operator bool() const;
std::vector<size_t>::const_iterator begin() const;
std::vector<size_t>::const_iterator end() const;
int I1() const;
int I2() const;
@@ -53,14 +52,12 @@ namespace Opm {
private:
void initIndexList();
const EclipseGrid& grid;
size_t m_dims[3] = { 0, 0, 0 };
size_t m_offset[3];
size_t m_stride[3];
bool m_isGlobal;
std::vector<size_t> global_index_list;
std::vector<index_pair> m_index_list;
std::vector<size_t> m_indexList;
int lower(int dim) const;
int upper(int dim) const;

View File

@@ -25,7 +25,6 @@
#include <memory>
#include <opm/parser/eclipse/EclipseState/Grid/Box.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
/*
This class implements a simple book keeping system for the current
@@ -54,7 +53,7 @@ namespace Opm {
class BoxManager {
public:
BoxManager(const EclipseGrid& grid);
BoxManager(int nx , int ny , int nz);
void setInputBox( int i1,int i2 , int j1 , int j2 , int k1 , int k2);
void setKeywordBox( int i1,int i2 , int j1 , int j2 , int k1 , int k2);
@@ -64,12 +63,14 @@ namespace Opm {
void endKeyword();
const Box& getActiveBox() const;
const Box& getGlobalBox() const;
const Box& getInputBox() const;
const Box& getKeywordBox() const;
private:
const EclipseGrid& grid;
std::unique_ptr<Box> m_globalBox;
std::unique_ptr<Box> m_inputBox;
std::unique_ptr<Box> m_keywordBox;
Box m_globalBox;
Box m_inputBox;
Box m_keywordBox;
};
}

View File

@@ -26,9 +26,9 @@
#include <opm/parser/eclipse/EclipseState/Grid/MinpvMode.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/PinchMode.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/GridDims.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/NNC.hpp>
#include <opm/io/eclipse/EclFile.hpp>
#include <ert/ecl/ecl_grid.h>
#include <ert/util/ert_unique_ptr.hpp>
#include <array>
#include <memory>
@@ -59,9 +59,9 @@ namespace Opm {
These constructors will make a copy of the src grid, with
zcorn and or actnum have been adjustments.
*/
EclipseGrid(const EclipseGrid& src) = default;
EclipseGrid(const EclipseGrid& src, const double* zcorn , const std::vector<int>& actnum);
EclipseGrid(const EclipseGrid& src, const std::vector<double>& zcorn , const std::vector<int>& actnum);
EclipseGrid(const EclipseGrid& src, const std::vector<int>& actnum);
EclipseGrid(const EclipseGrid& src, const double* zcorn, const std::vector<int>& actnum);
EclipseGrid(size_t nx, size_t ny, size_t nz,
double dx = 1.0, double dy = 1.0, double dz = 1.0);
@@ -77,6 +77,7 @@ namespace Opm {
/// explicitly. If a null pointer is passed, every cell is active.
EclipseGrid(const Deck& deck, const int * actnum = nullptr);
static bool hasGDFILE(const Deck& deck);
static bool hasCylindricalKeywords(const Deck& deck);
static bool hasCornerPointKeywords(const Deck&);
@@ -87,7 +88,8 @@ namespace Opm {
size_t activeIndex(size_t i, size_t j, size_t k) const;
size_t activeIndex(size_t globalIndex) const;
void save(const std::string& filename, bool formatted, const Opm::NNC& nnc, const Opm::UnitSystem& units) const;
void save(const std::string& filename, UnitSystem::UnitType output_units) const;
void addNNC(const NNC& nnc);
/*
Observe that the there is a getGlobalIndex(i,j,k)
implementation in the base class. This method - translating
@@ -103,7 +105,6 @@ namespace Opm {
applied in the 'THETA' direction; this will only apply if
the theta keywords entered sum up to exactly 360 degrees!
*/
bool circle( ) const;
bool isPinchActive( ) const;
double getPinchThresholdThickness( ) const;
@@ -113,6 +114,7 @@ namespace Opm {
MinpvMode::ModeEnum getMinpvMode() const;
const std::vector<double>& getMinpvVector( ) const;
/*
Will return a vector of nactive elements. The method will
behave differently depending on the lenght of the
@@ -125,7 +127,6 @@ namespace Opm {
??? : Exception.
*/
template<typename T>
std::vector<T> compressedVector(const std::vector<T>& input_vector) const {
if( input_vector.size() == this->getNumActive() ) {
@@ -150,13 +151,13 @@ namespace Opm {
/// Will return a vector a length num_active; where the value
/// of each element is the corresponding global index.
const std::vector<int>& getActiveMap() const;
const std::array<double, 3>& getCellCenter(size_t i,size_t j, size_t k) const;
const std::array<double, 3>& getCellCenter(size_t globalIndex) const;
std::array<double, 3> getCellCenter(size_t i,size_t j, size_t k) const;
std::array<double, 3> getCellCenter(size_t globalIndex) const;
std::array<double, 3> getCornerPos(size_t i,size_t j, size_t k, size_t corner_index) const;
double getCellVolume(size_t globalIndex) const;
double getCellVolume(size_t i , size_t j , size_t k) const;
double getCellThickness(size_t globalIndex) const;
double getCellThickness(size_t i , size_t j , size_t k) const;
double getCellThicknes(size_t globalIndex) const;
double getCellThicknes(size_t i , size_t j , size_t k) const;
std::array<double, 3> getCellDims(size_t i,size_t j, size_t k) const;
std::array<double, 3> getCellDims(size_t globalIndex) const;
bool cellActive( size_t globalIndex ) const;
@@ -165,28 +166,19 @@ namespace Opm {
double getCellDepth(size_t globalIndex) const;
ZcornMapper zcornMapper() const;
const std::vector<double>& getCOORD() const;
const std::vector<double>& getZCORN() const;
const std::vector<int>& getACTNUM( ) const;
const std::vector<double>& getMAPAXES() const;
const std::string& getMAPUNITS() const { return m_mapunits; } ;
/*
The fixupZCORN method is run as part of constructiong the grid. This will adjust the
z-coordinates to ensure that cells do not overlap. The return value is the number of
points which have been adjusted. The number of zcorn nodes that has ben fixed is
stored in private member zcorn_fixed.
The exportZCORN method will adjust the z coordinates to ensure that cells do not
overlap. The return value is the number of points which have been adjusted.
*/
size_t exportZCORN( std::vector<double>& zcorn) const;
size_t fixupZCORN();
size_t getZcornFixed() { return zcorn_fixed; };
// resetACTNUM with no arguments will make all cells in the grid active.
void resetACTNUM();
void resetACTNUM( const std::vector<int>& actnum);
void exportMAPAXES( std::vector<double>& mapaxes) const;
void exportCOORD( std::vector<double>& coord) const;
void exportACTNUM( std::vector<int>& actnum) const;
void resetACTNUM( const int * actnum);
bool equal(const EclipseGrid& other) const;
const ecl_grid_type * c_ptr() const;
private:
std::vector<double> m_minpvVector;
@@ -194,35 +186,25 @@ namespace Opm {
Value<double> m_pinch;
PinchMode::ModeEnum m_pinchoutMode;
PinchMode::ModeEnum m_multzMode;
mutable std::vector<double> volume_cache;
mutable std::vector< int > activeMap;
bool m_circle = false;
size_t zcorn_fixed = 0;
bool m_useActnumFromGdfile = false;
// Input grid data.
std::vector<double> m_zcorn;
std::vector<double> m_coord;
std::vector<double> m_mapaxes;
std::vector<int> m_actnum;
std::string m_mapunits;
// Mapping to/from active cells.
int m_nactive;
std::vector<int> m_active_to_global;
std::vector<int> m_global_to_active;
// Geometry data.
std::vector<double> m_volume;
std::vector<double> m_depth;
std::vector<double> m_dx;
std::vector<double> m_dy;
std::vector<double> m_dz;
std::vector<std::array<double, 3>> m_cellCenter;
void initGridFromEGridFile(Opm::EclIO::EclFile& egridfile, std::string fileName);
/*
The internal class grid_ptr is a a std::unique_ptr with
special copy semantics. The purpose of implementing this is
that the EclipseGrid class can now use the default
implementation for the copy and move constructors.
*/
using ert_ptr = ERT::ert_unique_ptr<ecl_grid_type , ecl_grid_free>;
class grid_ptr : public ert_ptr {
public:
using ert_ptr::unique_ptr;
grid_ptr() = default;
grid_ptr(grid_ptr&&) = default;
grid_ptr(const grid_ptr& src) :
ert_ptr( ecl_grid_alloc_copy( src.get() ) ) {}
};
grid_ptr m_grid;
void initBinaryGrid(const Deck& deck);
void initCornerPointGrid(const std::array<int,3>& dims ,
@@ -231,8 +213,6 @@ namespace Opm {
const int * actnum,
const double * mapaxes);
bool keywInputBeforeGdfile(const Deck& deck, const std::string keyword) const;
void initCylindricalGrid( const std::array<int, 3>&, const Deck&);
void initCartesianGrid( const std::array<int, 3>&, const Deck&);
void initCornerPointGrid( const std::array<int, 3>&, const Deck&);
@@ -249,20 +229,6 @@ namespace Opm {
static std::vector<double> createDVector(const std::array<int, 3>& dims, size_t dim, const std::string& DKey,
const std::string& DVKey, const Deck&);
static void scatterDim(const std::array<int, 3>& dims , size_t dim , const std::vector<double>& DV , std::vector<double>& D);
std::vector<double> makeCoordDxDyDzTops(const std::array<int, 3>& dims, const std::vector<double>& dx, const std::vector<double>& dy, const std::vector<double>& dz, const std::vector<double>& tops) const;
std::vector<double> makeZcornDzTops(const std::array<int, 3>& dims, const std::vector<double>& dz, const std::vector<double>& tops) const ;
std::vector<double> makeZcornDzvDepthz(const std::array<int, 3>& dims, const std::vector<double>& dzv, const std::vector<double>& depthz) const;
std::vector<double> makeCoordDxvDyvDzvDepthz(const std::array<int, 3>& dims, const std::vector<double>& dxv, const std::vector<double>& dyv, const std::vector<double>& dzv, const std::vector<double>& depthz) const;
double sumIdir(int j, int k, int i1, const std::array<int, 3>& dims, const std::vector<double>& dx) const;
double sumJdir(int i, int k, int j1, const std::array<int, 3>& dims, const std::vector<double>& dy) const;
double sumKdir(int i, int j, const std::array<int, 3>& dims, const std::vector<double>& dz) const;
void calculateGeometryData();
void getCellCorners(const std::array<int, 3>& ijk, const std::array<int, 3>& dims, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z) const;
};
class CoordMapper {

View File

@@ -54,6 +54,9 @@
namespace Opm {
void setKeywordBox( const DeckRecord& deckRecord,
BoxManager& boxManager);
class Eclipse3DProperties;
template <typename T>
@@ -178,7 +181,7 @@ namespace Opm {
/// this method exists for (friend) Eclipse3DProperties to be allowed initializing PORV and ACTNUM keyword
void postAddKeyword(const std::string& name,
const T defaultValue,
std::function< void( const std::vector<bool>& defaulted, std::vector< T >& ) > postProcessor,
std::function< void( std::vector< T >& ) > postProcessor,
const std::string& dimString,
const bool defaultInitializable );

View File

@@ -21,7 +21,6 @@
#include <functional>
#include <string>
#include <utility>
#include <vector>
/*
@@ -46,18 +45,7 @@ class GridPropertySupportedKeywordInfo {
GridPropertySupportedKeywordInfo() = default;
using init = std::function< std::vector< T >( size_t ) >;
/**
* Property post-processor function type.
*
* Defaulted flag (one element for each Cartesian cell/data element)
* identifies whether the property value was defaulted in that cell
* (true) or assigned through a deck mechanism (false).
*/
using post = std::function<
void(const std::vector<bool>& defaulted,
std::vector< T >&)
>;
using post = std::function< void( std::vector< T >& ) >;
GridPropertySupportedKeywordInfo(
const std::string& name,
@@ -94,37 +82,6 @@ class GridPropertySupportedKeywordInfo {
const post& postProcessor() const;
bool isDefaultInitializable() const;
/**
* Replace post-processor after object is created.
*
* XXX: This is essentially a hack, but it enables using
* post-processors that can't be created at construction time.
*
* One example of this use case is the post-processor for SOGCR in
* a run using Family I (SWOF/SGOF) saturation function tables.
* The SGOF table is implicitly defined in terms of the connate
* water saturation, and the critical oil-in-gas saturation
* post-processor needs to take this fact into account. That, in
* turn, means that the post-processor must have a way of
* accessing SWL data (defaulted or assigned) which means that the
* post-processor needs to be aware of the collection of grid
* properties, not just a single property in isolation.
*
* In our current system, the GridPropertySupportedKeywordInfo
* objects are constructor arguments to that collection and so
* have no way of referring to the collection itself. This method
* provides a mechanism for creating the post-processor once the
* collection is formed.
*
* \param[in] processor New post-processor function. Replaces
* existing post-processor, typically created at construction
* time.
*/
void setPostProcessor(post processor)
{
this->m_postProcessor = std::move(processor);
}
private:
std::string m_keywordName;
@@ -153,7 +110,6 @@ public:
void iset(size_t i , size_t j , size_t k , T value);
const std::vector<bool>& wasDefaulted() const;
const std::vector<T>& getData() const;
std::vector<T>& getData();
@@ -309,14 +265,10 @@ public:
private:
const DeckItem& getDeckItem( const DeckKeyword& );
void setDataPoint(size_t sourceIdx, size_t targetIdx, const DeckItem& deckItem);
void setElement(const typename std::vector<T>::size_type i,
const T value,
const bool defaulted = false);
size_t m_nx, m_ny, m_nz;
SupportedKeywordInfo m_kwInfo;
std::vector<T> m_data;
std::vector<bool> m_defaulted;
bool m_hasRunPostProcessor = false;
bool assigned = false;
};

View File

@@ -1,13 +1,17 @@
#ifndef OPM_EQUIL_HPP
#define OPM_EQUIL_HPP
#include <cstddef>
#include <vector>
namespace Opm {
class DeckKeyword;
class DeckRecord;
class EquilRecord {
public:
explicit EquilRecord( const DeckRecord& );
double datumDepth() const;
double datumDepthPressure() const;
double waterOilContactDepth() const;
@@ -19,9 +23,7 @@ namespace Opm {
bool wetGasInitConstantRv() const;
int initializationTargetAccuracy() const;
EquilRecord( double datum_depth_arg, double datum_depth_pc_arg, double woc_depth, double woc_pc, double goc_depth, double goc_pc, bool live_oil_init, bool wet_gas_init, int target_accuracy);
private:
double datum_depth;
double datum_depth_ps;
double water_oil_contact_depth;

View File

@@ -1,76 +0,0 @@
/*
Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_FOAMCONFIG_HPP
#define OPM_FOAMCONFIG_HPP
#include <cstddef>
#include <vector>
namespace Opm
{
class Deck;
class DeckRecord;
/// Foam behaviour data for a single SATNUM region.
class FoamData
{
public:
FoamData(const DeckRecord& FOAMFSC_record, const DeckRecord& FOAMROCK_record);
explicit FoamData(const DeckRecord& FOAMROCK_record);
double referenceSurfactantConcentration() const;
double exponent() const;
double minimumSurfactantConcentration() const;
bool allowDesorption() const;
double rockDensity() const;
private:
double reference_surfactant_concentration_;
double exponent_;
double minimum_surfactant_concentration_;
bool allow_desorption_;
double rock_density_;
};
/// Foam behaviour data for all SATNUM regions.
class FoamConfig
{
public:
FoamConfig() = default;
explicit FoamConfig(const Deck&);
const FoamData& getRecord(std::size_t index) const;
std::size_t size() const;
bool empty() const;
using const_iterator = std::vector<FoamData>::const_iterator;
const_iterator begin() const;
const_iterator end() const;
private:
std::vector<FoamData> data_;
};
} // end namespace Opm
#endif // OPM_FOAMCONFIG_HPP

View File

@@ -23,7 +23,6 @@
#include <string>
#include <opm/parser/eclipse/EclipseState/InitConfig/Equil.hpp>
#include <opm/parser/eclipse/EclipseState/InitConfig/FoamConfig.hpp>
namespace Opm {
@@ -42,22 +41,12 @@ namespace Opm {
bool hasEquil() const;
const Equil& getEquil() const;
bool hasFoamConfig() const;
const FoamConfig& getFoamConfig() const;
bool filleps() const
{
return this->m_filleps;
}
private:
Equil equil;
FoamConfig foamconfig;
bool m_filleps;
bool m_restartRequested = false;
int m_restartStep = 0;
std::string m_restartRootName;
Equil equil;
};
} //namespace Opm

View File

@@ -25,7 +25,6 @@
#include <opm/parser/eclipse/EclipseState/Tables/Tabdims.hpp>
#include <opm/parser/eclipse/EclipseState/EndpointScaling.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParams.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Action/Actdims.hpp>
namespace Opm {
class Deck;
@@ -38,13 +37,9 @@ enum class Phase {
SOLVENT = 3,
POLYMER = 4,
ENERGY = 5,
POLYMW = 6,
FOAM = 7
// If you add more entries to this enum, remember to update NUM_PHASES_IN_ENUM below.
POLYMW = 6
};
constexpr int NUM_PHASES_IN_ENUM = static_cast<int>(Phase::FOAM) + 1; // Used to get correct size of the bitset in class Phases.
Phase get_phase( const std::string& );
std::ostream& operator<<( std::ostream&, const Phase& );
@@ -52,12 +47,12 @@ class Phases {
public:
Phases() noexcept = default;
Phases( bool oil, bool gas, bool wat, bool solvent = false, bool polymer = false, bool energy = false,
bool polymw = false, bool foam = false ) noexcept;
bool polymw = false ) noexcept;
bool active( Phase ) const noexcept;
size_t size() const noexcept;
private:
std::bitset< NUM_PHASES_IN_ENUM > bits;
std::bitset< 7 > bits;
};
@@ -172,7 +167,6 @@ public:
const WellSegmentDims& wellSegmentDimensions() const noexcept;
int eclPhaseMask( ) const noexcept;
const EclHysterConfig& hysterPar() const noexcept;
const Actdims& actdims() const noexcept;
private:
Phases active_phases;
@@ -182,7 +176,6 @@ private:
WellSegmentDims wsegdims;
UDQParams udq_params;
EclHysterConfig hystpar;
Actdims m_actdims;
};

View File

@@ -1,46 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACTDIMS_HPP_
#define ACTDIMS_HPP_
#include <opm/parser/eclipse/Deck/Deck.hpp>
namespace Opm {
class Actdims {
public:
Actdims();
explicit Actdims(const Deck& deck);
std::size_t max_keywords() const;
std::size_t max_line_count() const;
std::size_t max_characters() const;
std::size_t max_conditions() const;
private:
std::size_t keywords;
std::size_t line_count;
std::size_t characters;
std::size_t conditions;
};
}
#endif

View File

@@ -25,35 +25,26 @@
#include <vector>
#include <memory>
#include <opm/parser/eclipse/EclipseState/Schedule/Action/ActionResult.hpp>
namespace Opm {
namespace Action {
class Context;
class ActionContext;
class ASTNode;
/*
The Action::AST class implements a tree with the result of the parsing of the
ACTIONX condition. The AST does not contain any context, that is supplied with
a Action::Context instace when calling the eval() methoid is called.
*/
class AST{
class ActionAST{
public:
AST() = default;
explicit AST(const std::vector<std::string>& tokens);
Result eval(const Context& context) const;
ActionAST() = default;
explicit ActionAST(const std::vector<std::string>& tokens);
bool eval(const ActionContext& context, std::vector<std::string>& matching_wells) const;
private:
/*
The use of a pointer here is to be able to create this class with only a
forward declaration of the ASTNode class. Would have prefered to use a
unique_ptr, but that requires writing custom destructors - the use of a
shared_ptr does not imply any shared ownership of the ASTNode.
shared_ptr does not imply any shared ownership.
*/
std::shared_ptr<ASTNode> condition;
};
}
}
#endif

View File

@@ -27,17 +27,13 @@
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
namespace Opm {
namespace Action {
/*
The Action::Context class is used as context when the ACTIONX condition is
evaluated. The Action::Context class is mainly just a thin wrapper around the
SummaryState class.
*/
class Context {
class ActionContext {
public:
explicit Context(const SummaryState& summary_state);
/*
Observe that the ActionContext takes a copy of the SummaryState object.
*/
explicit ActionContext(const SummaryState& summary_state);
/*
The get methods will first check the internal storage in the 'values' map
@@ -52,9 +48,8 @@ public:
std::vector<std::string> wells(const std::string& func) const;
private:
const SummaryState& summary_state;
SummaryState summary_state;
std::map<std::string, double> values;
};
}
}
#endif

View File

@@ -1,110 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
but eliminates the memory saving DynamicState is intended to enable. You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACTION_RESULT_HPP
#define ACTION_RESULT_HPP
#include <string>
#include <unordered_set>
#include <vector>
#include <memory>
namespace Opm {
namespace Action {
/*
The Action::Result class is used to hold the boolean result of a ACTIONX
condition like:
WWCT > 0.75
and also the final evaluation of an ACTIONX condition comes as a
Action::Result instance.
In addition to the overall truthness of the expression an Action::Result
instance can optionally have a set of matching wells. For instance the
the result of:
FWCT > 0.75
Will not contain any wells, whereas the result of:
WWCT > 0.75
will contain a set of all the wells matching the condition. The set of
matching wells can be queries with the wells() method. When a result with
wells and a result without wells are combined as:
WWCT > 0.50 AND FPR > 1000
The result will have all the wells corresponding to the first condition, when
several results with wells are combined with logical operators AND and OR the
set of matching wells are combined correspondingly. It is actually possible
to have a result which evaluates to true and still have and zero matching
wells - e.g.
WWCT > 1.25 OR FOPT > 1
If the condition evaluates to true the set of matching wells will be passed
to the Schedule::applyAction() method, and will be used in place of '?' in
keywords like WELOPEN.
*/
class WellSet {
public:
WellSet() = default;
explicit WellSet(const std::vector<std::string>& wells);
void add(const std::string& well);
std::size_t size() const;
std::vector<std::string> wells() const;
bool contains(const std::string& well) const;
WellSet& intersect(const WellSet& other);
WellSet& add(const WellSet& other);
private:
std::unordered_set<std::string> well_set;
};
class Result {
public:
explicit Result(bool result_arg);
Result(bool result_arg, const std::vector<std::string>& wells);
Result(bool result_arg, const WellSet& wells);
explicit operator bool() const;
std::vector<std::string> wells() const;
void add_well(const std::string& well);
Result& operator|=(const Result& other);
Result& operator&=(const Result& other);
private:
void assign(bool value);
bool result;
std::unique_ptr<WellSet> matching_wells;
};
}
}
#endif

View File

@@ -27,16 +27,8 @@
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Action/ActionAST.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Action/ActionResult.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Action/Condition.hpp>
namespace Opm {
class DeckKeyword;
namespace Action {
/*
The ActionX class internalizes the ACTIONX keyword. This keyword represents a
small in-deck programming language for the SCHEDULE section. In the deck the
@@ -61,6 +53,9 @@ namespace Action {
*/
class DeckKeyword;
class ActionContext;
class ActionX {
public:
ActionX(const std::string& name, size_t max_run, double max_wait, std::time_t start_time);
@@ -69,7 +64,7 @@ public:
void addKeyword(const DeckKeyword& kw);
bool ready(std::time_t sim_time) const;
Action::Result eval(std::time_t sim_time, const Action::Context& context) const;
bool eval(std::time_t sim_time, const ActionContext& context, std::vector<std::string>& wells) const;
std::string name() const { return this->m_name; }
@@ -79,13 +74,6 @@ public:
std::vector<DeckKeyword>::const_iterator begin() const;
std::vector<DeckKeyword>::const_iterator end() const;
static bool valid_keyword(const std::string& keyword);
/*
The conditions() and keyword_strings() methods, and their underlying data
members are only present to support writing formatted restart files.
*/
const std::vector<Condition>& conditions() const;
std::vector<std::string> keyword_strings() const;
private:
std::string m_name;
size_t m_max_run = 0;
@@ -93,12 +81,10 @@ private:
std::time_t m_start_time;
std::vector<DeckKeyword> keywords;
Action::AST condition;
std::vector<Condition> m_conditions;
ActionAST condition;
mutable size_t run_count = 0;
mutable std::time_t last_run = 0;
};
}
}
#endif /* WELL_HPP_ */

View File

@@ -23,17 +23,11 @@
#include <string>
#include <ctime>
#include <vector>
#include <map>
#include <opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.hpp>
namespace Opm {
namespace Action {
/*
The Actions class is a container of ACTIONX keywords. The main functionality
is to provide a list of ACTIONX keywords which are ready to be evaluated.
*/
class Actions {
public:
@@ -42,15 +36,10 @@ public:
bool empty() const;
void add(const ActionX& action);
bool ready(std::time_t sim_time) const;
const ActionX& get(const std::string& name) const;
const ActionX& get(std::size_t index) const;
ActionX& at(const std::string& name);
std::vector<const ActionX *> pending(std::time_t sim_time) const;
std::vector<ActionX>::const_iterator begin() const;
std::vector<ActionX>::const_iterator end() const;
private:
std::vector<ActionX> actions;
std::map<std::string, ActionX> actions;
};
}
}
#endif

View File

@@ -89,29 +89,6 @@ class DynamicState {
std::fill_n( this->m_data.begin(), this->initial_range, initial );
}
std::vector<std::pair<std::size_t, T>> unique() const {
if (this->m_data.empty())
return {};
const auto * current_value = std::addressof(this->m_data[0]);
std::size_t current_index = 0;
std::vector<std::pair<std::size_t, T>> result{{current_index, *current_value}};
while (true) {
if (this->m_data[current_index] != *current_value) {
current_value = std::addressof(this->m_data[current_index]);
result.emplace_back(current_index, *current_value);
}
current_index++;
if (current_index == this->m_data.size())
break;
}
return result;
}
/**
If the current value has been changed the method will
return true, otherwise it will return false.
@@ -203,10 +180,6 @@ class DynamicState {
}
std::size_t size() const {
return this->m_data.size();
}
private:
std::vector< T > m_data;
size_t initial_range;

View File

@@ -0,0 +1,152 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GROUP_HPP_
#define GROUP_HPP_
#include <memory>
#include <set>
#include <string>
#include <stddef.h>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
namespace Opm {
class TimeMap;
class Well;
namespace GroupInjection {
struct InjectionData {
explicit InjectionData( const TimeMap& );
DynamicState< Phase > phase;
DynamicState< GroupInjection::ControlEnum > controlMode;
DynamicState< double > rate;
DynamicState< double > surfaceFlowMaxRate;
DynamicState< double > reservoirFlowMaxRate;
DynamicState< double > targetReinjectFraction;
DynamicState< double > targetVoidReplacementFraction;
};
}
namespace GroupProduction {
struct ProductionData {
explicit ProductionData( const TimeMap& );
DynamicState< GroupProduction::ControlEnum > controlMode;
DynamicState< GroupProductionExceedLimit::ActionEnum > exceedAction;
DynamicState< double > oilTarget;
DynamicState< double > waterTarget;
DynamicState< double > gasTarget;
DynamicState< double > liquidTarget;
DynamicState< double > reservoirVolumeTarget;
};
}
class Group {
public:
Group(const std::string& name, const size_t& seqIndex, const TimeMap& timeMap , size_t creationTimeStep);
bool hasBeenDefined(size_t timeStep) const;
const std::string& name() const;
const size_t& seqIndex() const;
bool isProductionGroup(size_t timeStep) const;
bool isInjectionGroup(size_t timeStep) const;
void setProductionGroup(size_t timeStep, bool isProductionGroup);
void setInjectionGroup(size_t timeStep, bool isInjectionGroup_);
/******************************************************************/
void setInjectionPhase(size_t time_step, Phase);
Phase getInjectionPhase(size_t time_step) const;
void setInjectionControlMode(size_t time_step , GroupInjection::ControlEnum ControlMode);
GroupInjection::ControlEnum getInjectionControlMode( size_t time_step) const;
void setInjectionRate(size_t time_step , double rate);
double getInjectionRate( size_t time_step) const;
void setSurfaceMaxRate( size_t time_step , double rate);
double getSurfaceMaxRate( size_t time_step ) const;
void setReservoirMaxRate( size_t time_step , double rate);
double getReservoirMaxRate( size_t time_step ) const;
void setTargetReinjectFraction( size_t time_step , double rate);
double getTargetReinjectFraction( size_t time_step ) const;
void setTargetVoidReplacementFraction( size_t time_step , double rate);
double getTargetVoidReplacementFraction( size_t time_step ) const;
/******************************************************************/
void setProductionControlMode( size_t time_step , GroupProduction::ControlEnum controlMode);
GroupProduction::ControlEnum getProductionControlMode( size_t time_step ) const;
GroupProductionExceedLimit::ActionEnum getProductionExceedLimitAction(size_t time_step) const;
void setProductionExceedLimitAction(size_t time_step , GroupProductionExceedLimit::ActionEnum action);
void setOilTargetRate(size_t time_step , double oilTargetRate);
double getOilTargetRate(size_t time_step) const;
void setGasTargetRate(size_t time_step , double gasTargetRate);
double getGasTargetRate(size_t time_step) const;
void setWaterTargetRate(size_t time_step , double waterTargetRate);
double getWaterTargetRate(size_t time_step) const;
void setLiquidTargetRate(size_t time_step , double liquidTargetRate);
double getLiquidTargetRate(size_t time_step) const;
void setReservoirVolumeTargetRate(size_t time_step , double reservoirVolumeTargetRate);
double getReservoirVolumeTargetRate(size_t time_step) const;
void setGroupEfficiencyFactor(size_t time_step, double factor);
double getGroupEfficiencyFactor(size_t time_step) const;
void setTransferGroupEfficiencyFactor(size_t time_step, bool transfer);
bool getTransferGroupEfficiencyFactor(size_t time_step) const;
void setGroupNetVFPTable(size_t time_step, int table);
int getGroupNetVFPTable(size_t time_step) const;
static bool groupNameInGroupNamePattern(const std::string& groupName, const std::string& groupNamePattern);
/*****************************************************************/
bool hasWell(const std::string& wellName , size_t time_step) const;
const std::set< std::string >& getWells( size_t time_step ) const;
size_t numWells(size_t time_step) const;
void addWell(size_t time_step, const Well* well);
void delWell(size_t time_step, const std::string& wellName );
private:
size_t m_creationTimeStep;
std::string m_name;
size_t m_seqIndex;
GroupInjection::InjectionData m_injection;
GroupProduction::ProductionData m_production;
DynamicState< std::set< std::string > > m_wells;
DynamicState<int> m_isProductionGroup;
DynamicState<int> m_isInjectionGroup;
DynamicState<double> m_efficiencyFactor;
DynamicState<int> m_transferEfficiencyFactor;
DynamicState<int> m_groupNetVFPTable;
};
}
#endif /* GROUP_HPP_ */

View File

@@ -1,56 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <vector>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well2.hpp>
#ifndef GROUPTREE2
#define GROUPTREE2
namespace Opm {
class GTNode {
public:
GTNode(const Group2& group, const GTNode* parent);
void add_group(const GTNode& child_group);
void add_well(const Well2& well);
const std::vector<Well2>& wells() const;
const std::vector<GTNode>& groups() const;
const std::string& name() const;
const GTNode& parent() const;
const Group2& group() const;
private:
const Group2 m_group;
const GTNode * m_parent;
/*
Class T with a stl container <T> - supposedly undefined behavior before
C++17 - but it compiles without warnings.
*/
std::vector<GTNode> m_child_groups;
std::vector<Well2> m_wells;
};
}
#endif

View File

@@ -1,227 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GROUP2_HPP
#define GROUP2_HPP
#include <string>
#include <opm/parser/eclipse/Deck/UDAValue.hpp>
#include <opm/parser/eclipse/EclipseState/Util/IOrderSet.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
namespace Opm {
class SummaryState;
class Group2 {
public:
// A group can have both injection controls and production controls set at
// the same time, i.e. this enum is used as a bitmask.
enum class GroupType : unsigned {
NONE = 0,
PRODUCTION = 1,
INJECTION = 2,
MIXED = 3
};
enum class ExceedAction {
NONE = 0,
CON = 1,
CON_PLUS = 2, // String: "+CON"
WELL = 3,
PLUG = 4,
RATE = 5
};
static const std::string ExceedAction2String( ExceedAction enumValue );
static ExceedAction ExceedActionFromString( const std::string& stringValue );
enum class InjectionCMode : int {
NONE = 0,
RATE = 1,
RESV = 2,
REIN = 4,
VREP = 8,
FLD = 16
};
static const std::string InjectionCMode2String( InjectionCMode enumValue );
static InjectionCMode InjectionCModeFromString( const std::string& stringValue );
enum class ProductionCMode : int {
NONE = 0,
ORAT = 1,
WRAT = 2,
GRAT = 4,
LRAT = 8,
CRAT = 16,
RESV = 32,
PRBL = 64,
FLD = 128
};
static const std::string ProductionCMode2String( ProductionCMode enumValue );
static ProductionCMode ProductionCModeFromString( const std::string& stringValue );
enum class GuideRateTarget {
OIL = 0,
WAT = 1,
GAS = 2,
LIQ = 3,
RES = 4,
COMB = 5,
WGA = 6,
CVAL = 7,
INJV = 8,
POTN = 9,
FORM = 10,
NO_GUIDE_RATE = 11
};
static GuideRateTarget GuideRateTargetFromString( const std::string& stringValue );
struct GroupInjectionProperties {
Phase phase = Phase::WATER;
InjectionCMode cmode = InjectionCMode::NONE;
UDAValue surface_max_rate;
UDAValue resv_max_rate;
UDAValue target_reinj_fraction;
UDAValue target_void_fraction;
int injection_controls = 0;
bool operator==(const GroupInjectionProperties& other) const;
bool operator!=(const GroupInjectionProperties& other) const;
};
struct InjectionControls {
Phase phase;
InjectionCMode cmode;
double surface_max_rate;
double resv_max_rate;
double target_reinj_fraction;
double target_void_fraction;
int injection_controls = 0;
bool has_control(InjectionCMode control) const;
};
struct GroupProductionProperties {
ProductionCMode cmode = ProductionCMode::NONE;
ExceedAction exceed_action = ExceedAction::NONE;
UDAValue oil_target;
UDAValue water_target;
UDAValue gas_target;
UDAValue liquid_target;
double guide_rate;
GuideRateTarget guide_rate_def;
double resv_target = 0;
int production_controls = 0;
bool operator==(const GroupProductionProperties& other) const;
bool operator!=(const GroupProductionProperties& other) const;
};
struct ProductionControls {
ProductionCMode cmode;
ExceedAction exceed_action;
double oil_target;
double water_target;
double gas_target;
double liquid_target;
double guide_rate;
GuideRateTarget guide_rate_def;
double resv_target = 0;
int production_controls = 0;
bool has_control(ProductionCMode control) const;
};
Group2(const std::string& group_name, std::size_t insert_index_arg, std::size_t init_step_arg, double udq_undefined_arg, const UnitSystem& unit_system);
bool defined(std::size_t timeStep) const;
std::size_t insert_index() const;
const std::string& name() const;
int getGroupNetVFPTable() const;
bool updateNetVFPTable(int vfp_arg);
bool update_gefac(double gefac, bool transfer_gefac);
const std::string& parent() const;
bool updateParent(const std::string& parent);
bool updateInjection(const GroupInjectionProperties& injection);
bool updateProduction(const GroupProductionProperties& production);
bool isProductionGroup() const;
bool isInjectionGroup() const;
void setProductionGroup();
void setInjectionGroup();
double getGroupEfficiencyFactor() const;
bool getTransferGroupEfficiencyFactor() const;
std::size_t numWells() const;
bool addGroup(const std::string& group_name);
bool hasGroup(const std::string& group_name) const;
void delGroup(const std::string& group_name);
bool addWell(const std::string& well_name);
bool hasWell(const std::string& well_name) const;
void delWell(const std::string& well_name);
const std::vector<std::string>& wells() const;
const std::vector<std::string>& groups() const;
bool wellgroup() const;
ProductionControls productionControls(const SummaryState& st) const;
InjectionControls injectionControls(const SummaryState& st) const;
const GroupProductionProperties& productionProperties() const;
const GroupInjectionProperties& injectionProperties() const;
ProductionCMode production_cmode() const;
InjectionCMode injection_cmode() const;
Phase injection_phase() const;
bool has_control(ProductionCMode control) const;
bool has_control(InjectionCMode control) const;
private:
bool hasType(GroupType gtype) const;
void addType(GroupType new_gtype);
std::string m_name;
std::size_t m_insert_index;
std::size_t init_step;
double udq_undefined;
UnitSystem unit_system;
GroupType group_type;
double gefac;
bool transfer_gefac;
int vfp_table;
std::string parent_group;
IOrderSet<std::string> m_wells;
IOrderSet<std::string> m_groups;
GroupInjectionProperties injection_properties{};
GroupProductionProperties production_properties{};
};
Group2::GroupType operator |(Group2::GroupType lhs, Group2::GroupType rhs);
Group2::GroupType operator &(Group2::GroupType lhs, Group2::GroupType rhs);
}
#endif

View File

@@ -1,98 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GUIDE_RATE_HPP
#define GUIDE_RATE_HPP
#include <string>
#include <cstddef>
#include <ctime>
#include <unordered_map>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well2.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp>
namespace Opm {
class Schedule;
class GuideRate {
private:
struct GuideRateValue {
GuideRateValue() = default;
GuideRateValue(double t, double v, GuideRateModel::Target tg):
sim_time(t),
value(v),
target(tg)
{}
bool operator==(const GuideRateValue& other) const {
return (this->sim_time == other.sim_time &&
this->value == other.value);
}
bool operator!=(const GuideRateValue& other) const {
return !(*this == other);
}
double eval(GuideRateModel::Target target_arg) const;
double sim_time;
double value;
GuideRateModel::Target target;
};
struct Potential {
Potential() = default;
Potential(double op, double gp, double wp) :
oil_pot(op),
gas_pot(gp),
wat_pot(wp)
{}
double eval(Group2::GuideRateTarget target) const;
double eval(Well2::GuideRateTarget target) const;
double oil_pot;
double gas_pot;
double wat_pot;
};
public:
GuideRate(const Schedule& schedule);
void compute(const std::string& wgname, size_t report_step, double sim_time, double oil_pot, double gas_pot, double wat_pot);
double get(const std::string& well, Well2::GuideRateTarget target) const;
double get(const std::string& group, Group2::GuideRateTarget target) const;
private:
void well_compute(const std::string& wgname, size_t report_step, double sim_time, double oil_pot, double gas_pot, double wat_pot);
void group_compute(const std::string& wgname, size_t report_step, double sim_time, double oil_pot, double gas_pot, double wat_pot);
double eval_form(const GuideRateModel& model, double oil_pot, double gas_pot, double wat_pot, const GuideRateValue * prev) const;
double eval_group_pot() const;
double eval_group_resvinj() const;
std::unordered_map<std::string,GuideRateValue> values;
std::unordered_map<std::string,Potential> potentials;
const Schedule& schedule;
};
}
#endif

View File

@@ -1,65 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GUIDE_RATE_CONFIG_HPP
#define GUIDE_RATE_CONFIG_HPP
#include <string>
#include <unordered_map>
#include <memory>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateModel.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well2.hpp>
namespace Opm {
class GuideRateConfig {
public:
struct Well {
double guide_rate;
Well2::GuideRateTarget target;
double scaling_factor;
};
struct Group {
double guide_rate;
Group2::GuideRateTarget target;
};
const GuideRateModel& model() const;
bool has_model() const;
bool update_model(const GuideRateModel& model);
void update_well(const Well2& well);
void update_group(const Group2& group);
const Well& well(const std::string& well) const;
const Group& group(const std::string& group) const;
bool has_well(const std::string& well) const;
bool has_group(const std::string& group) const;
private:
std::shared_ptr<GuideRateModel> m_model;
std::unordered_map<std::string, Well> wells;
std::unordered_map<std::string, Group> groups;
};
}
#endif

View File

@@ -1,93 +0,0 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GUIDE_RATE_MODEL_HPP
#define GUIDE_RATE_MODEL_HPP
#include <opm/parser/eclipse/Deck/UDAValue.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well2.hpp>
namespace Opm {
class GuideRateModel {
public:
enum class Target {
OIL = 0,
LIQ = 1,
GAS = 2,
WAT = 3,
RES = 4,
COMB = 5,
NONE = 6
};
static Target TargetFromString(const std::string& s);
GuideRateModel(double time_interval_arg,
Target target_arg,
double A_arg,
double B_arg,
double C_arg,
double D_arg,
double E_arg,
double F_arg,
bool allow_increase_arg,
double damping_factor_arg,
bool use_free_gas_arg);
GuideRateModel() = default;
bool updateLINCOM(const UDAValue& alpha, const UDAValue& beta, const UDAValue& gamma);
double eval(double oil_pot, double gas_pot, double wat_pot) const;
double update_delay() const;
bool allow_increase() const;
double damping_factor() const;
bool operator==(const GuideRateModel& other) const;
bool operator!=(const GuideRateModel& other) const;
Target target() const;
static Target convert_target(Group2::GuideRateTarget group_target);
static Target convert_target(Well2::GuideRateTarget well_target);
private:
double pot(double oil_pot, double gas_pot, double wat_pot) const;
/*
Unfortunately the default values will give a GuideRateModel which can not
be evaluated, due to a division by zero problem.
*/
double time_interval = 0;
Target m_target = Target::NONE;
double A = 0;
double B = 0;
double C = 0;
double D = 0;
double E = 0;
double F = 0;
bool allow_increase_ = true;
double damping_factor_ = 1.0;
bool use_free_gas = false;
bool default_model = true;
UDAValue alpha;
UDAValue beta;
UDAValue gamma;
};
}
#endif

View File

@@ -0,0 +1,66 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GROUPTREE_HPP
#define GROUPTREE_HPP
#include <string>
#include <vector>
#include <map>
namespace Opm {
class GroupTree {
public:
void update( const std::string& name);
void update( const std::string& name, const std::string& parent);
void updateSeqIndex( const std::string& name, const std::string& other_parent);
bool exists( const std::string& group ) const;
const std::string& parent( const std::string& name ) const;
std::vector< std::string > children( const std::string& parent ) const;
const std::map<std::string , size_t>& nameSeqIndMap() const;
const std::map<size_t, std::string >& seqIndNameMap() const;
bool operator==( const GroupTree& ) const;
bool operator!=( const GroupTree& ) const;
private:
struct group {
std::string name;
std::string parent;
bool operator<( const group& rhs ) const;
bool operator==( const std::string& name ) const;
bool operator!=( const std::string& name ) const;
bool operator<( const std::string& name ) const;
bool operator==( const group& rhs ) const;
bool operator!=( const group& rhs ) const;
};
std::vector< group > groups = { group { "FIELD", "" } };
friend bool operator<( const std::string&, const group& );
std::vector< group >::iterator find( const std::string& );
std::map<std::string , size_t> m_nameSeqIndMap;
std::map<size_t, std::string > m_seqIndNameMap;
};
}
#endif /* GROUPTREE_HPP */

View File

@@ -23,6 +23,7 @@
#include <vector>
#include <map>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp>
namespace Opm {
@@ -31,41 +32,18 @@ namespace Opm {
class WellSegments {
public:
enum class LengthDepth{
INC = 0,
ABS = 1
};
static const std::string LengthDepthToString(LengthDepth enumValue);
static LengthDepth LengthDepthFromString(const std::string& stringValue);
enum class CompPressureDrop {
HFA = 0,
HF_ = 1,
H__ = 2
};
static const std::string CompPressureDropToString(CompPressureDrop enumValue);
static CompPressureDrop CompPressureDropFromString(const std::string& stringValue);
enum class MultiPhaseModel {
HO = 0,
DF = 1
};
static const std::string MultiPhaseModelToString(MultiPhaseModel enumValue);
static MultiPhaseModel MultiPhaseModelFromString(const std::string& stringValue);
WellSegments() = default;
const std::string& wellName() const;
std::string wellName() const;
int numberBranch() const;
int size() const;
double depthTopSegment() const;
double lengthTopSegment() const;
double volumeTopSegment() const;
CompPressureDrop compPressureDrop() const;
MultiPhaseModel multiPhaseModel() const;
WellSegment::LengthDepthEnum lengthDepthType() const;
WellSegment::CompPressureDropEnum compPressureDrop() const;
WellSegment::MultiPhaseModelEnum multiPhaseModel() const;
// mapping the segment number to the index in the vector of segments
int segmentNumberToIndex(const int segment_number) const;
@@ -78,16 +56,18 @@ namespace Opm {
const Segment& operator[](size_t idx) const;
void orderSegments();
void process(bool first_time);
void processABS();
void processINC(const bool first_time);
bool operator==( const WellSegments& ) const;
bool operator!=( const WellSegments& ) const;
private:
void processABS();
void processINC(const bool first_time);
// name of the well
std::string m_well_name;
// number of the branches
int m_number_branch;
// depth of the nodal point of the top segment
// it is taken as the BHP reference depth of the well
// BHP reference depth data from elsewhere will be ignored for multi-segmented wells
@@ -97,11 +77,11 @@ namespace Opm {
// effective wellbore volume of the top segment
double m_volume_top;
// type of the tubing length and depth information
LengthDepth m_length_depth_type;
WellSegment::LengthDepthEnum m_length_depth_type;
// components of the pressure drop to be included
CompPressureDrop m_comp_pressure_drop;
WellSegment::CompPressureDropEnum m_comp_pressure_drop;
// multi-phase flow model
MultiPhaseModel m_multiphase_model;
WellSegment::MultiPhaseModelEnum m_multiphase_model;
// There are X and Y cooridnate of the nodal point of the top segment
// Since they are not used for simulations and we are not supporting plotting,
// we are not handling them at the moment.
@@ -113,7 +93,6 @@ namespace Opm {
// storage index in the vector
std::map<int, int> segment_number_to_index;
};
std::ostream& operator<<( std::ostream&, const WellSegments& );
}
#endif

Some files were not shown because too many files have changed in this diff Show More