Compare commits
265 Commits
release/20
...
testing/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80918f030b | ||
|
|
1d55e923f9 | ||
|
|
cb525c5c75 | ||
|
|
b877c8b340 | ||
|
|
7a034ffd01 | ||
|
|
6e0c31bed4 | ||
|
|
ef63206925 | ||
|
|
0b6d36658d | ||
|
|
44f3b86547 | ||
|
|
bee4590aaa | ||
|
|
45e81a02fa | ||
|
|
085bbc263b | ||
|
|
3e95d3f42b | ||
|
|
6b93051616 | ||
|
|
d3249d965f | ||
|
|
4a10023c0d | ||
|
|
065b9c9c9f | ||
|
|
ae3c4e0d8c | ||
|
|
4d5ef337ec | ||
|
|
a2394c06f5 | ||
|
|
43e4f0ca87 | ||
|
|
cdf876fa15 | ||
|
|
12402916a7 | ||
|
|
0183fa884a | ||
|
|
e407e65b54 | ||
|
|
e072365234 | ||
|
|
070acf4bef | ||
|
|
451d52c18a | ||
|
|
bbb5e27e90 | ||
|
|
37ddd82545 | ||
|
|
3c90adeea9 | ||
|
|
903118736a | ||
|
|
18a22d8f68 | ||
|
|
46be17cf58 | ||
|
|
ce5c617f41 | ||
|
|
ca1833e6ed | ||
|
|
bb2e5e0370 | ||
|
|
f6cc04a4ab | ||
|
|
d6c56982cc | ||
|
|
ee6fab7395 | ||
|
|
93b8d26f86 | ||
|
|
0627a9f8ef | ||
|
|
3c88335852 | ||
|
|
ef3ef3142a | ||
|
|
9c6a0cc5d9 | ||
|
|
4502333751 | ||
|
|
64e5d123a2 | ||
|
|
f80644b616 | ||
|
|
6d58f519fd | ||
|
|
4a5333887b | ||
|
|
760d0d70b4 | ||
|
|
563c053d3a | ||
|
|
cbd44ff67a | ||
|
|
32dabd6572 | ||
|
|
3d61162e29 | ||
|
|
3fabf2aad3 | ||
|
|
3fa0064e5b | ||
|
|
62f267cf89 | ||
|
|
f16b45eeed | ||
|
|
7b301cb300 | ||
|
|
34b1b3a073 | ||
|
|
20d0565220 | ||
|
|
1695dfe78b | ||
|
|
387be05c77 | ||
|
|
349ee4657e | ||
|
|
7d7ec8efca | ||
|
|
5c1aa3657d | ||
|
|
bf58a16e33 | ||
|
|
84739c3bed | ||
|
|
1c21ec9d5c | ||
|
|
03b3be48b0 | ||
|
|
b9c68bdc6e | ||
|
|
7680d1900f | ||
|
|
0be3f2c76f | ||
|
|
d4c49398c5 | ||
|
|
687f108285 | ||
|
|
48047f8c7a | ||
|
|
3466776c1a | ||
|
|
efb2904beb | ||
|
|
d7c855906f | ||
|
|
19afcbf769 | ||
|
|
e4d39dc722 | ||
|
|
c7c2480c01 | ||
|
|
90cbad1163 | ||
|
|
5b5d895380 | ||
|
|
c38100a491 | ||
|
|
b5ff9bc393 | ||
|
|
3186a2d01a | ||
|
|
13d1ce4fbf | ||
|
|
4144d761dd | ||
|
|
71961c21b4 | ||
|
|
1b8e1b3197 | ||
|
|
1e4e565380 | ||
|
|
fa002c4408 | ||
|
|
9d5a43d4e6 | ||
|
|
6eb363e8e1 | ||
|
|
98e3bbcf1d | ||
|
|
976bfdab35 | ||
|
|
ca79b16b26 | ||
|
|
65639b0a03 | ||
|
|
986abc1bdc | ||
|
|
5c68a0aaa8 | ||
|
|
7a91bebd61 | ||
|
|
102bd6b728 | ||
|
|
fc3bc714fc | ||
|
|
89e95b0789 | ||
|
|
ffa4a8ef7b | ||
|
|
1f7a2d5459 | ||
|
|
3ffcff1773 | ||
|
|
cfb3d34467 | ||
|
|
b109ab7822 | ||
|
|
5c55957718 | ||
|
|
4d3c143af4 | ||
|
|
3a46555b6d | ||
|
|
a5cc1cfe48 | ||
|
|
6095fda39f | ||
|
|
a8d1545947 | ||
|
|
c212af9253 | ||
|
|
6461cc2a81 | ||
|
|
8895ee171a | ||
|
|
90f6b46837 | ||
|
|
04a3a9ada5 | ||
|
|
7a790a33bb | ||
|
|
d72c45cd62 | ||
|
|
bcfb195a83 | ||
|
|
0327393951 | ||
|
|
15dd449354 | ||
|
|
ad2af10c5a | ||
|
|
5bce16c4e9 | ||
|
|
9d16cc8ec4 | ||
|
|
1f1ecebec5 | ||
|
|
fd3000cd31 | ||
|
|
363b8589e6 | ||
|
|
93f7f50eb7 | ||
|
|
f3d82437fd | ||
|
|
d52d4cc3a6 | ||
|
|
7332ee4b18 | ||
|
|
2cb5f62591 | ||
|
|
08994de897 | ||
|
|
b8605532f4 | ||
|
|
2356cc35e5 | ||
|
|
83b63213f4 | ||
|
|
32722f3b9c | ||
|
|
d0580c2180 | ||
|
|
c3a11a2fb5 | ||
|
|
a50c823873 | ||
|
|
ba04fbb1ad | ||
|
|
acef0e411d | ||
|
|
aa04fee73f | ||
|
|
fa3d6029b3 | ||
|
|
f7950ca458 | ||
|
|
197b34d9ec | ||
|
|
c839f8dac7 | ||
|
|
7cedf056d7 | ||
|
|
261f6ac270 | ||
|
|
d1d9e214ce | ||
|
|
d2d9128e6a | ||
|
|
b22e00b92d | ||
|
|
6c7f6d7afb | ||
|
|
dc318f731f | ||
|
|
d4d2b813dd | ||
|
|
501b1dc760 | ||
|
|
bfbcd3e470 | ||
|
|
2574dc7542 | ||
|
|
fb0272f343 | ||
|
|
3085243117 | ||
|
|
c6536c0b2f | ||
|
|
5dba20496a | ||
|
|
97bb1c3413 | ||
|
|
0d0e123735 | ||
|
|
768326527a | ||
|
|
df289d455b | ||
|
|
6b9e0c5ef8 | ||
|
|
3975db2ff3 | ||
|
|
d39db2f0db | ||
|
|
b3eb6b58eb | ||
|
|
088ba8a19a | ||
|
|
d168e9ff67 | ||
|
|
46ab6dd8e1 | ||
|
|
66de108c68 | ||
|
|
58e4e5263e | ||
|
|
8fda1e036a | ||
|
|
3327d17c3f | ||
|
|
d299e003b7 | ||
|
|
37da204eb6 | ||
|
|
ccb7e5df3e | ||
|
|
1ee597206c | ||
|
|
163c3d435a | ||
|
|
3ad0b1c5ca | ||
|
|
476bfa1046 | ||
|
|
24f28e8a5d | ||
|
|
59bb98d312 | ||
|
|
f945032405 | ||
|
|
62c7706f30 | ||
|
|
a7ec8b1d53 | ||
|
|
d39ba17190 | ||
|
|
e654cba898 | ||
|
|
47d06c526f | ||
|
|
61b7977406 | ||
|
|
0b4f830d28 | ||
|
|
f6c795bed0 | ||
|
|
ab365481a7 | ||
|
|
6883c8ae21 | ||
|
|
b338e56730 | ||
|
|
28b7781017 | ||
|
|
56da8cd8f9 | ||
|
|
6168a35512 | ||
|
|
9a17457e6f | ||
|
|
aecf3f6470 | ||
|
|
3b84678db5 | ||
|
|
23ca927249 | ||
|
|
7163807296 | ||
|
|
5008501318 | ||
|
|
3c18add696 | ||
|
|
b9d2a08930 | ||
|
|
eb001a1e67 | ||
|
|
593af1c678 | ||
|
|
e6f318aa28 | ||
|
|
d078a96eae | ||
|
|
fea57c5031 | ||
|
|
fadab53590 | ||
|
|
b4ef14dfc0 | ||
|
|
b28527c0ec | ||
|
|
429c4e475c | ||
|
|
fcbcc9cda4 | ||
|
|
675858f1e0 | ||
|
|
427833b089 | ||
|
|
ba573b5834 | ||
|
|
6a8e7a9a05 | ||
|
|
580a64563f | ||
|
|
e6b57fa422 | ||
|
|
ba107498a1 | ||
|
|
183fd4eabb | ||
|
|
f2cb5fe9de | ||
|
|
5dd34b1308 | ||
|
|
8cfd477d3e | ||
|
|
bfb6553828 | ||
|
|
49edd1e54d | ||
|
|
6b78115229 | ||
|
|
901a44e92b | ||
|
|
01f87ea750 | ||
|
|
9303771a73 | ||
|
|
be9744ef68 | ||
|
|
6ec82f8947 | ||
|
|
ef29518fab | ||
|
|
cd9afa6aec | ||
|
|
bdef0ddfb0 | ||
|
|
e79b5bbc8c | ||
|
|
d0979638bc | ||
|
|
38640bffd6 | ||
|
|
464d557c80 | ||
|
|
1d02191178 | ||
|
|
51933168eb | ||
|
|
d0542ba9fe | ||
|
|
a2f27bd62d | ||
|
|
17767fab3a | ||
|
|
ce1f66b4e5 | ||
|
|
e864031bf4 | ||
|
|
76f678bf82 | ||
|
|
b5a2454d2c | ||
|
|
36c166cdc9 | ||
|
|
122158d713 | ||
|
|
a1e587ef09 | ||
|
|
a4228efc66 | ||
|
|
62b9548167 |
@@ -23,19 +23,25 @@ macro (dir_hook)
|
||||
endmacro (dir_hook)
|
||||
|
||||
# We need to define this variable in the installed cmake config file.
|
||||
set(OPM_PROJECT_EXTRA_CODE_INSTALLED "set(OPM_MACROS_ROOT ${CMAKE_INSTALL_PREFIX}/share/opm)
|
||||
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)")
|
||||
set(OPM_PROJECT_EXTRA_CODE_INSTALLED "#ENABLE_ECL_INPUT is needed by opm-common-prereq.cmake
|
||||
set(ENABLE_ECL_INPUT ${ENABLE_ECL_INPUT})
|
||||
set(OPM_MACROS_ROOT ${CMAKE_INSTALL_PREFIX}/share/opm)
|
||||
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)
|
||||
include(OpmPackage) #Make macros availabe after find_package(opm-common)")
|
||||
|
||||
set(OPM_PROJECT_EXTRA_CODE_INTREE "set(OPM_MACROS_ROOT ${OPM_MACROS_ROOT})
|
||||
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)")
|
||||
set(OPM_PROJECT_EXTRA_CODE_INTREE "#ENABLE_ECL_INPUT is needed by opm-common-prereq.cmake
|
||||
set(ENABLE_ECL_INPUT ${ENABLE_ECL_INPUT})
|
||||
set(OPM_MACROS_ROOT ${OPM_MACROS_ROOT})
|
||||
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)
|
||||
include(OpmPackage) #Make macros availabe after find_package(opm-common)")
|
||||
if(ENABLE_ECL_OUTPUT)
|
||||
set(OPM_PROJECT_EXTRA_CODE_INSTALLED "${OPM_PROJECT_EXTRA_CODE_INSTALLED}
|
||||
set(COMPARE_SUMMARY_COMMAND ${CMAKE_INSTALL_PREFIX}/bin${${name}_VER_DIR}/compareSummary)
|
||||
set(COMPARE_ECL_COMMAND ${CMAKE_INSTALL_PREFIX}/bin${${name}_VER_DIR}/compareECL)")
|
||||
set(COMPARE_ECL_COMMAND ${CMAKE_INSTALL_PREFIX}/bin${${name}_VER_DIR}/compareECL)
|
||||
set(OPM_PACK_COMMAND ${CMAKE_INSTALL_PREFIX}/bin${${name}_VER_DIR}/opmpack)")
|
||||
|
||||
set(OPM_PROJECT_EXTRA_CODE_INTREE "${OPM_PROJECT_EXTRA_CODE_INTREE}
|
||||
set(COMPARE_SUMMARY_COMMAND ${PROJECT_BINARY_DIR}/bin/compareSummary)
|
||||
set(COMPARE_ECL_COMMAND ${PROJECT_BINARY_DIR}/bin/compareECL)")
|
||||
set(COMPARE_ECL_COMMAND ${PROJECT_BINARY_DIR}/bin/compareECL)
|
||||
set(OPM_PACK_COMMAND ${PROJECT_BINARY_DIR}/bin/opmpack)")
|
||||
endif()
|
||||
|
||||
# project information is in dune.module. Read this file and set variables.
|
||||
@@ -124,5 +130,34 @@ endmacro (install_hook)
|
||||
# all setup common to the OPM library modules is done here
|
||||
include (OpmLibMain)
|
||||
|
||||
# Build the compare utilities
|
||||
if(ENABLE_ECL_INPUT)
|
||||
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 testutil opmcommon
|
||||
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
opm_add_test(test_compareSummary CONDITION ENABLE_ECL_INPUT
|
||||
LIBRARIES ${_libs})
|
||||
opm_add_test(test_EclFilesComparator CONDITION ENABLE_ECL_INPUT
|
||||
LIBRARIES ${_libs})
|
||||
if(HAVE_DYNAMIC_BOOST_TEST AND NOT BUILD_SHARED_LIBS)
|
||||
set_target_properties(test_compareSummary PROPERTIES
|
||||
COMPILE_DEFINITIONS BOOST_TEST_DYN_LINK)
|
||||
set_target_properties(test_EclFilesComparator PROPERTIES
|
||||
COMPILE_DEFINITIONS BOOST_TEST_DYN_LINK)
|
||||
endif()
|
||||
install(TARGETS compareECL DESTINATION bin)
|
||||
endif()
|
||||
|
||||
# Install build system files
|
||||
install(DIRECTORY cmake DESTINATION share/opm)
|
||||
|
||||
@@ -73,16 +73,17 @@ if(ENABLE_ECL_INPUT)
|
||||
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/Completion.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/CompletionSet.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/ActionX.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/Connection.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/WellConnections.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/Events.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/Group.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/GroupTree.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
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/MSW/updatingConnectionsWithSegments.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.cpp
|
||||
@@ -93,6 +94,8 @@ if(ENABLE_ECL_INPUT)
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/WellInjectionProperties.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/WellTestState.cpp
|
||||
src/opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.cpp
|
||||
src/opm/parser/eclipse/EclipseState/SimulationConfig/ThresholdPressure.cpp
|
||||
src/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp
|
||||
@@ -132,17 +135,23 @@ if(ENABLE_ECL_INPUT)
|
||||
endif()
|
||||
if(ENABLE_ECL_OUTPUT)
|
||||
list( APPEND MAIN_SOURCE_FILES
|
||||
src/opm/test_util/summaryIntegrationTest.cpp
|
||||
src/opm/test_util/summaryRegressionTest.cpp
|
||||
src/opm/test_util/summaryComparator.cpp
|
||||
src/opm/test_util/EclFilesComparator.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/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/LinearisedOutputTable.cpp
|
||||
src/opm/output/eclipse/LogiHEAD.cpp
|
||||
src/opm/output/eclipse/RestartIO.cpp
|
||||
src/opm/output/eclipse/Summary.cpp
|
||||
src/opm/output/eclipse/SummaryState.cpp
|
||||
src/opm/output/eclipse/Tables.cpp
|
||||
src/opm/output/eclipse/RegionCache.cpp
|
||||
src/opm/output/eclipse/RestartValue.cpp
|
||||
src/opm/output/data/Solution.cpp
|
||||
)
|
||||
endif()
|
||||
@@ -161,13 +170,14 @@ list (APPEND TEST_SOURCE_FILES
|
||||
)
|
||||
if(ENABLE_ECL_INPUT)
|
||||
list(APPEND TEST_SOURCE_FILES
|
||||
tests/parser/ACTIONX.cpp
|
||||
tests/parser/ADDREGTests.cpp
|
||||
tests/parser/AquiferCTTests.cpp
|
||||
tests/parser/AqudimsTests.cpp
|
||||
tests/parser/AquanconTests.cpp
|
||||
tests/parser/BoxTests.cpp
|
||||
tests/parser/ColumnSchemaTests.cpp
|
||||
tests/parser/CompletionTests.cpp
|
||||
tests/parser/ConnectionTests.cpp
|
||||
tests/parser/COMPSEGUnits.cpp
|
||||
tests/parser/CopyRegTests.cpp
|
||||
tests/parser/DeckTests.cpp
|
||||
@@ -216,22 +226,29 @@ if(ENABLE_ECL_INPUT)
|
||||
tests/parser/UnitTests.cpp
|
||||
tests/parser/ValueTests.cpp
|
||||
tests/parser/WellSolventTests.cpp
|
||||
tests/parser/WellTests.cpp)
|
||||
tests/parser/WellTests.cpp
|
||||
tests/parser/WTEST.cpp)
|
||||
endif()
|
||||
if(ENABLE_ECL_OUTPUT)
|
||||
list (APPEND TEST_SOURCE_FILES
|
||||
tests/test_compareSummary.cpp
|
||||
tests/test_EclFilesComparator.cpp
|
||||
tests/test_AggregateWellData.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_regionCache.cpp
|
||||
tests/test_Restart.cpp
|
||||
tests/test_RFT.cpp
|
||||
tests/test_Solution.cpp
|
||||
tests/test_Summary.cpp
|
||||
tests/test_Tables.cpp
|
||||
tests/test_Wells.cpp
|
||||
tests/test_WindowedArray.cpp
|
||||
tests/test_writenumwells.cpp
|
||||
tests/test_Solution.cpp
|
||||
tests/test_regionCache.cpp
|
||||
tests/test_serialize_ICON.cpp
|
||||
tests/test_serialize_SCON.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -241,6 +258,7 @@ list (APPEND TEST_DATA_FILES
|
||||
if(ENABLE_ECL_OUTPUT)
|
||||
list (APPEND TEST_DATA_FILES
|
||||
tests/FIRST_SIM.DATA
|
||||
tests/FIRST_SIM_THPRES.DATA
|
||||
tests/summary_deck.DATA
|
||||
tests/group_group.DATA
|
||||
tests/testblackoilstate3.DATA
|
||||
@@ -256,14 +274,9 @@ list (APPEND EXAMPLE_SOURCE_FILES
|
||||
if(ENABLE_ECL_INPUT)
|
||||
list (APPEND EXAMPLE_SOURCE_FILES
|
||||
examples/opmi.cpp
|
||||
examples/opmpack.cpp
|
||||
)
|
||||
endif()
|
||||
if(ENABLE_ECL_OUTPUT)
|
||||
list(APPEND EXAMPLE_SOURCE_FILES
|
||||
examples/test_util/compareECL.cpp
|
||||
examples/test_util/compareSummary.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
# programs listed here will not only be compiled, but also marked for
|
||||
# installation
|
||||
@@ -272,14 +285,9 @@ list (APPEND PROGRAM_SOURCE_FILES
|
||||
if(ENABLE_ECL_INPUT)
|
||||
list (APPEND PROGRAM_SOURCE_FILES
|
||||
examples/opmi.cpp
|
||||
examples/opmpack.cpp
|
||||
)
|
||||
endif()
|
||||
if(ENABLE_ECL_OUTPUT)
|
||||
list(APPEND PROGRAM_SOURCE_FILES
|
||||
examples/test_util/compareECL.cpp
|
||||
examples/test_util/compareSummary.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
list( APPEND PUBLIC_HEADER_FILES
|
||||
opm/common/ErrorMacros.hpp
|
||||
@@ -419,6 +427,7 @@ if(ENABLE_ECL_INPUT)
|
||||
opm/parser/eclipse/EclipseState/EclipseConfig.hpp
|
||||
opm/parser/eclipse/EclipseState/Aquancon.hpp
|
||||
opm/parser/eclipse/EclipseState/AquiferCT.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/ActionX.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.hpp
|
||||
@@ -435,13 +444,15 @@ if(ENABLE_ECL_INPUT)
|
||||
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/Completion.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/Connection.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/MSW/updatingConnectionsWithSegments.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/WellTestState.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp
|
||||
opm/parser/eclipse/EclipseState/SimulationConfig/ThresholdPressure.hpp
|
||||
opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.hpp
|
||||
opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp
|
||||
@@ -465,23 +476,28 @@ if(ENABLE_ECL_INPUT)
|
||||
endif()
|
||||
if(ENABLE_ECL_OUTPUT)
|
||||
list(APPEND PUBLIC_HEADER_FILES
|
||||
opm/output/OutputWriter.hpp
|
||||
opm/output/data/Wells.hpp
|
||||
opm/output/data/Cells.hpp
|
||||
opm/test_util/summaryRegressionTest.hpp
|
||||
opm/test_util/summaryIntegrationTest.hpp
|
||||
opm/test_util/summaryComparator.hpp
|
||||
opm/output/data/Solution.hpp
|
||||
opm/output/data/Wells.hpp
|
||||
opm/output/eclipse/VectorItems/intehead.hpp
|
||||
opm/output/eclipse/VectorItems/well.hpp
|
||||
opm/output/eclipse/AggregateWellData.hpp
|
||||
opm/output/eclipse/CharArrayNullTerm.hpp
|
||||
opm/output/eclipse/DoubHEAD.hpp
|
||||
opm/output/eclipse/EclipseGridInspector.hpp
|
||||
opm/output/eclipse/EclipseIOUtil.hpp
|
||||
opm/output/eclipse/EclipseIO.hpp
|
||||
opm/output/eclipse/EclipseIOUtil.hpp
|
||||
opm/output/eclipse/InteHEAD.hpp
|
||||
opm/output/eclipse/LogiHEAD.hpp
|
||||
opm/output/eclipse/LinearisedOutputTable.hpp
|
||||
opm/output/eclipse/RegionCache.hpp
|
||||
opm/output/eclipse/RestartIO.hpp
|
||||
opm/output/eclipse/RestartValue.hpp
|
||||
opm/output/eclipse/Summary.hpp
|
||||
opm/output/eclipse/SummaryState.hpp
|
||||
opm/output/eclipse/Tables.hpp
|
||||
opm/output/eclipse/RegionCache.hpp
|
||||
opm/output/data/Solution.hpp
|
||||
opm/test_util/EclFilesComparator.hpp
|
||||
opm/test_util/summaryRegressionTest.hpp
|
||||
opm/test_util/summaryComparator.hpp)
|
||||
opm/output/eclipse/WindowedArray.hpp
|
||||
opm/output/eclipse/WriteRestartHelpers.hpp
|
||||
opm/output/OutputWriter.hpp
|
||||
)
|
||||
endif()
|
||||
|
||||
21
CopyHeaders.cmake
Normal file
21
CopyHeaders.cmake
Normal file
@@ -0,0 +1,21 @@
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${BASE_DIR}/tmp_gen/ParserKeywords.cpp
|
||||
${BASE_DIR}/ParserKeywords.cpp)
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${BASE_DIR}/tmp_gen/inlinekw.cpp
|
||||
${BASE_DIR}/inlinekw.cpp)
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${BASE_DIR}/tmp_gen/include/opm/parser/eclipse/Parser/ParserKeywords.hpp
|
||||
${BASE_DIR}/include/opm/parser/eclipse/Parser/ParserKeywords.hpp)
|
||||
|
||||
|
||||
file(GLOB HDRS ${BASE_DIR}/tmp_gen/include/opm/parser/eclipse/Parser/ParserKeywords/*.hpp)
|
||||
|
||||
foreach(HDR ${HDRS})
|
||||
file(RELATIVE_PATH hdr ${BASE_DIR}/tmp_gen/include/opm/parser/eclipse/Parser/ParserKeywords ${HDR})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${HDR}
|
||||
${BASE_DIR}/include/opm/parser/eclipse/Parser/ParserKeywords/${hdr})
|
||||
endforeach()
|
||||
@@ -48,7 +48,6 @@ list(APPEND EXTRA_TESTS EclipseStateTests)
|
||||
|
||||
foreach (test BoxTest
|
||||
CheckDeckValidity
|
||||
CompletionsFromDeck
|
||||
EclipseGridCreateFromDeck
|
||||
IncludeTest
|
||||
IntegrationTests
|
||||
|
||||
@@ -38,11 +38,17 @@ configure_file(src/opm/parser/eclipse/keyword_list.argv.in keyword_list.argv)
|
||||
|
||||
# Generate keyword source
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_BINARY_DIR}/ParserKeywords.cpp ${PROJECT_BINARY_DIR}/inlinekw.cpp
|
||||
OUTPUT ${PROJECT_BINARY_DIR}/tmp_gen/ParserKeywords.cpp ${PROJECT_BINARY_DIR}/tmp_gen/inlinekw.cpp
|
||||
COMMAND genkw keyword_list.argv
|
||||
${PROJECT_BINARY_DIR}/ParserKeywords.cpp
|
||||
${PROJECT_BINARY_DIR}/include/
|
||||
${PROJECT_BINARY_DIR}/tmp_gen/ParserKeywords.cpp
|
||||
${PROJECT_BINARY_DIR}/tmp_gen/include/
|
||||
opm/parser/eclipse/Parser/ParserKeywords
|
||||
${PROJECT_BINARY_DIR}/inlinekw.cpp
|
||||
${PROJECT_BINARY_DIR}/tmp_gen/inlinekw.cpp
|
||||
DEPENDS genkw ${keyword_files} src/opm/parser/eclipse/share/keywords/keyword_list.cmake
|
||||
)
|
||||
|
||||
# To avoid some rebuilds
|
||||
add_custom_command(OUTPUT ParserKeywords.cpp inlinekw.cpp
|
||||
DEPENDS ${PROJECT_BINARY_DIR}/tmp_gen/ParserKeywords.cpp
|
||||
COMMAND ${CMAKE_COMMAND} -DBASE_DIR=${PROJECT_BINARY_DIR}
|
||||
-P ${PROJECT_SOURCE_DIR}/CopyHeaders.cmake)
|
||||
|
||||
@@ -52,6 +52,7 @@ int main (void) {
|
||||
HAVE_PARMETIS;
|
||||
HAVE_SUPERLU;
|
||||
HAVE_UMFPACK;
|
||||
HAVE_SUITESPARSE_UMFPACK;
|
||||
SUPERLU_INT_TYPE;
|
||||
HAVE_SLU_CDEFS_H;
|
||||
HAVE_SLU_DDEFS_H;
|
||||
|
||||
@@ -123,7 +123,7 @@ function (configure_la name target)
|
||||
mark_as_advanced (libtool_MAIN)
|
||||
# notify the user if it not found after we explicitly searched
|
||||
if (NOT libtool_MAIN)
|
||||
message (STATUS "Libtool not found!")
|
||||
message (STATUS "Not generating libtool archive (.la) since libtool was not found")
|
||||
endif (NOT libtool_MAIN)
|
||||
endif (NOT libtool_MAIN)
|
||||
if (libtool_MAIN)
|
||||
|
||||
@@ -47,7 +47,7 @@ macro (opm_defaults opm)
|
||||
endif(NOT PRECOMPILE_HEADERS)
|
||||
|
||||
# Use of OpenMP is considered experimental
|
||||
set (USE_OPENMP_DEFAULT OFF)
|
||||
set (USE_OPENMP_DEFAULT ON)
|
||||
|
||||
# if we are on a system where CMake 2.6 is the default (Hi RHEL 6!),
|
||||
# the configuration files for Boost will trip up the library paths
|
||||
|
||||
@@ -139,6 +139,12 @@ macro (find_and_append_package_to prefix name)
|
||||
set (${name}_FOUND FALSE)
|
||||
set (${NAME}_FOUND FALSE)
|
||||
else ()
|
||||
# List of components might differ for every module. Therefore we will
|
||||
# need to research for a library multiple times. _search_components
|
||||
# will hold the index of the string COMPONENTS in the list
|
||||
set(_ARGN_LIST ${ARGN}) # Create a real list to use with list commands
|
||||
list(FIND _ARGN_LIST "COMPONENTS" _search_components)
|
||||
|
||||
# using config mode is better than using module (aka. find) mode
|
||||
# because then the package has already done all its probes and
|
||||
# stored them in the config file for us
|
||||
@@ -147,8 +153,8 @@ macro (find_and_append_package_to prefix name)
|
||||
# We even need to repeat the search for opm-common once as this is done
|
||||
# in the top most CMakeLists.txt without querying defines, setting dependencies
|
||||
# and the likes which is only done via opm_find_package
|
||||
if (NOT DEFINED ${name}_FOUND AND NOT DEFINED ${NAME}_FOUND
|
||||
OR ("${name}" STREQUAL "opm-common" AND NOT _opm_common_deps_processed))
|
||||
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})
|
||||
@@ -164,11 +170,8 @@ macro (find_and_append_package_to prefix name)
|
||||
find_package (${name} ${ARGN_NO_REQUIRED} NO_CMAKE_SYSTEM_PACKAGE_REGISTRY NO_CMAKE_PACKAGE_REGISTRY)
|
||||
if(TARGET ecl)
|
||||
# Need to grab from target to enable transitional depends
|
||||
get_target_property(ecl_INCLUDE_DIRS ecl INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_target_property(ecl_LIBRARIES ecl INTERFACE_LINK_LIBRARIES)
|
||||
get_target_property(ecl_lib ecl LOCATION)
|
||||
set(ecl_LIBRARIES ecl ${ecl_lib} ${ecl_LIBRARIES})
|
||||
set(ecl_FOUND 1)
|
||||
#get_target_property(ecl_INCLUDE_DIRS ecl INTERFACE_INCLUDE_DIRECTORIES)
|
||||
set(ecl_LIBRARIES ecl)
|
||||
set(HAVE_ERT 1)
|
||||
endif()
|
||||
elseif(_${name}_exempted LESS 0 AND NOT _is_opm)
|
||||
@@ -197,10 +200,6 @@ macro (find_and_append_package_to prefix name)
|
||||
if (NOT DEFINED ${NAME}_FOUND)
|
||||
set (${NAME}_FOUND "${${name}_FOUND}")
|
||||
endif ()
|
||||
|
||||
if("${name}" STREQUAL "opm-common")
|
||||
set(_opm_common_deps_processed ON)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
# the variable "NAME" may be replaced during find_package (as this is
|
||||
|
||||
@@ -59,11 +59,7 @@ macro (find_opm_package module deps header lib defs prog conf)
|
||||
# top most CMakeLists.txt but we still need to search for its
|
||||
# dependencies
|
||||
if (${MODULE}_FOUND OR ${module}_FOUND)
|
||||
if (${module} STREQUAL "opm-common" AND NOT _opm_common_deps_processed)
|
||||
set(_opm_common_deps_processed ON)
|
||||
else()
|
||||
return ()
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
# variables to pass on to other packages
|
||||
@@ -84,31 +80,11 @@ macro (find_opm_package module deps header lib defs prog conf)
|
||||
# ${module}_CONFIG_VARS for dune modules.
|
||||
find_package(${module} ${_${module}_quiet} ${_${module}_required} CONFIG)
|
||||
|
||||
|
||||
# period because it should be something that evaluates to true
|
||||
# in find_package_handle_standard_args
|
||||
set (${module}_ALL_PREREQS ".")
|
||||
foreach (_dep IN ITEMS ${deps})
|
||||
separate_arguments (_${module}_args UNIX_COMMAND ${_dep})
|
||||
if (_${module}_args)
|
||||
# keep REQUIRED in the arguments only if we were required ourself
|
||||
# "required-ness" is not transitive as far as CMake is concerned
|
||||
# (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}")
|
||||
find_and_append_package_to (${module} ${_args_req} ${_${module}_quiet})
|
||||
list (GET _${module}_args 0 _name_only)
|
||||
string (TOUPPER "${_name_only}" _NAME_ONLY)
|
||||
string (REPLACE "-" "_" _NAME_ONLY "${_NAME_ONLY}")
|
||||
# check manually if it was found if REQUIRED; otherwise poison the
|
||||
# dependency list which is checked later (so that it will fail)
|
||||
if (("${_${module}_args}" MATCHES "REQUIRED") AND NOT (${_name_only}_FOUND OR ${_NAME_ONLY}_FOUND))
|
||||
list (APPEND ${module}_ALL_PREREQS "${_name_only}-NOTFOUND")
|
||||
endif ()
|
||||
else ()
|
||||
message (WARNING "Empty dependency in find module for ${module} (check for trailing semi-colon)")
|
||||
endif ()
|
||||
endforeach (_dep)
|
||||
if(NOT ${module}_DEPS)
|
||||
# set the dependencies used in find_package_deps
|
||||
set(${module}_DEPS "${deps}")
|
||||
endif()
|
||||
find_package_deps(${module})
|
||||
|
||||
# since find_and_append_package_to is a macro, this variable have
|
||||
# probably been overwritten (due to its common name); it is now
|
||||
@@ -181,6 +157,11 @@ macro (find_package_deps module)
|
||||
foreach (_dep IN ITEMS ${${module}_DEPS})
|
||||
separate_arguments (_${module}_args UNIX_COMMAND "${_dep}")
|
||||
if (_${module}_args)
|
||||
# keep REQUIRED in the arguments only if we were required ourself
|
||||
# "required-ness" is not transitive as far as CMake is concerned
|
||||
# (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-" OR _dep MATCHES "ewoms")
|
||||
set(deplist ${_dep})
|
||||
string(STRIP "${_dep}" _dep)
|
||||
|
||||
@@ -76,6 +76,7 @@ function (opm_cmake_config name)
|
||||
set (template_dir "${OPM_MACROS_ROOT}/cmake/Templates")
|
||||
|
||||
# write configuration file to locate library
|
||||
set(DUNE_PREFIX ${PROJECT_SOURCE_DIR})
|
||||
set(OPM_PROJECT_EXTRA_CODE ${OPM_PROJECT_EXTRA_CODE_INTREE})
|
||||
set(PREREQ_LOCATION "${PROJECT_SOURCE_DIR}")
|
||||
configure_cmake_file (${name} "config" "")
|
||||
@@ -123,6 +124,7 @@ function (opm_cmake_config name)
|
||||
# of the build directory (using the same input template)
|
||||
set(OPM_PROJECT_EXTRA_CODE ${OPM_PROJECT_EXTRA_CODE_INSTALLED})
|
||||
set(PREREQ_LOCATION "${CMAKE_INSTALL_PREFIX}/share/opm/cmake/Modules")
|
||||
set(DUNE_PREFIX ${CMAKE_INSTALL_PREFIX})
|
||||
configure_cmake_file (${name} "install" "")
|
||||
configure_vars (
|
||||
FILE CMAKE "${PROJECT_BINARY_DIR}/${${name}_NAME}-install.cmake"
|
||||
|
||||
@@ -228,6 +228,13 @@ macro(opm_add_test TestName)
|
||||
set(CURTEST_EXE_NAME ${TestName})
|
||||
endif()
|
||||
|
||||
# Strip test_ prefix from name
|
||||
if ("${TestName}" MATCHES "^test_([^/]*)$")
|
||||
string (REGEX REPLACE "^test_([^/]*)$" "\\1" _FANCY "${TestName}")
|
||||
else()
|
||||
set(_FANCY ${TestName})
|
||||
endif()
|
||||
|
||||
# try to auto-detect the name of the source file if SOURCES are not
|
||||
# explicitly specified.
|
||||
if (NOT CURTEST_SOURCES)
|
||||
@@ -331,7 +338,7 @@ macro(opm_add_test TestName)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_test(NAME ${TestName}
|
||||
add_test(NAME ${_FANCY}
|
||||
WORKING_DIRECTORY "${CURTEST_WORKING_DIRECTORY}"
|
||||
COMMAND ${CURTEST_COMMAND})
|
||||
|
||||
@@ -359,7 +366,7 @@ macro(opm_add_test TestName)
|
||||
# CDash dashboard. it this is removed, the test is just silently
|
||||
# ignored.
|
||||
if (NOT CURTEST_ONLY_COMPILE AND ADD_DISABLED_CTESTS)
|
||||
add_test(${TestName} skip_test_dummy)
|
||||
add_test(${_FANCY} skip_test_dummy)
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
@@ -21,9 +21,8 @@
|
||||
|
||||
# Prevent multiple inclusions
|
||||
if(NOT @opm-project_NAME@_FOUND)
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" @PREREQ_LOCATION@)
|
||||
include(@opm-project_NAME@-prereqs)
|
||||
# propagate these properties from one build system to the other
|
||||
set (@opm-project_NAME@_PREFIX "@DUNE_PREFIX@")
|
||||
set (@opm-project_NAME@_VERSION "@opm-project_VERSION@")
|
||||
set (@opm-project_NAME@_DEFINITIONS "@opm-project_DEFINITIONS@")
|
||||
set (@opm-project_NAME@_INCLUDE_DIRS "@opm-project_INCLUDE_DIRS@")
|
||||
@@ -72,6 +71,12 @@ if(NOT @opm-project_NAME@_FOUND)
|
||||
|
||||
# this is the contents of config.h as far as our probes can tell:
|
||||
|
||||
# extra code
|
||||
# extra code from variable OPM_PROJECT_EXTRA_CODE
|
||||
@OPM_PROJECT_EXTRA_CODE@
|
||||
# end extra code
|
||||
|
||||
# This call is at the bottom as we need to include
|
||||
# the OpmPackage Macros.
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" @PREREQ_LOCATION@)
|
||||
include(@opm-project_NAME@-prereqs)
|
||||
endif()
|
||||
|
||||
2
debian/changelog
vendored
2
debian/changelog
vendored
@@ -1,4 +1,4 @@
|
||||
opm-common (2018.04-rc1-1~xenial) xenial; urgency=medium
|
||||
opm-common (2015.10-1~trusty) trusty; urgency=medium
|
||||
|
||||
* New release
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
Module: opm-common
|
||||
Description: Open Porous Media Initiative shared infrastructure
|
||||
Version: 2018.04-rc1
|
||||
Label: 2018.04-rc1
|
||||
Version: 2018.10-pre
|
||||
Label: 2018.10-pre
|
||||
Maintainer: opm@opm-project.org
|
||||
MaintainerName: OPM community
|
||||
Url: http://opm-project.org
|
||||
|
||||
108
examples/opmpack.cpp
Normal file
108
examples/opmpack.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
Copyright 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/>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <getopt.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||
#include <opm/parser/eclipse/Parser/InputErrorAction.hpp>
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
|
||||
|
||||
inline void pack_deck( const char * deck_file, std::ostream& os) {
|
||||
Opm::ParseContext parseContext(Opm::InputError::WARN);
|
||||
Opm::Parser parser;
|
||||
|
||||
auto deck = parser.parseFile(deck_file, parseContext);
|
||||
os << deck;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void print_help_and_exit() {
|
||||
const char * help_text = R"(
|
||||
The opmpack program will load a deck, resolve all include
|
||||
files and then print it out again on stdout. All comments
|
||||
will be stripped and the value types will be validated.
|
||||
|
||||
By passing the option -o you can redirect the output to a file
|
||||
or a directory.
|
||||
|
||||
Print on stdout:
|
||||
|
||||
opmpack /path/to/case/CASE.DATA
|
||||
|
||||
|
||||
Print MY_CASE.DATA in /tmp:
|
||||
|
||||
opmpack -o /tmp /path/to/MY_CASE.DATA
|
||||
|
||||
|
||||
Print NEW_CASE in cwd:
|
||||
|
||||
opmpack -o NEW_CASE.DATA path/to/MY_CASE.DATA
|
||||
|
||||
|
||||
)";
|
||||
std::cerr << help_text << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int arg_offset = 1;
|
||||
bool stdout_output = true;
|
||||
const char * coutput_arg;
|
||||
|
||||
while (true) {
|
||||
int c;
|
||||
c = getopt(argc, argv, "o:");
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch(c) {
|
||||
case 'o':
|
||||
stdout_output = false;
|
||||
coutput_arg = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
arg_offset = optind;
|
||||
if (arg_offset >= argc)
|
||||
print_help_and_exit();
|
||||
|
||||
if (stdout_output)
|
||||
pack_deck(argv[arg_offset], std::cout);
|
||||
else {
|
||||
std::ofstream os;
|
||||
using path = boost::filesystem::path;
|
||||
path input_arg(argv[arg_offset]);
|
||||
path output_arg(coutput_arg);
|
||||
if (boost::filesystem::is_directory(output_arg)) {
|
||||
path output_path = output_arg / input_arg.filename();
|
||||
os.open(output_path.string());
|
||||
} else
|
||||
os.open(output_arg.string());
|
||||
|
||||
pack_deck(argv[arg_offset], os);
|
||||
}
|
||||
}
|
||||
|
||||
32
examples/test_util/Deviation.hpp
Normal file
32
examples/test_util/Deviation.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
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 DEVIATION_HPP
|
||||
#define DEVIATION_HPP
|
||||
|
||||
/*! \brief Deviation struct.
|
||||
\details The member variables are default initialized to -1,
|
||||
which is an invalid deviation value.
|
||||
*/
|
||||
struct Deviation {
|
||||
double abs = -1; //!< Absolute deviation
|
||||
double rel = -1; //!< Relative deviation
|
||||
};
|
||||
|
||||
#endif
|
||||
300
examples/test_util/EclFilesComparator.cpp
Normal file
300
examples/test_util/EclFilesComparator.cpp
Normal 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);
|
||||
}
|
||||
127
examples/test_util/EclFilesComparator.hpp
Normal file
127
examples/test_util/EclFilesComparator.hpp
Normal 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
|
||||
199
examples/test_util/EclIntegrationTest.cpp
Normal file
199
examples/test_util/EclIntegrationTest.cpp
Normal 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;
|
||||
}
|
||||
78
examples/test_util/EclIntegrationTest.hpp
Normal file
78
examples/test_util/EclIntegrationTest.hpp
Normal 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
|
||||
349
examples/test_util/EclRegressionTest.cpp
Normal file
349
examples/test_util/EclRegressionTest.cpp
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
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 (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;
|
||||
}
|
||||
84
examples/test_util/EclRegressionTest.hpp
Normal file
84
examples/test_util/EclRegressionTest.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
// 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;}
|
||||
|
||||
//! \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
|
||||
@@ -16,7 +16,11 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/test_util/EclFilesComparator.hpp>
|
||||
#include "EclIntegrationTest.hpp"
|
||||
#include "EclRegressionTest.hpp"
|
||||
#include "summaryIntegrationTest.hpp"
|
||||
#include "summaryRegressionTest.hpp"
|
||||
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
|
||||
#include <ert/util/util.h>
|
||||
@@ -29,32 +33,40 @@
|
||||
#include <getopt.h>
|
||||
|
||||
static void printHelp() {
|
||||
std::cout << "\ncompareECL compares ECLIPSE files (restart (.RST), unified restart (.UNRST), initial (.INIT) or .RFT) and gridsizes (from .EGRID or .GRID file) from two simulations.\n"
|
||||
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"
|
||||
<< "Example usage of the program: \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"
|
||||
@@ -107,19 +119,36 @@ int main(int argc, char** argv) {
|
||||
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 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:lnpPt:")) != -1) {
|
||||
while ((c = getopt(argc, argv, "hiIk:alnpPt:VRgs:m:vK")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
analysis = true;
|
||||
break;
|
||||
case 'g':
|
||||
findGreatestErrorRatio = true;
|
||||
throwTooGreatErrorRatio = false;
|
||||
break;
|
||||
case 'h':
|
||||
printHelp();
|
||||
return 0;
|
||||
@@ -130,29 +159,48 @@ int main(int argc, char** argv) {
|
||||
integrationTest = true;
|
||||
checkNumKeywords = true;
|
||||
break;
|
||||
case 'n':
|
||||
throwOnError = false;
|
||||
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 '?':
|
||||
if (optopt == 'k') {
|
||||
std::cerr << "Option k requires a keyword as argument, see manual (-h) for more information." << std::endl;
|
||||
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') {
|
||||
@@ -181,6 +229,7 @@ int main(int argc, char** argv) {
|
||||
<< "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);
|
||||
@@ -206,15 +255,67 @@ int main(int argc, char** argv) {
|
||||
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 (integrationTest) {
|
||||
IntegrationTest comparator(basename1, basename2, absTolerance, relTolerance);
|
||||
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);
|
||||
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;
|
||||
@@ -240,8 +341,9 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
RegressionTest comparator(file_type, basename1, basename2, absTolerance, relTolerance);
|
||||
ECLRegressionTest comparator(file_type, basename1, basename2, absTolerance, relTolerance);
|
||||
comparator.throwOnErrors(throwOnError);
|
||||
comparator.doAnalysis(analysis);
|
||||
if (printKeywords) {
|
||||
comparator.printKeywords();
|
||||
return 0;
|
||||
@@ -254,11 +356,11 @@ int main(int argc, char** argv) {
|
||||
comparator.setOnlyLastOccurrence(true);
|
||||
}
|
||||
if (specificKeyword) {
|
||||
comparator.gridCompare();
|
||||
comparator.gridCompare(volumecheck);
|
||||
comparator.resultsForKeyword(keyword);
|
||||
}
|
||||
else {
|
||||
comparator.gridCompare();
|
||||
comparator.gridCompare(volumecheck);
|
||||
comparator.results();
|
||||
}
|
||||
if (comparator.getNoErrors() > 0)
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <opm/test_util/summaryRegressionTest.hpp>
|
||||
#include <opm/test_util/summaryIntegrationTest.hpp>
|
||||
#include "summaryRegressionTest.hpp"
|
||||
#include "summaryIntegrationTest.hpp"
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
@@ -37,6 +37,7 @@ void printHelp(){
|
||||
std::cout << "The program is capable of performing both a regression test and an integration test, \nhowever only one type of test at a time. ";
|
||||
std::cout << "By default the program will run a regression test."<< std::endl;
|
||||
std::cout << "\nThe program have command line options:" << std::endl;
|
||||
std::cout << "-a \tRun a full analysis of errors." << std::endl;
|
||||
std::cout << "-h \t\tPrint help message." << std::endl << std::endl;
|
||||
std::cout << "For the regression test: " << std::endl;
|
||||
std::cout << "-r \t\tChoosing regression test (this is default)."<< std::endl;
|
||||
@@ -80,6 +81,7 @@ int main (int argc, char ** argv){
|
||||
bool throwExceptionForTooGreatErrorRatio = true;
|
||||
bool isRestartFile = false;
|
||||
bool throwOnError = true;
|
||||
bool analysis = false;
|
||||
const char* keyword = nullptr;
|
||||
const char* mainVariable = nullptr;
|
||||
int c = 0;
|
||||
@@ -88,8 +90,11 @@ int main (int argc, char ** argv){
|
||||
|
||||
//------------------------------------------------
|
||||
//For setting the options selected
|
||||
while ((c = getopt(argc, argv, "dghik:Km:npP:rRs:vV:")) != -1) {
|
||||
while ((c = getopt(argc, argv, "dghik:Km:napP:rRs:vV:")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
analysis = true;
|
||||
break;
|
||||
case 'd':
|
||||
throwExceptionForTooGreatErrorRatio = false;
|
||||
break;
|
||||
@@ -175,8 +180,9 @@ int main (int argc, char ** argv){
|
||||
|
||||
try {
|
||||
if(regressionTest){
|
||||
RegressionTest compare(basename1,basename2, absoluteTolerance, relativeTolerance);
|
||||
SummaryRegressionTest compare(basename1,basename2, absoluteTolerance, relativeTolerance);
|
||||
compare.throwOnErrors(throwOnError);
|
||||
compare.doAnalysis(analysis);
|
||||
if(printKeywords){compare.setPrintKeywords(true);}
|
||||
if(isRestartFile){compare.setIsRestartFile(true);}
|
||||
if(specificKeyword){
|
||||
@@ -188,7 +194,7 @@ int main (int argc, char ** argv){
|
||||
}
|
||||
}
|
||||
if(integrationTest){
|
||||
IntegrationTest compare(basename1,basename2, absoluteTolerance, relativeTolerance);
|
||||
SummaryIntegrationTest compare(basename1,basename2, absoluteTolerance, relativeTolerance);
|
||||
compare.throwOnErrors(throwOnError);
|
||||
if(findVectorWithGreatestErrorRatio){compare.setFindVectorWithGreatestErrorRatio(true);}
|
||||
if(allowSpikes){compare.setAllowSpikes(true);}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/test_util/summaryComparator.hpp>
|
||||
#include "summaryComparator.hpp"
|
||||
#include <ert/ecl/ecl_sum.h>
|
||||
#include <ert/util/stringlist.h>
|
||||
#include <ert/util/int_vector.h>
|
||||
@@ -25,9 +25,11 @@
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
|
||||
SummaryComparator::SummaryComparator(const char* basename1, const char* basename2, double absoluteTol, double relativeTol){
|
||||
ecl_sum1 = ecl_sum_fread_alloc_case(basename1, ":");
|
||||
ecl_sum2 = ecl_sum_fread_alloc_case(basename2, ":");
|
||||
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");
|
||||
}
|
||||
@@ -20,8 +20,10 @@
|
||||
#ifndef SUMMARYCOMPARATOR_HPP
|
||||
#define SUMMARYCOMPARATOR_HPP
|
||||
|
||||
#include "Deviation.hpp"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
@@ -46,13 +48,6 @@ struct ecl_sum_struct;
|
||||
typedef struct ecl_sum_struct ecl_sum_type;
|
||||
|
||||
|
||||
//! \brief Struct for storing the deviation between two values.
|
||||
struct Deviation {
|
||||
double abs = 0;//!< The absolute deviation
|
||||
double rel = 0; //!< The relative deviation
|
||||
};
|
||||
|
||||
|
||||
class SummaryComparator {
|
||||
private:
|
||||
double absoluteTolerance = 0; //!< The maximum absolute deviation that is allowed between two values.
|
||||
@@ -73,6 +68,8 @@ class SummaryComparator {
|
||||
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
|
||||
@@ -142,7 +139,9 @@ class SummaryComparator {
|
||||
//! \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 char* basename1, const char* basename2, double absoluteTolerance, double relativeTolerance);
|
||||
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.
|
||||
@@ -175,6 +174,9 @@ class SummaryComparator {
|
||||
|
||||
//! \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
|
||||
@@ -17,14 +17,14 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <opm/test_util/summaryIntegrationTest.hpp>
|
||||
#include "summaryIntegrationTest.hpp"
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <ert/ecl/ecl_sum.h>
|
||||
#include <ert/util/stringlist.h>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
void IntegrationTest::getIntegrationTest(){
|
||||
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);
|
||||
@@ -89,7 +89,7 @@ void IntegrationTest::getIntegrationTest(){
|
||||
}
|
||||
|
||||
|
||||
void IntegrationTest::getIntegrationTest(const char* keyword){
|
||||
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)
|
||||
@@ -115,9 +115,9 @@ void IntegrationTest::getIntegrationTest(const char* keyword){
|
||||
}
|
||||
|
||||
|
||||
void IntegrationTest::checkForKeyword(const std::vector<double>& timeVec1,
|
||||
const std::vector<double>& timeVec2,
|
||||
const char* keyword){
|
||||
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);
|
||||
@@ -130,7 +130,7 @@ void IntegrationTest::checkForKeyword(const std::vector<double>& timeVec1,
|
||||
}
|
||||
|
||||
|
||||
int IntegrationTest::checkDeviation(const Deviation& deviation){
|
||||
int SummaryIntegrationTest::checkDeviation(const Deviation& deviation){
|
||||
double absTol = getAbsTolerance();
|
||||
double relTol = getRelTolerance();
|
||||
if (deviation.rel> relTol && deviation.abs > absTol){
|
||||
@@ -140,10 +140,10 @@ int IntegrationTest::checkDeviation(const Deviation& deviation){
|
||||
}
|
||||
|
||||
|
||||
void IntegrationTest::findGreatestErrorRatio(const WellProductionVolume& volume,
|
||||
double &greatestRatio,
|
||||
const char* currentKeyword,
|
||||
std::string &greatestErrorRatio){
|
||||
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;
|
||||
@@ -154,7 +154,7 @@ void IntegrationTest::findGreatestErrorRatio(const WellProductionVolume& volume,
|
||||
}
|
||||
|
||||
|
||||
void IntegrationTest::volumeErrorCheck(const char* keyword){
|
||||
void SummaryIntegrationTest::volumeErrorCheck(const char* keyword){
|
||||
const smspec_node_type * 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.
|
||||
bool hist = smspec_node_is_historical(node);
|
||||
/* returns true if the keyword corresponds to a summary vector "history".
|
||||
@@ -199,7 +199,7 @@ void IntegrationTest::volumeErrorCheck(const char* keyword){
|
||||
}
|
||||
|
||||
|
||||
void IntegrationTest::updateVolumeError(const char* keyword){
|
||||
void SummaryIntegrationTest::updateVolumeError(const char* keyword){
|
||||
std::string keywordString(keyword);
|
||||
std::string firstFour = keywordString.substr(0,4);
|
||||
|
||||
@@ -223,7 +223,7 @@ void IntegrationTest::updateVolumeError(const char* keyword){
|
||||
}
|
||||
|
||||
|
||||
WellProductionVolume IntegrationTest::getWellProductionVolume(const char * keyword){
|
||||
WellProductionVolume SummaryIntegrationTest::getWellProductionVolume(const char * keyword){
|
||||
double total = integrate(*referenceVec, *referenceDataVec);
|
||||
double error = integrateError(*referenceVec, *referenceDataVec,
|
||||
*checkVec, *checkDataVec);
|
||||
@@ -239,7 +239,7 @@ WellProductionVolume IntegrationTest::getWellProductionVolume(const char * keywo
|
||||
}
|
||||
|
||||
|
||||
void IntegrationTest::evaluateWellProductionVolume(){
|
||||
void SummaryIntegrationTest::evaluateWellProductionVolume(){
|
||||
if(mainVariable.empty()){
|
||||
double ratioWOP, ratioWWP, ratioWGP, ratioWBHP;
|
||||
ratioWOP = WOP.error/WOP.total;
|
||||
@@ -266,7 +266,7 @@ void IntegrationTest::evaluateWellProductionVolume(){
|
||||
}
|
||||
|
||||
|
||||
void IntegrationTest::checkWithSpikes(const char* keyword){
|
||||
void SummaryIntegrationTest::checkWithSpikes(const char* keyword){
|
||||
int errorOccurrences = 0;
|
||||
size_t jvar = 0 ;
|
||||
bool spikeCurrent = false;
|
||||
@@ -295,9 +295,9 @@ void IntegrationTest::checkWithSpikes(const char* keyword){
|
||||
|
||||
|
||||
WellProductionVolume
|
||||
IntegrationTest::getSpecificWellVolume(const std::vector<double>& timeVec1,
|
||||
const std::vector<double>& timeVec2,
|
||||
const char* keyword){
|
||||
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);
|
||||
@@ -305,20 +305,8 @@ IntegrationTest::getSpecificWellVolume(const std::vector<double>& timeVec1,
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
bool IntegrationTest::checkUnits(const char * keyword){
|
||||
const smspec_node_type * node1 = ecl_sum_get_general_var_node (ecl_sum_fileShort ,keyword);
|
||||
const smspec_node_type * node2 = ecl_sum_get_general_var_node (ecl_sum_fileLong ,keyword);
|
||||
if(strcmp(smspec_node_get_unit(node1),smspec_node_get_unit(node2)) == 0){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
double IntegrationTest::integrate(const std::vector<double>& timeVec,
|
||||
const std::vector<double>& dataVec){
|
||||
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.");
|
||||
@@ -332,10 +320,10 @@ double IntegrationTest::integrate(const std::vector<double>& timeVec,
|
||||
}
|
||||
|
||||
|
||||
double IntegrationTest::integrateError(const std::vector<double>& timeVec1,
|
||||
const std::vector<double>& dataVec1,
|
||||
const std::vector<double>& timeVec2,
|
||||
const std::vector<double>& dataVec2){
|
||||
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.
|
||||
@@ -17,7 +17,7 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/test_util/summaryComparator.hpp>
|
||||
#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.
|
||||
@@ -35,7 +35,7 @@ struct WellProductionVolume{
|
||||
};
|
||||
|
||||
//! \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 IntegrationTest: public SummaryComparator {
|
||||
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.
|
||||
@@ -124,8 +124,9 @@ class IntegrationTest: public SummaryComparator {
|
||||
//! \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.
|
||||
IntegrationTest(const char* basename1, const char* basename2,
|
||||
double atol, double rtol) :
|
||||
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.
|
||||
@@ -16,13 +16,13 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/test_util/summaryRegressionTest.hpp>
|
||||
#include "summaryRegressionTest.hpp"
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <ert/ecl/ecl_sum.h>
|
||||
#include <ert/util/stringlist.h>
|
||||
#include <string>
|
||||
|
||||
void RegressionTest::getRegressionTest(){
|
||||
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.
|
||||
@@ -72,15 +72,39 @@ void RegressionTest::getRegressionTest(){
|
||||
}
|
||||
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
|
||||
else if (deviations.empty())
|
||||
std::cout << "Regression test succeeded." << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RegressionTest::getRegressionTest(const char* keyword){
|
||||
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.
|
||||
@@ -102,18 +126,22 @@ void RegressionTest::getRegressionTest(const char* keyword){
|
||||
|
||||
|
||||
|
||||
bool RegressionTest::checkDeviation(Deviation deviation, const char* keyword, int refIndex, int checkIndex){
|
||||
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){
|
||||
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.");
|
||||
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;
|
||||
@@ -121,7 +149,7 @@ bool RegressionTest::checkDeviation(Deviation deviation, const char* keyword, in
|
||||
|
||||
|
||||
|
||||
bool RegressionTest::checkForKeyword(std::vector<double>& timeVec1, std::vector<double>& timeVec2, const char* keyword){
|
||||
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);
|
||||
@@ -130,7 +158,7 @@ bool RegressionTest::checkForKeyword(std::vector<double>& timeVec1, std::vector<
|
||||
|
||||
|
||||
|
||||
bool RegressionTest::startTest(const char* keyword){
|
||||
bool SummaryRegressionTest::startTest(const char* keyword){
|
||||
size_t jvar = 0;
|
||||
Deviation deviation;
|
||||
bool result = true;
|
||||
@@ -20,10 +20,10 @@
|
||||
#ifndef SUMMARYREGRESSIONTEST_HPP
|
||||
#define SUMMARYREGRESSIONTEST_HPP
|
||||
|
||||
#include <opm/test_util/summaryComparator.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 RegressionTest: public SummaryComparator {
|
||||
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.
|
||||
@@ -55,7 +55,9 @@ class RegressionTest: public SummaryComparator {
|
||||
//! \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.
|
||||
RegressionTest(const char* basename1, const char* basename2, double relativeTol, double absoluteTol):
|
||||
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.
|
||||
@@ -16,9 +16,14 @@ then
|
||||
cp $OPM_TESTS_ROOT_PREDEFINED $WORKSPACE/deps/opm-tests -R
|
||||
fi
|
||||
else
|
||||
# Specified in trigger, download it
|
||||
source $WORKSPACE/deps/opm-common/jenkins/build-opm-module.sh
|
||||
clone_module opm-tests $OPM_TESTS_REVISION
|
||||
# We need a full repo checkout
|
||||
cp $OPM_TESTS_ROOT_PREDEFINED $WORKSPACE/deps/opm-tests -R
|
||||
pushd $WORKSPACE/deps/opm-tests
|
||||
# Then we fetch the PR branch
|
||||
git remote add PR https://github.com/OPM/opm-tests
|
||||
git fetch --depth 1 PR $OPM_TESTS_REVISION:branch_to_build
|
||||
git checkout branch_to_build
|
||||
popd
|
||||
fi
|
||||
else
|
||||
if ! test -d $WORKSPACE/deps/opm-tests
|
||||
|
||||
@@ -81,7 +81,7 @@ then
|
||||
PRNUMBER=${rev//[!0-9]/}
|
||||
DATA_PR=`curl -X GET https://api.github.com/repos/OPM/opm-tests/pulls?head=jenkins4opm:$BRANCH_NAME | grep '"number":' | awk -F ':' '{print $2}' | sed -e 's/,//' -e 's/ //'`
|
||||
git push -u jenkins4opm $BRANCH_NAME -f
|
||||
curl -d "{ \"body\": \"Existing PR https://github.com/OPM/opm-data/pull/$DATA_PR was updated\" }" -X POST https://api.github.com/repos/OPM/$MAIN_REPO/issues/$PRNUMBER/comments?access_token=$GH_TOKEN
|
||||
curl -d "{ \"body\": \"Existing PR https://github.com/OPM/opm-tests/pull/$DATA_PR was updated\" }" -X POST https://api.github.com/repos/OPM/$MAIN_REPO/issues/$PRNUMBER/comments?access_token=$GH_TOKEN
|
||||
else
|
||||
git-open-pull -u jenkins4opm --base-account OPM --base-repo opm-tests -r /tmp/cmsg $BRANCH_NAME
|
||||
fi
|
||||
|
||||
@@ -25,3 +25,7 @@ else()
|
||||
"Boost 1.44.0
|
||||
COMPONENTS system unit_test_framework REQUIRED")
|
||||
endif()
|
||||
# We need a defined target for libecl when linking.
|
||||
# The definition of the target is done implicitly below when
|
||||
# libecl is searched for.
|
||||
find_package_deps(opm-common)
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace Opm {
|
||||
double reservoir_gas = 0.0;
|
||||
};
|
||||
|
||||
struct Completion {
|
||||
struct Connection {
|
||||
using global_index = size_t;
|
||||
static const constexpr int restart_size = 2;
|
||||
|
||||
@@ -112,6 +112,7 @@ namespace Opm {
|
||||
double cell_pressure;
|
||||
double cell_saturation_water;
|
||||
double cell_saturation_gas;
|
||||
double effective_Kh;
|
||||
|
||||
template <class MessageBufferType>
|
||||
void write(MessageBufferType& buffer) const;
|
||||
@@ -125,7 +126,7 @@ namespace Opm {
|
||||
double thp;
|
||||
double temperature;
|
||||
int control;
|
||||
std::vector< Completion > completions;
|
||||
std::vector< Connection > connections;
|
||||
|
||||
inline bool flowing() const noexcept;
|
||||
template <class MessageBufferType>
|
||||
@@ -146,20 +147,20 @@ namespace Opm {
|
||||
}
|
||||
|
||||
|
||||
double get(const std::string& well_name , Completion::global_index completion_grid_index, Rates::opt m) const {
|
||||
double get(const std::string& well_name , Connection::global_index connection_grid_index, Rates::opt m) const {
|
||||
const auto& witr = this->find( well_name );
|
||||
if( witr == this->end() ) return 0.0;
|
||||
|
||||
const auto& well = witr->second;
|
||||
const auto& completion = std::find_if( well.completions.begin() ,
|
||||
well.completions.end() ,
|
||||
[=]( const Completion& c ) {
|
||||
return c.index == completion_grid_index; });
|
||||
const auto& connection = std::find_if( well.connections.begin() ,
|
||||
well.connections.end() ,
|
||||
[=]( const Connection& c ) {
|
||||
return c.index == connection_grid_index; });
|
||||
|
||||
if( completion == well.completions.end() )
|
||||
if( connection == well.connections.end() )
|
||||
return 0.0;
|
||||
|
||||
return completion->rates.get( m, 0.0 );
|
||||
return connection->rates.get( m, 0.0 );
|
||||
}
|
||||
|
||||
template <class MessageBufferType>
|
||||
@@ -288,7 +289,7 @@ namespace Opm {
|
||||
}
|
||||
|
||||
template <class MessageBufferType>
|
||||
void Completion::write(MessageBufferType& buffer) const {
|
||||
void Connection::write(MessageBufferType& buffer) const {
|
||||
buffer.write(this->index);
|
||||
this->rates.write(buffer);
|
||||
buffer.write(this->pressure);
|
||||
@@ -296,6 +297,7 @@ namespace Opm {
|
||||
buffer.write(this->cell_pressure);
|
||||
buffer.write(this->cell_saturation_water);
|
||||
buffer.write(this->cell_saturation_gas);
|
||||
buffer.write(this->effective_Kh);
|
||||
}
|
||||
|
||||
template <class MessageBufferType>
|
||||
@@ -305,9 +307,9 @@ namespace Opm {
|
||||
buffer.write(this->thp);
|
||||
buffer.write(this->temperature);
|
||||
buffer.write(this->control);
|
||||
unsigned int size = this->completions.size();
|
||||
unsigned int size = this->connections.size();
|
||||
buffer.write(size);
|
||||
for (const Completion& comp : this->completions)
|
||||
for (const Connection& comp : this->connections)
|
||||
comp.write(buffer);
|
||||
}
|
||||
|
||||
@@ -328,7 +330,7 @@ namespace Opm {
|
||||
}
|
||||
|
||||
template <class MessageBufferType>
|
||||
void Completion::read(MessageBufferType& buffer) {
|
||||
void Connection::read(MessageBufferType& buffer) {
|
||||
buffer.read(this->index);
|
||||
this->rates.read(buffer);
|
||||
buffer.read(this->pressure);
|
||||
@@ -336,6 +338,7 @@ namespace Opm {
|
||||
buffer.read(this->cell_pressure);
|
||||
buffer.read(this->cell_saturation_water);
|
||||
buffer.read(this->cell_saturation_gas);
|
||||
buffer.read(this->effective_Kh);
|
||||
}
|
||||
|
||||
template <class MessageBufferType>
|
||||
@@ -345,12 +348,12 @@ namespace Opm {
|
||||
buffer.read(this->thp);
|
||||
buffer.read(this->temperature);
|
||||
buffer.read(this->control);
|
||||
unsigned int size = 0.0; //this->completions.size();
|
||||
unsigned int size = 0.0; //this->connections.size();
|
||||
buffer.read(size);
|
||||
this->completions.resize(size);
|
||||
this->connections.resize(size);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto& comp = this->completions[ i ];
|
||||
auto& comp = this->connections[ i ];
|
||||
comp.read(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
99
opm/output/eclipse/AggregateWellData.hpp
Normal file
99
opm/output/eclipse/AggregateWellData.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
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_WELL_DATA_HPP
|
||||
#define OPM_AGGREGATE_WELL_DATA_HPP
|
||||
|
||||
#include <opm/output/eclipse/CharArrayNullTerm.hpp>
|
||||
#include <opm/output/eclipse/WindowedArray.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
class Schedule;
|
||||
class SummaryState;
|
||||
class UnitSystem;
|
||||
} // Opm
|
||||
|
||||
namespace Opm { namespace data {
|
||||
class WellRates;
|
||||
}} // Opm::data
|
||||
|
||||
namespace Opm { namespace RestartIO { namespace Helpers {
|
||||
|
||||
class AggregateWellData
|
||||
{
|
||||
public:
|
||||
explicit AggregateWellData(const std::vector<int>& inteHead);
|
||||
|
||||
void captureDeclaredWellData(const Opm::Schedule& sched,
|
||||
const Opm::UnitSystem& units,
|
||||
const std::size_t sim_step);
|
||||
|
||||
void captureDynamicWellData(const Opm::Schedule& sched,
|
||||
const std::size_t sim_step,
|
||||
const Opm::data::WellRates& xw,
|
||||
const Opm::SummaryState& smry);
|
||||
|
||||
/// Retrieve Integer Well Data Array.
|
||||
const std::vector<int>& getIWell() const
|
||||
{
|
||||
return this->iWell_.data();
|
||||
}
|
||||
|
||||
/// Retrieve Floating-Point (Real) Well Data Array.
|
||||
const std::vector<float>& getSWell() const
|
||||
{
|
||||
return this->sWell_.data();
|
||||
}
|
||||
|
||||
/// Retrieve Floating-Point (Double Precision) Well Data Array.
|
||||
const std::vector<double>& getXWell() const
|
||||
{
|
||||
return this->xWell_.data();
|
||||
}
|
||||
|
||||
/// Retrieve Character Well Data Array.
|
||||
const std::vector<CharArrayNullTerm<8>>& getZWell() const
|
||||
{
|
||||
return this->zWell_.data();
|
||||
}
|
||||
|
||||
private:
|
||||
/// Aggregate 'IWEL' array (Integer) for all wells.
|
||||
WindowedArray<int> iWell_;
|
||||
|
||||
/// Aggregate 'SWEL' array (Real) for all wells.
|
||||
WindowedArray<float> sWell_;
|
||||
|
||||
/// Aggregate 'XWEL' array (Double Precision) for all wells.
|
||||
WindowedArray<double> xWell_;
|
||||
|
||||
/// Aggregate 'ZWEL' array (Character) for all wells.
|
||||
WindowedArray<CharArrayNullTerm<8>> zWell_;
|
||||
|
||||
/// Maximum number of groups in model.
|
||||
int nWGMax_;
|
||||
};
|
||||
|
||||
}}} // Opm::RestartIO::Helpers
|
||||
|
||||
#endif // OPM_AGGREGATE_WELL_DATA_HPP
|
||||
103
opm/output/eclipse/CharArrayNullTerm.hpp
Normal file
103
opm/output/eclipse/CharArrayNullTerm.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
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_CHARARRAY_HEADER_HPP
|
||||
#define OPM_CHARARRAY_HEADER_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace Opm { namespace RestartIO { namespace Helpers {
|
||||
|
||||
/// Null-terminated, left adjusted, space padded array of N characters.
|
||||
///
|
||||
/// Simple container of character data. Exists solely for purpose of
|
||||
/// outputting std::string (or types convertible to std::string) as
|
||||
/// Fortran-style \code character (len=N) \endcode values.
|
||||
///
|
||||
/// \tparam N Number of characters.
|
||||
template <std::size_t N>
|
||||
class CharArrayNullTerm
|
||||
{
|
||||
public:
|
||||
CharArrayNullTerm()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
explicit CharArrayNullTerm(const std::string& s)
|
||||
: CharArrayNullTerm()
|
||||
{
|
||||
this->copy_in(s.c_str(), s.size());
|
||||
}
|
||||
|
||||
~CharArrayNullTerm() = default;
|
||||
|
||||
CharArrayNullTerm(const CharArrayNullTerm& rhs) = default;
|
||||
CharArrayNullTerm(CharArrayNullTerm&& rhs) = default;
|
||||
|
||||
CharArrayNullTerm& operator=(const CharArrayNullTerm& rhs) = default;
|
||||
CharArrayNullTerm& operator=(CharArrayNullTerm&& rhs) = default;
|
||||
|
||||
/// Assign from \code std::string \endcode.
|
||||
CharArrayNullTerm& operator=(const std::string& s)
|
||||
{
|
||||
this->clear();
|
||||
this->copy_in(s.data(), s.size());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char* c_str() const
|
||||
{
|
||||
return this->s_.data();
|
||||
}
|
||||
|
||||
private:
|
||||
enum : typename std::array<char, N + 1>::size_type { NChar = N };
|
||||
|
||||
std::array<char, NChar + 1> s_;
|
||||
|
||||
/// Clear contents of internal array (fill with ' ').
|
||||
void clear()
|
||||
{
|
||||
this->s_.fill(' ');
|
||||
this->s_[NChar] = '\0';
|
||||
}
|
||||
|
||||
/// Assign new value to internal array (left adjusted, space padded
|
||||
/// and null-terminated).
|
||||
void copy_in(const char* s,
|
||||
const typename std::array<char, NChar + 1>::size_type len)
|
||||
{
|
||||
const auto ncpy = std::min(len, static_cast<decltype(len)>(NChar));
|
||||
|
||||
// Note: Not strcpy() or strncpy() here. The former has no bounds
|
||||
// checking, the latter writes a null-terminator at position 'ncpy'
|
||||
// (s_[ncpy]) which violates the post condition if ncpy < NChar.
|
||||
std::memcpy(this->s_.data(), s,
|
||||
ncpy * sizeof *this->s_.data());
|
||||
}
|
||||
};
|
||||
|
||||
}}} // Opm::RestartIO::Helpers
|
||||
#endif // CHARARRAY_HEADER
|
||||
71
opm/output/eclipse/DoubHEAD.hpp
Executable file
71
opm/output/eclipse/DoubHEAD.hpp
Executable file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright 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_DOUBHEAD_HEADER_INCLUDED
|
||||
#define OPM_DOUBHEAD_HEADER_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
class Tuning;
|
||||
class Schedule;
|
||||
}
|
||||
|
||||
namespace Opm { namespace RestartIO {
|
||||
|
||||
class DoubHEAD
|
||||
{
|
||||
public:
|
||||
struct TimeStamp {
|
||||
std::chrono::time_point<std::chrono::system_clock> start;
|
||||
std::chrono::duration<double, std::chrono::seconds::period> elapsed;
|
||||
};
|
||||
|
||||
DoubHEAD();
|
||||
|
||||
~DoubHEAD() = default;
|
||||
DoubHEAD(const DoubHEAD& rhs) = default;
|
||||
DoubHEAD(DoubHEAD&& rhs) = default;
|
||||
|
||||
DoubHEAD& operator=(const DoubHEAD& rhs) = default;
|
||||
DoubHEAD& operator=(DoubHEAD&& rhs) = default;
|
||||
|
||||
DoubHEAD& tuningParameters(const Tuning& tuning,
|
||||
const std::size_t lookup_step,
|
||||
const double cnvT);
|
||||
|
||||
DoubHEAD& timeStamp(const TimeStamp& ts);
|
||||
|
||||
DoubHEAD& drsdt(const Schedule& sched,
|
||||
const std::size_t lookup_step);
|
||||
|
||||
const std::vector<double>& data() const
|
||||
{
|
||||
return this->data_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<double> data_;
|
||||
};
|
||||
|
||||
}} // Opm::RestartIO
|
||||
|
||||
#endif // OPM_DOUBHEAD_HEADER_INCLUDED
|
||||
@@ -173,12 +173,10 @@ public:
|
||||
void writeTimeStep( int report_step,
|
||||
bool isSubstep,
|
||||
double seconds_elapsed,
|
||||
data::Solution,
|
||||
data::Wells,
|
||||
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 std::map<std::string, std::vector<double>>& extra_restart = {},
|
||||
bool write_double = false);
|
||||
|
||||
|
||||
@@ -220,7 +218,7 @@ 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(const std::map<std::string, RestartKey>& keys, const std::map<std::string, bool>& extra_keys = {}) const;
|
||||
RestartValue loadRestart(const std::vector<RestartKey>& solution_keys, const std::vector<RestartKey>& extra_keys = {}) const;
|
||||
|
||||
|
||||
EclipseIO( const EclipseIO& ) = delete;
|
||||
|
||||
132
opm/output/eclipse/InteHEAD.hpp
Executable file
132
opm/output/eclipse/InteHEAD.hpp
Executable file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Copyright 2016, 2017, 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_INTEHEAD_HEADER_INCLUDED
|
||||
#define OPM_INTEHEAD_HEADER_INCLUDED
|
||||
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm { namespace RestartIO {
|
||||
|
||||
class InteHEAD
|
||||
{
|
||||
public:
|
||||
enum class UnitSystem {
|
||||
Metric, Field, Lab, PVT_M
|
||||
};
|
||||
|
||||
struct WellTableDim {
|
||||
int numWells;
|
||||
int maxPerf;
|
||||
int maxWellInGroup;
|
||||
int maxGroupInField;
|
||||
};
|
||||
|
||||
struct WellSegDims {
|
||||
int nsegwl;
|
||||
int nswlmx;
|
||||
int nsegmx;
|
||||
int nlbrmx;
|
||||
int nisegz;
|
||||
int nrsegz;
|
||||
int nilbrz;
|
||||
};
|
||||
|
||||
struct RegDims {
|
||||
int ntfip;
|
||||
int nmfipr;
|
||||
int nrfreg;
|
||||
int ntfreg;
|
||||
int nplmix;
|
||||
};
|
||||
|
||||
struct TimePoint {
|
||||
int year;
|
||||
int month; // 1..12
|
||||
int day; // 1..31
|
||||
|
||||
int hour; // 0..23
|
||||
int minute; // 0..59
|
||||
int second; // 0..59
|
||||
|
||||
int microseconds; // 0..999999
|
||||
};
|
||||
|
||||
struct Phases {
|
||||
int oil;
|
||||
int water;
|
||||
int gas;
|
||||
};
|
||||
|
||||
struct TuningPar {
|
||||
int newtmx;
|
||||
int newtmn;
|
||||
int litmax;
|
||||
int litmin;
|
||||
int mxwsit;
|
||||
int mxwpit;
|
||||
};
|
||||
|
||||
InteHEAD();
|
||||
~InteHEAD() = default;
|
||||
|
||||
InteHEAD(const InteHEAD& rhs) = default;
|
||||
InteHEAD(InteHEAD&& rhs) = default;
|
||||
|
||||
InteHEAD& operator=(const InteHEAD& rhs) = default;
|
||||
InteHEAD& operator=(InteHEAD&& rhs) = default;
|
||||
|
||||
InteHEAD& dimensions(const int nx, const int ny, const int nz);
|
||||
InteHEAD& dimensions(const std::array<int,3>& cartDims);
|
||||
InteHEAD& numActive(const int nactive);
|
||||
|
||||
InteHEAD& unitConventions(const UnitSystem& usys);
|
||||
InteHEAD& wellTableDimensions(const WellTableDim& wtdim);
|
||||
InteHEAD& calendarDate(const TimePoint& date);
|
||||
InteHEAD& activePhases(const Phases& phases);
|
||||
InteHEAD& params_NWELZ(const int niwelz, const int nswelz, const int nxwelz, const int nzwelz);
|
||||
InteHEAD& params_NCON(const int niconz, const int nsconz, const int nxconz);
|
||||
InteHEAD& params_GRPZ(const std::array<int, 4>& grpz);
|
||||
InteHEAD& params_NAAQZ(const int ncamax, const int niaaqz, const int nsaaqz, const int nxaaqz, const int nicaqz, const int nscaqz, const int nacaqz);
|
||||
InteHEAD& stepParam(const int tstep, const int report_step);
|
||||
InteHEAD& tuningParam(const TuningPar& tunpar);
|
||||
InteHEAD& variousParam(const int version, const int iprog);
|
||||
InteHEAD& wellSegDimensions(const WellSegDims& wsdim);
|
||||
InteHEAD& regionDimensions(const RegDims& rdim);
|
||||
|
||||
const std::vector<int>& data() const
|
||||
{
|
||||
return this->data_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<int> data_;
|
||||
};
|
||||
|
||||
std::time_t makeUTCTime(const std::tm& timePoint);
|
||||
|
||||
InteHEAD::TimePoint
|
||||
getSimulationTimePoint(const std::time_t start,
|
||||
const double elapsed);
|
||||
}} // Opm::RestartIO
|
||||
|
||||
#endif // OPM_INTEHEAD_HEADER_INCLUDED
|
||||
54
opm/output/eclipse/LogiHEAD.hpp
Normal file
54
opm/output/eclipse/LogiHEAD.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2016, 2017 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_LOGIHEAD_HEADER_INCLUDED
|
||||
#define OPM_LOGIHEAD_HEADER_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Opm { namespace RestartIO {
|
||||
|
||||
class LogiHEAD
|
||||
{
|
||||
public:
|
||||
LogiHEAD();
|
||||
~LogiHEAD() = default;
|
||||
|
||||
LogiHEAD(const LogiHEAD& rhs) = default;
|
||||
LogiHEAD(LogiHEAD&& rhs) = default;
|
||||
|
||||
LogiHEAD& operator=(const LogiHEAD& rhs) = default;
|
||||
LogiHEAD& operator=(LogiHEAD&& rhs) = default;
|
||||
|
||||
LogiHEAD& variousParam(const bool e300_radial,
|
||||
const bool e100_radial,
|
||||
const int nswlmx);
|
||||
|
||||
const std::vector<bool>& data() const
|
||||
{
|
||||
return this->data_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<bool> data_;
|
||||
};
|
||||
|
||||
}} // Opm::RestartIO
|
||||
|
||||
#endif // OPM_LOGIHEAD_HEADER_INCLUDED
|
||||
@@ -32,12 +32,12 @@ namespace out {
|
||||
public:
|
||||
RegionCache() = default;
|
||||
RegionCache(const Eclipse3DProperties& properties, const EclipseGrid& grid, const Schedule& schedule);
|
||||
const std::vector<std::pair<std::string,size_t>>& completions( int region_id ) const;
|
||||
const std::vector<std::pair<std::string,size_t>>& connections( int region_id ) const;
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::string,size_t>> completions_empty;
|
||||
std::vector<std::pair<std::string,size_t>> connections_empty;
|
||||
|
||||
std::map<int , std::vector<std::pair<std::string,size_t>>> completion_map;
|
||||
std::map<int , std::vector<std::pair<std::string,size_t>>> connection_map;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,22 +75,20 @@ namespace RestartIO {
|
||||
void save(const std::string& filename,
|
||||
int report_step,
|
||||
double seconds_elapsed,
|
||||
data::Solution cells,
|
||||
data::Wells wells,
|
||||
RestartValue value,
|
||||
const EclipseState& es,
|
||||
const EclipseGrid& grid,
|
||||
const Schedule& schedule,
|
||||
std::map<std::string, std::vector<double>> extra_data = {},
|
||||
bool write_double = false);
|
||||
bool write_double = false);
|
||||
|
||||
|
||||
RestartValue load( const std::string& filename,
|
||||
int report_step,
|
||||
const std::map<std::string, RestartKey>& keys,
|
||||
const std::vector<RestartKey>& solution_keys,
|
||||
const EclipseState& es,
|
||||
const EclipseGrid& grid,
|
||||
const Schedule& schedule,
|
||||
const std::map<std::string, bool>& extra_keys = {});
|
||||
const std::vector<RestartKey>& extra_keys = {});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,39 +22,30 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
|
||||
#include <opm/output/data/Solution.hpp>
|
||||
#include <opm/output/data/Wells.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
|
||||
/*
|
||||
Small convenience class used in the map passed to the
|
||||
RestartIO::load( ) function. A class instance can be constructed
|
||||
from a UnitSystem::measure value, which will default to a
|
||||
required key, but it can also be constructed from a
|
||||
two-parameter constructor, and then the required/not required
|
||||
can controlled explicitly:
|
||||
|
||||
|
||||
RestartIO::load(..., {{"PRESSURE" , UnitSystem::measure::pressure},
|
||||
{"MAX_SWAT" , {UnitSystem::measure::identity, false}} )
|
||||
|
||||
The RestartKey( ) for pressure is implicitly created from
|
||||
UnitSystem::measure::pressure and will be required, whereas the
|
||||
MAX_SWAT keyword is optional.
|
||||
|
||||
*/
|
||||
class RestartKey {
|
||||
public:
|
||||
|
||||
std::string key;
|
||||
UnitSystem::measure dim;
|
||||
bool required = true;
|
||||
bool required;
|
||||
|
||||
explicit RestartKey( UnitSystem::measure _dim)
|
||||
: dim(_dim)
|
||||
RestartKey( const std::string& _key, UnitSystem::measure _dim)
|
||||
: key(_key),
|
||||
dim(_dim),
|
||||
required(true)
|
||||
{}
|
||||
|
||||
|
||||
RestartKey( UnitSystem::measure _dim, bool _required)
|
||||
: dim(_dim),
|
||||
RestartKey( const std::string& _key, UnitSystem::measure _dim, bool _required)
|
||||
: key(_key),
|
||||
dim(_dim),
|
||||
required(_required)
|
||||
{}
|
||||
|
||||
@@ -62,32 +53,24 @@ namespace Opm {
|
||||
|
||||
|
||||
/*
|
||||
A simple struct - the only purpose is to facilitate return by value from the
|
||||
RestartIO::load( ) function.
|
||||
A simple class used to communicate values between the simulator and the
|
||||
RestartIO function.
|
||||
*/
|
||||
|
||||
|
||||
struct RestartValue {
|
||||
|
||||
class RestartValue {
|
||||
public:
|
||||
using ExtraVector = std::vector<std::pair<RestartKey, std::vector<double>>>;
|
||||
data::Solution solution;
|
||||
data::Wells wells;
|
||||
std::map<std::string,std::vector<double>> extra = {};
|
||||
ExtraVector extra;
|
||||
|
||||
RestartValue(data::Solution sol, data::Wells wells_arg);
|
||||
|
||||
RestartValue(data::Solution sol, data::Wells wells_arg, std::map<std::string, std::vector<double>> extra_arg) :
|
||||
solution(std::move(sol)),
|
||||
wells(std::move(wells_arg)),
|
||||
extra(std::move(extra_arg))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RestartValue(data::Solution sol, data::Wells wells_arg) :
|
||||
solution(std::move(sol)),
|
||||
wells(std::move(wells_arg))
|
||||
{
|
||||
}
|
||||
|
||||
bool hasExtra(const std::string& key) const;
|
||||
void addExtra(const std::string& key, UnitSystem::measure dimension, std::vector<double> data);
|
||||
void addExtra(const std::string& key, std::vector<double> data);
|
||||
const std::vector<double>& getExtra(const std::string& key) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
|
||||
#include <opm/output/eclipse/SummaryState.hpp>
|
||||
#include <opm/output/data/Wells.hpp>
|
||||
#include <opm/output/eclipse/RegionCache.hpp>
|
||||
|
||||
@@ -61,6 +62,8 @@ class Summary {
|
||||
|
||||
~Summary();
|
||||
|
||||
const SummaryState& get_restart_vectors() const;
|
||||
|
||||
private:
|
||||
class keyword_handlers;
|
||||
|
||||
@@ -68,8 +71,8 @@ class Summary {
|
||||
out::RegionCache regionCache;
|
||||
ERT::ert_unique_ptr< ecl_sum_type, ecl_sum_free > ecl_sum;
|
||||
std::unique_ptr< keyword_handlers > handlers;
|
||||
const ecl_sum_tstep_type* prev_tstep = nullptr;
|
||||
double prev_time_elapsed = 0;
|
||||
SummaryState prev_state;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
50
opm/output/eclipse/SummaryState.hpp
Normal file
50
opm/output/eclipse/SummaryState.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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 SUMMARY_STATE_H
|
||||
#define SUMMARY_STATE_H
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Opm{
|
||||
|
||||
|
||||
/*
|
||||
The purpose of this class is to serve as a small container object for
|
||||
computed, ready to use summary values. The values will typically be used by
|
||||
the UDQ, WTEST and ACTIONX calculations. Observe that all value *have been
|
||||
converted to the correct output units*.
|
||||
*/
|
||||
class SummaryState {
|
||||
public:
|
||||
typedef std::unordered_map<std::string, double>::const_iterator const_iterator;
|
||||
|
||||
void add(const std::string& key, double value);
|
||||
double get(const std::string&) const;
|
||||
bool has(const std::string& key) const;
|
||||
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
private:
|
||||
std::unordered_map<std::string,double> values;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
90
opm/output/eclipse/VectorItems/intehead.hpp
Normal file
90
opm/output/eclipse/VectorItems/intehead.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright (c) 2018 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_INTEHEAD_HPP
|
||||
#define OPM_OUTPUT_ECLIPSE_VECTOR_INTEHEAD_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
|
||||
|
||||
// This is a subset of the items in src/opm/output/eclipse/InteHEAD.cpp .
|
||||
// Promote items from that list to this in order to make them public.
|
||||
enum intehead : std::vector<int>::size_type {
|
||||
ISNUM = 0, // An encoded integer corresponding to the
|
||||
// time the file was created. For files not
|
||||
// originating from ECLIPSE, this value may
|
||||
// be set to zero.
|
||||
|
||||
VERSION = 1, // Simulator version
|
||||
UNIT = 2, // Units convention
|
||||
// 1: METRIC, 2: FIELD, 3: LAB, 4: PVT-M
|
||||
|
||||
NX = 8, // #cells in X direction (Cartesian)
|
||||
NY = 9, // #cells in Y direction (Cartesian)
|
||||
NZ = 10, // #cells in Z direction (Cartesian)
|
||||
NACTIV = 11, // Number of active cells
|
||||
|
||||
PHASE = 14, // Phase indicator:
|
||||
// 1: oil, 2: water, 3: O/W, 4: gas,
|
||||
// 5: G/O, 6: G/W, 7: O/G/W
|
||||
|
||||
NWELLS = 16, // Number of wells
|
||||
NCWMAX = 17, // Maximum number of completions per well
|
||||
NWGMAX = 19, // Maximum number of wells in any well group
|
||||
NGMAXZ = 20, // Maximum number of groups in field
|
||||
|
||||
NIWELZ = 24, // Number of data elements per well in IWEL array
|
||||
// (default 97 for ECLIPSE, 94 for ECLIPSE 300).
|
||||
NSWELZ = 25, // Number of data elements per well in SWEL array
|
||||
NXWELZ = 26, // Number of delements per well in XWEL array
|
||||
NZWELZ = 27, // Number of 8-character words per well in ZWEL array
|
||||
|
||||
NICONZ = 32, // Number of data elements per completion
|
||||
// in ICON array (default 19)
|
||||
NSCONZ = 33, // Number of data elements per completion in SCON array
|
||||
NXCONZ = 34, // Number of data elements per completion in XCON array
|
||||
|
||||
NIGRPZ = 36, // Number of data elements per group in IGRP array
|
||||
NSGRPZ = 37, // Number of data elements per group in SGRP array
|
||||
NXGRPZ = 38, // Number of data elements per group in XGRP array
|
||||
NZGRPZ = 39, // Number of data elements per group in ZGRP array
|
||||
|
||||
NCAMAX = 41, // Maximum number of analytic aquifer connections
|
||||
|
||||
NIAAQZ = 42, // Number of data elements per aquifer in IAAQ array
|
||||
NSAAQZ = 43, // Number of data elements per aquifer in SAAQ array
|
||||
NXAAQZ = 44, // Number of data elements per aquifer in XAAQ array
|
||||
|
||||
NICAQZ = 45, // Number of data elements per aquifer connection in ICAQ array
|
||||
NSCAQZ = 46, // Number of data elements per aquifer connection in SCAQ array
|
||||
NACAQZ = 47, // Number of data elements per aquifer connection in ACAQ array
|
||||
|
||||
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)
|
||||
NLBRMX = 177, // Maximum number of lateral branches (item 3 of WSEGDIMS)
|
||||
|
||||
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
|
||||
};
|
||||
}}}} // Opm::RestartIO::Helpers::VectorItems
|
||||
|
||||
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_INTEHEAD_HPP
|
||||
164
opm/output/eclipse/VectorItems/well.hpp
Normal file
164
opm/output/eclipse/VectorItems/well.hpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
Copyright (c) 2018 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_WELL_HPP
|
||||
#define OPM_OUTPUT_ECLIPSE_VECTOR_WELL_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
|
||||
|
||||
namespace IWell {
|
||||
enum index : std::vector<int>::size_type {
|
||||
IHead = 0, // I-location (one-based) of well head
|
||||
JHead = 1, // J-location (one-based) of well head
|
||||
FirstK = 2, // Layer ID (one-based) of top/first connection
|
||||
LastK = 3, // Layer ID (one-based) of bottom/last connection
|
||||
NConn = 4, // Number of active cells connected to well
|
||||
Group = 5, // Index (one-based) of well's current group
|
||||
WType = 6, // Well type
|
||||
WCtrl = 7, // Well control
|
||||
|
||||
item9 = 8, // Unknown
|
||||
item11 = 10, // Unknown
|
||||
|
||||
VFPTab = 11, // ID (one-based) of well's current VFP table
|
||||
|
||||
item18 = 17, // Unknown
|
||||
item25 = 24, // Unknown
|
||||
item32 = 31, // Unknown
|
||||
item48 = 47, // Unknown
|
||||
item50 = 49, // Unknown
|
||||
|
||||
MsWID = 70, // Multisegment well ID
|
||||
// Value 0 for regular wells
|
||||
// Value 1..#MS wells for MS wells
|
||||
NWseg = 71, // Number of well segments
|
||||
// Value 0 for regular wells
|
||||
// Value #segments for MS wells
|
||||
|
||||
CompOrd = 98, // Well's completion ordering scheme.
|
||||
};
|
||||
|
||||
namespace Value {
|
||||
enum WellType : int {
|
||||
WTUnk = 0, // Unknown well type (OPM only)
|
||||
Producer = 1, // Well is producer
|
||||
OilInj = 2, // Well is oil injector
|
||||
WatInj = 3, // Well is water injector
|
||||
GasInj = 4, // Well is gas injector
|
||||
};
|
||||
|
||||
enum WellCtrlMode : int {
|
||||
WMCtlUnk = -10, // Unknown well control mode (OPM only)
|
||||
Group = - 1, // Well under group control
|
||||
Shut = 0, // Well is shut
|
||||
OilRate = 1, // Well controlled by oil rate
|
||||
WatRate = 2, // Well controlled by water rate
|
||||
GasRate = 3, // Well controlled by gas rate
|
||||
LiqRate = 4, // Well controlled by liquid rate
|
||||
|
||||
ResVRate = 5, // Well controlled by
|
||||
// reservoir voidage rate
|
||||
|
||||
THP = 6, // Well controlled by
|
||||
// tubing head pressure target
|
||||
|
||||
BHP = 7, // Well controlled by
|
||||
// bottom-hole pressure target
|
||||
|
||||
CombRate = 9, // Well controlled by linearly
|
||||
// combined rate target
|
||||
};
|
||||
|
||||
enum CompOrder : int {
|
||||
Track = 0, // Connections ordered along
|
||||
// well track (increasing MD)
|
||||
|
||||
Depth = 1, // Connections ordered by inceasing
|
||||
// true vertical depth. Not really
|
||||
// supported in OPM Flow.
|
||||
|
||||
Input = 2, // Connections listed in order of
|
||||
// appearance in simulation model's
|
||||
// COMPDAT keyword.
|
||||
};
|
||||
} // Value
|
||||
} // IWell
|
||||
|
||||
namespace SWell {
|
||||
enum index : std::vector<float>::size_type {
|
||||
OilRateTarget = 0, // Well's current oil rate production target
|
||||
WatRateTarget = 1, // Well's current water rate production target
|
||||
GasRateTarget = 2, // Well's current gas rate production target
|
||||
LiqRateTarget = 3, // Well's current liquid rate production target
|
||||
ResVRateTarget = 4, // Well's current reservoir voidate rate
|
||||
// production target
|
||||
|
||||
THPTarget = 5, // Well's tubing head pressure target
|
||||
BHPTarget = 6, // Well's bottom hole pressure target
|
||||
|
||||
DatumDepth = 9, // Well's reference depth for BHP
|
||||
};
|
||||
} // SWell
|
||||
|
||||
namespace XWell {
|
||||
enum index : std::vector<double>::size_type {
|
||||
OilPrRate = 0, // Well's oil production rate
|
||||
WatPrRate = 1, // Well's water production rate
|
||||
GasPrRate = 2, // Well's gas production rate
|
||||
LiqPrRate = 3, // Well's liquid production rate
|
||||
VoidPrRate = 4, // Well's reservoir voidage production rate
|
||||
|
||||
FlowBHP = 6, // Well's flowing/producing bottom hole pressure
|
||||
WatCut = 7, // Well's producing water cut
|
||||
GORatio = 8, // Well's producing gas/oil ratio
|
||||
|
||||
OilPrTotal = 18, // Well's total cumulative oil production
|
||||
WatPrTotal = 19, // Well's total cumulative water production
|
||||
GasPrTotal = 20, // Well's total cumulative gas production
|
||||
VoidPrTotal = 21, // Well's total cumulative reservoir
|
||||
// voidage production
|
||||
|
||||
WatInjTotal = 23, // Well's total cumulative water injection
|
||||
GasInjTotal = 24, // Well's total cumulative gas injection
|
||||
|
||||
GasFVF = 34, // Well's producing gas formation volume factor.
|
||||
|
||||
item37 = 36, // Unknown
|
||||
item38 = 37, // Unknown
|
||||
|
||||
BHPTarget = 41, // Well's current BHP Target/Limit
|
||||
|
||||
item82 = 81, // Unknown
|
||||
item83 = 82, // Unknown
|
||||
|
||||
WatVoidPrRate = 122, // Well's voidage production rate
|
||||
GasVoidPrRate = 123, // Well's voidage production rate
|
||||
};
|
||||
} // XWell
|
||||
|
||||
namespace ZWell {
|
||||
enum index : std::vector<const char*>::size_type {
|
||||
WellName = 0, // Well name
|
||||
};
|
||||
} // ZWell
|
||||
}}}} // Opm::RestartIO::Helpers::VectorItems
|
||||
|
||||
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_WELL_HPP
|
||||
262
opm/output/eclipse/WindowedArray.hpp
Normal file
262
opm/output/eclipse/WindowedArray.hpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
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_WINDOWED_ARRAY_HPP
|
||||
#define OPM_WINDOWED_ARRAY_HPP
|
||||
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
|
||||
/// \file
|
||||
///
|
||||
/// Provide facilities to simplify constructing restart vectors
|
||||
/// such as IWEL or RSEG.
|
||||
|
||||
namespace Opm { namespace RestartIO { namespace Helpers {
|
||||
|
||||
/// Provide read-only and read/write access to constantly sized
|
||||
/// portions/windows of a linearised buffer with an implied
|
||||
/// 1D array structure.
|
||||
///
|
||||
/// Intended as backing store for vectors that have a constant
|
||||
/// number of items per entity (e.g., N integer data items for
|
||||
/// each active group at a report step).
|
||||
///
|
||||
/// \tparam T Element type for underlying data items.
|
||||
template <typename T>
|
||||
class WindowedArray
|
||||
{
|
||||
public:
|
||||
/// Read/write access.
|
||||
using WriteWindow = boost::iterator_range<
|
||||
typename std::vector<T>::iterator>;
|
||||
|
||||
/// Read-only access.
|
||||
using ReadWindow = boost::iterator_range<
|
||||
typename std::vector<T>::const_iterator>;
|
||||
|
||||
using Idx = typename std::vector<T>::size_type;
|
||||
|
||||
/// Distinct compile-time type for number of windows in
|
||||
/// underlying storage.
|
||||
struct NumWindows { Idx value; };
|
||||
|
||||
/// Distinct compile-time type for size of windows
|
||||
/// (number of data items per window.)
|
||||
struct WindowSize { Idx value; };
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param[in] n Number of windows.
|
||||
/// \param[in] sz Number of data items per window.
|
||||
explicit WindowedArray(const NumWindows n, const WindowSize sz)
|
||||
: x_ (n.value * sz.value)
|
||||
, windowSize_(sz.value)
|
||||
{}
|
||||
|
||||
/// Retrieve number of windows allocated for this array.
|
||||
Idx numWindows() const
|
||||
{
|
||||
return this->x_.size() / this->windowSize_;
|
||||
}
|
||||
|
||||
/// Retrieve number of data items per windows.
|
||||
Idx windowSize() const
|
||||
{
|
||||
return this->windowSize_;
|
||||
}
|
||||
|
||||
/// Request read/write access to individual window.
|
||||
///
|
||||
/// \param[in] window Numeric ID of particular read/write window.
|
||||
/// Must be in range \code [0 .. numWindows()-1] \endcode.
|
||||
WriteWindow operator[](const Idx window)
|
||||
{
|
||||
assert ((window < this->numWindows()) &&
|
||||
"Window ID Out of Bounds");
|
||||
|
||||
auto b = std::begin(this->x_) + window*this->windowSize_;
|
||||
auto e = b + this->windowSize_;
|
||||
|
||||
return { b, e };
|
||||
}
|
||||
|
||||
/// Request read-only access to individual window.
|
||||
///
|
||||
/// \param[in] window Numeric ID of particular read-only window.
|
||||
/// Must be in range \code [0 .. numWindows()-1] \endcode.
|
||||
ReadWindow operator[](const Idx window) const
|
||||
{
|
||||
assert ((window < this->numWindows()) &&
|
||||
"Window ID Out of Bounds");
|
||||
|
||||
auto b = std::begin(this->x_) + window*this->windowSize_;
|
||||
auto e = b + this->windowSize_;
|
||||
|
||||
return { b, e };
|
||||
}
|
||||
|
||||
/// Get read-only access to full, linearised data items for
|
||||
/// all windows.
|
||||
const std::vector<T>& data() const
|
||||
{
|
||||
return this->x_;
|
||||
}
|
||||
|
||||
/// Extract full, linearised data items for all windows.
|
||||
///
|
||||
/// Destroys the internal state of the \c WindowedArray.
|
||||
std::vector<T> getDataDestructively()
|
||||
{
|
||||
return std::move(this->x_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> x_;
|
||||
|
||||
Idx windowSize_;
|
||||
};
|
||||
|
||||
|
||||
/// Provide read-only and read/write access to constantly sized
|
||||
/// portions/windows of a linearised buffer with an implied
|
||||
/// row/column matrix (2D array) structure.
|
||||
///
|
||||
/// Intended as backing store for vectors that have a constant
|
||||
/// number of items per sub-entity of a fixed number of containing
|
||||
/// entities (e.g., K double precision data items for each of N
|
||||
/// maximum well connections for each of M maximum active wells at
|
||||
/// a particular report step).
|
||||
///
|
||||
/// \tparam T Element type for underlying data items.
|
||||
template <typename T>
|
||||
class WindowedMatrix
|
||||
{
|
||||
private:
|
||||
using NumWindows = typename WindowedArray<T>::NumWindows;
|
||||
|
||||
public:
|
||||
using WriteWindow = typename WindowedArray<T>::WriteWindow;
|
||||
using ReadWindow = typename WindowedArray<T>::ReadWindow;
|
||||
using WindowSize = typename WindowedArray<T>::WindowSize;
|
||||
using Idx = typename WindowedArray<T>::Idx;
|
||||
|
||||
/// Distinct compile-time type for number of matrix rows
|
||||
/// in underlying storage.
|
||||
struct NumRows { Idx value; };
|
||||
|
||||
/// Distinct compile-time type for number of matrix columns
|
||||
/// in underlying storage.
|
||||
struct NumCols { Idx value; };
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param[in] nRows Number of rows.
|
||||
/// \param[in] nCols Number of columns.
|
||||
/// \param[in] sz Number of data items per (row,column) window.
|
||||
explicit WindowedMatrix(const NumRows& nRows,
|
||||
const NumCols& nCols,
|
||||
const WindowSize& sz)
|
||||
: data_ (NumWindows{ nRows.value * nCols.value }, sz)
|
||||
, numCols_(nCols.value)
|
||||
{}
|
||||
|
||||
/// Retrieve number of columns allocated for this matrix.
|
||||
Idx numCols() const
|
||||
{
|
||||
return this->numCols_;
|
||||
}
|
||||
|
||||
/// Retrieve number of rows allocated for this matrix.
|
||||
Idx numRows() const
|
||||
{
|
||||
return this->data_.numWindows() / this->numCols();
|
||||
}
|
||||
|
||||
/// Retrieve number of data items per windows.
|
||||
Idx windowSize() const
|
||||
{
|
||||
return this->data_.windowSize();
|
||||
}
|
||||
|
||||
/// Request read/write access to individual window.
|
||||
///
|
||||
/// \param[in] row Numeric ID of particular row in matrix.
|
||||
/// Must be in range \code [0 .. numRows()-1] \endcode.
|
||||
///
|
||||
/// \param[in] col Numeric ID of particular column in matrix.
|
||||
/// Must be in range \code [0 .. numCols()-1] \endcode.
|
||||
///
|
||||
/// \return Read/write window at position \code (row,col) \endcode.
|
||||
WriteWindow operator()(const Idx row, const Idx col)
|
||||
{
|
||||
return this->data_[ this->i(row, col) ];
|
||||
}
|
||||
|
||||
/// Request read-only access to individual window.
|
||||
///
|
||||
/// \param[in] row Numeric ID of particular row in matrix.
|
||||
/// Must be in range \code [0 .. numRows()-1] \endcode.
|
||||
///
|
||||
/// \param[in] col Numeric ID of particular column in matrix.
|
||||
/// Must be in range \code [0 .. numCols()-1] \endcode.
|
||||
///
|
||||
/// \return Read-only window at position \code (row,col) \endcode.
|
||||
ReadWindow operator()(const Idx row, const Idx col) const
|
||||
{
|
||||
return this->data_[ this->i(row, col) ];
|
||||
}
|
||||
|
||||
/// Get read-only access to full, linearised data items for
|
||||
/// all windows.
|
||||
auto data() const
|
||||
-> decltype(std::declval<const WindowedArray<T>>().data())
|
||||
{
|
||||
return this->data_.data();
|
||||
}
|
||||
|
||||
/// Extract full, linearised data items for all windows.
|
||||
///
|
||||
/// Destroys the internal state of the \c WindowedMatrix.
|
||||
auto getDataDestructively()
|
||||
-> decltype(std::declval<WindowedArray<T>>()
|
||||
.getDataDestructively())
|
||||
{
|
||||
return this->data_.getDataDestructively();
|
||||
}
|
||||
|
||||
private:
|
||||
WindowedArray<T> data_;
|
||||
|
||||
Idx numCols_;
|
||||
|
||||
/// Row major (C) order.
|
||||
Idx i(const Idx row, const Idx col) const
|
||||
{
|
||||
return row*this->numCols() + col;
|
||||
}
|
||||
};
|
||||
|
||||
}}} // Opm::RestartIO::Helpers
|
||||
|
||||
#endif // OPM_WINDOW_ARRAY_HPP
|
||||
79
opm/output/eclipse/WriteRestartHelpers.hpp
Executable file
79
opm/output/eclipse/WriteRestartHelpers.hpp
Executable file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
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_WRITE_RESTART_HELPERS_HPP
|
||||
#define OPM_WRITE_RESTART_HELPERS_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
// Missing definitions (really belong in ert/ecl_well/well_const.h, but not
|
||||
// defined there)
|
||||
#define SCON_KH_INDEX 3
|
||||
|
||||
|
||||
// Forward declarations
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class EclipseGrid;
|
||||
class EclipseState;
|
||||
class Schedule;
|
||||
class Well;
|
||||
class UnitSystem;
|
||||
|
||||
} // Opm
|
||||
|
||||
namespace Opm { namespace RestartIO { namespace Helpers {
|
||||
|
||||
const double UNIMPLEMENTED_VALUE = 1e-100; // placeholder for values not yet available
|
||||
|
||||
std::vector<double>
|
||||
createDoubHead(const EclipseState& es,
|
||||
const Schedule& sched,
|
||||
const std::size_t lookup_step,
|
||||
const double simTime);
|
||||
|
||||
|
||||
|
||||
std::vector<int>
|
||||
createInteHead(const EclipseState& es,
|
||||
const EclipseGrid& grid,
|
||||
const Schedule& sched,
|
||||
const double simTime,
|
||||
const int num_solver_steps,
|
||||
const int lookup_step, // The integer index used to look up dynamic properties, e.g. the number of well.
|
||||
const int report_step); // The integer number this INTEHEAD keyword will be saved to, typically report_step = lookup_step + 1.
|
||||
|
||||
std::vector<bool>
|
||||
createLogiHead(const EclipseState& es);
|
||||
|
||||
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
|
||||
|
||||
#endif // OPM_WRITE_RESTART_HELPERS_HPP
|
||||
@@ -131,6 +131,9 @@ namespace Opm {
|
||||
|
||||
Deck( const Deck& );
|
||||
|
||||
//! \brief Deleted assignment operator.
|
||||
Deck& operator=(const Deck& rhs) = delete;
|
||||
|
||||
void addKeyword( DeckKeyword&& keyword );
|
||||
void addKeyword( const DeckKeyword& keyword );
|
||||
|
||||
@@ -141,7 +144,8 @@ namespace Opm {
|
||||
UnitSystem& getActiveUnitSystem();
|
||||
UnitSystem& getDefaultUnitSystem();
|
||||
|
||||
const std::string getDataFile() const;
|
||||
const std::string& getInputPath() const;
|
||||
const std::string& getDataFile() const;
|
||||
void setDataFile(const std::string& dataFile);
|
||||
|
||||
iterator begin();
|
||||
@@ -156,6 +160,7 @@ namespace Opm {
|
||||
UnitSystem activeUnits;
|
||||
|
||||
std::string m_dataFile;
|
||||
std::string input_path;
|
||||
};
|
||||
}
|
||||
#endif /* DECK_HPP */
|
||||
|
||||
@@ -28,7 +28,8 @@ namespace Opm {
|
||||
|
||||
class DeckOutput {
|
||||
public:
|
||||
explicit DeckOutput(std::ostream& s);
|
||||
explicit DeckOutput(std::ostream& s, int precision = 10);
|
||||
~DeckOutput();
|
||||
void stash_default( );
|
||||
|
||||
void start_record( );
|
||||
@@ -51,9 +52,11 @@ namespace Opm {
|
||||
size_t default_count;
|
||||
size_t row_count;
|
||||
bool record_on;
|
||||
int org_precision;
|
||||
|
||||
template <typename T> void write_value(const T& value);
|
||||
void write_sep( );
|
||||
void set_precision(int precision);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Tables/TableContainer.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Tables/AqutabTable.hpp>
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
@@ -57,9 +58,10 @@ namespace Opm {
|
||||
k_a , //aquifer permeability
|
||||
c1, // 0.008527 (METRIC, PVT-M); 0.006328 (FIELD); 3.6 (LAB)
|
||||
h , //aquifer thickness
|
||||
p0, //Initial aquifer pressure at datum depth, d0
|
||||
theta , //angle subtended by the aquifer boundary
|
||||
c2 ; //6.283 (METRIC, PVT-M); 1.1191 (FIELD); 6.283 (LAB).
|
||||
|
||||
|
||||
std::vector<double> td, pi;
|
||||
};
|
||||
|
||||
|
||||
@@ -49,10 +49,14 @@ namespace Opm {
|
||||
public:
|
||||
|
||||
Eclipse3DProperties() = default;
|
||||
|
||||
Eclipse3DProperties(const Deck& deck,
|
||||
const TableManager& tableManager,
|
||||
const EclipseGrid& eclipseGrid);
|
||||
|
||||
Eclipse3DProperties( UnitSystem unit_system,
|
||||
const TableManager& tableManager,
|
||||
const EclipseGrid& eclipseGrid);
|
||||
|
||||
std::vector< int > getRegions( const std::string& keyword ) const;
|
||||
std::string getDefaultRegionKeyword() const;
|
||||
|
||||
@@ -181,9 +181,9 @@ 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;
|
||||
|
||||
/*
|
||||
The internal class grid_ptr is a a std::unique_ptr with
|
||||
special copy semantics. The purpose of implementing this is
|
||||
|
||||
@@ -52,14 +52,14 @@ namespace Opm {
|
||||
|
||||
class MULTREGTRecord {
|
||||
public:
|
||||
MULTREGTRecord(const DeckRecord& deckRecord , const std::string& defaultRegion);
|
||||
MULTREGTRecord(int src, int target, double trans_mult, int directions, MULTREGT::NNCBehaviourEnum nnc_behaviour, const std::string& region_name);
|
||||
|
||||
Value<int> m_srcRegion;
|
||||
Value<int> m_targetRegion;
|
||||
double m_transMultiplier;
|
||||
int m_directions;
|
||||
MULTREGT::NNCBehaviourEnum m_nncBehaviour;
|
||||
Value<std::string> m_region;
|
||||
int src_value;
|
||||
int target_value;
|
||||
int directions;
|
||||
double trans_mult;
|
||||
MULTREGT::NNCBehaviourEnum nnc_behaviour;
|
||||
std::string region_name;
|
||||
};
|
||||
|
||||
typedef std::map< std::pair<int , int> , const MULTREGTRecord * > MULTREGTSearchMap;
|
||||
@@ -75,7 +75,7 @@ namespace Opm {
|
||||
double getRegionMultiplier(size_t globalCellIdx1, size_t globalCellIdx2, FaceDir::DirEnum faceDir) const;
|
||||
|
||||
private:
|
||||
void addKeyword( const DeckKeyword& deckKeyword, const std::string& defaultRegion);
|
||||
void addKeyword( const Eclipse3DProperties& props, const DeckKeyword& deckKeyword, const std::string& defaultRegion);
|
||||
void assertKeywordSupported(const DeckKeyword& deckKeyword, const std::string& defaultRegion);
|
||||
std::vector< MULTREGTRecord > m_records;
|
||||
std::map<std::string , MULTREGTSearchMap> m_searchMap;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#ifndef OPM_INIT_CONFIG_HPP
|
||||
#define OPM_INIT_CONFIG_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/InitConfig/Equil.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
70
opm/parser/eclipse/EclipseState/Schedule/ActionX.hpp
Normal file
70
opm/parser/eclipse/EclipseState/Schedule/ActionX.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
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 ActionX_HPP_
|
||||
#define ActionX_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Opm {
|
||||
/*
|
||||
The ActionX class internalizes the ACTIONX keyword. This keyword represents a
|
||||
small in-deck programming language for the SCHEDULE section. In the deck the
|
||||
ACTIONX keyword comes together with a 'ENDACTIO' kewyord and then a list of
|
||||
regular keywords in the between. The principle is then that ACTIONX represents
|
||||
a condition, and when that condition is satisfied the keywords are applied. In
|
||||
the example below the ACTIONX keyword defines a condition whether well OPX has
|
||||
watercut above 0.75, when the condition is met the WELOPEN keyword is applied
|
||||
- and the well is shut.
|
||||
|
||||
ACTIONX
|
||||
'NAME' /
|
||||
WWCT OPX > 0.50 /
|
||||
/
|
||||
|
||||
WELOPEN
|
||||
'OPX' OPEN /
|
||||
/
|
||||
|
||||
ENDACTION
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class DeckKeyword;
|
||||
|
||||
class ActionX {
|
||||
public:
|
||||
ActionX(const std::string& name, size_t max_run, double max_wait);
|
||||
explicit ActionX(const DeckKeyword& kw);
|
||||
|
||||
void addKeyword(const DeckKeyword& kw);
|
||||
|
||||
const std::string& name() const;
|
||||
private:
|
||||
std::string m_name;
|
||||
size_t max_run;
|
||||
double max_wait;
|
||||
|
||||
std::vector<DeckKeyword> keywords;
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* WELL_HPP_ */
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
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 COMPLETIONSET_HPP_
|
||||
#define COMPLETIONSET_HPP_
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Completion.hpp>
|
||||
|
||||
namespace Opm {
|
||||
class EclipseGrid;
|
||||
|
||||
class CompletionSet {
|
||||
public:
|
||||
CompletionSet() = default;
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
CompletionSet( std::initializer_list< Completion > );
|
||||
|
||||
using const_iterator = std::vector< Completion >::const_iterator;
|
||||
|
||||
void add( Completion );
|
||||
size_t size() const;
|
||||
const Completion& get(size_t index) const;
|
||||
const Completion& getFromIJK(const int i, const int j, const int k) const;
|
||||
|
||||
const_iterator begin() const { return this->m_completions.begin(); }
|
||||
const_iterator end() const { return this->m_completions.end(); }
|
||||
void filter(const EclipseGrid& grid);
|
||||
bool allCompletionsShut() const;
|
||||
/// Order completions irrespective of input order.
|
||||
/// The algorithm used is the following:
|
||||
/// 1. The completion nearest to the given (well_i, well_j)
|
||||
/// coordinates in terms of the completion's (i, j) is chosen
|
||||
/// to be the first completion. If non-unique, choose one with
|
||||
/// lowest z-depth (shallowest).
|
||||
/// 2. Choose next completion to be nearest to current in (i, j) sense.
|
||||
/// If non-unique choose closest in z-depth (not logical cartesian k).
|
||||
///
|
||||
/// \param[in] well_i logical cartesian i-coordinate of well head
|
||||
/// \param[in] well_j logical cartesian j-coordinate of well head
|
||||
/// \param[in] grid EclipseGrid object, used for cell depths
|
||||
void orderCompletions(size_t well_i, size_t well_j);
|
||||
|
||||
bool operator==( const CompletionSet& ) const;
|
||||
bool operator!=( const CompletionSet& ) const;
|
||||
|
||||
private:
|
||||
std::vector< Completion > m_completions;
|
||||
size_t findClosestCompletion(int oi, int oj, double oz, size_t start_pos);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -21,11 +21,12 @@
|
||||
#ifndef COMPLETION_HPP_
|
||||
#define COMPLETION_HPP_
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Util/Value.hpp>
|
||||
|
||||
@@ -34,74 +35,53 @@ namespace Opm {
|
||||
|
||||
class DeckKeyword;
|
||||
class DeckRecord;
|
||||
class Well;
|
||||
class EclipseGrid;
|
||||
class Eclipse3DProperties;
|
||||
|
||||
class Completion {
|
||||
class Connection {
|
||||
public:
|
||||
Completion(int i, int j , int k ,
|
||||
Connection(int i, int j , int k ,
|
||||
int complnum,
|
||||
double depth,
|
||||
WellCompletion::StateEnum state ,
|
||||
const Value<double>& connectionTransmissibilityFactor,
|
||||
const Value<double>& diameter,
|
||||
const Value<double>& skinFactor,
|
||||
const Value<double>& Kh,
|
||||
const int satTableId,
|
||||
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z);
|
||||
const WellCompletion::DirectionEnum direction);
|
||||
|
||||
Completion(const Completion&, WellCompletion::StateEnum newStatus);
|
||||
Completion(const Completion&, double wellPi);
|
||||
Completion(const Completion&, int complnum );
|
||||
Completion(const Completion& completion_initial, int segment_number, double center_depth);
|
||||
|
||||
bool sameCoordinate(const Completion& other) const;
|
||||
bool sameCoordinate(const int i, const int j, const int k) const;
|
||||
|
||||
int getI() const;
|
||||
int getJ() const;
|
||||
int getK() const;
|
||||
int complnum() const;
|
||||
WellCompletion::StateEnum getState() const;
|
||||
double getConnectionTransmissibilityFactor() const;
|
||||
double getWellPi() const;
|
||||
const Value<double>& getConnectionTransmissibilityFactorAsValueObject() const;
|
||||
double getDiameter() const;
|
||||
double getSkinFactor() const;
|
||||
int getSatTableId() const;
|
||||
void fixDefaultIJ(int wellHeadI , int wellHeadJ);
|
||||
void shift_complnum( int );
|
||||
int getSegmentNumber() const;
|
||||
double getCenterDepth() const;
|
||||
bool attachedToSegment() const;
|
||||
const Value<double>& getConnectionTransmissibilityFactorAsValueObject() const;
|
||||
const Value<double>& getEffectiveKhAsValueObject() const;
|
||||
|
||||
WellCompletion::DirectionEnum getDirection() const;
|
||||
bool operator==( const Connection& ) const;
|
||||
bool operator!=( const Connection& ) const;
|
||||
|
||||
static std::map< std::string, std::vector< Completion > >
|
||||
fromCOMPDAT( const EclipseGrid& grid,
|
||||
const Eclipse3DProperties& eclipseProperties,
|
||||
const DeckKeyword& compdatKeyword,
|
||||
const std::vector< const Well* >& );
|
||||
|
||||
bool operator==( const Completion& ) const;
|
||||
bool operator!=( const Completion& ) const;
|
||||
WellCompletion::DirectionEnum dir;
|
||||
double center_depth;
|
||||
WellCompletion::StateEnum state;
|
||||
int sat_tableId;
|
||||
int complnum;
|
||||
|
||||
private:
|
||||
int m_i, m_j, m_k;
|
||||
int m_complnum;
|
||||
std::array<int,3> ijk;
|
||||
Value<double> m_diameter;
|
||||
Value<double> m_connectionTransmissibilityFactor;
|
||||
double m_wellPi;
|
||||
Value<double> m_skinFactor;
|
||||
int m_satTableId;
|
||||
WellCompletion::StateEnum m_state;
|
||||
WellCompletion::DirectionEnum m_direction;
|
||||
Value<double> getDiameterAsValueObject() const;
|
||||
Value<double> getSkinFactorAsValueObject() const;
|
||||
Value<double> m_Kh;
|
||||
|
||||
public:
|
||||
// related segment number
|
||||
// -1 means the completion is not related to segment
|
||||
int m_segment_number = -1;
|
||||
double m_center_depth;
|
||||
int segment_number = -1;
|
||||
double wellPi = 1.0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ namespace Opm {
|
||||
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);
|
||||
|
||||
/*****************************************************************/
|
||||
|
||||
|
||||
@@ -30,13 +30,13 @@ namespace Opm {
|
||||
|
||||
class DeckKeyword;
|
||||
|
||||
class SegmentSet {
|
||||
class WellSegments {
|
||||
public:
|
||||
SegmentSet() = default;
|
||||
WellSegments() = default;
|
||||
|
||||
std::string wellName() const;
|
||||
int numberBranch() const;
|
||||
int numberSegment() const;
|
||||
int size() const;
|
||||
double depthTopSegment() const;
|
||||
double lengthTopSegment() const;
|
||||
double volumeTopSegment() const;
|
||||
@@ -50,7 +50,7 @@ namespace Opm {
|
||||
|
||||
void addSegment(Segment new_segment);
|
||||
|
||||
void segmentsFromWELSEGSKeyword( const DeckKeyword& welsegsKeyword);
|
||||
void loadWELSEGS( const DeckKeyword& welsegsKeyword);
|
||||
|
||||
const Segment& getFromSegmentNumber(const int segment_number) const;
|
||||
|
||||
@@ -59,8 +59,8 @@ namespace Opm {
|
||||
void processABS();
|
||||
void processINC(const bool first_time);
|
||||
|
||||
bool operator==( const SegmentSet& ) const;
|
||||
bool operator!=( const SegmentSet& ) const;
|
||||
bool operator==( const WellSegments& ) const;
|
||||
bool operator!=( const WellSegments& ) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace Opm {
|
||||
std::vector< Segment > m_segments;
|
||||
// the mapping from the segment number to the
|
||||
// storage index in the vector
|
||||
std::map<int, int> m_segment_number_to_index;
|
||||
std::map<int, int> segment_number_to_index;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UPDATING_COMPLETIONS_WITH_SEGMENTS
|
||||
#define UPDATING_COMPLETIONS_WITH_SEGMENTS
|
||||
#ifndef UPDATING_CONNECTIONS_WITH_SEGMENTS
|
||||
#define UPDATING_CONNECTIONS_WITH_SEGMENTS
|
||||
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
|
||||
|
||||
namespace Opm {
|
||||
CompletionSet updatingCompletionsWithSegments(const DeckKeyword& compsegs, const CompletionSet& input_completions, const SegmentSet& segments);
|
||||
WellConnections * newConnectionsWithSegments(const DeckKeyword& compsegs, const WellConnections& input_connections, const WellSegments& segments);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
@@ -64,7 +65,7 @@ namespace Opm
|
||||
Schedule(const Deck& deck,
|
||||
const EclipseState& es,
|
||||
const ParseContext& parseContext = ParseContext());
|
||||
|
||||
|
||||
/*
|
||||
* If the input deck does not specify a start time, Eclipse's 1. Jan
|
||||
* 1983 is defaulted
|
||||
@@ -78,7 +79,7 @@ namespace Opm
|
||||
|
||||
size_t numWells() const;
|
||||
size_t numWells(size_t timestep) const;
|
||||
size_t getMaxNumCompletionsForWells(size_t timestep) const;
|
||||
size_t getMaxNumConnectionsForWells(size_t timestep) const;
|
||||
bool hasWell(const std::string& wellName) const;
|
||||
const Well* getWell(const std::string& wellName) const;
|
||||
std::vector< const Well* > getOpenWells(size_t timeStep) const;
|
||||
@@ -98,6 +99,8 @@ namespace Opm
|
||||
std::vector< const Well* > getWellsMatching( const std::string& ) const;
|
||||
const OilVaporizationProperties& getOilVaporizationProperties(size_t timestep) const;
|
||||
|
||||
const WellTestConfig& wtestConfig(size_t timestep) const;
|
||||
|
||||
const GroupTree& getGroupTree(size_t t) const;
|
||||
size_t numGroups() const;
|
||||
bool hasGroup(const std::string& groupName) const;
|
||||
@@ -105,19 +108,20 @@ namespace Opm
|
||||
std::vector< const Group* > getGroups() const;
|
||||
const Tuning& getTuning() const;
|
||||
const MessageLimits& getMessageLimits() const;
|
||||
void invalidNamePattern (const std::string& namePattern, const ParseContext& parseContext, const DeckKeyword& keyword) const;
|
||||
|
||||
const Events& getEvents() const;
|
||||
const Deck& getModifierDeck(size_t timeStep) const;
|
||||
bool hasOilVaporizationProperties() const;
|
||||
const VFPProdTable& getVFPProdTable(int table_id, size_t timeStep) const;
|
||||
const VFPInjTable& getVFPInjTable(int table_id, size_t timeStep) const;
|
||||
std::map<int, VFPProdTable> getVFPProdTables(size_t timeStep) const;
|
||||
std::map<int, VFPInjTable> getVFPInjTables(size_t timeStep) const;
|
||||
std::map<int, std::shared_ptr<const VFPProdTable> > getVFPProdTables(size_t timeStep) const;
|
||||
std::map<int, std::shared_ptr<const VFPInjTable> > getVFPInjTables(size_t timeStep) const;
|
||||
/*
|
||||
Will remove all completions which are connected to cell which is not
|
||||
active. Will scan through all wells and all timesteps.
|
||||
*/
|
||||
void filterCompletions(const EclipseGrid& grid);
|
||||
void filterConnections(const EclipseGrid& grid);
|
||||
|
||||
private:
|
||||
TimeMap m_timeMap;
|
||||
@@ -132,10 +136,13 @@ namespace Opm
|
||||
Phases m_phases;
|
||||
std::map<int, DynamicState<std::shared_ptr<VFPProdTable>>> vfpprod_tables;
|
||||
std::map<int, DynamicState<std::shared_ptr<VFPInjTable>>> vfpinj_tables;
|
||||
DynamicState<std::shared_ptr<WellTestConfig>> wtest_config;
|
||||
|
||||
WellProducer::ControlModeEnum m_controlModeWHISTCTL;
|
||||
|
||||
std::vector< Well* > getWells(const std::string& wellNamePattern);
|
||||
std::vector< Group* > getGroups(const std::string& groupNamePattern);
|
||||
|
||||
void updateWellStatus( Well& well, size_t reportStep , WellCommon::StatusEnum status);
|
||||
void addWellToGroup( Group& newGroup , Well& well , size_t timeStep);
|
||||
void iterateScheduleSection(const ParseContext& parseContext , const SCHEDULESection& , const EclipseGrid& grid,
|
||||
@@ -145,42 +152,52 @@ namespace Opm
|
||||
void addWell(const std::string& wellName, const DeckRecord& record, size_t timeStep, WellCompletion::CompletionOrderEnum wellCompletionOrder);
|
||||
void handleCOMPORD(const ParseContext& parseContext, const DeckKeyword& compordKeyword, size_t currentStep);
|
||||
void handleWELSPECS( const SCHEDULESection&, size_t, size_t );
|
||||
void handleWCONProducer( const DeckKeyword& keyword, size_t currentStep, bool isPredictionMode);
|
||||
void handleWCONHIST( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWCONPROD( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWCONProducer( const DeckKeyword& keyword, size_t currentStep, bool isPredictionMode, const ParseContext& parseContext);
|
||||
void handleWCONHIST( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWGRUPCON( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleCOMPDAT( const DeckKeyword& keyword, size_t currentStep, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties);
|
||||
void handleCOMPDAT( const DeckKeyword& keyword, size_t currentStep, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties, const ParseContext& parseContext);
|
||||
void handleCOMPLUMP( const DeckKeyword& keyword, size_t currentStep );
|
||||
void handleWELSEGS( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleCOMPSEGS( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWPOLYMER( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWSOLVENT( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWTEMP( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWINJTEMP( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWCONINJH( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWELOPEN( const DeckKeyword& keyword, size_t currentStep );
|
||||
void handleWELTARG( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleGCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleGCONPROD( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleGEFAC( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWEFAC( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWPOLYMER( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWSOLVENT( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWINJTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWCONINJH( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWELOPEN( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext );
|
||||
void handleWELTARG( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleGCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleGCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleGEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleTUNING( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleGRUPNET( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWRFT( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWTEST( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWRFTPLT( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWPIMULT( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleDRSDT( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleDRVDT( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleVAPPARS( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWECON( const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleWECON( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
|
||||
void handleWHISTCTL(const ParseContext& parseContext, const DeckKeyword& keyword);
|
||||
void handleMESSAGES(const DeckKeyword& keyword, size_t currentStep);
|
||||
void handleVFPPROD(const DeckKeyword& vfpprodKeyword, const UnitSystem& unit_system, size_t currentStep);
|
||||
void handleVFPINJ(const DeckKeyword& vfpprodKeyword, const UnitSystem& unit_system, size_t currentStep);
|
||||
void checkUnhandledKeywords( const SCHEDULESection& ) const;
|
||||
void checkIfAllConnectionsIsShut(size_t currentStep);
|
||||
void handleKeyword(size_t& currentStep,
|
||||
const SCHEDULESection& section,
|
||||
size_t keywordIdx,
|
||||
const DeckKeyword& keyword,
|
||||
const ParseContext& parseContext,
|
||||
const EclipseGrid& grid,
|
||||
const Eclipse3DProperties& eclipseProperties,
|
||||
const UnitSystem& unit_system,
|
||||
std::vector<std::pair<const DeckKeyword*, size_t > >& rftProperties);
|
||||
|
||||
static double convertInjectionRateToSI(double rawRate, WellInjector::TypeEnum wellType, const Opm::UnitSystem &unitSystem);
|
||||
static double convertInjectionRateToSI(double rawRate, Phase wellPhase, const Opm::UnitSystem &unitSystem);
|
||||
|
||||
@@ -27,23 +27,23 @@
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellEconProductionLimits.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellInjectionProperties.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
template< typename > class DynamicState;
|
||||
|
||||
class Completion;
|
||||
class CompletionSet;
|
||||
class COnnection;
|
||||
class WellConnections;
|
||||
class Segment;
|
||||
class SegmentSet;
|
||||
class WellSegments;
|
||||
class TimeMap;
|
||||
class EclipseGrid;
|
||||
|
||||
@@ -94,10 +94,29 @@ namespace Opm {
|
||||
bool isInjector(size_t timeStep) const;
|
||||
void addWELSPECS(const DeckRecord& deckRecord);
|
||||
|
||||
void addCompletions(size_t time_step, const std::vector< Completion >& );
|
||||
void addCompletionSet(size_t time_step, CompletionSet );
|
||||
const CompletionSet& getCompletions(size_t timeStep) const;
|
||||
const CompletionSet& getCompletions() const;
|
||||
/*
|
||||
The getCompletions() function will return a map:
|
||||
|
||||
{
|
||||
1 : [Connection, Connection],
|
||||
2 : [Connection, Connection, Connecton],
|
||||
-3 : [Connection]
|
||||
-7 : [Connection]
|
||||
}
|
||||
|
||||
The integer ID's correspond to the COMPLETION id given by the COMPLUMP
|
||||
keyword. All positive id values come from COMPLUMP, whereas the
|
||||
negative values are arbitrary negative id values for connections which
|
||||
have not been lumped together in a completion. In the case of negative
|
||||
id values the list of connections always has exactly one element.
|
||||
*/
|
||||
|
||||
std::map<int, std::vector<Connection>> getCompletions(size_t time_step) const;
|
||||
const WellConnections& getConnections(size_t timeStep) const;
|
||||
const WellConnections& getConnections() const;
|
||||
WellConnections getActiveConnections(size_t timeStep, const EclipseGrid& grid) const;
|
||||
WellConnections * newWellConnections(size_t time_step);
|
||||
void updateWellConnections(size_t time_step, WellConnections * new_set );
|
||||
|
||||
/* The rate of a given phase under the following assumptions:
|
||||
* * Returns zero if production is requested for an injector (and vice
|
||||
@@ -147,7 +166,7 @@ namespace Opm {
|
||||
|
||||
static bool wellNameInWellNamePattern(const std::string& wellName, const std::string& wellNamePattern);
|
||||
|
||||
WellCompletion::CompletionOrderEnum getWellCompletionOrdering() const;
|
||||
WellCompletion::CompletionOrderEnum getWellConnectionOrdering() const;
|
||||
|
||||
bool getAllowCrossFlow() const;
|
||||
bool getAutomaticShutIn() const;
|
||||
@@ -156,19 +175,26 @@ namespace Opm {
|
||||
|
||||
// for multi-segment wells
|
||||
bool isMultiSegment(size_t time_step) const;
|
||||
const SegmentSet& getSegmentSet(size_t time_step) const;
|
||||
const WellSegments& getWellSegments(size_t time_step) const;
|
||||
|
||||
void addSegmentSet(size_t time_step, SegmentSet new_segmentset);
|
||||
void addWellSegments(size_t time_step, WellSegments new_segmentset);
|
||||
|
||||
const Events& getEvents() const;
|
||||
void addEvent(ScheduleEvents::Events event, size_t reportStep);
|
||||
bool hasEvent(uint64_t eventMask, size_t reportStep) const;
|
||||
void handleCOMPLUMP(const DeckRecord& record, size_t time_step);
|
||||
void handleCOMPDAT(size_t time_step, const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties);
|
||||
void handleCOMPSEGS(const DeckKeyword& keyword, size_t time_step);
|
||||
void handleWELOPEN(const DeckRecord& record, size_t time_step, WellCompletion::StateEnum status);
|
||||
void handleWPIMULT(const DeckRecord& record, size_t time_step);
|
||||
void handleWELSEGS(const DeckKeyword& keyword, size_t time_step);
|
||||
|
||||
|
||||
/*
|
||||
Will remove all completions which are attached to inactive cells. Will
|
||||
scan through all timesteps.
|
||||
*/
|
||||
void filterCompletions(const EclipseGrid& grid);
|
||||
void filterConnections(const EclipseGrid& grid);
|
||||
private:
|
||||
size_t m_creationTimeStep;
|
||||
std::string m_name;
|
||||
@@ -182,7 +208,7 @@ namespace Opm {
|
||||
DynamicState< double > m_efficiencyFactors;
|
||||
|
||||
DynamicState< int > m_isProducer;
|
||||
DynamicState< CompletionSet > m_completions;
|
||||
DynamicState< std::shared_ptr<WellConnections> > m_completions;
|
||||
DynamicState< WellProductionProperties > m_productionProperties;
|
||||
DynamicState< WellInjectionProperties > m_injectionProperties;
|
||||
DynamicState< WellPolymerProperties > m_polymerProperties;
|
||||
@@ -202,7 +228,7 @@ namespace Opm {
|
||||
bool m_automaticShutIn;
|
||||
// WELSEGS DATA - for mutli-segment wells
|
||||
// flag indicating if the well is a multi-segment well
|
||||
DynamicState< SegmentSet > m_segmentset;
|
||||
DynamicState< WellSegments > m_segmentset;
|
||||
size_t timesteps;
|
||||
Events events;
|
||||
};
|
||||
|
||||
95
opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp
Normal file
95
opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
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 CONNECTIONSET_HPP_
|
||||
#define CONNECTIONSET_HPP_
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Connection.hpp>
|
||||
|
||||
namespace Opm {
|
||||
class EclipseGrid;
|
||||
class Eclipse3DProperties;
|
||||
class WellConnections {
|
||||
public:
|
||||
WellConnections() = default;
|
||||
WellConnections(int headI, int headJ);
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
WellConnections(const WellConnections& src, const EclipseGrid& grid);
|
||||
void addConnection(int i, int j , int k ,
|
||||
double depth,
|
||||
WellCompletion::StateEnum state ,
|
||||
const Value<double>& connectionTransmissibilityFactor,
|
||||
const Value<double>& diameter,
|
||||
const Value<double>& skinFactor,
|
||||
const Value<double>& Kh,
|
||||
const int satTableId,
|
||||
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z);
|
||||
void loadCOMPDAT(const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties);
|
||||
|
||||
using const_iterator = std::vector< Connection >::const_iterator;
|
||||
|
||||
void add( Connection );
|
||||
size_t size() const;
|
||||
const Connection& get(size_t index) const;
|
||||
const Connection& getFromIJK(const int i, const int j, const int k) const;
|
||||
Connection& getFromIJK(const int i, const int j, const int k);
|
||||
|
||||
const_iterator begin() const { return this->m_connections.begin(); }
|
||||
const_iterator end() const { return this->m_connections.end(); }
|
||||
void filter(const EclipseGrid& grid);
|
||||
bool allConnectionsShut() const;
|
||||
/// Order connections irrespective of input order.
|
||||
/// The algorithm used is the following:
|
||||
/// 1. The connection nearest to the given (well_i, well_j)
|
||||
/// coordinates in terms of the connection's (i, j) is chosen
|
||||
/// to be the first connection. If non-unique, choose one with
|
||||
/// lowest z-depth (shallowest).
|
||||
/// 2. Choose next connection to be nearest to current in (i, j) sense.
|
||||
/// If non-unique choose closest in z-depth (not logical cartesian k).
|
||||
///
|
||||
/// \param[in] well_i logical cartesian i-coordinate of well head
|
||||
/// \param[in] well_j logical cartesian j-coordinate of well head
|
||||
/// \param[in] grid EclipseGrid object, used for cell depths
|
||||
void orderConnections(size_t well_i, size_t well_j);
|
||||
|
||||
bool operator==( const WellConnections& ) const;
|
||||
bool operator!=( const WellConnections& ) const;
|
||||
|
||||
private:
|
||||
void addConnection(int i, int j , int k ,
|
||||
int complnum,
|
||||
double depth,
|
||||
WellCompletion::StateEnum state ,
|
||||
const Value<double>& connectionTransmissibilityFactor,
|
||||
const Value<double>& diameter,
|
||||
const Value<double>& skinFactor,
|
||||
const Value<double>& Kh,
|
||||
const int satTableId,
|
||||
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z);
|
||||
|
||||
std::vector< Connection > m_connections;
|
||||
size_t findClosestConnection(int oi, int oj, double oz, size_t start_pos);
|
||||
int headI, headJ;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -55,7 +55,10 @@ namespace Opm {
|
||||
bool operator!=(const WellProductionProperties& other) const;
|
||||
WellProductionProperties();
|
||||
|
||||
static WellProductionProperties history(double BHPLimit, const DeckRecord& record);
|
||||
static WellProductionProperties history(const WellProductionProperties& prevProperties,
|
||||
const DeckRecord& record,
|
||||
const WellProducer::ControlModeEnum controlModeWHISTCL);
|
||||
|
||||
static WellProductionProperties prediction( const DeckRecord& record, bool addGroupProductionControl );
|
||||
|
||||
bool hasProductionControl(WellProducer::ControlModeEnum controlModeArg) const {
|
||||
@@ -72,6 +75,9 @@ namespace Opm {
|
||||
m_productionControls += controlModeArg;
|
||||
}
|
||||
|
||||
// this is used to check whether the specified control mode is an effective history matching production mode
|
||||
static bool effectiveHistoryProductionControl(const WellProducer::ControlModeEnum cmode);
|
||||
|
||||
private:
|
||||
int m_productionControls = 0;
|
||||
|
||||
|
||||
64
opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp
Normal file
64
opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 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 WELLTEST_CONFIG_H
|
||||
#define WELLTEST_CONFIG_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class WellTestConfig {
|
||||
public:
|
||||
enum Reason {
|
||||
PHYSICAL = 1,
|
||||
ECONOMIC = 2,
|
||||
GROUP = 4,
|
||||
THP_DESIGN=8,
|
||||
COMPLETION=16,
|
||||
};
|
||||
|
||||
struct WTESTWell {
|
||||
std::string name;
|
||||
Reason shut_reason;
|
||||
double test_interval;
|
||||
int num_test;
|
||||
double startup_time;
|
||||
};
|
||||
|
||||
WellTestConfig();
|
||||
void add_well(const std::string& well, Reason reason, double test_interval, int num_test, double startup_time);
|
||||
void add_well(const std::string& well, const std::string& reasons, double test_interval, int num_test, double startup_time);
|
||||
void drop_well(const std::string& well);
|
||||
bool has(const std::string& well) const;
|
||||
bool has(const std::string& well, Reason reason) const;
|
||||
const WTESTWell& get(const std::string& well, Reason reason) const;
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
std::vector<WTESTWell> wells;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
117
opm/parser/eclipse/EclipseState/Schedule/WellTestState.hpp
Normal file
117
opm/parser/eclipse/EclipseState/Schedule/WellTestState.hpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright 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 WELLTEST_STATE_H
|
||||
#define WELLTEST_STATE_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class WellTestState {
|
||||
public:
|
||||
/*
|
||||
This class implements a small mutable state object which keeps track of
|
||||
which wells have been automatically closed by the simulator, and by
|
||||
checking with the WTEST configuration object the class can return a list
|
||||
(well_name,reason) pairs for wells which should be checked as candiates
|
||||
for opening.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
struct ClosedWell {
|
||||
std::string name;
|
||||
WellTestConfig::Reason reason;
|
||||
double last_test;
|
||||
int num_attempt;
|
||||
};
|
||||
|
||||
|
||||
struct ClosedCompletion {
|
||||
std::string wellName;
|
||||
int complnum;
|
||||
double last_test;
|
||||
int num_attempt;
|
||||
};
|
||||
|
||||
/*
|
||||
The simulator has decided to close a particular well; we then add it here
|
||||
as a closed well with a particualar reason.
|
||||
*/
|
||||
void addClosedWell(const std::string& well_name, WellTestConfig::Reason reason, double sim_time);
|
||||
|
||||
/*
|
||||
The simulator has decided to close a particular completion in a well; we then add it here
|
||||
as a closed completions
|
||||
*/
|
||||
void addClosedCompletion(const std::string& well_name, int complnum, double sim_time);
|
||||
|
||||
/*
|
||||
The update will consult the WellTestConfig object and return a list of
|
||||
wells which should be checked for possible reopening; observe that the
|
||||
update method will update the internal state of the object by counting up
|
||||
the openiing attempts, and also set the time for the last attempt to open.
|
||||
*/
|
||||
std::vector<std::pair<std::string, WellTestConfig::Reason>> updateWell(const WellTestConfig& config, double sim_time);
|
||||
|
||||
/*
|
||||
The update will consult the WellTestConfig object and return a list of
|
||||
completions which should be checked for possible reopening; observe that the
|
||||
update method will update the internal state of the object by counting up
|
||||
the openiing attempts, and also set the time for the last attempt to open.
|
||||
*/
|
||||
std::vector<std::pair<std::string, int>> updateCompletion(const WellTestConfig& config, double sim_time);
|
||||
|
||||
|
||||
/*
|
||||
If the simulator decides that a constraint is no longer met the dropWell()
|
||||
method should be called to indicate that this reason for keeping the well
|
||||
closed is no longer active.
|
||||
*/
|
||||
void dropWell(const std::string& well_name, WellTestConfig::Reason reason);
|
||||
|
||||
/*
|
||||
If the simulator decides that a constraint is no longer met the dropCompletion()
|
||||
method should be called to indicate that this reason for keeping the well
|
||||
closed is no longer active.
|
||||
*/
|
||||
void dropCompletion(const std::string& well_name, int complnum);
|
||||
|
||||
bool hasWell(const std::string& well_name, WellTestConfig::Reason reason) const;
|
||||
void openWell(const std::string& well_name);
|
||||
|
||||
bool hasCompletion(const std::string& well_name, const int complnum) const;
|
||||
|
||||
size_t sizeWells() const;
|
||||
size_t sizeCompletions() const;
|
||||
|
||||
private:
|
||||
std::vector<ClosedWell> wells;
|
||||
std::vector<ClosedCompletion> completions;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,11 +31,12 @@ namespace Opm {
|
||||
|
||||
public:
|
||||
|
||||
SimulationConfig(const Deck& deck,
|
||||
SimulationConfig(bool restart,
|
||||
const Deck& deck,
|
||||
const Eclipse3DProperties& gridProperties);
|
||||
|
||||
const ThresholdPressure& getThresholdPressure() const;
|
||||
bool hasThresholdPressure() const;
|
||||
bool useThresholdPressure() const;
|
||||
bool useCPR() const;
|
||||
bool hasDISGAS() const;
|
||||
bool hasVAPOIL() const;
|
||||
|
||||
@@ -32,8 +32,8 @@ namespace Opm {
|
||||
class ThresholdPressure {
|
||||
|
||||
public:
|
||||
|
||||
ThresholdPressure(const Deck& deck,
|
||||
ThresholdPressure(bool restart,
|
||||
const Deck& deck,
|
||||
const Eclipse3DProperties& eclipseProperties);
|
||||
|
||||
|
||||
@@ -63,8 +63,11 @@ namespace Opm {
|
||||
*/
|
||||
double getThresholdPressure(int r1 , int r2) const;
|
||||
size_t size() const;
|
||||
|
||||
bool active() const;
|
||||
bool restart() const;
|
||||
private:
|
||||
bool m_active;
|
||||
bool m_restart;
|
||||
static std::pair<int,int> makeIndex(int r1 , int r2);
|
||||
void addPair(int r1 , int r2 , const std::pair<bool , double>& valuePair);
|
||||
void addBarrier(int r1 , int r2);
|
||||
|
||||
@@ -39,7 +39,6 @@ public:
|
||||
double owSurfaceTension() const;
|
||||
const Flag& flag() const;
|
||||
const Direction& direction() const;
|
||||
operator bool() const { return m_exists; }
|
||||
|
||||
private:
|
||||
Flag m_flag; // JFUNC flag: WATER, GAS, or BOTH. Default BOTH
|
||||
@@ -48,7 +47,6 @@ private:
|
||||
double m_alphaFactor; // alternative porosity term. Default 0.5
|
||||
double m_betaFactor; // alternative permeability term. Default 0.5
|
||||
Direction m_direction; // XY, X, Y, Z. Default XY
|
||||
const bool m_exists; // will be true if JFunc is specified in the deck
|
||||
};
|
||||
} // Opm::
|
||||
|
||||
|
||||
@@ -50,10 +50,10 @@ namespace Opm {
|
||||
|
||||
class Eqldims;
|
||||
class Regdims;
|
||||
|
||||
class TableManager {
|
||||
public:
|
||||
explicit TableManager( const Deck& deck );
|
||||
TableManager() = default;
|
||||
|
||||
const TableContainer& getTables( const std::string& tableName ) const;
|
||||
const TableContainer& operator[](const std::string& tableName) const;
|
||||
@@ -293,12 +293,10 @@ namespace Opm {
|
||||
std::shared_ptr<Eqldims> m_eqldims;
|
||||
Aqudims m_aqudims;
|
||||
|
||||
const bool hasImptvd;// if deck has keyword IMPTVD
|
||||
const bool hasEnptvd;// if deck has keyword ENPTVD
|
||||
const bool hasEqlnum;// if deck has keyword EQLNUM
|
||||
|
||||
|
||||
const JFunc m_jfunc;
|
||||
const bool hasImptvd = false;// if deck has keyword IMPTVD
|
||||
const bool hasEnptvd = false;// if deck has keyword ENPTVD
|
||||
const bool hasEqlnum = false;// if deck has keyword EQLNUM
|
||||
std::shared_ptr<JFunc> jfunc;
|
||||
|
||||
double m_rtemp;
|
||||
};
|
||||
|
||||
@@ -40,14 +40,9 @@ namespace Opm {
|
||||
bool hasKeyword(const std::string& keyword) const;
|
||||
std::shared_ptr<const ParserKeyword> getKeyword(const std::string& keyword) const;
|
||||
std::string getJsonFile(const std::string& keyword) const;
|
||||
size_t loadKeywordDirectory(const std::string& pathname);
|
||||
size_t loadKeywordDirectory(boost::filesystem::path& path);
|
||||
void loadKeyword(const std::string& filename);
|
||||
void loadKeyword(boost::filesystem::path& path);
|
||||
|
||||
static std::vector<std::string> sortSubdirectories( const std::string& directory );
|
||||
size_t loadMultipleKeywordDirectories(const std::string& directory);
|
||||
|
||||
std::map<std::string , std::shared_ptr<ParserKeyword> >::const_iterator keyword_begin( ) const;
|
||||
std::map<std::string , std::shared_ptr<ParserKeyword> >::const_iterator keyword_end( ) const;
|
||||
private:
|
||||
|
||||
@@ -243,6 +243,13 @@ namespace Opm {
|
||||
const static std::string SUMMARY_UNKNOWN_WELL;
|
||||
const static std::string SUMMARY_UNKNOWN_GROUP;
|
||||
|
||||
/*
|
||||
A well must be specified (e.g. WELSPECS) and have completions
|
||||
(e.g. COMPDAT) to be able to set control mode (e.g. WCONPROD).
|
||||
A well missing specification and/or completion(s) will throw.
|
||||
*/
|
||||
const static std::string SCHEDULE_INVALID_NAME;
|
||||
|
||||
private:
|
||||
void initDefault();
|
||||
void initEnv();
|
||||
|
||||
@@ -58,7 +58,9 @@ namespace Opm {
|
||||
gas_surface_rate,
|
||||
rate,
|
||||
transmissibility,
|
||||
effective_Kh,
|
||||
mass,
|
||||
mass_rate,
|
||||
gas_oil_ratio,
|
||||
oil_gas_ratio,
|
||||
water_cut,
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
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 <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 Deviation struct.
|
||||
\details The member variables are default initialized to -1,
|
||||
which is an invalid deviation value.
|
||||
*/
|
||||
struct Deviation {
|
||||
double abs = -1; //!< Absolute deviation
|
||||
double rel = -1; //!< Relative deviation
|
||||
};
|
||||
|
||||
|
||||
/*! \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
|
||||
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 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 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 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 RegressionTest: 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;
|
||||
|
||||
// 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 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.
|
||||
RegressionTest(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;}
|
||||
|
||||
//! \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, 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;
|
||||
//! \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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \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 IntegrationTest: 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.
|
||||
IntegrationTest(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
|
||||
@@ -2,7 +2,7 @@
|
||||
# spec file for package opm-common
|
||||
#
|
||||
|
||||
%define tag rc1
|
||||
%define tag final
|
||||
|
||||
Name: opm-common
|
||||
Version: 2018.04
|
||||
@@ -12,7 +12,7 @@ License: GPL-3.0
|
||||
Group: Development/Libraries/C and C++
|
||||
Url: http://www.opm-project.org/
|
||||
Source0: https://github.com/OPM/%{name}/archive/release/%{version}/%{tag}.tar.gz#/%{name}-%{version}.tar.gz
|
||||
BuildRequires: git doxygen bc devtoolset-6-toolchain ecl-devel
|
||||
BuildRequires: git doxygen bc devtoolset-6-toolchain ecl-devel openmpi-devel mpich-devel zlib-devel
|
||||
%{?el6:BuildRequires: cmake3 boost148-devel}
|
||||
%{!?el6:BuildRequires: cmake boost-devel}
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
@@ -27,6 +27,20 @@ Group: System/Libraries
|
||||
%description -n libopm-common1
|
||||
This package contains library for opm-common
|
||||
|
||||
%package -n libopm-common1-openmpi
|
||||
Summary: OPM-common - library
|
||||
Group: System/Libraries
|
||||
|
||||
%description -n libopm-common1-openmpi
|
||||
This package contains library for opm-common
|
||||
|
||||
%package -n libopm-common1-mpich
|
||||
Summary: OPM-common - library
|
||||
Group: System/Libraries
|
||||
|
||||
%description -n libopm-common1-mpich
|
||||
This package contains library for opm-common
|
||||
|
||||
%package devel
|
||||
Summary: Development and header files for opm-common
|
||||
Group: Development/Libraries/C and C++
|
||||
@@ -35,6 +49,48 @@ Requires: %{name} = %{version}
|
||||
%description devel
|
||||
This package contains the development and header files for opm-common
|
||||
|
||||
%package openmpi-devel
|
||||
Summary: Development and header files for opm-common
|
||||
Group: Development/Libraries/C and C++
|
||||
Requires: %{name} = %{version}
|
||||
Requires: libopm-common1-openmpi = %{version}
|
||||
|
||||
%description openmpi-devel
|
||||
This package contains the development and header files for opm-common
|
||||
|
||||
%package mpich-devel
|
||||
Summary: Development and header files for opm-common
|
||||
Group: Development/Libraries/C and C++
|
||||
Requires: %{name} = %{version}
|
||||
Requires: libopm-common1-mpich = %{version}
|
||||
|
||||
%description mpich-devel
|
||||
This package contains the development and header files for opm-common
|
||||
|
||||
%package bin
|
||||
Summary: Applications for opm-common
|
||||
Group: System/Binaries
|
||||
Requires: %{name} = %{version}
|
||||
|
||||
%description bin
|
||||
This package the applications for opm-common
|
||||
|
||||
%package openmpi-bin
|
||||
Summary: Applications for opm-common
|
||||
Group: System/Binaries
|
||||
Requires: libopm-common1-openmpi = %{version}
|
||||
|
||||
%description openmpi-bin
|
||||
This package the applications for opm-common
|
||||
|
||||
%package mpich-bin
|
||||
Summary: Applications for opm-common
|
||||
Group: System/Binaries
|
||||
Requires: libopm-common1-mpich = %{version}
|
||||
|
||||
%description mpich-bin
|
||||
This package the applications for opm-common
|
||||
|
||||
%package doc
|
||||
Summary: Documentation files for opm-common
|
||||
Group: Documentation
|
||||
@@ -49,11 +105,45 @@ This package contains the documentation files for opm-common
|
||||
# consider using -DUSE_VERSIONED_DIR=ON if backporting
|
||||
%build
|
||||
scl enable devtoolset-6 bash
|
||||
%{?el6:cmake28} %{?!el6:cmake} -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSTRIP_DEBUGGING_SYMBOLS=ON -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gfortran %{?el6:-DBOOST_LIBRARYDIR=%{_libdir}/boost148 -DBOOST_INCLUDEDIR=%{_includedir}/boost148}
|
||||
make
|
||||
mkdir serial
|
||||
cd serial
|
||||
%{?el6:cmake3} %{?!el6:cmake} -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSTRIP_DEBUGGING_SYMBOLS=ON -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gfortran %{?el6:-DBOOST_LIBRARYDIR=%{_libdir}/boost148 -DBOOST_INCLUDEDIR=%{_includedir}/boost148} ..
|
||||
make %{?_smp_mflags}
|
||||
make test
|
||||
cd ..
|
||||
|
||||
mkdir openmpi
|
||||
cd openmpi
|
||||
%{?el6:module load openmpi-x86_64}
|
||||
%{?!el6:module load mpi/openmpi-x86_64}
|
||||
%{?el6:cmake3} %{?!el6:cmake} -DUSE_MPI=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSTRIP_DEBUGGING_SYMBOLS=ON -DCMAKE_INSTALL_PREFIX=%{_prefix}/lib64/openmpi -DCMAKE_INSTALL_LIBDIR=lib -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gfortran %{?el6:-DBOOST_LIBRARYDIR=%{_libdir}/boost148 -DBOOST_INCLUDEDIR=%{_includedir}/boost148} ..
|
||||
make %{?_smp_mflags}
|
||||
make test
|
||||
cd ..
|
||||
|
||||
mkdir mpich
|
||||
cd mpich
|
||||
%{?el6:module rm openmpi-x86_64}
|
||||
%{?el6:module load mpich-x86_64}
|
||||
%{?!el6:module rm mpi/openmpi-x86_64}
|
||||
%{?!el6:module load mpi/mpich-x86_64}
|
||||
%{?el6:cmake3} %{?!el6:cmake} -DUSE_MPI=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSTRIP_DEBUGGING_SYMBOLS=ON -DCMAKE_INSTALL_PREFIX=%{_prefix}/lib64/mpich -DCMAKE_INSTALL_LIBDIR=lib -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gfortran %{?el6:-DBOOST_LIBRARYDIR=%{_libdir}/boost148 -DBOOST_INCLUDEDIR=%{_includedir}/boost148} ..
|
||||
make %{?_smp_mflags}
|
||||
make test
|
||||
|
||||
%install
|
||||
cd serial
|
||||
make install DESTDIR=${RPM_BUILD_ROOT}
|
||||
make install-html DESTDIR=${RPM_BUILD_ROOT}
|
||||
cd ..
|
||||
cd openmpi
|
||||
make install DESTDIR=${RPM_BUILD_ROOT}
|
||||
mv ${RPM_BUILD_ROOT}/usr/lib64/openmpi/include/* ${RPM_BUILD_ROOT}/usr/include/openmpi-x86_64/
|
||||
cd ..
|
||||
|
||||
cd mpich
|
||||
make install DESTDIR=${RPM_BUILD_ROOT}
|
||||
mv ${RPM_BUILD_ROOT}/usr/lib64/mpich/include/* ${RPM_BUILD_ROOT}/usr/include/mpich-x86_64/
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
@@ -64,15 +154,50 @@ rm -rf %{buildroot}
|
||||
%files doc
|
||||
%{_docdir}/*
|
||||
|
||||
%files bin
|
||||
%{_bindir}/*
|
||||
|
||||
%files openmpi-bin
|
||||
%{_libdir}/openmpi/bin/*
|
||||
|
||||
%files mpich-bin
|
||||
%{_libdir}/mpich/bin/*
|
||||
|
||||
%files -n libopm-common1
|
||||
%defattr(-,root,root,-)
|
||||
%{_libdir}/*.so.*
|
||||
|
||||
%files -n libopm-common1-openmpi
|
||||
%defattr(-,root,root,-)
|
||||
%{_libdir}/openmpi/lib/*.so.*
|
||||
|
||||
%files -n libopm-common1-mpich
|
||||
%defattr(-,root,root,-)
|
||||
%{_libdir}/mpich/lib/*.so.*
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
%{_libdir}/dunecontrol/*
|
||||
/usr/lib/dunecontrol/*
|
||||
%{_libdir}/pkgconfig/*
|
||||
%{_includedir}/*
|
||||
%{_datadir}/cmake/*
|
||||
%{_datadir}/opm/*
|
||||
%{_libdir}/*.so
|
||||
|
||||
%files openmpi-devel
|
||||
%defattr(-,root,root,-)
|
||||
%{_libdir}/openmpi/lib/dunecontrol/*
|
||||
%{_libdir}/openmpi/lib/pkgconfig/*
|
||||
%{_includedir}/openmpi-x86_64/*
|
||||
%{_libdir}/openmpi/share/cmake/*
|
||||
%{_libdir}/openmpi/share/opm/*
|
||||
%{_libdir}/openmpi/lib/*.so
|
||||
|
||||
%files mpich-devel
|
||||
%defattr(-,root,root,-)
|
||||
%{_libdir}/mpich/lib/dunecontrol/*
|
||||
%{_libdir}/mpich/lib/pkgconfig/*
|
||||
%{_includedir}/mpich-x86_64/*
|
||||
%{_libdir}/mpich/share/cmake/*
|
||||
%{_libdir}/mpich/share/opm/*
|
||||
%{_libdir}/mpich/lib/*.so
|
||||
|
||||
@@ -23,7 +23,20 @@
|
||||
#include <iostream>
|
||||
#include <errno.h> // For errno
|
||||
#include <stdio.h> // For fileno() and stdout
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// MS put some POSIX-like functions in io.h, but prefix them with underscore
|
||||
// since they are considered "vendor" and not standard functions.
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#include <io.h>
|
||||
#define isatty _isatty
|
||||
#elif defined(__MINGW32__)
|
||||
// MinGW also has the isatty function in io.h instead of unistd.h, but without
|
||||
// the underscore.
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h> // For isatty()
|
||||
#endif
|
||||
|
||||
namespace Opm {
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <opm/common/utility/numeric/calculateCellVol.hpp>
|
||||
|
||||
@@ -126,6 +127,12 @@ double calculateCellVol(const std::vector<double>& X, const std::vector<double>&
|
||||
vect[j] = Y.data();
|
||||
} else if (permutation[j] == 3){
|
||||
vect[j] = Z.data();
|
||||
} else {
|
||||
// this condition can never happen, since all values in 'permutation'
|
||||
// is covered, but compiler analysis may not be deep enough to not give
|
||||
// warnings about 'vect' being uninitialized further down.
|
||||
assert(false);
|
||||
vect[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
811
src/opm/output/eclipse/AggregateWellData.cpp
Normal file
811
src/opm/output/eclipse/AggregateWellData.cpp
Normal file
@@ -0,0 +1,811 @@
|
||||
/*
|
||||
Copyright 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/>.
|
||||
*/
|
||||
|
||||
#include <opm/output/eclipse/AggregateWellData.hpp>
|
||||
|
||||
#include <opm/output/eclipse/VectorItems/intehead.hpp>
|
||||
#include <opm/output/eclipse/VectorItems/well.hpp>
|
||||
|
||||
#include <opm/output/data/Wells.hpp>
|
||||
|
||||
#include <opm/output/eclipse/SummaryState.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
namespace VI = Opm::RestartIO::Helpers::VectorItems;
|
||||
|
||||
// #####################################################################
|
||||
// Class Opm::RestartIO::Helpers::AggregateWellData
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
std::size_t numWells(const std::vector<int>& inteHead)
|
||||
{
|
||||
return inteHead[VI::intehead::NWELLS];
|
||||
}
|
||||
|
||||
int maxNumGroups(const std::vector<int>& inteHead)
|
||||
{
|
||||
return inteHead[VI::intehead::NWGMAX];
|
||||
}
|
||||
|
||||
std::string trim(const std::string& s)
|
||||
{
|
||||
const auto b = s.find_first_not_of(" \t");
|
||||
if (b == std::string::npos) {
|
||||
// All blanks. Return empty.
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto e = s.find_last_not_of(" \t");
|
||||
assert ((e != std::string::npos) && "Logic Error");
|
||||
|
||||
// Remove leading/trailing blanks.
|
||||
return s.substr(b, e - b + 1);
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
groupNames(const std::vector<const Opm::Group*>& groups)
|
||||
{
|
||||
auto gnms = std::vector<std::string>{};
|
||||
gnms.reserve(groups.size());
|
||||
|
||||
for (const auto* group : groups) {
|
||||
gnms.push_back(trim(group->name()));
|
||||
}
|
||||
|
||||
return gnms;
|
||||
}
|
||||
|
||||
template <typename WellOp>
|
||||
void wellLoop(const std::vector<const Opm::Well*>& wells,
|
||||
WellOp&& wellOp)
|
||||
{
|
||||
for (auto nWell = wells.size(), wellID = 0*nWell;
|
||||
wellID < nWell; ++wellID)
|
||||
{
|
||||
const auto* well = wells[wellID];
|
||||
|
||||
if (well == nullptr) { continue; }
|
||||
|
||||
wellOp(*well, wellID);
|
||||
}
|
||||
}
|
||||
|
||||
namespace IWell {
|
||||
std::size_t entriesPerWell(const std::vector<int>& inteHead)
|
||||
{
|
||||
return inteHead[VI::intehead::NIWELZ];
|
||||
}
|
||||
|
||||
Opm::RestartIO::Helpers::WindowedArray<int>
|
||||
allocate(const std::vector<int>& inteHead)
|
||||
{
|
||||
using WV = Opm::RestartIO::Helpers::WindowedArray<int>;
|
||||
|
||||
return WV {
|
||||
WV::NumWindows{ numWells(inteHead) },
|
||||
WV::WindowSize{ entriesPerWell(inteHead) }
|
||||
};
|
||||
}
|
||||
|
||||
int groupIndex(const std::string& grpName,
|
||||
const std::vector<std::string>& groupNames,
|
||||
const int maxGroups)
|
||||
{
|
||||
if (grpName == "FIELD") {
|
||||
// Not really supposed to happen since wells are
|
||||
// not supposed to be parented dirctly to FIELD.
|
||||
return maxGroups + 1;
|
||||
}
|
||||
|
||||
auto b = std::begin(groupNames);
|
||||
auto e = std::end (groupNames);
|
||||
auto i = std::find(b, e, grpName);
|
||||
|
||||
if (i == e) {
|
||||
// Not really supposed to happen since wells are
|
||||
// not supposed to be parented dirctly to FIELD.
|
||||
return maxGroups + 1;
|
||||
}
|
||||
|
||||
// One-based indexing.
|
||||
return std::distance(b, i) + 1;
|
||||
}
|
||||
|
||||
int wellType(const Opm::Well& well,
|
||||
const std::size_t sim_step)
|
||||
{
|
||||
using WTypeVal = ::Opm::RestartIO::Helpers::
|
||||
VectorItems::IWell::Value::WellType;
|
||||
|
||||
if (well.isProducer(sim_step)) {
|
||||
return WTypeVal::Producer;
|
||||
}
|
||||
|
||||
using IType = ::Opm::WellInjector::TypeEnum;
|
||||
|
||||
const auto itype = well
|
||||
.getInjectionProperties(sim_step).injectorType;
|
||||
|
||||
switch (itype) {
|
||||
case IType::OIL: return WTypeVal::OilInj;
|
||||
case IType::WATER: return WTypeVal::WatInj;
|
||||
case IType::GAS: return WTypeVal::GasInj;
|
||||
default: return WTypeVal::WTUnk;
|
||||
}
|
||||
}
|
||||
|
||||
int wellVFPTab(const Opm::Well& well,
|
||||
const std::size_t sim_step)
|
||||
{
|
||||
if (well.isInjector(sim_step)) {
|
||||
return well.getInjectionProperties(sim_step).VFPTableNumber;
|
||||
}
|
||||
|
||||
return well.getProductionProperties(sim_step).VFPTableNumber;
|
||||
}
|
||||
|
||||
int ctrlMode(const Opm::Well& well,
|
||||
const std::size_t sim_step)
|
||||
{
|
||||
using WMCtrlVal = ::Opm::RestartIO::Helpers::
|
||||
VectorItems::IWell::Value::WellCtrlMode;
|
||||
|
||||
{
|
||||
const auto stat = well.getStatus(sim_step);
|
||||
|
||||
using WStat = ::Opm::WellCommon::StatusEnum;
|
||||
|
||||
if ((stat == WStat::SHUT) || (stat == WStat::STOP)) {
|
||||
return WMCtrlVal::Shut;
|
||||
}
|
||||
}
|
||||
|
||||
if (well.isInjector(sim_step)) {
|
||||
const auto& prop = well
|
||||
.getInjectionProperties(sim_step);
|
||||
|
||||
const auto wmctl = prop.controlMode;
|
||||
const auto wtype = prop.injectorType;
|
||||
|
||||
using CMode = ::Opm::WellInjector::ControlModeEnum;
|
||||
using WType = ::Opm::WellInjector::TypeEnum;
|
||||
|
||||
switch (wmctl) {
|
||||
case CMode::RATE: {
|
||||
switch (wtype) {
|
||||
case WType::OIL: return WMCtrlVal::OilRate;
|
||||
case WType::WATER: return WMCtrlVal::WatRate;
|
||||
case WType::GAS: return WMCtrlVal::GasRate;
|
||||
case WType::MULTI: return WMCtrlVal::WMCtlUnk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMode::RESV: return WMCtrlVal::ResVRate;
|
||||
case CMode::THP: return WMCtrlVal::THP;
|
||||
case CMode::BHP: return WMCtrlVal::BHP;
|
||||
case CMode::GRUP: return WMCtrlVal::Group;
|
||||
|
||||
default:
|
||||
return WMCtrlVal::WMCtlUnk;
|
||||
}
|
||||
}
|
||||
else if (well.isProducer(sim_step)) {
|
||||
const auto& prop = well
|
||||
.getProductionProperties(sim_step);
|
||||
|
||||
using CMode = ::Opm::WellProducer::ControlModeEnum;
|
||||
|
||||
switch (prop.controlMode) {
|
||||
case CMode::ORAT: return WMCtrlVal::OilRate;
|
||||
case CMode::WRAT: return WMCtrlVal::WatRate;
|
||||
case CMode::GRAT: return WMCtrlVal::GasRate;
|
||||
case CMode::LRAT: return WMCtrlVal::LiqRate;
|
||||
case CMode::RESV: return WMCtrlVal::ResVRate;
|
||||
case CMode::THP: return WMCtrlVal::THP;
|
||||
case CMode::BHP: return WMCtrlVal::BHP;
|
||||
case CMode::CRAT: return WMCtrlVal::CombRate;
|
||||
case CMode::GRUP: return WMCtrlVal::Group;
|
||||
|
||||
default: return WMCtrlVal::WMCtlUnk;
|
||||
}
|
||||
}
|
||||
|
||||
return WMCtrlVal::WMCtlUnk;
|
||||
}
|
||||
|
||||
int compOrder(const Opm::Well& well)
|
||||
{
|
||||
using WCO = ::Opm::WellCompletion::CompletionOrderEnum;
|
||||
using COVal = ::Opm::RestartIO::Helpers::
|
||||
VectorItems::IWell::Value::CompOrder;
|
||||
|
||||
switch (well.getWellConnectionOrdering()) {
|
||||
case WCO::TRACK: return COVal::Track;
|
||||
case WCO::DEPTH: return COVal::Depth;
|
||||
case WCO::INPUT: return COVal::Input;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class IWellArray>
|
||||
void staticContrib(const Opm::Well& well,
|
||||
const std::size_t msWellID,
|
||||
const std::vector<std::string>& groupNames,
|
||||
const int maxGroups,
|
||||
const std::size_t sim_step,
|
||||
IWellArray& iWell)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::IWell::index;
|
||||
|
||||
iWell[Ix::IHead] = well.getHeadI(sim_step) + 1;
|
||||
iWell[Ix::JHead] = well.getHeadJ(sim_step) + 1;
|
||||
|
||||
// Connections
|
||||
{
|
||||
const auto& conn = well.getConnections(sim_step);
|
||||
|
||||
iWell[Ix::NConn] = static_cast<int>(conn.size());
|
||||
iWell[Ix::FirstK] = (iWell[Ix::NConn] == 0)
|
||||
? 0 : conn.get(0).getK() + 1;
|
||||
|
||||
iWell[Ix::LastK] = (iWell[Ix::NConn] == 0)
|
||||
? 0 : conn.get(conn.size() - 1).getK() + 1;
|
||||
}
|
||||
|
||||
iWell[Ix::Group] =
|
||||
groupIndex(trim(well.getGroupName(sim_step)),
|
||||
groupNames, maxGroups);
|
||||
|
||||
iWell[Ix::WType] = wellType (well, sim_step);
|
||||
iWell[Ix::WCtrl] = ctrlMode (well, sim_step);
|
||||
iWell[Ix::VFPTab] = wellVFPTab(well, sim_step);
|
||||
|
||||
// The following items aren't fully characterised yet, but
|
||||
// needed for restart of M2. Will need further refinement.
|
||||
iWell[Ix::item18] = -100;
|
||||
iWell[Ix::item25] = - 1;
|
||||
iWell[Ix::item32] = 7;
|
||||
iWell[Ix::item48] = - 1;
|
||||
|
||||
iWell[Ix::item50] = iWell[Ix::WCtrl];
|
||||
|
||||
// Multi-segmented well information
|
||||
iWell[Ix::MsWID] = 0; // MS Well ID (0 or 1..#MS wells)
|
||||
iWell[Ix::NWseg] = 0; // Number of well segments
|
||||
if (well.isMultiSegment(sim_step)) {
|
||||
iWell[Ix::MsWID] = static_cast<int>(msWellID);
|
||||
iWell[Ix::NWseg] =
|
||||
well.getWellSegments(sim_step).size();
|
||||
}
|
||||
|
||||
iWell[Ix::CompOrd] = compOrder(well);
|
||||
}
|
||||
|
||||
template <class IWellArray>
|
||||
void dynamicContribShut(IWellArray& iWell)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::IWell::index;
|
||||
|
||||
iWell[Ix::item9 ] = -1000;
|
||||
iWell[Ix::item11] = -1000;
|
||||
}
|
||||
|
||||
template <class IWellArray>
|
||||
void dynamicContribOpen(const Opm::data::Well& xw,
|
||||
IWellArray& iWell)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::IWell::index;
|
||||
|
||||
const auto any_flowing_conn =
|
||||
std::any_of(std::begin(xw.connections),
|
||||
std::end (xw.connections),
|
||||
[](const Opm::data::Connection& c)
|
||||
{
|
||||
return c.rates.any();
|
||||
});
|
||||
|
||||
iWell[Ix::item9] = any_flowing_conn
|
||||
? iWell[Ix::WCtrl] : -1;
|
||||
|
||||
iWell[Ix::item11] = 1;
|
||||
}
|
||||
} // IWell
|
||||
|
||||
namespace SWell {
|
||||
std::size_t entriesPerWell(const std::vector<int>& inteHead)
|
||||
{
|
||||
assert ((inteHead[VI::intehead::NSWELZ] > 121) &&
|
||||
"SWEL must allocate at least 122 elements per well");
|
||||
|
||||
return inteHead[VI::intehead::NSWELZ];
|
||||
}
|
||||
|
||||
float datumDepth(const Opm::Well& well,
|
||||
const std::size_t sim_step)
|
||||
{
|
||||
if (well.isMultiSegment(sim_step)) {
|
||||
// Datum depth for multi-segment wells is
|
||||
// depth of top-most segment.
|
||||
return well.getWellSegments(sim_step)
|
||||
.depthTopSegment();
|
||||
}
|
||||
|
||||
// Not a multi-segment well--i.e., this is a regular
|
||||
// well. Use well's reference depth.
|
||||
return well.getRefDepth(sim_step);
|
||||
}
|
||||
|
||||
Opm::RestartIO::Helpers::WindowedArray<float>
|
||||
allocate(const std::vector<int>& inteHead)
|
||||
{
|
||||
using WV = Opm::RestartIO::Helpers::WindowedArray<float>;
|
||||
|
||||
return WV {
|
||||
WV::NumWindows{ numWells(inteHead) },
|
||||
WV::WindowSize{ entriesPerWell(inteHead) }
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<float> defaultSWell()
|
||||
{
|
||||
const auto dflt = -1.0e+20f;
|
||||
const auto infty = 1.0e+20f;
|
||||
const auto zero = 0.0f;
|
||||
const auto one = 1.0f;
|
||||
const auto half = 0.5f;
|
||||
|
||||
// Initial data by Statoil ASA.
|
||||
return { // 122 Items (0..121)
|
||||
// 0 1 2 3 4 5
|
||||
infty, infty, infty, infty, infty, infty, // 0.. 5 ( 0)
|
||||
one , zero , zero , zero , zero , 1.0e-05f, // 6.. 11 ( 1)
|
||||
zero , zero , infty, infty, zero , dflt , // 12.. 17 ( 2)
|
||||
infty, infty, infty, infty, infty, zero , // 18.. 23 ( 3)
|
||||
one , zero , zero , zero , zero , zero , // 24.. 29 ( 4)
|
||||
zero , one , zero , infty, zero , zero , // 30.. 35 ( 5)
|
||||
zero , zero , zero , zero , zero , zero , // 36.. 41 ( 6)
|
||||
zero , zero , zero , zero , zero , zero , // 42.. 47 ( 7)
|
||||
zero , zero , zero , zero , zero , zero , // 48.. 53 ( 8)
|
||||
infty, zero , zero , zero , zero , zero , // 54.. 59 ( 9)
|
||||
zero , zero , zero , zero , zero , zero , // 60.. 65 (10)
|
||||
zero , zero , zero , zero , zero , zero , // 66.. 71 (11)
|
||||
zero , zero , zero , zero , zero , zero , // 72.. 77 (12)
|
||||
zero , infty, infty, zero , zero , one , // 78.. 83 (13)
|
||||
one , one , zero , infty, zero , infty, // 84.. 89 (14)
|
||||
one , dflt , one , zero , zero , zero , // 90.. 95 (15)
|
||||
zero , zero , zero , zero , zero , zero , // 96..101 (16)
|
||||
zero , zero , zero , zero , zero , zero , // 102..107 (17)
|
||||
zero , zero , half , one , zero , zero , // 108..113 (18)
|
||||
zero , zero , zero , zero , zero , infty, // 114..119 (19)
|
||||
zero , one , // 120..121 (20)
|
||||
};
|
||||
}
|
||||
|
||||
template <class SWellArray>
|
||||
void assignDefaultSWell(SWellArray& sWell)
|
||||
{
|
||||
const auto& init = defaultSWell();
|
||||
|
||||
const auto sz = static_cast<
|
||||
decltype(init.size())>(sWell.size());
|
||||
|
||||
auto b = std::begin(init);
|
||||
auto e = b + std::min(init.size(), sz);
|
||||
|
||||
std::copy(b, e, std::begin(sWell));
|
||||
}
|
||||
|
||||
template <class SWellArray>
|
||||
void staticContrib(const Opm::Well& well,
|
||||
const Opm::UnitSystem& units,
|
||||
const std::size_t sim_step,
|
||||
SWellArray& sWell)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SWell::index;
|
||||
using M = ::Opm::UnitSystem::measure;
|
||||
|
||||
auto swprop = [&units](const M u, const double x) -> float
|
||||
{
|
||||
return static_cast<float>(units.from_si(u, x));
|
||||
};
|
||||
|
||||
assignDefaultSWell(sWell);
|
||||
|
||||
if (well.isProducer(sim_step)) {
|
||||
const auto& pp = well.getProductionProperties(sim_step);
|
||||
|
||||
using PP = ::Opm::WellProducer::ControlModeEnum;
|
||||
|
||||
if (pp.hasProductionControl(PP::ORAT)) {
|
||||
sWell[Ix::OilRateTarget] =
|
||||
swprop(M::liquid_surface_rate, pp.OilRate);
|
||||
}
|
||||
|
||||
if (pp.hasProductionControl(PP::WRAT)) {
|
||||
sWell[Ix::WatRateTarget] =
|
||||
swprop(M::liquid_surface_rate, pp.WaterRate);
|
||||
}
|
||||
|
||||
if (pp.hasProductionControl(PP::GRAT)) {
|
||||
sWell[Ix::GasRateTarget] =
|
||||
swprop(M::gas_surface_rate, pp.GasRate);
|
||||
}
|
||||
|
||||
if (pp.hasProductionControl(PP::LRAT)) {
|
||||
sWell[Ix::LiqRateTarget] =
|
||||
swprop(M::liquid_surface_rate, pp.LiquidRate);
|
||||
}
|
||||
else if (pp.hasProductionControl(PP::ORAT) &&
|
||||
pp.hasProductionControl(PP::WRAT))
|
||||
{
|
||||
sWell[Ix::LiqRateTarget] =
|
||||
swprop(M::liquid_surface_rate, pp.OilRate + pp.WaterRate);
|
||||
}
|
||||
|
||||
if (pp.hasProductionControl(PP::RESV)) {
|
||||
sWell[Ix::ResVRateTarget] =
|
||||
swprop(M::rate, pp.ResVRate);
|
||||
}
|
||||
|
||||
if (pp.hasProductionControl(PP::THP)) {
|
||||
sWell[Ix::THPTarget] =
|
||||
swprop(M::pressure, pp.THPLimit);
|
||||
}
|
||||
|
||||
sWell[Ix::BHPTarget] = pp.hasProductionControl(PP::BHP)
|
||||
? swprop(M::pressure, pp.BHPLimit)
|
||||
: swprop(M::pressure, 100.0e3*::Opm::unit::psia);
|
||||
}
|
||||
else if (well.isInjector(sim_step)) {
|
||||
const auto& ip = well.getInjectionProperties(sim_step);
|
||||
|
||||
using IP = ::Opm::WellInjector::ControlModeEnum;
|
||||
|
||||
if (ip.hasInjectionControl(IP::THP)) {
|
||||
sWell[Ix::THPTarget] = swprop(M::pressure, ip.THPLimit);
|
||||
}
|
||||
|
||||
sWell[Ix::BHPTarget] = ip.hasInjectionControl(IP::BHP)
|
||||
? swprop(M::pressure, ip.BHPLimit)
|
||||
: swprop(M::pressure, 1.0*::Opm::unit::atm);
|
||||
}
|
||||
|
||||
sWell[Ix::DatumDepth] =
|
||||
swprop(M::length, datumDepth(well, sim_step));
|
||||
}
|
||||
} // SWell
|
||||
|
||||
namespace XWell {
|
||||
std::size_t entriesPerWell(const std::vector<int>& inteHead)
|
||||
{
|
||||
assert ((inteHead[VI::intehead::NXWELZ] > 123) &&
|
||||
"XWEL must allocate at least 124 elements per well");
|
||||
|
||||
return inteHead[VI::intehead::NXWELZ];
|
||||
}
|
||||
|
||||
Opm::RestartIO::Helpers::WindowedArray<double>
|
||||
allocate(const std::vector<int>& inteHead)
|
||||
{
|
||||
using WV = Opm::RestartIO::Helpers::WindowedArray<double>;
|
||||
|
||||
return WV {
|
||||
WV::NumWindows{ numWells(inteHead) },
|
||||
WV::WindowSize{ entriesPerWell(inteHead) }
|
||||
};
|
||||
}
|
||||
|
||||
template <class XWellArray>
|
||||
void staticContrib(const ::Opm::Well& well,
|
||||
const Opm::UnitSystem& units,
|
||||
const std::size_t sim_step,
|
||||
XWellArray& xWell)
|
||||
{
|
||||
using M = ::Opm::UnitSystem::measure;
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
|
||||
|
||||
const auto bhpTarget = well.isInjector(sim_step)
|
||||
? well.getInjectionProperties (sim_step).BHPLimit
|
||||
: well.getProductionProperties(sim_step).BHPLimit;
|
||||
|
||||
xWell[Ix::BHPTarget] = units.from_si(M::pressure, bhpTarget);
|
||||
}
|
||||
|
||||
template <class XWellArray>
|
||||
void assignProducer(const std::string& well,
|
||||
const ::Opm::SummaryState& smry,
|
||||
XWellArray& xWell)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
|
||||
|
||||
auto get = [&smry, &well](const std::string& vector)
|
||||
{
|
||||
return smry.get(vector + ':' + well);
|
||||
};
|
||||
|
||||
xWell[Ix::OilPrRate] = get("WOPR");
|
||||
xWell[Ix::WatPrRate] = get("WWPR");
|
||||
xWell[Ix::GasPrRate] = get("WGPR");
|
||||
|
||||
xWell[Ix::LiqPrRate] = xWell[Ix::OilPrRate]
|
||||
+ xWell[Ix::WatPrRate];
|
||||
|
||||
xWell[Ix::VoidPrRate] = get("WVPR");
|
||||
|
||||
xWell[Ix::FlowBHP] = get("WBHP");
|
||||
xWell[Ix::WatCut] = get("WWCT");
|
||||
xWell[Ix::GORatio] = get("WGOR");
|
||||
|
||||
xWell[Ix::OilPrTotal] = get("WOPT");
|
||||
xWell[Ix::WatPrTotal] = get("WWPT");
|
||||
xWell[Ix::GasPrTotal] = get("WGPT");
|
||||
xWell[Ix::VoidPrTotal] = get("WVPT");
|
||||
|
||||
// Not fully characterised.
|
||||
xWell[Ix::item37] = xWell[Ix::WatPrRate];
|
||||
xWell[Ix::item38] = xWell[Ix::GasPrRate];
|
||||
}
|
||||
|
||||
template <class XWellArray>
|
||||
void assignWaterInjector(const std::string& well,
|
||||
const ::Opm::SummaryState& smry,
|
||||
XWellArray& xWell)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
|
||||
|
||||
auto get = [&smry, &well](const std::string& vector)
|
||||
{
|
||||
return smry.get(vector + ':' + well);
|
||||
};
|
||||
|
||||
// Injection rates reported as negative, cumulative
|
||||
// totals as positive.
|
||||
xWell[Ix::WatPrRate] = -get("WWIR");
|
||||
xWell[Ix::LiqPrRate] = xWell[Ix::WatPrRate];
|
||||
|
||||
xWell[Ix::FlowBHP] = get("WBHP");
|
||||
|
||||
xWell[Ix::WatInjTotal] = get("WWIT");
|
||||
|
||||
xWell[Ix::item37] = xWell[Ix::WatPrRate];
|
||||
xWell[Ix::item82] = xWell[Ix::WatInjTotal];
|
||||
|
||||
xWell[Ix::WatVoidPrRate] = -get("WWVIR");
|
||||
}
|
||||
|
||||
template <class XWellArray>
|
||||
void assignGasInjector(const std::string& well,
|
||||
const ::Opm::SummaryState& smry,
|
||||
XWellArray& xWell)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
|
||||
|
||||
auto get = [&smry, &well](const std::string& vector)
|
||||
{
|
||||
return smry.get(vector + ':' + well);
|
||||
};
|
||||
|
||||
// Injection rates reported as negative production rates,
|
||||
// cumulative injection totals as positive.
|
||||
xWell[Ix::GasPrRate] = -get("WGIR");
|
||||
xWell[Ix::VoidPrRate] = -get("WGVIR");
|
||||
|
||||
xWell[Ix::FlowBHP] = get("WBHP");
|
||||
|
||||
xWell[Ix::GasInjTotal] = get("WGIT");
|
||||
|
||||
xWell[Ix::GasFVF] = xWell[Ix::VoidPrRate]
|
||||
/ xWell[Ix::GasPrRate];
|
||||
|
||||
// Not fully characterised.
|
||||
xWell[Ix::item38] = xWell[Ix::GasPrRate];
|
||||
xWell[Ix::item83] = xWell[Ix::GasInjTotal];
|
||||
|
||||
xWell[Ix::GasVoidPrRate] = xWell[Ix::VoidPrRate];
|
||||
}
|
||||
|
||||
template <class XWellArray>
|
||||
void dynamicContrib(const ::Opm::Well& well,
|
||||
const ::Opm::SummaryState& smry,
|
||||
const std::size_t sim_step,
|
||||
XWellArray& xWell)
|
||||
{
|
||||
if (well.isProducer(sim_step)) {
|
||||
assignProducer(well.name(), smry, xWell);
|
||||
}
|
||||
else if (well.isInjector(sim_step)) {
|
||||
using IType = ::Opm::WellInjector::TypeEnum;
|
||||
|
||||
const auto itype = well
|
||||
.getInjectionProperties(sim_step).injectorType;
|
||||
|
||||
switch (itype) {
|
||||
case IType::OIL:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
case IType::WATER:
|
||||
assignWaterInjector(well.name(), smry, xWell);
|
||||
break;
|
||||
|
||||
case IType::GAS:
|
||||
assignGasInjector(well.name(), smry, xWell);
|
||||
break;
|
||||
|
||||
case IType::MULTI:
|
||||
assignWaterInjector(well.name(), smry, xWell);
|
||||
assignGasInjector (well.name(), smry, xWell);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // XWell
|
||||
|
||||
namespace ZWell {
|
||||
std::size_t entriesPerWell(const std::vector<int>& inteHead)
|
||||
{
|
||||
assert ((inteHead[VI::intehead::NZWELZ] > 1) &&
|
||||
"ZWEL must allocate at least 1 element per well");
|
||||
|
||||
return inteHead[VI::intehead::NZWELZ];
|
||||
}
|
||||
|
||||
Opm::RestartIO::Helpers::WindowedArray<
|
||||
Opm::RestartIO::Helpers::CharArrayNullTerm<8>
|
||||
>
|
||||
allocate(const std::vector<int>& inteHead)
|
||||
{
|
||||
using WV = Opm::RestartIO::Helpers::WindowedArray<
|
||||
Opm::RestartIO::Helpers::CharArrayNullTerm<8>
|
||||
>;
|
||||
|
||||
return WV {
|
||||
WV::NumWindows{ numWells(inteHead) },
|
||||
WV::WindowSize{ entriesPerWell(inteHead) }
|
||||
};
|
||||
}
|
||||
|
||||
template <class ZWellArray>
|
||||
void staticContrib(const Opm::Well& well, ZWellArray& zWell)
|
||||
{
|
||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::ZWell::index;
|
||||
|
||||
zWell[Ix::WellName] = well.name();
|
||||
}
|
||||
} // ZWell
|
||||
} // Anonymous
|
||||
|
||||
// =====================================================================
|
||||
|
||||
Opm::RestartIO::Helpers::AggregateWellData::
|
||||
AggregateWellData(const std::vector<int>& inteHead)
|
||||
: iWell_ (IWell::allocate(inteHead))
|
||||
, sWell_ (SWell::allocate(inteHead))
|
||||
, xWell_ (XWell::allocate(inteHead))
|
||||
, zWell_ (ZWell::allocate(inteHead))
|
||||
, nWGMax_(maxNumGroups(inteHead))
|
||||
{}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void
|
||||
Opm::RestartIO::Helpers::AggregateWellData::
|
||||
captureDeclaredWellData(const Schedule& sched,
|
||||
const UnitSystem& units,
|
||||
const std::size_t sim_step)
|
||||
{
|
||||
const auto& wells = sched.getWells(sim_step);
|
||||
|
||||
// Static contributions to IWEL array.
|
||||
{
|
||||
const auto grpNames = groupNames(sched.getGroups());
|
||||
auto msWellID = std::size_t{0};
|
||||
|
||||
wellLoop(wells, [&grpNames, &msWellID, sim_step, this]
|
||||
(const Well& well, const std::size_t wellID) -> void
|
||||
{
|
||||
msWellID += well.isMultiSegment(sim_step); // 1-based index.
|
||||
auto iw = this->iWell_[wellID];
|
||||
|
||||
IWell::staticContrib(well, msWellID, grpNames,
|
||||
this->nWGMax_, sim_step, iw);
|
||||
});
|
||||
}
|
||||
|
||||
// Static contributions to SWEL array.
|
||||
wellLoop(wells, [&units, sim_step, this]
|
||||
(const Well& well, const std::size_t wellID) -> void
|
||||
{
|
||||
auto sw = this->sWell_[wellID];
|
||||
|
||||
SWell::staticContrib(well, units, sim_step, sw);
|
||||
});
|
||||
|
||||
// Static contributions to XWEL array.
|
||||
wellLoop(wells, [&units, sim_step, this]
|
||||
(const Well& well, const std::size_t wellID) -> void
|
||||
{
|
||||
auto xw = this->xWell_[wellID];
|
||||
|
||||
XWell::staticContrib(well, units, sim_step, xw);
|
||||
});
|
||||
|
||||
// Static contributions to ZWEL array.
|
||||
wellLoop(wells,
|
||||
[this](const Well& well, const std::size_t wellID) -> void
|
||||
{
|
||||
auto zw = this->zWell_[wellID];
|
||||
|
||||
ZWell::staticContrib(well, zw);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void
|
||||
Opm::RestartIO::Helpers::AggregateWellData::
|
||||
captureDynamicWellData(const Schedule& sched,
|
||||
const std::size_t sim_step,
|
||||
const Opm::data::WellRates& xw,
|
||||
const ::Opm::SummaryState& smry)
|
||||
{
|
||||
const auto& wells = sched.getWells(sim_step);
|
||||
|
||||
// Dynamic contributions to IWEL array.
|
||||
wellLoop(wells, [this, &xw]
|
||||
(const Well& well, const std::size_t wellID) -> void
|
||||
{
|
||||
auto iWell = this->iWell_[wellID];
|
||||
|
||||
auto i = xw.find(well.name());
|
||||
if ((i == std::end(xw)) || !i->second.flowing()) {
|
||||
IWell::dynamicContribShut(iWell);
|
||||
}
|
||||
else {
|
||||
IWell::dynamicContribOpen(i->second, iWell);
|
||||
}
|
||||
});
|
||||
|
||||
// Dynamic contributions to XWEL array.
|
||||
wellLoop(wells, [this, sim_step, &smry]
|
||||
(const Well& well, const std::size_t wellID) -> void
|
||||
{
|
||||
auto xw = this->xWell_[wellID];
|
||||
|
||||
XWell::dynamicContrib(well, smry, sim_step, xw);
|
||||
});
|
||||
}
|
||||
89
src/opm/output/eclipse/CreateDoubHead.cpp
Executable file
89
src/opm/output/eclipse/CreateDoubHead.cpp
Executable file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
|
||||
|
||||
#include <opm/output/eclipse/DoubHEAD.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
Opm::RestartIO::DoubHEAD::TimeStamp
|
||||
computeTimeStamp(const ::Opm::Schedule& sched,
|
||||
const double elapsed)
|
||||
{
|
||||
return {
|
||||
std::chrono::system_clock::from_time_t(sched.getStartTime()),
|
||||
std::chrono::duration<
|
||||
double, std::chrono::seconds::period>{ elapsed },
|
||||
};
|
||||
}
|
||||
|
||||
double getTimeConv(const ::Opm::UnitSystem& us)
|
||||
{
|
||||
switch (us.getType()) {
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC:
|
||||
return static_cast<double>(Opm::Metric::Time);
|
||||
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_FIELD:
|
||||
return static_cast<double>(Opm::Field::Time);
|
||||
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_LAB:
|
||||
return static_cast<double>(Opm::Lab::Time);
|
||||
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_PVT_M:
|
||||
return static_cast<double>(Opm::PVT_M::Time);
|
||||
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_INPUT:
|
||||
throw std::invalid_argument {
|
||||
"Cannot Run Simulation With Non-Standard Units"
|
||||
};
|
||||
}
|
||||
|
||||
return static_cast<double>(Opm::Metric::Time);
|
||||
}
|
||||
} // Anonymous
|
||||
|
||||
// #####################################################################
|
||||
// Public Interface (createDoubHead()) Below Separator
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
std::vector<double>
|
||||
Opm::RestartIO::Helpers::
|
||||
createDoubHead(const EclipseState& es,
|
||||
const Schedule& sched,
|
||||
const std::size_t lookup_step,
|
||||
const double simTime)
|
||||
{
|
||||
const auto dh = DoubHEAD{}
|
||||
.tuningParameters(sched.getTuning(), lookup_step,
|
||||
getTimeConv(es.getDeckUnitSystem()))
|
||||
.timeStamp (computeTimeStamp(sched, simTime))
|
||||
.drsdt (sched, lookup_step)
|
||||
;
|
||||
|
||||
return dh.data();
|
||||
}
|
||||
240
src/opm/output/eclipse/CreateInteHead.cpp
Executable file
240
src/opm/output/eclipse/CreateInteHead.cpp
Executable file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
|
||||
|
||||
#include <opm/output/eclipse/InteHEAD.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Tables/Regdims.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Tables/TableManager.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
Opm::RestartIO::InteHEAD::WellTableDim
|
||||
getWellTableDims(const ::Opm::Runspec& rspec,
|
||||
const ::Opm::Schedule& sched,
|
||||
const std::size_t lookup_step)
|
||||
{
|
||||
const auto& wd = rspec.wellDimensions();
|
||||
|
||||
const auto numWells = static_cast<int>(sched.numWells(lookup_step));
|
||||
|
||||
const auto maxPerf = wd.maxConnPerWell();
|
||||
const auto maxWellInGroup = wd.maxWellsPerGroup();
|
||||
const auto maxGroupInField = wd.maxGroupsInField();
|
||||
|
||||
return {
|
||||
numWells,
|
||||
maxPerf,
|
||||
maxWellInGroup,
|
||||
maxGroupInField,
|
||||
};
|
||||
}
|
||||
|
||||
std::array<int, 4> getNGRPZ(const ::Opm::Runspec& rspec)
|
||||
{
|
||||
const auto& wd = rspec.wellDimensions();
|
||||
|
||||
const int nigrpz = 97 + std::max(wd.maxWellsPerGroup(),
|
||||
wd.maxGroupsInField());
|
||||
const int nsgrpz = 112;
|
||||
const int nxgrpz = 180;
|
||||
const int nzgrpz = 5;
|
||||
|
||||
return {
|
||||
nigrpz,
|
||||
nsgrpz,
|
||||
nxgrpz,
|
||||
nzgrpz
|
||||
};
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD::UnitSystem
|
||||
getUnitConvention(const ::Opm::UnitSystem& us)
|
||||
{
|
||||
using US = ::Opm::RestartIO::InteHEAD::UnitSystem;
|
||||
|
||||
switch (us.getType()) {
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC:
|
||||
return US::Metric;
|
||||
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_FIELD:
|
||||
return US::Field;
|
||||
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_LAB:
|
||||
return US::Lab;
|
||||
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_PVT_M:
|
||||
return US::PVT_M;
|
||||
|
||||
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_INPUT:
|
||||
throw std::invalid_argument {
|
||||
"Cannot Run Simulation With Non-Standard Units"
|
||||
};
|
||||
}
|
||||
|
||||
return US::Metric;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD::Phases
|
||||
getActivePhases(const ::Opm::Runspec& rspec)
|
||||
{
|
||||
auto phases = ::Opm::RestartIO::InteHEAD::Phases{};
|
||||
|
||||
const auto& phasePred = rspec.phases();
|
||||
|
||||
phases.oil = phasePred.active(Opm::Phase::OIL);
|
||||
phases.water = phasePred.active(Opm::Phase::WATER);
|
||||
phases.gas = phasePred.active(Opm::Phase::GAS);
|
||||
|
||||
return phases;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD::TuningPar
|
||||
getTuningPars(const ::Opm::Tuning& tuning,
|
||||
const std::size_t lookup_step)
|
||||
{
|
||||
const auto& newtmx = tuning.getNEWTMX(lookup_step);
|
||||
const auto& newtmn = tuning.getNEWTMN(lookup_step);
|
||||
const auto& litmax = tuning.getLITMAX(lookup_step);
|
||||
const auto& litmin = tuning.getLITMIN(lookup_step);
|
||||
const auto& mxwsit = tuning.getMXWSIT(lookup_step);
|
||||
const auto& mxwpit = tuning.getMXWPIT(lookup_step);
|
||||
|
||||
return {
|
||||
newtmx,
|
||||
newtmn,
|
||||
litmax,
|
||||
litmin,
|
||||
mxwsit,
|
||||
mxwpit,
|
||||
};
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD::WellSegDims
|
||||
getWellSegDims(const ::Opm::Runspec& rspec,
|
||||
const ::Opm::Schedule& sched,
|
||||
const std::size_t lookup_step)
|
||||
{
|
||||
const auto& wsd = rspec.wellSegmentDimensions();
|
||||
|
||||
const auto& sched_wells = sched.getWells(lookup_step);
|
||||
|
||||
const auto nsegwl =
|
||||
std::count_if(std::begin(sched_wells), std::end(sched_wells),
|
||||
[lookup_step](const Opm::Well* wellPtr)
|
||||
{
|
||||
return wellPtr->isMultiSegment(lookup_step);
|
||||
});
|
||||
|
||||
const auto nswlmx = wsd.maxSegmentedWells();
|
||||
const auto nsegmx = wsd.maxSegmentsPerWell();
|
||||
const auto nlbrmx = wsd.maxLateralBranchesPerWell();
|
||||
const auto nisegz = 22; // Number of entries per segment in ISEG.
|
||||
const auto nrsegz = 140; // Number of entries per segment in RSEG array.
|
||||
const auto nilbrz = 10; // Number of entries per segment in ILBR array.
|
||||
|
||||
return {
|
||||
static_cast<int>(nsegwl),
|
||||
nswlmx,
|
||||
nsegmx,
|
||||
nlbrmx,
|
||||
nisegz,
|
||||
nrsegz,
|
||||
nilbrz
|
||||
};
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD::RegDims
|
||||
getRegDims(const ::Opm::TableManager& tdims,
|
||||
const ::Opm::Regdims& rdims)
|
||||
{
|
||||
const auto ntfip = tdims.numFIPRegions();
|
||||
const auto nmfipr = rdims.getNMFIPR();
|
||||
const auto nrfreg = rdims.getNRFREG();
|
||||
const auto ntfreg = rdims.getNTFREG();
|
||||
const auto nplmix = rdims.getNPLMIX();
|
||||
|
||||
return {
|
||||
static_cast<int>(ntfip),
|
||||
static_cast<int>(nmfipr),
|
||||
static_cast<int>(nrfreg),
|
||||
static_cast<int>(ntfreg),
|
||||
static_cast<int>(nplmix),
|
||||
};
|
||||
}
|
||||
} // Anonymous
|
||||
|
||||
// #####################################################################
|
||||
// Public Interface (createInteHead()) Below Separator
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
std::vector<int>
|
||||
Opm::RestartIO::Helpers::
|
||||
createInteHead(const EclipseState& es,
|
||||
const EclipseGrid& grid,
|
||||
const Schedule& sched,
|
||||
const double simTime,
|
||||
const int num_solver_steps,
|
||||
const int lookup_step,
|
||||
const int report_step)
|
||||
{
|
||||
const auto& rspec = es.runspec();
|
||||
const auto& tdim = es.getTableManager();
|
||||
const auto& rdim = tdim.getRegdims();
|
||||
|
||||
const auto ih = InteHEAD{}
|
||||
.dimensions (grid.getNXYZ())
|
||||
.numActive (static_cast<int>(grid.getNumActive()))
|
||||
.unitConventions (getUnitConvention(es.getDeckUnitSystem()))
|
||||
.wellTableDimensions(getWellTableDims(rspec, sched, lookup_step))
|
||||
.calendarDate (getSimulationTimePoint(sched.posixStartTime(), simTime))
|
||||
.activePhases (getActivePhases(rspec))
|
||||
// The numbers below have been determined experimentally to work
|
||||
// across a range of reference cases, but are not guaranteed to be
|
||||
// universally valid.
|
||||
.params_NWELZ (155, 122, 130, 3) // n{isxz}welz: number of data elements per well in {ISXZ}WELL
|
||||
.params_NCON (25, 40, 58) // n{isx}conz: number of data elements per completion in ICON
|
||||
.params_GRPZ (getNGRPZ(rspec))
|
||||
// ncamax: max number of analytical aquifer connections
|
||||
// n{isx}aaqz: number of data elements per aquifer in {ISX}AAQ
|
||||
// n{isa}caqz: number of data elements per aquifer connection in {ISA}CAQ
|
||||
.params_NAAQZ (1, 18, 24, 10, 7, 2, 4)
|
||||
.stepParam (num_solver_steps, report_step)
|
||||
.tuningParam (getTuningPars(sched.getTuning(), lookup_step))
|
||||
.wellSegDimensions (getWellSegDims(rspec, sched, lookup_step))
|
||||
.regionDimensions (getRegDims(tdim, rdim))
|
||||
.variousParam (2014, 100) // Output should be compatible with Eclipse 100, 2014 version.
|
||||
;
|
||||
|
||||
return ih.data();
|
||||
}
|
||||
45
src/opm/output/eclipse/CreateLogiHead.cpp
Normal file
45
src/opm/output/eclipse/CreateLogiHead.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
|
||||
|
||||
#include <opm/output/eclipse/LogiHEAD.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
// #####################################################################
|
||||
// Public Interface (createLogiHead()) Below Separator
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
std::vector<bool>
|
||||
Opm::RestartIO::Helpers::
|
||||
createLogiHead(const EclipseState& es)
|
||||
{
|
||||
const auto& rspec = es.runspec();
|
||||
const auto& wsd = rspec.wellSegmentDimensions();
|
||||
|
||||
const auto lh = LogiHEAD{}
|
||||
.variousParam(false, false, wsd.maxSegmentedWells())
|
||||
;
|
||||
|
||||
return lh.data();
|
||||
}
|
||||
603
src/opm/output/eclipse/DoubHEAD.cpp
Executable file
603
src/opm/output/eclipse/DoubHEAD.cpp
Executable file
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <opm/output/eclipse/DoubHEAD.hpp>
|
||||
|
||||
// Note: DynamicState.hpp and <map> are prerequisites of Tuning.hpp
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp>
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <opm/output/eclipse/InteHEAD.hpp> // Opm::RestartIO::makeUTCTime()
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
#include <ratio>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
enum Index : std::vector<double>::size_type {
|
||||
// 0..9
|
||||
SimTime = 0,
|
||||
TsInit = 1,
|
||||
TsMaxz = 2,
|
||||
TsMinz = 3,
|
||||
TsMchp = 4,
|
||||
TsFMax = 5,
|
||||
TsFMin = 6,
|
||||
TsFcnv = 7,
|
||||
TrgTTE = 8,
|
||||
TrgCNV = 9,
|
||||
|
||||
// 10..19
|
||||
TrgMBE = 10,
|
||||
TrgLCV = 11,
|
||||
dh_012 = 12,
|
||||
dh_013 = 13,
|
||||
dh_014 = 14,
|
||||
dh_015 = 15,
|
||||
XxxTTE = 16,
|
||||
XxxCNV = 17,
|
||||
XxxMBE = 18,
|
||||
XxxLCV = 19,
|
||||
|
||||
// 20..29
|
||||
XxxWFL = 20,
|
||||
dh_021 = 21,
|
||||
dh_022 = 22,
|
||||
dh_023 = 23,
|
||||
dh_024 = 24,
|
||||
dRsdt = 25,
|
||||
dh_026 = 26,
|
||||
dh_027 = 27,
|
||||
dh_028 = 28,
|
||||
dh_029 = 29,
|
||||
|
||||
// 30..39
|
||||
dh_030 = 30,
|
||||
dh_031 = 31,
|
||||
dh_032 = 32,
|
||||
dh_033 = 33,
|
||||
dh_034 = 34,
|
||||
dh_035 = 35,
|
||||
dh_036 = 36,
|
||||
dh_037 = 37,
|
||||
dh_038 = 38,
|
||||
dh_039 = 39,
|
||||
|
||||
// 40..49
|
||||
dh_040 = 40,
|
||||
dh_041 = 41,
|
||||
dh_042 = 42,
|
||||
dh_043 = 43,
|
||||
dh_044 = 44,
|
||||
dh_045 = 45,
|
||||
dh_046 = 46,
|
||||
dh_047 = 47,
|
||||
dh_048 = 48,
|
||||
dh_049 = 49,
|
||||
|
||||
// 50..59
|
||||
dh_050 = 50,
|
||||
dh_051 = 51,
|
||||
dh_052 = 52,
|
||||
dh_053 = 53,
|
||||
dh_054 = 54,
|
||||
dh_055 = 55,
|
||||
dh_056 = 56,
|
||||
dh_057 = 57,
|
||||
dh_058 = 58,
|
||||
dh_059 = 59,
|
||||
|
||||
// 60..69
|
||||
dh_060 = 60,
|
||||
dh_061 = 61,
|
||||
dh_062 = 62,
|
||||
dh_063 = 63,
|
||||
dh_064 = 64,
|
||||
dh_065 = 65,
|
||||
dh_066 = 66,
|
||||
dh_067 = 67,
|
||||
dh_068 = 68,
|
||||
dh_069 = 69,
|
||||
|
||||
// 70..79
|
||||
dh_070 = 70,
|
||||
dh_071 = 71,
|
||||
dh_072 = 72,
|
||||
dh_073 = 73,
|
||||
dh_074 = 74,
|
||||
dh_075 = 75,
|
||||
dh_076 = 76,
|
||||
dh_077 = 77,
|
||||
dh_078 = 78,
|
||||
dh_079 = 79,
|
||||
|
||||
// 80..89
|
||||
dh_080 = 80,
|
||||
dh_081 = 81,
|
||||
TrgDPR = 82,
|
||||
TfDIFF = 83,
|
||||
DdpLim = 84,
|
||||
DdsLim = 85,
|
||||
dh_086 = 86,
|
||||
dh_087 = 87,
|
||||
dh_088 = 88,
|
||||
dh_089 = 89,
|
||||
|
||||
// 90..99
|
||||
dh_090 = 90,
|
||||
dh_091 = 91,
|
||||
dh_092 = 92,
|
||||
dh_093 = 93,
|
||||
dh_094 = 94,
|
||||
dh_095 = 95,
|
||||
dh_096 = 96,
|
||||
dh_097 = 97,
|
||||
dh_098 = 98,
|
||||
ThrUPT = 99,
|
||||
|
||||
// 100..109
|
||||
XxxDPR = 100,
|
||||
TrgFIP = 101,
|
||||
TrgSFT = 102,
|
||||
dh_103 = 103,
|
||||
dh_104 = 104,
|
||||
dh_105 = 105,
|
||||
dh_106 = 106,
|
||||
dh_107 = 107,
|
||||
dh_108 = 108,
|
||||
dh_109 = 109,
|
||||
|
||||
// 110..119
|
||||
dh_110 = 110,
|
||||
dh_111 = 111,
|
||||
dh_112 = 112,
|
||||
dh_113 = 113,
|
||||
dh_114 = 114,
|
||||
dh_115 = 115,
|
||||
dh_116 = 116,
|
||||
dh_117 = 117,
|
||||
dh_118 = 118,
|
||||
dh_119 = 119,
|
||||
|
||||
// 120..129
|
||||
dh_120 = 120,
|
||||
dh_121 = 121,
|
||||
dh_122 = 122,
|
||||
dh_123 = 123,
|
||||
dh_124 = 124,
|
||||
dh_125 = 125,
|
||||
dh_126 = 126,
|
||||
dh_127 = 127,
|
||||
dh_128 = 128,
|
||||
dh_129 = 129,
|
||||
|
||||
// 130..139
|
||||
dh_130 = 130,
|
||||
dh_131 = 131,
|
||||
dh_132 = 132,
|
||||
dh_133 = 133,
|
||||
dh_134 = 134,
|
||||
dh_135 = 135,
|
||||
dh_136 = 136,
|
||||
dh_137 = 137,
|
||||
dh_138 = 138,
|
||||
dh_139 = 139,
|
||||
|
||||
// 140..149
|
||||
dh_140 = 140,
|
||||
dh_141 = 141,
|
||||
dh_142 = 142,
|
||||
dh_143 = 143,
|
||||
dh_144 = 144,
|
||||
dh_145 = 145,
|
||||
dh_146 = 146,
|
||||
dh_147 = 147,
|
||||
dh_148 = 148,
|
||||
dh_149 = 149,
|
||||
|
||||
// 150..159
|
||||
dh_150 = 150,
|
||||
dh_151 = 151,
|
||||
dh_152 = 152,
|
||||
dh_153 = 153,
|
||||
dh_154 = 154,
|
||||
dh_155 = 155,
|
||||
dh_156 = 156,
|
||||
dh_157 = 157,
|
||||
dh_158 = 158,
|
||||
dh_159 = 159,
|
||||
|
||||
// 160..169
|
||||
Start = 160,
|
||||
Time = 161,
|
||||
dh_162 = 162,
|
||||
dh_163 = 163,
|
||||
dh_164 = 164,
|
||||
dh_165 = 165,
|
||||
dh_166 = 166,
|
||||
dh_167 = 167,
|
||||
dh_168 = 168,
|
||||
dh_169 = 169,
|
||||
|
||||
// 170..179
|
||||
dh_170 = 170,
|
||||
dh_171 = 171,
|
||||
dh_172 = 172,
|
||||
dh_173 = 173,
|
||||
dh_174 = 174,
|
||||
dh_175 = 175,
|
||||
dh_176 = 176,
|
||||
dh_177 = 177,
|
||||
dh_178 = 178,
|
||||
dh_179 = 179,
|
||||
|
||||
// 180..189
|
||||
dh_180 = 180,
|
||||
dh_181 = 181,
|
||||
dh_182 = 182,
|
||||
dh_183 = 183,
|
||||
dh_184 = 184,
|
||||
dh_185 = 185,
|
||||
dh_186 = 186,
|
||||
dh_187 = 187,
|
||||
dh_188 = 188,
|
||||
dh_189 = 189,
|
||||
|
||||
// 190..199
|
||||
dh_190 = 190,
|
||||
dh_191 = 191,
|
||||
dh_192 = 192,
|
||||
dh_193 = 193,
|
||||
dh_194 = 194,
|
||||
dh_195 = 195,
|
||||
dh_196 = 196,
|
||||
dh_197 = 197,
|
||||
dh_198 = 198,
|
||||
dh_199 = 199,
|
||||
|
||||
// 200..209
|
||||
dh_200 = 200,
|
||||
dh_201 = 201,
|
||||
dh_202 = 202,
|
||||
dh_203 = 203,
|
||||
dh_204 = 204,
|
||||
dh_205 = 205,
|
||||
dh_206 = 206,
|
||||
dh_207 = 207,
|
||||
dh_208 = 208,
|
||||
dh_209 = 209,
|
||||
|
||||
// 210..219
|
||||
dh_210 = 210,
|
||||
dh_211 = 211,
|
||||
dh_212 = 212,
|
||||
dh_213 = 213,
|
||||
dh_214 = 214,
|
||||
dh_215 = 215,
|
||||
dh_216 = 216,
|
||||
dh_217 = 217,
|
||||
dh_218 = 218,
|
||||
dh_219 = 219,
|
||||
|
||||
// 220..227
|
||||
dh_220 = 220,
|
||||
dh_221 = 221,
|
||||
dh_222 = 222,
|
||||
dh_223 = 223,
|
||||
dh_224 = 224,
|
||||
dh_225 = 225,
|
||||
dh_226 = 226,
|
||||
dh_227 = 227,
|
||||
dh_228 = 228,
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
NUMBER_OF_ITEMS // MUST be last element of enum.
|
||||
};
|
||||
|
||||
namespace {
|
||||
/// Convert std::tm{} to Date-Number.
|
||||
///
|
||||
/// ECL Restrictions:
|
||||
/// - Calendar start: 1st January 0000
|
||||
/// - Year length: 365.25 days
|
||||
/// - No special leap year handling
|
||||
///
|
||||
/// \param[in] year tm::tm_year of date (years since 1900).
|
||||
///
|
||||
/// \param[in] yday tm::tm_yday of date (days since 1st January).
|
||||
///
|
||||
/// \return Date-number corresponding to specified day-of-year in
|
||||
/// specified year, subject to restrictions outlined above.
|
||||
double toDateNum(const int year, const int yday)
|
||||
{
|
||||
return std::floor(365.25 * (year + 1900))
|
||||
+ (yday + 1); // Day of year [1 .. 365]
|
||||
}
|
||||
|
||||
double toDateNum(const std::chrono::time_point<std::chrono::system_clock> tp)
|
||||
{
|
||||
const auto t0 = std::chrono::system_clock::to_time_t(tp);
|
||||
const auto tm0 = *std::gmtime(&t0);
|
||||
|
||||
// Set clock to 01:00:00+0000 on 2001-<month>-<day> to get
|
||||
// "accurate" day-of-year calculation (no leap year, no DST offset,
|
||||
// not previous day reported).
|
||||
auto tm1 = std::tm{};
|
||||
tm1.tm_year = 101; // 2001
|
||||
tm1.tm_mon = tm0.tm_mon;
|
||||
tm1.tm_mday = tm0.tm_mday;
|
||||
|
||||
tm1.tm_hour = 1;
|
||||
tm1.tm_min = 0;
|
||||
tm1.tm_sec = 0;
|
||||
tm1.tm_isdst = 0;
|
||||
|
||||
const auto t1 = ::Opm::RestartIO::makeUTCTime(tm1);
|
||||
|
||||
if (t1 != static_cast<std::time_t>(-1)) {
|
||||
tm1 = *std::gmtime(&t1); // Get new tm_yday.
|
||||
return toDateNum(tm0.tm_year, tm1.tm_yday);
|
||||
}
|
||||
|
||||
// Failed to convert tm1 to time_t (unexpected). Use initial value.
|
||||
return toDateNum(tm0.tm_year, tm0.tm_yday);
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// Public Interface (DoubHEAD member functions) Below Separator
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
Opm::RestartIO::DoubHEAD::DoubHEAD()
|
||||
: data_(Index::NUMBER_OF_ITEMS, -1.0e20)
|
||||
{
|
||||
// Numbers below have unknown usage, values have been determined by
|
||||
// experiments to be constant across a range of reference cases.
|
||||
this->data_[Index::dh_024] = 1.0e+20;
|
||||
this->data_[Index::dh_026] = 0.0;
|
||||
this->data_[Index::dh_027] = 0.0;
|
||||
this->data_[Index::dh_028] = 0.0;
|
||||
this->data_[Index::dh_050] = 0.01;
|
||||
this->data_[Index::dh_054] = 1.0e+20;
|
||||
this->data_[Index::dh_055] = 1.0e+20;
|
||||
this->data_[Index::dh_063] = 1.0e+20;
|
||||
this->data_[Index::dh_064] = 1.0e+20;
|
||||
this->data_[Index::dh_065] = 0.0;
|
||||
this->data_[Index::dh_066] = 0.0;
|
||||
this->data_[Index::dh_069] = -1.0;
|
||||
this->data_[Index::dh_080] = 1.0e+20;
|
||||
this->data_[Index::dh_081] = 1.0e+20;
|
||||
this->data_[Index::dh_091] = 0.0;
|
||||
this->data_[Index::dh_092] = 0.0;
|
||||
this->data_[Index::dh_093] = 0.0;
|
||||
this->data_[Index::dh_096] = 0.0;
|
||||
this->data_[Index::dh_105] = 1.0;
|
||||
this->data_[Index::dh_108] = 0.0;
|
||||
this->data_[Index::dh_109] = 0.0;
|
||||
this->data_[Index::dh_110] = 0.0;
|
||||
|
||||
this->data_[Index::dh_123] = 365.0;
|
||||
this->data_[Index::dh_124] = 0.1;
|
||||
this->data_[Index::dh_125] = 0.15;
|
||||
this->data_[Index::dh_126] = 3.0;
|
||||
this->data_[Index::dh_127] = 0.3;
|
||||
this->data_[Index::dh_128] = 0.1;
|
||||
this->data_[Index::dh_129] = 0.1;
|
||||
|
||||
this->data_[Index::dh_130] = 0.001;
|
||||
this->data_[Index::dh_131] = 1.0e-7;
|
||||
this->data_[Index::dh_132] = 1.0e-4;
|
||||
this->data_[Index::dh_133] = 10.0;
|
||||
this->data_[Index::dh_134] = 0.01;
|
||||
this->data_[Index::dh_135] = 1.0e-6;
|
||||
this->data_[Index::dh_136] = 0.001;
|
||||
this->data_[Index::dh_137] = 0.001;
|
||||
|
||||
this->data_[Index::dh_140] = 1.0e-20; // check this value
|
||||
this->data_[Index::dh_141] = 1.013;
|
||||
this->data_[Index::dh_142] = 0.0;
|
||||
this->data_[Index::dh_143] = 1.0;
|
||||
this->data_[Index::dh_145] = 0.3;
|
||||
this->data_[Index::dh_146] = 2.0;
|
||||
this->data_[Index::dh_147] = 0.0;
|
||||
this->data_[Index::dh_148] = 0.0;
|
||||
this->data_[Index::dh_149] = 0.0;
|
||||
|
||||
this->data_[Index::dh_150] = 0.0;
|
||||
this->data_[Index::dh_151] = 0.0;
|
||||
this->data_[Index::dh_152] = 0.0;
|
||||
this->data_[Index::dh_153] = 0.0;
|
||||
this->data_[Index::dh_154] = 0.0;
|
||||
|
||||
this->data_[Index::dh_162] = 1.0;
|
||||
this->data_[Index::dh_163] = 0.2;
|
||||
this->data_[Index::dh_164] = 0.4;
|
||||
this->data_[Index::dh_165] = 1.2;
|
||||
this->data_[Index::dh_166] = 0.3;
|
||||
this->data_[Index::dh_167] = 1.0;
|
||||
|
||||
this->data_[Index::dh_170] = 0.4;
|
||||
this->data_[Index::dh_171] = 0.7;
|
||||
this->data_[Index::dh_172] = 2.0;
|
||||
this->data_[Index::dh_178] = 1.0;
|
||||
this->data_[Index::dh_179] = 1.0;
|
||||
|
||||
this->data_[Index::dh_180] = 1.0;
|
||||
this->data_[Index::dh_181] = 0.0;
|
||||
this->data_[Index::dh_182] = 0.0;
|
||||
this->data_[Index::dh_183] = 1.0;
|
||||
this->data_[Index::dh_184] = 1.0e-4;
|
||||
this->data_[Index::dh_185] = 0.0;
|
||||
this->data_[Index::dh_186] = 0.0;
|
||||
this->data_[Index::dh_187] = 1.0e+20;
|
||||
this->data_[Index::dh_188] = 1.0e+20;
|
||||
this->data_[Index::dh_189] = 1.0e+20;
|
||||
|
||||
this->data_[Index::dh_190] = 1.0e+20;
|
||||
this->data_[Index::dh_191] = 1.0e+20;
|
||||
this->data_[Index::dh_192] = 1.0e+20;
|
||||
this->data_[Index::dh_193] = 1.0e+20;
|
||||
this->data_[Index::dh_194] = 1.0e+20;
|
||||
this->data_[Index::dh_195] = 1.0e+20;
|
||||
this->data_[Index::dh_196] = 1.0e+20;
|
||||
this->data_[Index::dh_197] = 1.0e+20;
|
||||
this->data_[Index::dh_198] = 1.0e+20;
|
||||
this->data_[Index::dh_199] = 1.0;
|
||||
|
||||
this->data_[Index::dh_200] = 0.0;
|
||||
this->data_[Index::dh_201] = 0.0;
|
||||
this->data_[Index::dh_202] = 0.0;
|
||||
this->data_[Index::dh_203] = 0.0;
|
||||
this->data_[Index::dh_204] = 0.0;
|
||||
this->data_[Index::dh_205] = 0.0;
|
||||
this->data_[Index::dh_206] = 0.0;
|
||||
this->data_[Index::dh_207] = 0.0;
|
||||
this->data_[Index::dh_208] = 0.0;
|
||||
this->data_[Index::dh_209] = 0.0;
|
||||
|
||||
this->data_[Index::dh_210] = 0.0;
|
||||
this->data_[Index::dh_211] = 0.0;
|
||||
this->data_[Index::dh_214] = 1.0e-4;
|
||||
this->data_[Index::dh_215] = -2.0e+20;
|
||||
this->data_[Index::dh_217] = 0.0;
|
||||
this->data_[Index::dh_218] = 0.0;
|
||||
this->data_[Index::dh_219] = 0.0;
|
||||
|
||||
this->data_[Index::dh_220] = 0.01;
|
||||
this->data_[Index::dh_221] = 1.0;
|
||||
this->data_[Index::dh_222] = 0.0;
|
||||
this->data_[Index::dh_223] = 1.0e+20;
|
||||
this->data_[Index::dh_225] = 0.0;
|
||||
this->data_[Index::dh_226] = 0.0;
|
||||
this->data_[Index::dh_227] = 0.0;
|
||||
|
||||
this->data_[Index::TsInit] = 1.0;
|
||||
this->data_[Index::TsMaxz] = 365.0;
|
||||
this->data_[Index::TsMinz] = 0.1;
|
||||
this->data_[Index::TsMchp] = 0.15;
|
||||
this->data_[Index::TsFMax] = 3.0;
|
||||
this->data_[Index::TsFMin] = 0.3;
|
||||
this->data_[Index::TsFcnv] = 0.1;
|
||||
this->data_[Index::TrgTTE] = 0.1;
|
||||
this->data_[Index::TrgCNV] = 0.001;
|
||||
this->data_[Index::TrgMBE] = 1.0E-7;
|
||||
this->data_[Index::TrgLCV] = 0.0001;
|
||||
|
||||
this->data_[Index::XxxTTE] = 10.0;
|
||||
this->data_[Index::XxxCNV] = 0.01;
|
||||
this->data_[Index::XxxMBE] = 1.0e-6;
|
||||
this->data_[Index::XxxLCV] = 0.001;
|
||||
this->data_[Index::XxxWFL] = 0.001;
|
||||
|
||||
this->data_[Index::dRsdt] = 1.0e+20; // "Infinity"
|
||||
|
||||
this->data_[Index::TrgDPR] = 1.0e+6;
|
||||
this->data_[Index::TfDIFF] = 1.25;
|
||||
this->data_[Index::DdpLim] = 1.0e+6;
|
||||
this->data_[Index::DdsLim] = 1.0e+6;
|
||||
|
||||
|
||||
this->data_[Index::ThrUPT] = 1.0e+20;
|
||||
this->data_[Index::XxxDPR] = 1.0e+20;
|
||||
this->data_[Index::TrgFIP] = 0.025;
|
||||
this->data_[Index::TrgSFT] = 1.0e+20;
|
||||
}
|
||||
|
||||
Opm::RestartIO::DoubHEAD&
|
||||
Opm::RestartIO::DoubHEAD::tuningParameters(const Tuning& tuning,
|
||||
const std::size_t lookup_step,
|
||||
const double cnvT)
|
||||
{
|
||||
// Record 1
|
||||
this->data_[Index::TsInit] = tuning.getTSINIT(lookup_step) / cnvT;
|
||||
this->data_[Index::TsMaxz] = tuning.getTSMAXZ(lookup_step) / cnvT;
|
||||
this->data_[Index::TsMinz] = tuning.getTSMINZ(lookup_step) / cnvT;
|
||||
this->data_[Index::TsMchp] = tuning.getTSMCHP(lookup_step) / cnvT;
|
||||
this->data_[Index::TsFMax] = tuning.getTSFMAX(lookup_step);
|
||||
this->data_[Index::TsFMin] = tuning.getTSFMIN(lookup_step);
|
||||
this->data_[Index::TsFcnv] = tuning.getTSFCNV(lookup_step);
|
||||
this->data_[Index::ThrUPT] = tuning.getTHRUPT(lookup_step);
|
||||
this->data_[Index::TfDIFF] = tuning.getTFDIFF(lookup_step);
|
||||
|
||||
// Record 2
|
||||
this->data_[Index::TrgTTE] = tuning.getTRGTTE(lookup_step);
|
||||
this->data_[Index::TrgCNV] = tuning.getTRGCNV(lookup_step);
|
||||
this->data_[Index::TrgMBE] = tuning.getTRGMBE(lookup_step);
|
||||
this->data_[Index::TrgLCV] = tuning.getTRGLCV(lookup_step);
|
||||
this->data_[Index::XxxTTE] = tuning.getXXXTTE(lookup_step);
|
||||
this->data_[Index::XxxCNV] = tuning.getXXXCNV(lookup_step);
|
||||
this->data_[Index::XxxMBE] = tuning.getXXXMBE(lookup_step);
|
||||
this->data_[Index::XxxLCV] = tuning.getXXXLCV(lookup_step);
|
||||
this->data_[Index::XxxWFL] = tuning.getXXXWFL(lookup_step);
|
||||
this->data_[Index::TrgFIP] = tuning.getTRGFIP(lookup_step);
|
||||
this->data_[Index::TrgSFT] = tuning.getTRGSFT(lookup_step);
|
||||
|
||||
// Record 3
|
||||
this->data_[Index::TrgDPR] = tuning.getTRGDPR(lookup_step);
|
||||
this->data_[Index::XxxDPR] = tuning.getXXXDPR(lookup_step);
|
||||
this->data_[Index::DdpLim] = tuning.getDDPLIM(lookup_step);
|
||||
this->data_[Index::DdsLim] = tuning.getDDSLIM(lookup_step);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::DoubHEAD&
|
||||
Opm::RestartIO::DoubHEAD::timeStamp(const TimeStamp& ts)
|
||||
{
|
||||
using day = std::chrono::duration<double,
|
||||
std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>
|
||||
>;
|
||||
|
||||
// Elapsed time in days
|
||||
this->data_[Index::SimTime] = day{ ts.elapsed }.count();
|
||||
|
||||
// Start time in date-numbers
|
||||
this->data_[Index::Start] = toDateNum(ts.start);
|
||||
|
||||
// Simulation time-stamp in date-numbers
|
||||
this->data_[Index::Time] = this->data_[Index::Start]
|
||||
+ this->data_[Index::SimTime];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::DoubHEAD&
|
||||
Opm::RestartIO::DoubHEAD::drsdt(const Schedule& sched,
|
||||
const std::size_t lookup_step)
|
||||
{
|
||||
const auto& vappar =
|
||||
sched.getOilVaporizationProperties(lookup_step);
|
||||
|
||||
this->data_[dRsdt] =
|
||||
(vappar.getType() == Opm::OilVaporizationEnum::DRSDT)
|
||||
? vappar.getMaxDRSDT()
|
||||
: 1.0e+20;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/GridProperty.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
|
||||
@@ -153,30 +153,30 @@ void RFT::writeTimeStep( std::vector< const Well* > wells,
|
||||
|
||||
const auto& wellData = wellDatas.at(well->name());
|
||||
|
||||
if (wellData.completions.empty())
|
||||
if (wellData.connections.empty())
|
||||
continue;
|
||||
|
||||
for( const auto& completion : well->getCompletions( report_step ) ) {
|
||||
for( const auto& connection : well->getConnections( report_step ) ) {
|
||||
|
||||
const size_t i = size_t( completion.getI() );
|
||||
const size_t j = size_t( completion.getJ() );
|
||||
const size_t k = size_t( completion.getK() );
|
||||
const size_t i = size_t( connection.getI() );
|
||||
const size_t j = size_t( connection.getJ() );
|
||||
const size_t k = size_t( connection.getK() );
|
||||
|
||||
if( !grid.cellActive( i, j, k ) ) continue;
|
||||
|
||||
const auto index = grid.getGlobalIndex( i, j, k );
|
||||
const double depth = grid.getCellDepth( i, j, k );
|
||||
|
||||
const auto& completionData = std::find_if( wellData.completions.begin(),
|
||||
wellData.completions.end(),
|
||||
[=]( const data::Completion& c ) {
|
||||
const auto& connectionData = std::find_if( wellData.connections.begin(),
|
||||
wellData.connections.end(),
|
||||
[=]( const data::Connection& c ) {
|
||||
return c.index == index;
|
||||
} );
|
||||
|
||||
|
||||
const double press = units.from_si(UnitSystem::measure::pressure,completionData->cell_pressure);
|
||||
const double satwat = units.from_si(UnitSystem::measure::identity, completionData->cell_saturation_water);
|
||||
const double satgas = units.from_si(UnitSystem::measure::identity, completionData->cell_saturation_gas);
|
||||
const double press = units.from_si(UnitSystem::measure::pressure,connectionData->cell_pressure);
|
||||
const double satwat = units.from_si(UnitSystem::measure::identity, connectionData->cell_saturation_water);
|
||||
const double satgas = units.from_si(UnitSystem::measure::identity, connectionData->cell_saturation_gas);
|
||||
|
||||
auto* cell = ecl_rft_cell_alloc_RFT(
|
||||
i, j, k, depth, press, satwat, satgas );
|
||||
@@ -418,12 +418,10 @@ void EclipseIO::writeInitial( data::Solution simProps, std::map<std::string, std
|
||||
void EclipseIO::writeTimeStep(int report_step,
|
||||
bool isSubstep,
|
||||
double secs_elapsed,
|
||||
data::Solution cells,
|
||||
data::Wells wells,
|
||||
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 std::map<std::string, std::vector<double>>& extra_restart,
|
||||
bool write_double)
|
||||
{
|
||||
|
||||
@@ -448,7 +446,7 @@ void EclipseIO::writeTimeStep(int report_step,
|
||||
secs_elapsed,
|
||||
es,
|
||||
schedule,
|
||||
wells ,
|
||||
value.wells ,
|
||||
single_summary_values ,
|
||||
region_summary_values,
|
||||
block_summary_values);
|
||||
@@ -469,7 +467,7 @@ void EclipseIO::writeTimeStep(int report_step,
|
||||
report_step,
|
||||
ioConfig.getFMTOUT() );
|
||||
|
||||
RestartIO::save( filename , report_step, secs_elapsed, cells, wells, es , grid , schedule, extra_restart , write_double);
|
||||
RestartIO::save( filename , report_step, secs_elapsed, value, es , grid , schedule, write_double);
|
||||
}
|
||||
|
||||
|
||||
@@ -489,7 +487,7 @@ void EclipseIO::writeTimeStep(int report_step,
|
||||
secs_elapsed + this->impl->schedule.posixStartTime(),
|
||||
units.from_si( UnitSystem::measure::time, secs_elapsed ),
|
||||
units,
|
||||
wells );
|
||||
value.wells );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,7 +495,7 @@ void EclipseIO::writeTimeStep(int report_step,
|
||||
|
||||
|
||||
|
||||
RestartValue EclipseIO::loadRestart(const std::map<std::string, RestartKey>& keys, const std::map<std::string, bool>& extra_keys) const {
|
||||
RestartValue EclipseIO::loadRestart(const std::vector<RestartKey>& solution_keys, const std::vector<RestartKey>& extra_keys) const {
|
||||
const auto& es = this->impl->es;
|
||||
const auto& grid = this->impl->grid;
|
||||
const auto& schedule = this->impl->schedule;
|
||||
@@ -508,7 +506,7 @@ RestartValue EclipseIO::loadRestart(const std::map<std::string, RestartKey>& key
|
||||
report_step,
|
||||
false );
|
||||
|
||||
return RestartIO::load( filename , report_step , keys , es, grid , schedule, extra_keys);
|
||||
return RestartIO::load( filename , report_step , solution_keys , es, grid , schedule, extra_keys);
|
||||
}
|
||||
|
||||
EclipseIO::EclipseIO( const EclipseState& es,
|
||||
|
||||
720
src/opm/output/eclipse/InteHEAD.cpp
Normal file
720
src/opm/output/eclipse/InteHEAD.cpp
Normal file
@@ -0,0 +1,720 @@
|
||||
#include <opm/output/eclipse/InteHEAD.hpp>
|
||||
|
||||
#include <opm/output/eclipse/VectorItems/intehead.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <ratio>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// Public INTEHEAD items are recorded in the common header file
|
||||
//
|
||||
// opm/output/eclipse/VectorItems/intehead.hpp
|
||||
//
|
||||
// Promote items from 'index' to that list to make them public.
|
||||
// The 'index' list always uses public items where available.
|
||||
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
|
||||
|
||||
enum index : std::vector<int>::size_type {
|
||||
ISNUM = VI::intehead::ISNUM , // 0 0 An encoded integer corresponding to the time the file was created. For files not originating from ECLIPSE, this value may be set to zero.
|
||||
VERSION = VI::intehead::VERSION , // 0 0
|
||||
UNIT = VI::intehead::UNIT , // (1,2,3) 1 units type: 1 - METRIC, 2 - FIELD, 3 - LAB
|
||||
ih_003 = 3 , // 0 0
|
||||
ih_004 = 4 , // 0 0
|
||||
ih_005 = 5 , // 0 0
|
||||
ih_006 = 6 , // 0 0
|
||||
ih_007 = 7 , // 0 0
|
||||
NX = VI::intehead::NX , // NX 137 Grid x-direction dimension, NX
|
||||
NY = VI::intehead::NY , // NY 236 Grid x-direction dimension, NY
|
||||
NZ = VI::intehead::NZ , // NZ 58 Grid x-direction dimension, NZ
|
||||
NACTIV = VI::intehead::NACTIV , // NACTIV? 89022 NACTIV = number of active cells
|
||||
ih_012 = 12 , // 0 0
|
||||
ih_013 = 13 , // 0 0
|
||||
PHASE = VI::intehead::PHASE , // IPHS 7 IPHS = phase indicator: 1 - oil, 2 - water, 3 - oil/water, 4 - gas, 5 – oil/gas, 6 - gas/water, 7 - oil/water/gas (ECLIPSE output only)
|
||||
ih_015 = 15 , // 0 0
|
||||
NWELLS = VI::intehead::NWELLS , // NWELLS 39 NWELL = number of wells
|
||||
NCWMAX = VI::intehead::NCWMAX , // NCWMAX 108 Weldims item2 NCWMAX = maximum number of completions per well
|
||||
ih_018 = 18 , // NGRP? 0 Number of actual groups
|
||||
NWGMAX = VI::intehead::NWGMAX , // NWGMAX 0 maximum of weldims item3 or item4 NWGMAX = maximum number of wells in any well group
|
||||
NGMAXZ = VI::intehead::NGMAXZ , // NGMAXZ 0 weldims item3 + 1 NGMAXZ = maximum number of groups in field
|
||||
ih_021 = 21 , // 0 0
|
||||
ih_022 = 22 , // 0 0
|
||||
ih_023 = 23 , // 0 0
|
||||
NIWELZ = VI::intehead::NIWELZ , // NIWELZ 155 155 NIWELZ = no of data elements per well in IWEL array (default 97 for ECLIPSE, 94 for ECLIPSE 300)
|
||||
NSWELZ = VI::intehead::NSWELZ , // NSWELZ 122 122 NSWELZ = number of daelements per well in SWEL array
|
||||
NXWELZ = VI::intehead::NXWELZ , // NXWELZ 130 130 NXWELZ = number of delements per well in XWEL array
|
||||
NZWELZ = VI::intehead::NZWELZ , // NZWEL 3 3 NZWEL = no of 8-character words per well in ZWEL array (= 3)
|
||||
ih_028 = 28 , // 0 0
|
||||
ih_029 = 29 , // 0 0
|
||||
ih_030 = 30 , // 0 0
|
||||
ih_031 = 31 , // 0 0
|
||||
NICONZ = VI::intehead::NICONZ , // 25 15 25 NICON = no of data elements per completion in ICON array (default 19)
|
||||
NSCONZ = VI::intehead::NSCONZ , // 40 0 NSCONZ = number of data elements per completion in SCON array
|
||||
NXCONZ = VI::intehead::NXCONZ , // 58 0 58 NXCONZ = number of data elements per completion in XCON array
|
||||
ih_035 = 35 , // 0 0
|
||||
NIGRPZ = VI::intehead::NIGRPZ , // 97+intehead_array[19] 0 97 + intehead[19] NIGRPZ = no of data elements per group in IGRP array
|
||||
NSGRPZ = VI::intehead::NSGRPZ , // 112 0 112 NSGRPZ = number of data elements per group in SGRP array
|
||||
NXGRPZ = VI::intehead::NXGRPZ , // 180 0 180 NXGRPZ = number of data elements per group in XGRP array
|
||||
NZGRPZ = VI::intehead::NZGRPZ , // 5 0 NZGRPZ = number of data elements per group in ZGRP array
|
||||
ih_040 = 40 , // 0 0
|
||||
NCAMAX = VI::intehead::NCAMAX , // 1 0 NCAMAX = maximum number of analytic aquifer connections
|
||||
NIAAQZ = VI::intehead::NIAAQZ , // 18 0 NIAAQZ = number of data elements per aquifer in IAAQ array
|
||||
NSAAQZ = VI::intehead::NSAAQZ , // 24 0 NSAAQZ = number of data elements per aquifer in SAAQ array
|
||||
NXAAQZ = VI::intehead::NXAAQZ , // 10 0 NXAAQZ = number of data elements per aquifer in XAAQ array
|
||||
NICAQZ = VI::intehead::NICAQZ , // 7 0 NSCAQZ= number of data elements per aquifer connection in SCAQ array
|
||||
NSCAQZ = VI::intehead::NSCAQZ , // 2 0
|
||||
NACAQZ = VI::intehead::NACAQZ , // 4 0
|
||||
ih_048 = 48 , // 0 0
|
||||
ih_049 = 49 , // 0 0
|
||||
ih_050 = 50 , // 0 0
|
||||
ih_051 = 51 , // 0 0
|
||||
ih_052 = 52 , // 0 0
|
||||
ih_053 = 53 , // 0 0
|
||||
ih_054 = 54 , // 0 0
|
||||
ih_055 = 55 , // 0 0
|
||||
ih_056 = 56 , // 0 0
|
||||
ih_057 = 57 , // 0 0
|
||||
ih_058 = 58 , // 0 0
|
||||
ih_059 = 59 , // 0 0
|
||||
ih_060 = 60 , // 0 0
|
||||
ih_061 = 61 , // 0 0
|
||||
ih_062 = 62 , // 0 0
|
||||
ih_063 = 63 , // 0 0
|
||||
DAY = 64 , // IDAY 2 IDAY = calendar day at this report time
|
||||
MONTH = 65 , // IMON 6 IMON = calendar month at this report time
|
||||
YEAR = 66 , // IYEAR 2016 IYEAR = calendar year at this report time
|
||||
NUM_SOLVER_STEPS = 67 , // The number of solver steps the simulator has performed so far.
|
||||
REPORT_STEP = 68 , // The sequence/report number for for this restart file.
|
||||
ih_069 = 69 , // 0 0
|
||||
ih_070 = 70 , // 0 0
|
||||
ih_071 = 71 , // 0 0
|
||||
ih_072 = 72 , // 0 0
|
||||
ih_073 = 73 , // 0 0
|
||||
ih_074 = 74 , // 0 0
|
||||
ih_075 = 75 , // 0 0
|
||||
ih_076 = 76 , // 0 0 2
|
||||
ih_077 = 77 , // 0 0
|
||||
ih_078 = 78 , // 0 0
|
||||
ih_079 = 79 , // 0 0
|
||||
NEWTMX = 80 , // 0 0 Tuning,Record3,Item1
|
||||
NEWTMN = 81 , // 0 0 Tuning,Record3,Item2
|
||||
LITMAX = 82 , // 0 0 Tuning,Record3,Item3
|
||||
LITMIN = 83 , // 0 0 Tuning,Record3,Item4
|
||||
ih_084 = 84 , // 0 0 Tuning,Record3,Item5
|
||||
ih_085 = 85 , // 0 0 Tuning,Record3,Item6
|
||||
MXWSIT = 86 , // 0 0
|
||||
MXWPIT = 87 , // 0 0
|
||||
ih_088 = 88 , // 0 0
|
||||
NTFIP = 89 , // 0 0 REGDIMS item1, or TABDIMS item 5
|
||||
ih_090 = 90 , // 0 0
|
||||
ih_091 = 91 , // 0 0
|
||||
ih_092 = 92 , // 0 0
|
||||
ih_093 = 93 , // 0 0
|
||||
IPROG = 94 , // 0 100 IPROG = simulation program identifier: 100 - ECLIPSE 100, 300 - ECLIPSE 300, 500 - ECLIPSE 300 (thermal option), negative - Other simulator
|
||||
INITSIZE = 95 , // 0 0
|
||||
ih_096 = 96 , // 0 0
|
||||
ih_097 = 97 , // 0 0
|
||||
ih_098 = 98 , // 0 0
|
||||
NMFIPR = 99 , // 0 0 REGDIMS item2
|
||||
ih_100 = 100 , // 0 0
|
||||
ih_101 = 101 , // 0 0 1
|
||||
ih_102 = 102 , // 0 0
|
||||
ih_103 = 103 , // 0 0 1
|
||||
ih_104 = 104 , // 0 0
|
||||
ih_105 = 105 , // 0 0
|
||||
ih_106 = 106 , // 0 0
|
||||
ih_107 = 107 , // 0 0
|
||||
ih_108 = 108 , // 0 0
|
||||
ih_109 = 109 , // 0 0
|
||||
ih_110 = 110 , // 0 0
|
||||
ih_111 = 111 , // 0 0
|
||||
ih_112 = 112 , // 0 0
|
||||
ih_113 = 113 , // 0 0
|
||||
ih_114 = 114 , // 0 0
|
||||
ih_115 = 115 , // 0 0
|
||||
ih_116 = 116 , // 0 0
|
||||
ih_117 = 117 , // 0 0
|
||||
ih_118 = 118 , // 0 0
|
||||
ih_119 = 119 , // 0 0
|
||||
ih_120 = 120 , // 0 0
|
||||
ih_121 = 121 , // 0 0
|
||||
ih_122 = 122 , // 0 0
|
||||
ih_123 = 123 , // 0 0
|
||||
ih_124 = 124 , // 0 0
|
||||
ih_125 = 125 , // 0 0
|
||||
ih_126 = 126 , // 0 0
|
||||
ih_127 = 127 , // 0 0
|
||||
ih_128 = 128 , // 0 0
|
||||
ih_129 = 129 , // 0 0
|
||||
ih_130 = 130 , // 0 0
|
||||
NODMAX = 131 , // 0 0 NODMAX = maximum number of nodes in extended network option
|
||||
NBRMAX = 132 , // 0 0 NBRMAX = maximum number of branches in extended network option
|
||||
NIBRAN = 133 , // 0 0 NIBRAN = number of entries per branch in the IBRAN array
|
||||
NRBRAN = 134 , // 0 0 NRBRAN = number of tries per branch in the RBRAN array
|
||||
NINODE = 135 , // 0 0 NINODE = number of entries per node in the INODE array
|
||||
NRNODE = 136 , // 0 0 NRNODE = number of entries per node in the RNODE array
|
||||
NZNODE = 137 , // 0 0 NZNODE = number of entries per node in the ZNODE array
|
||||
NINOBR = 138 , // 0 0 NINOBR = size of the INOBR array
|
||||
ih_139 = 139 , // 0 0
|
||||
ih_140 = 140 , // 0 0
|
||||
ih_141 = 141 , // 0 0
|
||||
ih_142 = 142 , // 0 0
|
||||
ih_143 = 143 , // 0 0
|
||||
ih_144 = 144 , // 0 0
|
||||
ih_145 = 145 , // 0 0
|
||||
ih_146 = 146 , // 0 0
|
||||
ih_147 = 147 , // 0 0
|
||||
ih_148 = 148 , // 0 0
|
||||
ih_149 = 149 , // 0 0
|
||||
ih_150 = 150 , // 0 0
|
||||
ih_151 = 151 , // 0 0
|
||||
ih_152 = 152 , // 0 0
|
||||
ih_153 = 153 , // 0 0
|
||||
ih_154 = 154 , // 0 0
|
||||
ih_155 = 155 , // 0 0
|
||||
ih_156 = 156 , // 0 0
|
||||
ih_157 = 157 , // 0 0
|
||||
ih_158 = 158 , // 0 0
|
||||
ih_159 = 159 , // 0 0
|
||||
ih_160 = 160 , // 0 0
|
||||
ih_161 = 161 , // 0 0
|
||||
NGCAUS = 162 , // 0 0 NGCAUS = maximum number of aquifer connections actually used.
|
||||
ih_163 = 163 , // 0 0
|
||||
ih_164 = 164 , // 0 0
|
||||
ih_165 = 165 , // 0 0
|
||||
ih_166 = 166 , // 0 0
|
||||
ih_167 = 167 , // 0 0
|
||||
ih_168 = 168 , // 0 0
|
||||
ih_169 = 169 , // 0 0
|
||||
ih_170 = 170 , // 0 0
|
||||
ih_171 = 171 , // 0 0
|
||||
ih_172 = 172 , // 0 0
|
||||
ih_173 = 173 , // 0 0
|
||||
NSEGWL = VI::intehead::NSEGWL , // 0 0 number of mswm wells defined with WELSEG
|
||||
NSWLMX = VI::intehead::NSWLMX , // NSWLMX 0 Item 1 in WSEGDIMS keyword (runspec section) NSWLMX = maximum number of segmented wells
|
||||
NSEGMX = VI::intehead::NSEGMX , // NSEGMX 0 Item 2 in WSEGDIMS keyword (runspec section) NSEGMX = maximum number of segments per well
|
||||
NLBRMX = VI::intehead::NLBRMX , // NLBRMX 0 Item 3 in WSEGDIMS keyword (runspec section) NLBRMX = maximum number of lateral branches per well
|
||||
NISEGZ = VI::intehead::NISEGZ , // 22 0 22 NISEGZ = number of entries per segment in ISEG array
|
||||
NRSEGZ = VI::intehead::NRSEGZ , // 140 0 140 NRSEGZ = number of entries per segment in RSEG array
|
||||
NILBRZ = VI::intehead::NILBRZ , // 10 10 NILBRZ = number of entries per segment in ILBR array
|
||||
RSTSIZE = 181 , // 0
|
||||
ih_182 = 182 , // 0
|
||||
ih_183 = 183 , // 0
|
||||
ih_184 = 184 , // 0
|
||||
ih_185 = 185 , // 0
|
||||
ih_186 = 186 , // 0
|
||||
ih_187 = 187 , // 0
|
||||
ih_188 = 188 , // 0
|
||||
ih_189 = 189 , // 0
|
||||
ih_190 = 190 , // 0
|
||||
ih_191 = 191 , // 0
|
||||
ih_192 = 192 , // 0
|
||||
ih_193 = 193 , // 0
|
||||
ih_194 = 194 , // 0
|
||||
ih_195 = 195 , // 0
|
||||
ih_196 = 196 , // 0
|
||||
ih_197 = 197 , // 0
|
||||
ih_198 = 198 , // 0
|
||||
ih_199 = 199 , // 0
|
||||
ih_200 = 200 , // 0
|
||||
ih_201 = 201 , // 0
|
||||
ih_202 = 202 , // 0
|
||||
ih_203 = 203 , // 0
|
||||
ih_204 = 204 , // 0
|
||||
ih_205 = 205 , // 0
|
||||
IHOURZ = 206 , // IHOURZ IHOURZ = current simulation time HH:MM:SS – number of hours (HH) (0-23).
|
||||
IMINTS = 207 , // IMINTS IMINTS = current simulation time HH:MM:SS - number of minutes (MM) (0-59).
|
||||
ih_208 = 208 , // 0
|
||||
ih_209 = 209 , // 0
|
||||
ih_210 = 210 , // 0
|
||||
ih_211 = 211 , // 0
|
||||
ih_212 = 212 , // 0
|
||||
ih_213 = 213 , // 0
|
||||
ih_214 = 214 , // 0
|
||||
ih_215 = 215 , // 0
|
||||
ih_216 = 216 , // 0
|
||||
ih_217 = 217 , // 0
|
||||
ih_218 = 218 , // 0
|
||||
ih_219 = 219 , // 0
|
||||
ih_220 = 220 , // 0
|
||||
ih_221 = 221 , // 0
|
||||
ih_222 = 222 , // 0
|
||||
NIIAQN = 223 , // 0 NIIAQN = number of lines of integer AQUNUM data.
|
||||
NIRAQN = 224 , // 0 NIRAQN = number of lines of real AQUNUM data.
|
||||
ih_225 = 225 , // 0
|
||||
NUMAQN = 226 , // 0 NUMAQN = number of lines of AQUNUM data entered.
|
||||
ih_227 = 227 , // 0
|
||||
ih_228 = 228 , // 0
|
||||
ih_229 = 229 , // 0
|
||||
ih_230 = 230 , // 0
|
||||
ih_231 = 231 , // 0
|
||||
ih_232 = 232 , // 0
|
||||
ih_233 = 233 , // 0
|
||||
NICOTZ = 234 , // 0 NICOTZ = number of entries in the ICOT array
|
||||
NXCOTZ = 235 , // 0 NXCOTZ = number of entries in the XCOT array
|
||||
NIWETZ = 236 , // 0 NIWETZ = number of entries in the IWET array
|
||||
NXWETZ = 237 , // 0 NXWETZ = number of entries in the XWET array
|
||||
NIGRTZ = 238 , // 0 NIGRTZ = number of entries in the IGRT array
|
||||
NXGRTZ = 239 , // 0 NXGRTZ = number of entries in the XGRT array
|
||||
NSTRA2 = 240 , // 0 NSTRA2 = number of tracers + 2
|
||||
ih_241 = 241 , // 0
|
||||
ih_242 = 242 , // 0
|
||||
ih_243 = 243 , // 0
|
||||
ih_244 = 244 , // 0
|
||||
ih_245 = 245 , // 0
|
||||
ih_246 = 246 , // 0
|
||||
ih_247 = 247 , // 0
|
||||
ih_248 = 248 , // 0
|
||||
ih_249 = 249 , // 0
|
||||
ih_250 = 250 , // 0
|
||||
ih_251 = 251 , // 0
|
||||
MAAQID = 252 , // 0 MAAQID = maximum number of analytic aquifers
|
||||
ih_253 = 253 , // 0
|
||||
ih_254 = 254 , // 0
|
||||
ih_255 = 255 , // 0
|
||||
ih_256 = 256 , // 0
|
||||
ih_257 = 257 , // 0
|
||||
ih_258 = 258 , // 0
|
||||
ih_259 = 259 , // 0
|
||||
ih_260 = 260 , // 0
|
||||
ih_261 = 261 , // 0
|
||||
ih_262 = 262 , // 0
|
||||
ih_263 = 263 , // 0
|
||||
ih_264 = 264 , // 0
|
||||
ih_265 = 265 , // 0
|
||||
ih_266 = 266 , // 0
|
||||
ih_267 = 267 , // 0
|
||||
ih_268 = 268 , // 0
|
||||
ih_269 = 269 , // 0
|
||||
ih_270 = 270 , // 0
|
||||
NCRDMX = 271 , // 0 NCRDMX = maximum number of chord segment links per well
|
||||
ih_272 = 272 , // 0
|
||||
ih_273 = 273 , // 0
|
||||
ih_274 = 274 , // 0
|
||||
ih_275 = 275 , // 0
|
||||
ih_276 = 276 , // 0
|
||||
ih_277 = 277 , // 0
|
||||
ih_278 = 278 , // 0
|
||||
ih_279 = 279 , // 0
|
||||
ih_280 = 280 , // 0
|
||||
ih_281 = 281 , // 0
|
||||
ih_282 = 282 , // 0
|
||||
ih_283 = 283 , // 0
|
||||
ih_284 = 284 , // 0
|
||||
ih_285 = 285 , // 0
|
||||
ih_286 = 286 , // 0
|
||||
ih_287 = 287 , // 0
|
||||
ih_288 = 288 , // 0
|
||||
ih_289 = 289 , // 0
|
||||
ih_290 = 290 , // 0
|
||||
ih_291 = 291 , // 0
|
||||
ih_292 = 292 , // 0
|
||||
ih_293 = 293 , // 0
|
||||
ih_294 = 294 , // 0
|
||||
ih_295 = 295 , // 0
|
||||
ih_296 = 296 , // 0
|
||||
ih_297 = 297 , // 0
|
||||
ih_298 = 298 , // 0
|
||||
ih_299 = 299 , // 0
|
||||
ih_300 = 300 , // 0
|
||||
ih_301 = 301 , // 0
|
||||
ih_302 = 302 , // 0
|
||||
ih_303 = 303 , // 0
|
||||
ih_304 = 304 , // 0
|
||||
ih_305 = 305 , // 0
|
||||
ih_306 = 306 , // 0
|
||||
ih_307 = 307 , // 0
|
||||
ih_308 = 308 , // 0
|
||||
ih_309 = 309 , // 0
|
||||
ih_310 = 310 , // 0
|
||||
ih_311 = 311 , // 0
|
||||
ih_312 = 312 , // 0
|
||||
ih_313 = 313 , // 0
|
||||
ih_314 = 314 , // 0
|
||||
ih_315 = 315 , // 0
|
||||
ih_316 = 316 , // 0
|
||||
ih_317 = 317 , // 0
|
||||
ih_318 = 318 , // 0
|
||||
ih_319 = 319 , // 0
|
||||
ih_320 = 320 , // 0
|
||||
ih_321 = 321 , // 0
|
||||
ih_322 = 322 , // 0
|
||||
ih_323 = 323 , // 0
|
||||
ih_324 = 324 , // 0
|
||||
ih_325 = 325 , // 0
|
||||
ih_326 = 326 , // 0
|
||||
ih_327 = 327 , // 0
|
||||
ih_328 = 328 , // 0
|
||||
ih_329 = 329 , // 0
|
||||
ih_330 = 330 , // 0
|
||||
ih_331 = 331 , // 0
|
||||
ih_332 = 332 , // 0
|
||||
ih_333 = 333 , // 0
|
||||
ih_334 = 334 , // 0
|
||||
ih_335 = 335 , // 0
|
||||
ih_336 = 336 , // 0
|
||||
ih_337 = 337 , // 0
|
||||
ih_338 = 338 , // 0
|
||||
ih_339 = 339 , // 0
|
||||
ih_340 = 340 , // 0
|
||||
ih_341 = 341 , // 0
|
||||
ih_342 = 342 , // 0
|
||||
ih_343 = 343 , // 0
|
||||
ih_344 = 344 , // 0
|
||||
ih_345 = 345 , // 0
|
||||
ih_346 = 346 , // 0
|
||||
ih_347 = 347 , // 0
|
||||
ih_348 = 348 , // 0
|
||||
ih_349 = 349 , // 0
|
||||
ih_350 = 350 , // 0
|
||||
ih_351 = 351 , // 0
|
||||
ih_352 = 352 , // 0
|
||||
ih_353 = 353 , // 0
|
||||
ih_354 = 354 , // 0
|
||||
ih_355 = 355 , // 0
|
||||
ih_356 = 356 , // 0
|
||||
ih_357 = 357 , // 0
|
||||
ih_358 = 358 , // 0
|
||||
ih_359 = 359 , // 0
|
||||
ih_360 = 360 , // 0
|
||||
ih_361 = 361 , // 0
|
||||
ih_362 = 362 , // 0
|
||||
ih_363 = 363 , // 0
|
||||
ih_364 = 364 , // 0
|
||||
ih_365 = 365 , // 0
|
||||
ih_366 = 366 , // 0
|
||||
ih_367 = 367 , // 0
|
||||
ih_368 = 368 , // 0
|
||||
ih_369 = 369 , // 0
|
||||
ih_370 = 370 , // 0
|
||||
ih_371 = 371 , // 0
|
||||
ih_372 = 372 , // 0
|
||||
ih_373 = 373 , // 0
|
||||
ih_374 = 374 , // 0
|
||||
ih_375 = 375 , // 0
|
||||
ih_376 = 376 , // 0
|
||||
ih_377 = 377 , // 0
|
||||
ih_378 = 378 , // 0
|
||||
ih_379 = 379 , // 0
|
||||
ih_380 = 380 , // 0
|
||||
ih_381 = 381 , // 0
|
||||
ih_382 = 382 , // 0
|
||||
ih_383 = 383 , // 0
|
||||
ih_384 = 384 , // 0
|
||||
ih_385 = 385 , // 0
|
||||
ih_386 = 386 , // 0
|
||||
ih_387 = 387 , // 0
|
||||
ih_388 = 388 , // 0
|
||||
ih_389 = 389 , // 0
|
||||
ih_390 = 390 , // 0
|
||||
ih_391 = 391 , // 0
|
||||
ih_392 = 392 , // 0
|
||||
ih_393 = 393 , // 0
|
||||
ih_394 = 394 , // 0
|
||||
ih_395 = 395 , // 0
|
||||
ih_396 = 396 , // 0
|
||||
ih_397 = 397 , // 0
|
||||
ih_398 = 398 , // 0
|
||||
ih_399 = 399 , // 0
|
||||
ih_400 = 400 , // 0
|
||||
ih_401 = 401 , // 0
|
||||
ih_402 = 402 , // 0
|
||||
ih_403 = 403 , // 0
|
||||
ih_404 = 404 , // 0
|
||||
ih_405 = 405 , // 0
|
||||
ih_406 = 406 , // 0
|
||||
ih_407 = 407 , // 0
|
||||
ih_408 = 408 , // 0
|
||||
ih_409 = 409 , // 0
|
||||
ISECND = 410 , // 0 ISECND = current simulation time HH:MM:SS - number of seconds (SS), reported in microseconds (0-59,999,999)
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
INTEHEAD_NUMBER_OF_ITEMS // MUST be last element of enum.
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// Public Interface Below Separator
|
||||
// =====================================================================
|
||||
|
||||
Opm::RestartIO::InteHEAD::InteHEAD()
|
||||
: data_(INTEHEAD_NUMBER_OF_ITEMS, 0)
|
||||
{}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::
|
||||
dimensions(const int nx, const int ny, const int nz)
|
||||
{
|
||||
this -> data_[NX] = nx;
|
||||
this -> data_[NY] = ny;
|
||||
this -> data_[NZ] = nz;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::
|
||||
dimensions(const std::array<int,3>& cartDims)
|
||||
{
|
||||
return this->dimensions(cartDims[0], cartDims[1], cartDims[2]);
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::numActive(const int nactive)
|
||||
{
|
||||
this->data_[NACTIV] = nactive;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::unitConventions(const UnitSystem& usys)
|
||||
{
|
||||
const auto unit = [&usys]()
|
||||
{
|
||||
switch (usys) {
|
||||
case UnitSystem::Metric: return 1;
|
||||
case UnitSystem::Field: return 2;
|
||||
case UnitSystem::Lab: return 3;
|
||||
case UnitSystem::PVT_M: return 4;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}();
|
||||
|
||||
this->data_[UNIT] = unit;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::wellTableDimensions(const WellTableDim& wtdim)
|
||||
{
|
||||
this->data_[NWELLS] = wtdim.numWells;
|
||||
this->data_[NCWMAX] = wtdim.maxPerf;
|
||||
|
||||
this->data_[NWGMAX] = std::max(wtdim.maxWellInGroup,
|
||||
wtdim.maxGroupInField);
|
||||
|
||||
this->data_[NGMAXZ] = wtdim.maxGroupInField + 1;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::calendarDate(const TimePoint& timePoint)
|
||||
{
|
||||
this->data_[DAY] = timePoint.day;
|
||||
this->data_[MONTH] = timePoint.month;
|
||||
this->data_[YEAR] = timePoint.year;
|
||||
|
||||
this->data_[IHOURZ] = timePoint.hour;
|
||||
this->data_[IMINTS] = timePoint.minute;
|
||||
|
||||
// Microseonds...
|
||||
this->data_[ISECND] =
|
||||
((timePoint.second * 1000) * 1000) + timePoint.microseconds;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::activePhases(const Phases& phases)
|
||||
{
|
||||
const auto iphs =
|
||||
(static_cast<unsigned int> (phases.oil) << 0u)
|
||||
| (static_cast<unsigned int>(phases.water) << 1u)
|
||||
| (static_cast<unsigned int>(phases.gas) << 2u);
|
||||
|
||||
this->data_[PHASE] = static_cast<int>(iphs);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::
|
||||
params_NWELZ(const int niwelz, const int nswelz, const int nxwelz, const int nzwelz)
|
||||
{
|
||||
this -> data_[NIWELZ] = niwelz;
|
||||
this -> data_[NSWELZ] = nswelz;
|
||||
this -> data_[NXWELZ] = nxwelz;
|
||||
this -> data_[NZWELZ] = nzwelz;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::
|
||||
params_NCON(const int niconz, const int nsconz, const int nxconz)
|
||||
{
|
||||
this -> data_[NICONZ] = niconz;
|
||||
this -> data_[NSCONZ] = nsconz;
|
||||
this -> data_[NXCONZ] = nxconz;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::
|
||||
params_GRPZ(const std::array<int, 4>& grpz)
|
||||
{
|
||||
this -> data_[NIGRPZ] = grpz[0];
|
||||
this -> data_[NSGRPZ] = grpz[1];
|
||||
this -> data_[NXGRPZ] = grpz[2];
|
||||
this -> data_[NZGRPZ] = grpz[3];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::
|
||||
params_NAAQZ(const int ncamax,
|
||||
const int niaaqz,
|
||||
const int nsaaqz,
|
||||
const int nxaaqz,
|
||||
const int nicaqz,
|
||||
const int nscaqz,
|
||||
const int nacaqz)
|
||||
{
|
||||
this -> data_[NCAMAX] = ncamax;
|
||||
this -> data_[NIAAQZ] = niaaqz;
|
||||
this -> data_[NSAAQZ] = nsaaqz;
|
||||
this -> data_[NXAAQZ] = nxaaqz;
|
||||
this -> data_[NICAQZ] = nicaqz;
|
||||
this -> data_[NSCAQZ] = nscaqz;
|
||||
this -> data_[NACAQZ] = nacaqz;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::
|
||||
stepParam(const int num_solver_steps, const int report_step)
|
||||
{
|
||||
this -> data_[NUM_SOLVER_STEPS] = num_solver_steps;
|
||||
this -> data_[REPORT_STEP] = report_step;
|
||||
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::tuningParam(const TuningPar& tunpar)
|
||||
{
|
||||
this->data_[NEWTMX] = tunpar.newtmx;
|
||||
this->data_[NEWTMN] = tunpar.newtmn;
|
||||
this->data_[LITMAX] = tunpar.litmax;
|
||||
this->data_[LITMIN] = tunpar.litmin;
|
||||
this->data_[MXWSIT] = tunpar.mxwsit;
|
||||
this->data_[MXWPIT] = tunpar.mxwpit;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::variousParam(const int version,
|
||||
const int iprog)
|
||||
{
|
||||
this->data_[VERSION] = version;
|
||||
this->data_[IPROG] = iprog;
|
||||
// ih_076: Usage unknown, experiments fails (zero determinant in well message) with too low numbers. 5 is highest observed across reference cases.
|
||||
this->data_[ih_076] = 5;
|
||||
// ih_101: Usage unknown, value fixed across reference cases.
|
||||
this->data_[ih_101] = 1;
|
||||
// ih_103: Usage unknown, value not fixed across reference cases, experiments generate warning with 0 but not with 1.
|
||||
this->data_[ih_103] = 1;
|
||||
// ih_200: Usage unknown, value fixed across reference cases.
|
||||
this->data_[ih_200] = 1;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::wellSegDimensions(const WellSegDims& wsdim)
|
||||
{
|
||||
this->data_[NSEGWL] = wsdim.nsegwl;
|
||||
this->data_[NSWLMX] = wsdim.nswlmx;
|
||||
this->data_[NSEGMX] = wsdim.nsegmx;
|
||||
this->data_[NLBRMX] = wsdim.nlbrmx;
|
||||
this->data_[NISEGZ] = wsdim.nisegz;
|
||||
this->data_[NRSEGZ] = wsdim.nrsegz;
|
||||
this->data_[NILBRZ] = wsdim.nilbrz;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD&
|
||||
Opm::RestartIO::InteHEAD::regionDimensions(const RegDims& rdim)
|
||||
{
|
||||
this->data_[NTFIP] = rdim.ntfip;
|
||||
this->data_[NMFIPR] = rdim.nmfipr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// Free functions (calendar/time utilities)
|
||||
// =====================================================================
|
||||
|
||||
namespace {
|
||||
std::time_t advance(const std::time_t tp, const double sec)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
using TP = time_point<system_clock>;
|
||||
using DoubSec = duration<double, seconds::period>;
|
||||
|
||||
const auto t = system_clock::from_time_t(tp) +
|
||||
duration_cast<TP::duration>(DoubSec(sec));
|
||||
|
||||
return system_clock::to_time_t(t);
|
||||
}
|
||||
}
|
||||
|
||||
std::time_t
|
||||
Opm::RestartIO::makeUTCTime(const std::tm& timePoint)
|
||||
{
|
||||
auto tp = timePoint; // Mutable copy.
|
||||
const auto ltime = std::mktime(&tp);
|
||||
auto tmval = *std::gmtime(<ime); // Mutable.
|
||||
|
||||
// offset = ltime - tmval
|
||||
// == #seconds by which 'ltime' is AHEAD of tmval.
|
||||
const auto offset =
|
||||
std::difftime(ltime, std::mktime(&tmval));
|
||||
|
||||
// Advance 'ltime' by 'offset' so that std::gmtime(return value) will
|
||||
// have the same broken-down elements as 'tp'.
|
||||
return advance(ltime, offset);
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD::TimePoint
|
||||
Opm::RestartIO::getSimulationTimePoint(const std::time_t start,
|
||||
const double elapsed)
|
||||
{
|
||||
const auto now = advance(start, elapsed);
|
||||
const auto tp = *std::gmtime(&now);
|
||||
|
||||
auto sec = 0.0; // Not really used here.
|
||||
auto usec = std::floor(1.0e6 * std::modf(elapsed, &sec));
|
||||
|
||||
return {
|
||||
// Y-m-d
|
||||
tp.tm_year + 1900,
|
||||
tp.tm_mon + 1,
|
||||
tp.tm_mday ,
|
||||
|
||||
// H:M:S
|
||||
tp.tm_hour ,
|
||||
tp.tm_min ,
|
||||
std::min(tp.tm_sec, 59), // Ignore leap seconds
|
||||
|
||||
// Fractional seconds in microsecond resolution.
|
||||
static_cast<int>(usec),
|
||||
};
|
||||
}
|
||||
165
src/opm/output/eclipse/LogiHEAD.cpp
Normal file
165
src/opm/output/eclipse/LogiHEAD.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#include <opm/output/eclipse/LogiHEAD.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
enum index : std::vector<int>::size_type {
|
||||
lh_000 = 0 , // TRUE
|
||||
lh_001 = 1 , // TRUE
|
||||
lh_002 = 2 , // FALSE
|
||||
lh_003 = 3 , // FALSE Flag set to FALSE for a non-radial model, TRUE for a radial model (ECLIPSE 300 and other simulators)
|
||||
lh_004 = 4 , // FALSE Flag set to FALSE for a non-radial model, TRUE for a radial model (ECLIPSE 100)
|
||||
lh_005 = 5 , // FALSE
|
||||
lh_006 = 6 , // FALSE
|
||||
lh_007 = 7 , // FALSE
|
||||
lh_008 = 8 , // FALSE
|
||||
lh_009 = 9 , // FALSE
|
||||
lh_010 = 10 , // FALSE
|
||||
lh_011 = 11 , // FALSE
|
||||
lh_012 = 12 , // FALSE
|
||||
lh_013 = 13 , // FALSE
|
||||
lh_014 = 14 , // FALSE Flag for dual porosity model
|
||||
lh_015 = 15 , // FALSE
|
||||
lh_016 = 16 , // TRUE
|
||||
lh_017 = 17 , // FALSE
|
||||
lh_018 = 18 , // TRUE
|
||||
lh_019 = 19 , //
|
||||
lh_020 = 20 , // FALSE
|
||||
lh_021 = 21 , // FALSE
|
||||
lh_022 = 22 , // FALSE
|
||||
lh_023 = 23 , // FALSE
|
||||
lh_024 = 24 , // FALSE
|
||||
lh_025 = 25 , // FALSE
|
||||
lh_026 = 26 , // FALSE
|
||||
lh_027 = 27 , // FALSE
|
||||
lh_028 = 28 , // FALSE
|
||||
lh_029 = 29 , // FALSE
|
||||
lh_030 = 30 , // FALSE Flag for coalbed methane (ECLIPSE 100)
|
||||
lh_031 = 31 , // TRUE
|
||||
lh_032 = 32 , // FALSE
|
||||
lh_033 = 33 , // FALSE
|
||||
lh_034 = 34 , // FALSE
|
||||
lh_035 = 35 , // FALSE
|
||||
lh_036 = 36 , // FALSE
|
||||
lh_037 = 37 , //
|
||||
lh_038 = 38 , // FALSE
|
||||
lh_039 = 39 , // FALSE
|
||||
lh_040 = 40 , // FALSE
|
||||
lh_041 = 41 , // FALSE
|
||||
lh_042 = 42 , // FALSE
|
||||
lh_043 = 43 , //
|
||||
lh_044 = 44 , // TRUE
|
||||
lh_045 = 45 , // FALSE
|
||||
lh_046 = 46 , // FALSE
|
||||
lh_047 = 47 , // FALSE
|
||||
lh_048 = 48 , //
|
||||
lh_049 = 49 , // FALSE
|
||||
lh_050 = 50 , // FALSE
|
||||
lh_051 = 51 , // FALSE
|
||||
lh_052 = 52 , // FALSE
|
||||
lh_053 = 53 , // FALSE
|
||||
lh_054 = 54 , // FALSE
|
||||
lh_055 = 55 , // FALSE
|
||||
lh_056 = 56 , // FALSE
|
||||
lh_057 = 57 , // FALSE
|
||||
lh_058 = 58 , // FALSE
|
||||
lh_059 = 59 , // FALSE
|
||||
lh_060 = 60 , // FALSE
|
||||
lh_061 = 61 , // FALSE
|
||||
lh_062 = 62 , // FALSE
|
||||
lh_063 = 63 , // FALSE
|
||||
lh_064 = 64 , // FALSE
|
||||
lh_065 = 65 , // FALSE
|
||||
lh_066 = 66 , // FALSE
|
||||
lh_067 = 67 , // FALSE
|
||||
lh_068 = 68 , // FALSE
|
||||
lh_069 = 69 , // FALSE
|
||||
lh_070 = 70 , // FALSE
|
||||
lh_071 = 71 , // FALSE
|
||||
lh_072 = 72 , // FALSE
|
||||
lh_073 = 73 , // FALSE
|
||||
lh_074 = 74 , // FALSE
|
||||
lh_075 = 75 , // TRUE If segmented well model is used
|
||||
lh_076 = 76 , // TRUE
|
||||
lh_077 = 77 , // FALSE
|
||||
lh_078 = 78 , // FALSE
|
||||
lh_079 = 79 , // FALSE
|
||||
lh_080 = 80 , // FALSE
|
||||
lh_081 = 81 , // FALSE
|
||||
lh_082 = 82 , // FALSE
|
||||
lh_083 = 83 , // FALSE
|
||||
lh_084 = 84 , // FALSE
|
||||
lh_085 = 85 , // FALSE
|
||||
lh_086 = 86 , //
|
||||
lh_087 = 87 , // TRUE
|
||||
lh_088 = 88 , // FALSE
|
||||
lh_089 = 89 , // FALSE
|
||||
lh_090 = 90 , // FALSE
|
||||
lh_091 = 91 , // FALSE
|
||||
lh_092 = 92 , // FALSE
|
||||
lh_093 = 93 , //
|
||||
lh_094 = 94 , // FALSE
|
||||
lh_095 = 95 , // FALSE
|
||||
lh_096 = 96 , //
|
||||
lh_097 = 97 , // FALSE
|
||||
lh_098 = 98 , // FALSE
|
||||
lh_099 = 99 , // TRUE
|
||||
lh_100 = 100 , // FALSE
|
||||
lh_101 = 101 , // FALSE
|
||||
lh_102 = 102 , // FALSE
|
||||
lh_103 = 103 , // FALSE
|
||||
lh_104 = 104 , // FALSE
|
||||
lh_105 = 105 , // FALSE
|
||||
lh_106 = 106 , // FALSE
|
||||
lh_107 = 107 , // FALSE
|
||||
lh_108 = 108 , // FALSE
|
||||
lh_109 = 109 , // FALSE
|
||||
lh_110 = 110 , // FALSE
|
||||
lh_111 = 111 , // FALSE
|
||||
lh_112 = 112 , // FALSE
|
||||
lh_113 = 113 , // TRUE
|
||||
lh_114 = 114 , // TRUE
|
||||
lh_115 = 115 , // TRUE
|
||||
lh_116 = 116 , // FALSE
|
||||
lh_117 = 117 , // TRUE
|
||||
lh_118 = 118 , // FALSE
|
||||
lh_119 = 119 , // FALSE
|
||||
lh_120 = 120 , // FALSE
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
LOGIHEAD_NUMBER_OF_ITEMS // MUST be last element of enum.
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// Public Interface Below Separator
|
||||
// =====================================================================
|
||||
|
||||
Opm::RestartIO::LogiHEAD::LogiHEAD()
|
||||
: data_(LOGIHEAD_NUMBER_OF_ITEMS, false)
|
||||
{}
|
||||
|
||||
Opm::RestartIO::LogiHEAD&
|
||||
Opm::RestartIO::LogiHEAD::
|
||||
variousParam(const bool e300_radial, const bool e100_radial, const int nswlmx)
|
||||
{
|
||||
this -> data_[lh_000] = true;
|
||||
this -> data_[lh_001] = true;
|
||||
this -> data_[lh_003] = e300_radial;
|
||||
this -> data_[lh_004] = e100_radial;
|
||||
this -> data_[lh_016] = true;
|
||||
this -> data_[lh_018] = true;
|
||||
this -> data_[lh_031] = true;
|
||||
this -> data_[lh_044] = true;
|
||||
this -> data_[lh_075] = nswlmx >= 1; // True if MS Wells exist.
|
||||
this -> data_[lh_076] = true;
|
||||
this -> data_[lh_087] = true;
|
||||
this -> data_[lh_099] = true;
|
||||
this -> data_[lh_113] = true;
|
||||
this -> data_[lh_114] = true;
|
||||
this -> data_[lh_115] = true;
|
||||
this -> data_[lh_117] = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -18,8 +18,8 @@
|
||||
*/
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Completion.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Connection.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/GridProperty.hpp>
|
||||
@@ -35,13 +35,13 @@ RegionCache::RegionCache(const Eclipse3DProperties& properties, const EclipseGri
|
||||
|
||||
const auto& wells = schedule.getWells();
|
||||
for (const auto& well : wells) {
|
||||
const auto& completions = well->getCompletions( );
|
||||
for (const auto& c : completions) {
|
||||
const auto& connections = well->getConnections( );
|
||||
for (const auto& c : connections) {
|
||||
size_t global_index = grid.getGlobalIndex( c.getI() , c.getJ() , c.getK());
|
||||
if (grid.cellActive( global_index )) {
|
||||
size_t active_index = grid.activeIndex( global_index );
|
||||
int region_id =fipnum.iget( global_index );
|
||||
auto& well_index_list = this->completion_map[ region_id ];
|
||||
auto& well_index_list = this->connection_map[ region_id ];
|
||||
well_index_list.push_back( { well->name() , active_index } );
|
||||
}
|
||||
}
|
||||
@@ -49,10 +49,10 @@ RegionCache::RegionCache(const Eclipse3DProperties& properties, const EclipseGri
|
||||
}
|
||||
|
||||
|
||||
const std::vector<std::pair<std::string,size_t>>& RegionCache::completions( int region_id ) const {
|
||||
const auto iter = this->completion_map.find( region_id );
|
||||
if (iter == this->completion_map.end())
|
||||
return this->completions_empty;
|
||||
const std::vector<std::pair<std::string,size_t>>& RegionCache::connections( int region_id ) const {
|
||||
const auto iter = this->connection_map.find( region_id );
|
||||
if (iter == this->connection_map.end())
|
||||
return this->connections_empty;
|
||||
else
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Tables/Eqldims.hpp>
|
||||
|
||||
#include <opm/output/eclipse/RestartIO.hpp>
|
||||
|
||||
@@ -53,16 +54,28 @@ namespace RestartIO {
|
||||
|
||||
|
||||
namespace {
|
||||
/*
|
||||
The RestartValue structure has an 'extra' container which can be used to
|
||||
add extra fields to the restart file. The extra field is used both to add
|
||||
OPM specific fields like 'OPMEXTRA', and eclipse standard fields like
|
||||
THRESHPR. In the case of e.g. THRESHPR this should - if present - be added
|
||||
in the SOLUTION section of the restart file. The std::set extra_solution
|
||||
just enumerates the keys which should be in the solution section.
|
||||
*/
|
||||
|
||||
static const std::set<std::string> extra_solution = {"THRESHPR"};
|
||||
|
||||
|
||||
|
||||
static const int NIWELZ = 11; //Number of data elements per well in IWEL array in restart file
|
||||
static const int NZWELZ = 3; //Number of 8-character words per well in ZWEL array restart file
|
||||
static const int NICONZ = 15; //Number of data elements per completion in ICON array restart file
|
||||
static const int NICONZ = 15; //Number of data elements per connection in ICON array restart file
|
||||
|
||||
/**
|
||||
* The constants NIWELZ and NZWELZ referes to the number of
|
||||
* elements per well that we write to the IWEL and ZWEL eclipse
|
||||
* restart file data arrays. The constant NICONZ refers to the
|
||||
* number of elements per completion in the eclipse restart file
|
||||
* number of elements per connection in the eclipse restart file
|
||||
* ICON data array.These numbers are written to the INTEHEAD
|
||||
* header.
|
||||
*
|
||||
@@ -103,15 +116,14 @@ namespace {
|
||||
|
||||
|
||||
inline data::Solution restoreSOLUTION( ecl_file_view_type* file_view,
|
||||
const std::map<std::string, RestartKey>& keys,
|
||||
const UnitSystem& units,
|
||||
const std::vector<RestartKey>& solution_keys,
|
||||
int numcells) {
|
||||
|
||||
data::Solution sol;
|
||||
for (const auto& pair : keys) {
|
||||
const std::string& key = pair.first;
|
||||
UnitSystem::measure dim = pair.second.dim;
|
||||
bool required = pair.second.required;
|
||||
data::Solution sol( false );
|
||||
for (const auto& value : solution_keys) {
|
||||
const std::string& key = value.key;
|
||||
UnitSystem::measure dim = value.dim;
|
||||
bool required = value.required;
|
||||
|
||||
if( !ecl_file_view_has_kw( file_view, key.c_str() ) ) {
|
||||
if (required)
|
||||
@@ -130,8 +142,6 @@ namespace {
|
||||
+ ", mismatched number of cells" );
|
||||
|
||||
std::vector<double> data = double_vector( ecl_kw );
|
||||
units.to_si( dim , data );
|
||||
|
||||
sol.insert( key, dim, data , data::TargetType::RESTART_SOLUTION );
|
||||
}
|
||||
|
||||
@@ -142,12 +152,12 @@ namespace {
|
||||
using rt = data::Rates::opt;
|
||||
data::Wells restore_wells( const ecl_kw_type * opm_xwel,
|
||||
const ecl_kw_type * opm_iwel,
|
||||
int restart_step,
|
||||
int sim_step,
|
||||
const EclipseState& es,
|
||||
const EclipseGrid& grid,
|
||||
const Schedule& schedule) {
|
||||
|
||||
const auto& sched_wells = schedule.getWells( restart_step );
|
||||
const auto& sched_wells = schedule.getWells( sim_step );
|
||||
std::vector< rt > phases;
|
||||
{
|
||||
const auto& phase = es.runspec().phases();
|
||||
@@ -159,8 +169,8 @@ data::Wells restore_wells( const ecl_kw_type * opm_xwel,
|
||||
const auto well_size = [&]( size_t acc, const Well* w ) {
|
||||
return acc
|
||||
+ 2 + phases.size()
|
||||
+ ( w->getCompletions( restart_step ).size()
|
||||
* (phases.size() + data::Completion::restart_size) );
|
||||
+ ( w->getConnections( sim_step ).size()
|
||||
* (phases.size() + data::Connection::restart_size) );
|
||||
};
|
||||
|
||||
const auto expected_xwel_size = std::accumulate( sched_wells.begin(),
|
||||
@@ -194,22 +204,22 @@ data::Wells restore_wells( const ecl_kw_type * opm_xwel,
|
||||
for( auto phase : phases )
|
||||
well.rates.set( phase, *opm_xwel_data++ );
|
||||
|
||||
for( const auto& sc : sched_well->getCompletions( restart_step ) ) {
|
||||
for( const auto& sc : sched_well->getConnections( sim_step ) ) {
|
||||
const auto i = sc.getI(), j = sc.getJ(), k = sc.getK();
|
||||
if( !grid.cellActive( i, j, k ) || sc.getState() == WellCompletion::SHUT ) {
|
||||
opm_xwel_data += data::Completion::restart_size + phases.size();
|
||||
if( !grid.cellActive( i, j, k ) || sc.state == WellCompletion::SHUT ) {
|
||||
opm_xwel_data += data::Connection::restart_size + phases.size();
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto active_index = grid.activeIndex( i, j, k );
|
||||
|
||||
well.completions.emplace_back();
|
||||
auto& completion = well.completions.back();
|
||||
completion.index = active_index;
|
||||
completion.pressure = *opm_xwel_data++;
|
||||
completion.reservoir_rate = *opm_xwel_data++;
|
||||
well.connections.emplace_back();
|
||||
auto& connection = well.connections.back();
|
||||
connection.index = active_index;
|
||||
connection.pressure = *opm_xwel_data++;
|
||||
connection.reservoir_rate = *opm_xwel_data++;
|
||||
for( auto phase : phases )
|
||||
completion.rates.set( phase, *opm_xwel_data++ );
|
||||
connection.rates.set( phase, *opm_xwel_data++ );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,12 +230,13 @@ data::Wells restore_wells( const ecl_kw_type * opm_xwel,
|
||||
/* should take grid as argument because it may be modified from the simulator */
|
||||
RestartValue load( const std::string& filename,
|
||||
int report_step,
|
||||
const std::map<std::string, RestartKey>& keys,
|
||||
const std::vector<RestartKey>& solution_keys,
|
||||
const EclipseState& es,
|
||||
const EclipseGrid& grid,
|
||||
const Schedule& schedule,
|
||||
const std::map<std::string, bool>& extra_keys) {
|
||||
const std::vector<RestartKey>& extra_keys) {
|
||||
|
||||
int sim_step = std::max(report_step - 1, 0);
|
||||
const bool unified = ( ERT::EclFiletype( filename ) == ECL_UNIFIED_RESTART_FILE );
|
||||
ERT::ert_unique_ptr< ecl_file_type, ecl_file_close > file(ecl_file_open( filename.c_str(), 0 ));
|
||||
ecl_file_view_type * file_view;
|
||||
@@ -247,23 +258,32 @@ RestartValue load( const std::string& filename,
|
||||
const ecl_kw_type * opm_iwel = ecl_file_view_iget_named_kw( file_view, "OPM_IWEL", 0 );
|
||||
|
||||
UnitSystem units( static_cast<ert_ecl_unit_enum>(ecl_kw_iget_int( intehead , INTEHEAD_UNIT_INDEX )));
|
||||
RestartValue rst_value( restoreSOLUTION( file_view, keys, units , grid.getNumActive( )),
|
||||
restore_wells( opm_xwel, opm_iwel, report_step , es, grid, schedule));
|
||||
RestartValue rst_value( restoreSOLUTION( file_view, solution_keys, grid.getNumActive( )),
|
||||
restore_wells( opm_xwel, opm_iwel, sim_step , es, grid, schedule));
|
||||
|
||||
for (const auto& pair : extra_keys) {
|
||||
const std::string& key = pair.first;
|
||||
bool required = pair.second;
|
||||
for (const auto& extra : extra_keys) {
|
||||
const std::string& key = extra.key;
|
||||
bool required = extra.required;
|
||||
|
||||
if (ecl_file_view_has_kw( file_view , key.c_str())) {
|
||||
const ecl_kw_type * ecl_kw = ecl_file_view_iget_named_kw( file_view , key.c_str() , 0 );
|
||||
const double * data_ptr = ecl_kw_get_double_ptr( ecl_kw );
|
||||
const double * end_ptr = data_ptr + ecl_kw_get_size( ecl_kw );
|
||||
rst_value.extra[ key ] = { data_ptr, end_ptr };
|
||||
rst_value.addExtra(key, extra.dim, {data_ptr, end_ptr});
|
||||
} else if (required)
|
||||
throw std::runtime_error("No such key in file: " + key);
|
||||
|
||||
}
|
||||
|
||||
// Convert solution fields and extra data from user units to SI
|
||||
rst_value.solution.convertToSI(units);
|
||||
for (auto & extra_value : rst_value.extra) {
|
||||
const auto& restart_key = extra_value.first;
|
||||
auto & data = extra_value.second;
|
||||
|
||||
units.to_si(restart_key.dim, data);
|
||||
}
|
||||
|
||||
return rst_value;
|
||||
}
|
||||
|
||||
@@ -273,31 +293,32 @@ RestartValue load( const std::string& filename,
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<int> serialize_ICON( int report_step,
|
||||
std::vector<int> serialize_ICON( int sim_step,
|
||||
int ncwmax,
|
||||
const std::vector<const Well*>& sched_wells) {
|
||||
const std::vector<const Well*>& sched_wells,
|
||||
const EclipseGrid& /*grid*/) {
|
||||
|
||||
size_t well_offset = 0;
|
||||
std::vector<int> data( sched_wells.size() * ncwmax * NICONZ , 0 );
|
||||
for (const Well* well : sched_wells) {
|
||||
const auto& completions = well->getCompletions( report_step );
|
||||
size_t completion_offset = 0;
|
||||
for( const auto& completion : completions) {
|
||||
size_t offset = well_offset + completion_offset;
|
||||
const auto& connections = well->getConnections( sim_step );
|
||||
size_t connection_offset = 0;
|
||||
for( const auto& connection : connections) {
|
||||
size_t offset = well_offset + connection_offset;
|
||||
data[ offset + ICON_IC_INDEX ] = 1;
|
||||
|
||||
data[ offset + ICON_I_INDEX ] = completion.getI() + 1;
|
||||
data[ offset + ICON_J_INDEX ] = completion.getJ() + 1;
|
||||
data[ offset + ICON_K_INDEX ] = completion.getK() + 1;
|
||||
data[ offset + ICON_DIRECTION_INDEX ] = completion.getDirection();
|
||||
data[ offset + ICON_I_INDEX ] = connection.getI() + 1;
|
||||
data[ offset + ICON_J_INDEX ] = connection.getJ() + 1;
|
||||
data[ offset + ICON_K_INDEX ] = connection.getK() + 1;
|
||||
data[ offset + ICON_DIRECTION_INDEX ] = connection.dir;
|
||||
{
|
||||
const auto open = WellCompletion::StateEnum::OPEN;
|
||||
data[ offset + ICON_STATUS_INDEX ] = completion.getState() == open
|
||||
data[ offset + ICON_STATUS_INDEX ] = connection.state == open
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
completion_offset += NICONZ;
|
||||
connection_offset += NICONZ;
|
||||
}
|
||||
well_offset += ncwmax * NICONZ;
|
||||
}
|
||||
@@ -305,16 +326,17 @@ std::vector<int> serialize_ICON( int report_step,
|
||||
}
|
||||
|
||||
std::vector<int> serialize_IWEL( size_t step,
|
||||
const std::vector<const Well *>& wells) {
|
||||
const std::vector<const Well *>& wells,
|
||||
const EclipseGrid& grid) {
|
||||
|
||||
std::vector<int> data( wells.size() * NIWELZ , 0 );
|
||||
size_t offset = 0;
|
||||
for (const auto well : wells) {
|
||||
const auto& completions = well->getCompletions( step );
|
||||
const auto& connections = well->getActiveConnections( step, grid );
|
||||
|
||||
data[ offset + IWEL_HEADI_INDEX ] = well->getHeadI( step ) + 1;
|
||||
data[ offset + IWEL_HEADJ_INDEX ] = well->getHeadJ( step ) + 1;
|
||||
data[ offset + IWEL_CONNECTIONS_INDEX ] = completions.size();
|
||||
data[ offset + IWEL_CONNECTIONS_INDEX ] = connections.size();
|
||||
data[ offset + IWEL_GROUP_INDEX ] = 1;
|
||||
|
||||
data[ offset + IWEL_TYPE_INDEX ] = to_ert_welltype( *well, step );
|
||||
@@ -349,7 +371,7 @@ std::vector< int > serialize_OPM_IWEL( const data::Wells& wells,
|
||||
}
|
||||
|
||||
std::vector< double > serialize_OPM_XWEL( const data::Wells& wells,
|
||||
int report_step,
|
||||
int sim_step,
|
||||
const std::vector< const Well* >& sched_wells,
|
||||
const Phases& phase_spec,
|
||||
const EclipseGrid& grid ) {
|
||||
@@ -364,9 +386,9 @@ std::vector< double > serialize_OPM_XWEL( const data::Wells& wells,
|
||||
std::vector< double > xwel;
|
||||
for( const auto* sched_well : sched_wells ) {
|
||||
|
||||
if( wells.count( sched_well->name() ) == 0 || sched_well->getStatus(report_step) == Opm::WellCommon::SHUT) {
|
||||
const auto elems = (sched_well->getCompletions( report_step ).size()
|
||||
* (phases.size() + data::Completion::restart_size))
|
||||
if( wells.count( sched_well->name() ) == 0 || sched_well->getStatus(sim_step) == Opm::WellCommon::SHUT) {
|
||||
const auto elems = (sched_well->getConnections( sim_step ).size()
|
||||
* (phases.size() + data::Connection::restart_size))
|
||||
+ 2 /* bhp, temperature */
|
||||
+ phases.size();
|
||||
|
||||
@@ -382,32 +404,32 @@ std::vector< double > serialize_OPM_XWEL( const data::Wells& wells,
|
||||
for( auto phase : phases )
|
||||
xwel.push_back( well.rates.get( phase ) );
|
||||
|
||||
for( const auto& sc : sched_well->getCompletions( report_step ) ) {
|
||||
for( const auto& sc : sched_well->getConnections( sim_step ) ) {
|
||||
const auto i = sc.getI(), j = sc.getJ(), k = sc.getK();
|
||||
|
||||
const auto rs_size = phases.size() + data::Completion::restart_size;
|
||||
if( !grid.cellActive( i, j, k ) || sc.getState() == WellCompletion::SHUT ) {
|
||||
const auto rs_size = phases.size() + data::Connection::restart_size;
|
||||
if( !grid.cellActive( i, j, k ) || sc.state == WellCompletion::SHUT ) {
|
||||
xwel.insert( xwel.end(), rs_size, 0.0 );
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto active_index = grid.activeIndex( i, j, k );
|
||||
const auto at_index = [=]( const data::Completion& c ) {
|
||||
const auto at_index = [=]( const data::Connection& c ) {
|
||||
return c.index == active_index;
|
||||
};
|
||||
const auto& completion = std::find_if( well.completions.begin(),
|
||||
well.completions.end(),
|
||||
const auto& connection = std::find_if( well.connections.begin(),
|
||||
well.connections.end(),
|
||||
at_index );
|
||||
|
||||
if( completion == well.completions.end() ) {
|
||||
if( connection == well.connections.end() ) {
|
||||
xwel.insert( xwel.end(), rs_size, 0.0 );
|
||||
continue;
|
||||
}
|
||||
|
||||
xwel.push_back( completion->pressure );
|
||||
xwel.push_back( completion->reservoir_rate );
|
||||
xwel.push_back( connection->pressure );
|
||||
xwel.push_back( connection->reservoir_rate );
|
||||
for( auto phase : phases )
|
||||
xwel.push_back( completion->rates.get( phase ) );
|
||||
xwel.push_back( connection->rates.get( phase ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,6 +458,7 @@ void write_kw(ecl_rst_file_type * rst_file , ERT::EclKW< T >&& kw) {
|
||||
}
|
||||
|
||||
void writeHeader(ecl_rst_file_type * rst_file,
|
||||
int sim_step,
|
||||
int report_step,
|
||||
time_t posix_time,
|
||||
double sim_days,
|
||||
@@ -451,11 +474,11 @@ void writeHeader(ecl_rst_file_type * rst_file,
|
||||
rsthead_data.nx = grid.getNX();
|
||||
rsthead_data.ny = grid.getNY();
|
||||
rsthead_data.nz = grid.getNZ();
|
||||
rsthead_data.nwells = schedule.numWells(report_step);
|
||||
rsthead_data.nwells = schedule.numWells(sim_step);
|
||||
rsthead_data.niwelz = NIWELZ;
|
||||
rsthead_data.nzwelz = NZWELZ;
|
||||
rsthead_data.niconz = NICONZ;
|
||||
rsthead_data.ncwmax = schedule.getMaxNumCompletionsForWells(report_step);
|
||||
rsthead_data.ncwmax = schedule.getMaxNumConnectionsForWells(sim_step);
|
||||
rsthead_data.phase_sum = ert_phase_mask;
|
||||
rsthead_data.sim_days = sim_days;
|
||||
rsthead_data.unit_system = units.getEclType( );
|
||||
@@ -472,15 +495,15 @@ void writeHeader(ecl_rst_file_type * rst_file,
|
||||
ERT::ert_unique_ptr< ecl_kw_type, ecl_kw_free > kw_ptr;
|
||||
|
||||
if (write_double) {
|
||||
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw.c_str() , data.size() , ECL_DOUBLE );
|
||||
ecl_kw_set_memcpy_data( ecl_kw , data.data() );
|
||||
kw_ptr.reset( ecl_kw );
|
||||
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw.c_str() , data.size() , ECL_DOUBLE );
|
||||
ecl_kw_set_memcpy_data( ecl_kw , data.data() );
|
||||
kw_ptr.reset( ecl_kw );
|
||||
} else {
|
||||
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw.c_str() , data.size() , ECL_FLOAT );
|
||||
float * float_data = ecl_kw_get_float_ptr( ecl_kw );
|
||||
for (size_t i=0; i < data.size(); i++)
|
||||
float_data[i] = data[i];
|
||||
kw_ptr.reset( ecl_kw );
|
||||
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw.c_str() , data.size() , ECL_FLOAT );
|
||||
float * float_data = ecl_kw_get_float_ptr( ecl_kw );
|
||||
for (size_t i=0; i < data.size(); i++)
|
||||
float_data[i] = data[i];
|
||||
kw_ptr.reset( ecl_kw );
|
||||
}
|
||||
|
||||
return kw_ptr;
|
||||
@@ -488,26 +511,35 @@ void writeHeader(ecl_rst_file_type * rst_file,
|
||||
|
||||
|
||||
|
||||
void writeSolution(ecl_rst_file_type* rst_file, const data::Solution& solution, bool write_double) {
|
||||
ecl_rst_file_start_solution( rst_file );
|
||||
for (const auto& elm: solution) {
|
||||
if (elm.second.target == data::TargetType::RESTART_SOLUTION)
|
||||
ecl_rst_file_add_kw( rst_file , ecl_kw(elm.first, elm.second.data, write_double).get());
|
||||
}
|
||||
ecl_rst_file_end_solution( rst_file );
|
||||
void writeSolution(ecl_rst_file_type* rst_file, const RestartValue& value, bool write_double) {
|
||||
ecl_rst_file_start_solution( rst_file );
|
||||
for (const auto& elm: value.solution) {
|
||||
if (elm.second.target == data::TargetType::RESTART_SOLUTION)
|
||||
ecl_rst_file_add_kw( rst_file , ecl_kw(elm.first, elm.second.data, write_double).get());
|
||||
}
|
||||
for (const auto& elm: value.extra) {
|
||||
const std::string& key = elm.first.key;
|
||||
const std::vector<double>& data = elm.second;
|
||||
if (extra_solution.find(key) != extra_solution.end())
|
||||
/*
|
||||
Observe that the extra data is unconditionally written in double precision.
|
||||
*/
|
||||
ecl_rst_file_add_kw(rst_file, ecl_kw(key, data, true).get());
|
||||
}
|
||||
ecl_rst_file_end_solution( rst_file );
|
||||
|
||||
for (const auto& elm: solution) {
|
||||
if (elm.second.target == data::TargetType::RESTART_AUXILIARY)
|
||||
ecl_rst_file_add_kw( rst_file , ecl_kw(elm.first, elm.second.data, write_double).get());
|
||||
}
|
||||
for (const auto& elm: value.solution) {
|
||||
if (elm.second.target == data::TargetType::RESTART_AUXILIARY)
|
||||
ecl_rst_file_add_kw( rst_file , ecl_kw(elm.first, elm.second.data, write_double).get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void writeExtraData(ecl_rst_file_type* rst_file, const std::map<std::string,std::vector<double>>& extra_data) {
|
||||
for (const auto& pair : extra_data) {
|
||||
const std::string& key = pair.first;
|
||||
const std::vector<double>& data = pair.second;
|
||||
{
|
||||
void writeExtraData(ecl_rst_file_type* rst_file, const RestartValue::ExtraVector& extra_data) {
|
||||
for (const auto& extra_value : extra_data) {
|
||||
const std::string& key = extra_value.first.key;
|
||||
const std::vector<double>& data = extra_value.second;
|
||||
if (extra_solution.find(key) == extra_solution.end()) {
|
||||
ecl_kw_type * ecl_kw = ecl_kw_alloc_new_shared( key.c_str() , data.size() , ECL_DOUBLE , const_cast<double *>(data.data()));
|
||||
ecl_rst_file_add_kw( rst_file , ecl_kw);
|
||||
ecl_kw_free( ecl_kw );
|
||||
@@ -517,15 +549,15 @@ void writeExtraData(ecl_rst_file_type* rst_file, const std::map<std::string,std:
|
||||
|
||||
|
||||
|
||||
void writeWell(ecl_rst_file_type* rst_file, int report_step, const EclipseState& es , const EclipseGrid& grid, const Schedule& schedule, const data::Wells& wells) {
|
||||
const auto sched_wells = schedule.getWells(report_step);
|
||||
void writeWell(ecl_rst_file_type* rst_file, int sim_step, const EclipseState& es , const EclipseGrid& grid, const Schedule& schedule, const data::Wells& wells) {
|
||||
const auto sched_wells = schedule.getWells(sim_step);
|
||||
const auto& phases = es.runspec().phases();
|
||||
const size_t ncwmax = schedule.getMaxNumCompletionsForWells(report_step);
|
||||
const size_t ncwmax = schedule.getMaxNumConnectionsForWells(sim_step);
|
||||
|
||||
const auto opm_xwel = serialize_OPM_XWEL( wells, report_step, sched_wells, phases, grid );
|
||||
const auto opm_xwel = serialize_OPM_XWEL( wells, sim_step, sched_wells, phases, grid );
|
||||
const auto opm_iwel = serialize_OPM_IWEL( wells, sched_wells );
|
||||
const auto iwel_data = serialize_IWEL(report_step, sched_wells);
|
||||
const auto icon_data = serialize_ICON(report_step , ncwmax, sched_wells);
|
||||
const auto iwel_data = serialize_IWEL(sim_step, sched_wells, grid);
|
||||
const auto icon_data = serialize_ICON(sim_step , ncwmax, sched_wells, grid);
|
||||
const auto zwel_data = serialize_ZWEL( sched_wells );
|
||||
|
||||
write_kw( rst_file, ERT::EclKW< int >( IWEL_KW, iwel_data) );
|
||||
@@ -535,44 +567,45 @@ void writeWell(ecl_rst_file_type* rst_file, int report_step, const EclipseState&
|
||||
write_kw( rst_file, ERT::EclKW< int >( ICON_KW, icon_data ) );
|
||||
}
|
||||
|
||||
void checkSaveArguments(const data::Solution& cells,
|
||||
const EclipseGrid& grid,
|
||||
const std::map<std::string, std::vector<double>>& extra_data) {
|
||||
void checkSaveArguments(const EclipseState& es,
|
||||
const RestartValue& restart_value,
|
||||
const EclipseGrid& grid) {
|
||||
|
||||
const std::set<std::string> reserved_keys = {"LOGIHEAD", "INTEHEAD" ,"DOUBHEAD", "IWEL", "XWEL","ICON", "XCON" , "OPM_IWEL" , "OPM_XWEL", "ZWEL"};
|
||||
for (const auto& elm: restart_value.solution)
|
||||
if (elm.second.data.size() != grid.getNumActive())
|
||||
throw std::runtime_error("Wrong size on solution vector: " + elm.first);
|
||||
|
||||
for (const auto& pair : extra_data) {
|
||||
const std::string& key = pair.first;
|
||||
if (key.size() > 8)
|
||||
throw std::runtime_error("The keys in extra data must have maximum eight characaters");
|
||||
|
||||
if (cells.has( key ))
|
||||
throw std::runtime_error("The keys used must unique across Solution and extra_data");
|
||||
if (es.getSimulationConfig().getThresholdPressure().size() > 0) {
|
||||
// If the the THPRES option is active the restart_value should have a
|
||||
// THPRES field. This is not enforced here because not all the opm
|
||||
// simulators have been updated to include the THPRES values.
|
||||
if (!restart_value.hasExtra("THRESHPR")) {
|
||||
OpmLog::warning("This model has THPRES active - should have THPRES as part of restart data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (reserved_keys.find( key ) != reserved_keys.end())
|
||||
throw std::runtime_error("The extra_data uses a reserved key");
|
||||
}
|
||||
|
||||
for (const auto& elm: cells)
|
||||
if (elm.second.data.size() != grid.getNumActive())
|
||||
throw std::runtime_error("Wrong size on solution vector: " + elm.first);
|
||||
}
|
||||
size_t num_regions = es.getTableManager().getEqldims().getNumEquilRegions();
|
||||
const auto& thpres = restart_value.getExtra("THRESHPR");
|
||||
if (thpres.size() != num_regions * num_regions)
|
||||
throw std::runtime_error("THPRES vector has invalid size - should have num_region * num_regions.");
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
|
||||
void save(const std::string& filename,
|
||||
int report_step,
|
||||
double seconds_elapsed,
|
||||
data::Solution cells,
|
||||
data::Wells wells,
|
||||
RestartValue value,
|
||||
const EclipseState& es,
|
||||
const EclipseGrid& grid,
|
||||
const Schedule& schedule,
|
||||
std::map<std::string, std::vector<double>> extra_data,
|
||||
bool write_double)
|
||||
bool write_double)
|
||||
{
|
||||
checkSaveArguments( cells, grid, extra_data );
|
||||
checkSaveArguments(es, value, grid);
|
||||
{
|
||||
int sim_step = std::max(report_step - 1, 0);
|
||||
int ert_phase_mask = es.runspec().eclPhaseMask( );
|
||||
const auto& units = es.getUnits();
|
||||
time_t posix_time = schedule.posixStartTime() + seconds_elapsed;
|
||||
@@ -584,14 +617,20 @@ void save(const std::string& filename,
|
||||
else
|
||||
rst_file.reset( ecl_rst_file_open_write( filename.c_str() ) );
|
||||
|
||||
// Convert solution fields and extra values from SI to user units.
|
||||
value.solution.convertFromSI(units);
|
||||
for (auto & extra_value : value.extra) {
|
||||
const auto& restart_key = extra_value.first;
|
||||
auto & data = extra_value.second;
|
||||
|
||||
cells.convertFromSI( units );
|
||||
writeHeader( rst_file.get() , report_step, posix_time , sim_time, ert_phase_mask, units, schedule , grid );
|
||||
writeWell( rst_file.get() , report_step, es , grid, schedule, wells);
|
||||
writeSolution( rst_file.get() , cells , write_double );
|
||||
writeExtraData( rst_file.get() , extra_data );
|
||||
units.from_si(restart_key.dim, data);
|
||||
}
|
||||
|
||||
writeHeader( rst_file.get(), sim_step, report_step, posix_time , sim_time, ert_phase_mask, units, schedule , grid );
|
||||
writeWell( rst_file.get(), sim_step, es , grid, schedule, value.wells);
|
||||
writeSolution( rst_file.get(), value, write_double );
|
||||
writeExtraData( rst_file.get(), value.extra );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
85
src/opm/output/eclipse/RestartValue.cpp
Normal file
85
src/opm/output/eclipse/RestartValue.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
|
||||
#include <opm/output/eclipse/RestartValue.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
namespace {
|
||||
|
||||
const std::set<std::string> reserved_keys = {"LOGIHEAD", "INTEHEAD" ,"DOUBHEAD", "IWEL", "XWEL","ICON", "XCON" , "OPM_IWEL" , "OPM_XWEL", "ZWEL"};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
RestartValue::RestartValue(data::Solution sol, data::Wells wells_arg) :
|
||||
solution(std::move(sol)),
|
||||
wells(std::move(wells_arg))
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<double>& RestartValue::getExtra(const std::string& key) const {
|
||||
const auto iter = std::find_if(this->extra.begin(),
|
||||
this->extra.end(),
|
||||
[&](const std::pair<RestartKey, std::vector<double>>& pair)
|
||||
{
|
||||
return (pair.first.key == key);
|
||||
});
|
||||
if (iter == this->extra.end())
|
||||
throw std::invalid_argument("No such extra key " + key);
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool RestartValue::hasExtra(const std::string& key) const {
|
||||
const auto iter = std::find_if(this->extra.begin(),
|
||||
this->extra.end(),
|
||||
[&](const std::pair<RestartKey, std::vector<double>>& pair)
|
||||
{
|
||||
return (pair.first.key == key);
|
||||
});
|
||||
return (iter != this->extra.end());
|
||||
}
|
||||
|
||||
void RestartValue::addExtra(const std::string& key, UnitSystem::measure dimension, std::vector<double> data) {
|
||||
if (key.size() > 8)
|
||||
throw std::runtime_error("The keys used for Eclipse output must be maximum 8 characters long.");
|
||||
|
||||
if (this->hasExtra(key))
|
||||
throw std::runtime_error("The keys in the extra vector must be unique.");
|
||||
|
||||
if (this->solution.has(key))
|
||||
throw std::runtime_error("The key " + key + " is already present in the solution section.");
|
||||
|
||||
if (reserved_keys.find(key) != reserved_keys.end())
|
||||
throw std::runtime_error("Can not use reserved key:" + key);
|
||||
|
||||
this->extra.push_back( std::make_pair(RestartKey(key, dimension), std::move(data)));
|
||||
}
|
||||
|
||||
void RestartValue::addExtra(const std::string& key, std::vector<double> data) {
|
||||
this->addExtra(key, UnitSystem::measure::identity, std::move(data));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -17,7 +17,12 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exception>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||
|
||||
@@ -32,12 +37,87 @@
|
||||
#include <opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
|
||||
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
|
||||
|
||||
#include <opm/output/eclipse/SummaryState.hpp>
|
||||
#include <opm/output/eclipse/Summary.hpp>
|
||||
#include <opm/output/eclipse/RegionCache.hpp>
|
||||
|
||||
#include <ert/ecl/ecl_smspec.h>
|
||||
#include <ert/ecl/ecl_kw_magic.h>
|
||||
|
||||
namespace {
|
||||
std::vector<std::string> requiredRestartVectors()
|
||||
{
|
||||
return {
|
||||
"OPR", "WPR", "GPR", "VPR",
|
||||
"OPT", "WPT", "GPT", "VPT",
|
||||
"WIR", "GIR",
|
||||
"WIT", "GIT",
|
||||
"WCT", "GOR",
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>
|
||||
requiredRestartVectors(const ::Opm::Schedule& sched)
|
||||
{
|
||||
auto entities = std::vector<std::pair<std::string, std::string>>{};
|
||||
|
||||
const auto& vectors = requiredRestartVectors();
|
||||
|
||||
auto makeEntities = [&vectors, &entities]
|
||||
(const char cat, const std::string& name)
|
||||
{
|
||||
for (const auto& vector : vectors) {
|
||||
entities.emplace_back(cat + vector, name);
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto* well : sched.getWells()) {
|
||||
const auto& well_name = well->name();
|
||||
|
||||
makeEntities('W', well_name);
|
||||
|
||||
entities.emplace_back("WBHP" , well_name);
|
||||
entities.emplace_back("WGVIR", well_name);
|
||||
entities.emplace_back("WWVIR", well_name);
|
||||
}
|
||||
|
||||
for (const auto* grp : sched.getGroups()) {
|
||||
const auto& grp_name = grp->name();
|
||||
|
||||
if (grp_name != "FIELD") {
|
||||
makeEntities('G', grp_name);
|
||||
}
|
||||
}
|
||||
|
||||
makeEntities('F', "FIELD");
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
std::string genKey(const std::string& vector,
|
||||
const std::string& entity)
|
||||
{
|
||||
return (entity == "FIELD")
|
||||
? vector
|
||||
: vector + ':' + entity;
|
||||
}
|
||||
|
||||
ERT::ert_unique_ptr<smspec_node_type, smspec_node_free>
|
||||
makeRestartVectorSMSPEC(const std::string& vector,
|
||||
const std::string& entity)
|
||||
{
|
||||
const auto var_type =
|
||||
ecl_smspec_identify_var_type(vector.c_str());
|
||||
|
||||
const int dims[] = { 1, 1, 1 };
|
||||
|
||||
return ERT::ert_unique_ptr<smspec_node_type, smspec_node_free> {
|
||||
smspec_node_alloc(var_type, entity.c_str(), vector.c_str(),
|
||||
"UNIT", ":", dims, 0, 0, 0.0f)
|
||||
};
|
||||
}
|
||||
} // namespace Anonymous
|
||||
|
||||
/*
|
||||
* This class takes simulator state and parser-provided information and
|
||||
* orchestrates ert to write simulation results as requested by the SUMMARY
|
||||
@@ -54,6 +134,7 @@ using rt = data::Rates::opt;
|
||||
using measure = UnitSystem::measure;
|
||||
constexpr const bool injector = true;
|
||||
constexpr const bool producer = false;
|
||||
constexpr const bool polymer = true;
|
||||
|
||||
/* Some numerical value with its unit tag embedded to enable caller to apply
|
||||
* unit conversion. This removes a lot of boilerplate. ad-hoc solution to poor
|
||||
@@ -80,6 +161,10 @@ measure div_unit( measure denom, measure div ) {
|
||||
div == measure::time )
|
||||
return measure::gas_surface_volume;
|
||||
|
||||
if( denom == measure::mass_rate &&
|
||||
div == measure::time )
|
||||
return measure::mass;
|
||||
|
||||
return measure::identity;
|
||||
}
|
||||
|
||||
@@ -98,6 +183,9 @@ measure mul_unit( measure lhs, measure rhs ) {
|
||||
( rhs == measure::rate && lhs == measure::time ) )
|
||||
return measure::volume;
|
||||
|
||||
if( lhs == measure::mass_rate && rhs == measure::time)
|
||||
return measure::mass;
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
@@ -195,7 +283,7 @@ double efac( const std::vector<std::pair<std::string,double>>& eff_factors, cons
|
||||
return (it != eff_factors.end()) ? it->second : 1;
|
||||
}
|
||||
|
||||
template< rt phase, bool injection = true >
|
||||
template< rt phase, bool injection = true, bool polymer = false >
|
||||
inline quantity rate( const fn_args& args ) {
|
||||
double sum = 0.0;
|
||||
|
||||
@@ -205,13 +293,19 @@ inline quantity rate( const fn_args& args ) {
|
||||
|
||||
double eff_fac = efac( args.eff_factors, name );
|
||||
|
||||
const auto v = args.wells.at(name).rates.get(phase, 0.0) * eff_fac;
|
||||
double concentration = polymer
|
||||
? sched_well->getPolymerProperties( args.sim_step ).m_polymerConcentration
|
||||
: 1;
|
||||
|
||||
const auto v = args.wells.at(name).rates.get(phase, 0.0) * eff_fac * concentration;
|
||||
|
||||
if( ( v > 0 ) == injection )
|
||||
sum += v;
|
||||
}
|
||||
|
||||
if( !injection ) sum *= -1;
|
||||
|
||||
if( polymer ) return { sum, measure::mass_rate };
|
||||
return { sum, rate_unit< phase >() };
|
||||
}
|
||||
|
||||
@@ -232,7 +326,7 @@ inline quantity flowing( const fn_args& args ) {
|
||||
measure::identity };
|
||||
}
|
||||
|
||||
template< rt phase, bool injection = true >
|
||||
template< rt phase, bool injection = true, bool polymer = false >
|
||||
inline quantity crate( const fn_args& args ) {
|
||||
const quantity zero = { 0, rate_unit< phase >() };
|
||||
// The args.num value is the literal value which will go to the
|
||||
@@ -242,24 +336,29 @@ inline quantity crate( const fn_args& args ) {
|
||||
const size_t global_index = args.num - 1;
|
||||
if( args.schedule_wells.empty() ) return zero;
|
||||
|
||||
const auto& name = args.schedule_wells.front()->name();
|
||||
const auto& well = args.schedule_wells.front();
|
||||
const auto& name = well->name();
|
||||
if( args.wells.count( name ) == 0 ) return zero;
|
||||
|
||||
const auto& well = args.wells.at( name );
|
||||
const auto& completion = std::find_if( well.completions.begin(),
|
||||
well.completions.end(),
|
||||
[=]( const data::Completion& c ) {
|
||||
const auto& well_data = args.wells.at( name );
|
||||
const auto& completion = std::find_if( well_data.connections.begin(),
|
||||
well_data.connections.end(),
|
||||
[=]( const data::Connection& c ) {
|
||||
return c.index == global_index;
|
||||
} );
|
||||
|
||||
if( completion == well.completions.end() ) return zero;
|
||||
if( completion == well_data.connections.end() ) return zero;
|
||||
|
||||
double eff_fac = efac( args.eff_factors, name );
|
||||
double concentration = polymer
|
||||
? well->getPolymerProperties( args.sim_step ).m_polymerConcentration
|
||||
: 1;
|
||||
|
||||
const auto v = completion->rates.get( phase, 0.0 ) * eff_fac;
|
||||
auto v = completion->rates.get( phase, 0.0 ) * eff_fac * concentration;
|
||||
if( ( v > 0 ) != injection ) return zero;
|
||||
if( !injection ) v *= -1;
|
||||
|
||||
if( !injection ) return { -v, rate_unit< phase >() };
|
||||
if( polymer ) return { v, measure::mass_rate };
|
||||
return { v, rate_unit< phase >() };
|
||||
}
|
||||
|
||||
@@ -317,15 +416,7 @@ inline quantity production_history( const fn_args& args ) {
|
||||
* For well data, looking up historical rates (both for production and
|
||||
* injection) before simulation actually starts is impossible and
|
||||
* nonsensical. We therefore default to writing zero (which is what eclipse
|
||||
* seems to do as well). Additionally, when an input deck is parsed,
|
||||
* timesteps and rates are structured as such:
|
||||
*
|
||||
* The rates observed in timestep N is denoted at timestep N-1, i.e. at the
|
||||
* **end** of the previous timestep. Which means that what observed at
|
||||
* timestep 1 is denoted at timestep 0, and what happens "on" timestep 0
|
||||
* doesn't exist and would in code give an arithmetic error. We therefore
|
||||
* special-case timestep N == 0, and for all other timesteps look up the
|
||||
* value *reported* at N-1 which applies to timestep N.
|
||||
* seems to do as well).
|
||||
*/
|
||||
|
||||
double sum = 0.0;
|
||||
@@ -388,9 +479,9 @@ inline quantity duration( const fn_args& args ) {
|
||||
template<rt phase , bool injection>
|
||||
quantity region_rate( const fn_args& args ) {
|
||||
double sum = 0;
|
||||
const auto& well_completions = args.regionCache.completions( args.num );
|
||||
const auto& well_connections = args.regionCache.connections( args.num );
|
||||
|
||||
for (const auto& pair : well_completions) {
|
||||
for (const auto& pair : well_connections) {
|
||||
|
||||
double eff_fac = efac( args.eff_factors, pair.first );
|
||||
|
||||
@@ -433,11 +524,13 @@ static const std::unordered_map< std::string, ofun > funs = {
|
||||
{ "WOIR", rate< rt::oil, injector > },
|
||||
{ "WGIR", rate< rt::gas, injector > },
|
||||
{ "WNIR", rate< rt::solvent, injector > },
|
||||
{ "WCIR", rate< rt::wat, injector, polymer > },
|
||||
|
||||
{ "WWIT", mul( rate< rt::wat, injector >, duration ) },
|
||||
{ "WOIT", mul( rate< rt::oil, injector >, duration ) },
|
||||
{ "WGIT", mul( rate< rt::gas, injector >, duration ) },
|
||||
{ "WNIT", mul( rate< rt::solvent, injector >, duration ) },
|
||||
{ "WCIT", mul( rate< rt::wat, injector, polymer >, duration ) },
|
||||
{ "WVIT", mul( sum( sum( rate< rt::reservoir_water, injector >, rate< rt::reservoir_oil, injector > ),
|
||||
rate< rt::reservoir_gas, injector > ), duration ) },
|
||||
|
||||
@@ -490,12 +583,14 @@ static const std::unordered_map< std::string, ofun > funs = {
|
||||
{ "GOIR", rate< rt::oil, injector > },
|
||||
{ "GGIR", rate< rt::gas, injector > },
|
||||
{ "GNIR", rate< rt::solvent, injector > },
|
||||
{ "GCIR", rate< rt::wat, injector, polymer > },
|
||||
{ "GVIR", sum( sum( rate< rt::reservoir_water, injector >, rate< rt::reservoir_oil, injector > ),
|
||||
rate< rt::reservoir_gas, injector > ) },
|
||||
{ "GWIT", mul( rate< rt::wat, injector >, duration ) },
|
||||
{ "GOIT", mul( rate< rt::oil, injector >, duration ) },
|
||||
{ "GGIT", mul( rate< rt::gas, injector >, duration ) },
|
||||
{ "GNIT", mul( rate< rt::solvent, injector >, duration ) },
|
||||
{ "GCIT", mul( rate< rt::wat, injector, polymer >, duration ) },
|
||||
{ "GVIT", mul( sum( sum( rate< rt::reservoir_water, injector >, rate< rt::reservoir_oil, injector > ),
|
||||
rate< rt::reservoir_gas, injector > ), duration ) },
|
||||
|
||||
@@ -599,6 +694,7 @@ static const std::unordered_map< std::string, ofun > funs = {
|
||||
|
||||
{ "CWIR", crate< rt::wat, injector > },
|
||||
{ "CGIR", crate< rt::gas, injector > },
|
||||
{ "CCIR", crate< rt::wat, injector, polymer > },
|
||||
{ "CWIT", mul( crate< rt::wat, injector >, duration ) },
|
||||
{ "CGIT", mul( crate< rt::gas, injector >, duration ) },
|
||||
{ "CNIT", mul( crate< rt::solvent, injector >, duration ) },
|
||||
@@ -612,6 +708,7 @@ static const std::unordered_map< std::string, ofun > funs = {
|
||||
{ "COPT", mul( crate< rt::oil, producer >, duration ) },
|
||||
{ "CGPT", mul( crate< rt::gas, producer >, duration ) },
|
||||
{ "CNPT", mul( crate< rt::solvent, producer >, duration ) },
|
||||
{ "CCIT", mul( crate< rt::wat, injector, polymer >, duration ) },
|
||||
|
||||
{ "FWPR", rate< rt::wat, producer > },
|
||||
{ "FOPR", rate< rt::oil, producer > },
|
||||
@@ -628,7 +725,7 @@ static const std::unordered_map< std::string, ofun > funs = {
|
||||
{ "FWPT", mul( rate< rt::wat, producer >, duration ) },
|
||||
{ "FOPT", mul( rate< rt::oil, producer >, duration ) },
|
||||
{ "FGPT", mul( rate< rt::gas, producer >, duration ) },
|
||||
{ "FNPT", mul( rate< rt::solvent >, duration ) },
|
||||
{ "FNPT", mul( rate< rt::solvent, producer >, duration ) },
|
||||
{ "FLPT", mul( sum( rate< rt::wat, producer >, rate< rt::oil, producer > ),
|
||||
duration ) },
|
||||
{ "FVPT", mul(sum (sum( rate< rt::reservoir_water, producer>, rate< rt::reservoir_oil, producer >),
|
||||
@@ -644,6 +741,7 @@ static const std::unordered_map< std::string, ofun > funs = {
|
||||
{ "FOIR", rate< rt::oil, injector > },
|
||||
{ "FGIR", rate< rt::gas, injector > },
|
||||
{ "FNIR", rate< rt::solvent, injector > },
|
||||
{ "FCIR", rate< rt::wat, injector, polymer > },
|
||||
{ "FVIR", sum( sum( rate< rt::reservoir_water, injector>, rate< rt::reservoir_oil, injector >),
|
||||
rate< rt::reservoir_gas, injector>)},
|
||||
|
||||
@@ -652,6 +750,7 @@ static const std::unordered_map< std::string, ofun > funs = {
|
||||
{ "FOIT", mul( rate< rt::oil, injector >, duration ) },
|
||||
{ "FGIT", mul( rate< rt::gas, injector >, duration ) },
|
||||
{ "FNIT", mul( rate< rt::solvent, injector >, duration ) },
|
||||
{ "FCIT", mul( rate< rt::wat, injector, polymer >, duration ) },
|
||||
{ "FLIT", mul( sum( rate< rt::wat, injector >, rate< rt::oil, injector > ),
|
||||
duration ) },
|
||||
{ "FVIT", mul( sum( sum( rate< rt::reservoir_water, injector>, rate< rt::reservoir_oil, injector >),
|
||||
@@ -783,8 +882,8 @@ inline std::vector< const Well* > find_wells( const Schedule& schedule,
|
||||
|
||||
const auto region = smspec_node_get_num( node );
|
||||
|
||||
for ( const auto& completion : regionCache.completions( region ) ){
|
||||
const auto& w_name = completion.first;
|
||||
for ( const auto& connection : regionCache.connections( region ) ){
|
||||
const auto& w_name = connection.first;
|
||||
const auto& well = schedule.getWell( w_name );
|
||||
|
||||
const auto& it = std::find_if( wells.begin(), wells.end(),
|
||||
@@ -812,7 +911,10 @@ class Summary::keyword_handlers {
|
||||
std::map< std::pair <std::string, int>, smspec_node_type* > region_nodes;
|
||||
std::map< std::pair <std::string, int>, smspec_node_type* > block_nodes;
|
||||
|
||||
|
||||
// Memory management for restart-related summary vectors
|
||||
// that are not requested in SUMMARY section.
|
||||
std::vector<ERT::ert_unique_ptr<smspec_node_type,
|
||||
smspec_node_free>> rstvec_backing_store;
|
||||
};
|
||||
|
||||
Summary::Summary( const EclipseState& st,
|
||||
@@ -944,7 +1046,8 @@ Summary::Summary( const EclipseState& st,
|
||||
node.num(), // NUMS value for the summary output.
|
||||
{}, // Well results - data::Wells
|
||||
{}, // Region <-> cell mappings.
|
||||
this->grid};
|
||||
this->grid,
|
||||
{}};
|
||||
|
||||
const auto val = handle( no_args );
|
||||
|
||||
@@ -963,6 +1066,42 @@ Summary::Summary( const EclipseState& st,
|
||||
for ( const auto& keyword : unsupported_keywords ) {
|
||||
Opm::OpmLog::info("Keyword " + std::string(keyword) + " is unhandled");
|
||||
}
|
||||
|
||||
// Guarantee existence of certain summary vectors (mostly rates and
|
||||
// cumulative totals for wells, groups, and field) that are required
|
||||
// for simulation restart.
|
||||
{
|
||||
auto& rvec = this->handlers->rstvec_backing_store;
|
||||
auto& hndlrs = this->handlers->handlers;
|
||||
|
||||
for (const auto& vector : requiredRestartVectors(schedule)) {
|
||||
const auto& kw = vector.first;
|
||||
const auto& entity = vector.second;
|
||||
|
||||
const auto key = genKey(kw, entity);
|
||||
if (ecl_sum_has_key(this->ecl_sum.get(), key.c_str())) {
|
||||
// Vector already requested in SUMMARY section.
|
||||
// Don't add a second evaluation of this.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto func = funs.find(kw);
|
||||
if (func == std::end(funs)) {
|
||||
throw std::logic_error {
|
||||
"Unable to find handler for '" + kw + "'"
|
||||
};
|
||||
}
|
||||
|
||||
rvec.push_back(makeRestartVectorSMSPEC(kw, entity));
|
||||
hndlrs.emplace_back(rvec.back().get(), func->second);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& pair : this->handlers->handlers) {
|
||||
const auto * nodeptr = pair.first;
|
||||
if (smspec_node_is_total(nodeptr))
|
||||
this->prev_state.add(smspec_node_get_gen_key1(nodeptr), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1036,6 +1175,7 @@ void Summary::add_timestep( int report_step,
|
||||
|
||||
auto* tstep = ecl_sum_add_tstep( this->ecl_sum.get(), report_step, secs_elapsed );
|
||||
const double duration = secs_elapsed - this->prev_time_elapsed;
|
||||
SummaryState st;
|
||||
|
||||
/* report_step is the number of the file we are about to write - i.e. for instance CASE.S$report_step
|
||||
* for the data in a non-unified summary file.
|
||||
@@ -1059,12 +1199,11 @@ void Summary::add_timestep( int report_step,
|
||||
this->grid,
|
||||
eff_factors});
|
||||
|
||||
const auto unit_applied_val = es.getUnits().from_si( val.unit, val.value );
|
||||
const auto res = smspec_node_is_total( f.first ) && prev_tstep
|
||||
? ecl_sum_tstep_get_from_key( prev_tstep, genkey ) + unit_applied_val
|
||||
: unit_applied_val;
|
||||
double unit_applied_val = es.getUnits().from_si( val.unit, val.value );
|
||||
if (smspec_node_is_total(f.first))
|
||||
unit_applied_val += this->prev_state.get(genkey);
|
||||
|
||||
ecl_sum_tstep_set_from_node( tstep, f.first, res );
|
||||
st.add(genkey, unit_applied_val);
|
||||
}
|
||||
|
||||
for( const auto& value_pair : single_values ) {
|
||||
@@ -1072,10 +1211,11 @@ void Summary::add_timestep( int report_step,
|
||||
const auto node_pair = this->handlers->single_value_nodes.find( key );
|
||||
if (node_pair != this->handlers->single_value_nodes.end()) {
|
||||
const auto * nodeptr = node_pair->second;
|
||||
const auto * genkey = smspec_node_get_gen_key1( nodeptr );
|
||||
const auto unit = single_values_units.at( key );
|
||||
double si_value = value_pair.second;
|
||||
double output_value = es.getUnits().from_si(unit , si_value );
|
||||
ecl_sum_tstep_set_from_node( tstep, nodeptr , output_value );
|
||||
st.add(genkey, output_value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,11 +1225,13 @@ void Summary::add_timestep( int report_step,
|
||||
const auto node_pair = this->handlers->region_nodes.find( std::make_pair(key, reg+1) );
|
||||
if (node_pair != this->handlers->region_nodes.end()) {
|
||||
const auto * nodeptr = node_pair->second;
|
||||
const auto* genkey = smspec_node_get_gen_key1( nodeptr );
|
||||
const auto unit = region_units.at( key );
|
||||
|
||||
assert (smspec_node_get_num( nodeptr ) - 1 == static_cast<int>(reg));
|
||||
double si_value = value_pair.second[reg];
|
||||
double output_value = es.getUnits().from_si(unit , si_value );
|
||||
ecl_sum_tstep_set_from_node( tstep, nodeptr , output_value );
|
||||
st.add(genkey, output_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1099,14 +1241,23 @@ void Summary::add_timestep( int report_step,
|
||||
const auto node_pair = this->handlers->block_nodes.find( key );
|
||||
if (node_pair != this->handlers->block_nodes.end()) {
|
||||
const auto * nodeptr = node_pair->second;
|
||||
const auto * genkey = smspec_node_get_gen_key1( nodeptr );
|
||||
const auto unit = block_units.at( key.first );
|
||||
double si_value = value_pair.second;
|
||||
double output_value = es.getUnits().from_si(unit , si_value );
|
||||
ecl_sum_tstep_set_from_node( tstep, nodeptr , output_value );
|
||||
st.add(genkey, output_value);
|
||||
}
|
||||
}
|
||||
|
||||
this->prev_tstep = tstep;
|
||||
for (const auto& pair: st) {
|
||||
const auto* key = pair.first.c_str();
|
||||
|
||||
if (ecl_sum_has_key(this->ecl_sum.get(), key)) {
|
||||
ecl_sum_tstep_set_from_key(tstep, key, pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
this->prev_state = st;
|
||||
this->prev_time_elapsed = secs_elapsed;
|
||||
}
|
||||
|
||||
@@ -1116,5 +1267,9 @@ void Summary::write() {
|
||||
|
||||
Summary::~Summary() {}
|
||||
|
||||
const SummaryState& Summary::get_restart_vectors() const
|
||||
{
|
||||
return this->prev_state;
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace Opm::out
|
||||
|
||||
52
src/opm/output/eclipse/SummaryState.cpp
Normal file
52
src/opm/output/eclipse/SummaryState.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
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 <opm/output/eclipse/SummaryState.hpp>
|
||||
|
||||
namespace Opm{
|
||||
|
||||
void SummaryState::add(const std::string& key, double value) {
|
||||
this->values[key] = value;
|
||||
}
|
||||
|
||||
|
||||
bool SummaryState::has(const std::string& key) const {
|
||||
return (this->values.find(key) != this->values.end());
|
||||
}
|
||||
|
||||
|
||||
double SummaryState::get(const std::string& key) const {
|
||||
const auto iter = this->values.find(key);
|
||||
if (iter == this->values.end())
|
||||
throw std::invalid_argument("XX No such key: " + key);
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
SummaryState::const_iterator SummaryState::begin() const {
|
||||
return this->values.begin();
|
||||
}
|
||||
|
||||
|
||||
SummaryState::const_iterator SummaryState::end() const {
|
||||
return this->values.end();
|
||||
}
|
||||
|
||||
}
|
||||
115
src/opm/output/eclipse/WellDataSerializers.cpp
Normal file
115
src/opm/output/eclipse/WellDataSerializers.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
|
||||
#include <ert/ecl_well/well_const.h> // containts ICON_XXX_INDEX
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
|
||||
#include <vector>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
std::vector<double>
|
||||
Opm::RestartIO::Helpers::
|
||||
serialize_SCON(int lookup_step,
|
||||
int ncwmax,
|
||||
int nsconz,
|
||||
const std::vector<const Well*>& sched_wells,
|
||||
const UnitSystem& units)
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
const size_t well_field_size = ncwmax * nsconz;
|
||||
std::vector<double> data(sched_wells.size() * well_field_size, 0);
|
||||
size_t well_offset = 0;
|
||||
for (const Opm::Well* well : sched_wells) {
|
||||
const auto& connections = well->getConnections( lookup_step );
|
||||
size_t connection_offset = 0;
|
||||
bool explicit_ctf_not_found = false;
|
||||
for (const auto& connection : connections) {
|
||||
const size_t offset = well_offset + connection_offset;
|
||||
const auto& ctf = connection.getConnectionTransmissibilityFactorAsValueObject();
|
||||
if (ctf.hasValue()) {
|
||||
// CTF explicitly set in deck, overrides calculation
|
||||
// from Peaceman model. We should also give the Kh
|
||||
// factor, we output an explicitly invalid value
|
||||
// instead. This is acceptable since it will not be
|
||||
// used (the explicit CTF factor is used instead).
|
||||
const double ctf_SI = ctf.getValue();
|
||||
const double ctf_output = units.from_si(UnitSystem::measure::transmissibility, ctf_SI);
|
||||
data[ offset + SCON_CF_INDEX ] = ctf_output;
|
||||
data[ offset + SCON_KH_INDEX ] = UNIMPLEMENTED_VALUE;
|
||||
} else {
|
||||
// CTF not set in deck, Peaceman formula used to
|
||||
// compute it. Here we should store the data for the
|
||||
// connection required to recalculate the CTF (the Kh
|
||||
// factor), as well as the actual CTF used by the
|
||||
// simulator, but that requires access to more data
|
||||
// from the simulator. As an interim measure we write
|
||||
// invalid values and give a warning.
|
||||
data[ offset + SCON_CF_INDEX ] = UNIMPLEMENTED_VALUE;
|
||||
data[ offset + SCON_KH_INDEX ] = UNIMPLEMENTED_VALUE;
|
||||
explicit_ctf_not_found = true;
|
||||
}
|
||||
connection_offset += nsconz;
|
||||
}
|
||||
if (explicit_ctf_not_found) {
|
||||
OpmLog::warning("restart output connection data missing",
|
||||
"Explicit connection transmissibility factors for well " + well->name() + " missing, writing dummy values to restart file.");
|
||||
}
|
||||
well_offset += well_field_size;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
std::vector<int>
|
||||
Opm::RestartIO::Helpers::
|
||||
serialize_ICON(int lookup_step,
|
||||
int ncwmax,
|
||||
int niconz,
|
||||
const std::vector<const Opm::Well*>& sched_wells)
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
const size_t well_field_size = ncwmax * niconz;
|
||||
std::vector<int> data(sched_wells.size() * well_field_size, 0);
|
||||
size_t well_offset = 0;
|
||||
for (const Opm::Well* well : sched_wells) {
|
||||
const auto& connections = well->getConnections( lookup_step );
|
||||
size_t connection_offset = 0;
|
||||
for (const auto& connection : connections) {
|
||||
const size_t offset = well_offset + connection_offset;
|
||||
|
||||
data[ offset + ICON_IC_INDEX ] = connection.complnum;
|
||||
data[ offset + ICON_I_INDEX ] = connection.getI() + 1;
|
||||
data[ offset + ICON_J_INDEX ] = connection.getJ() + 1;
|
||||
data[ offset + ICON_K_INDEX ] = connection.getK() + 1;
|
||||
data[ offset + ICON_DIRECTION_INDEX ] = connection.dir;
|
||||
data[ offset + ICON_STATUS_INDEX ] =
|
||||
(connection.state == WellCompletion::StateEnum::OPEN) ?
|
||||
1 : -1000;
|
||||
data[ offset + ICON_SEGMENT_INDEX ] =
|
||||
connection.attachedToSegment() ?
|
||||
connection.segment_number : 0;
|
||||
connection_offset += niconz;
|
||||
}
|
||||
|
||||
well_offset += well_field_size;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -13,7 +13,6 @@
|
||||
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/>.
|
||||
*/
|
||||
|
||||
@@ -139,7 +138,8 @@ namespace Opm {
|
||||
keywordList( std::move( x ) ),
|
||||
defaultUnits( UnitSystem::newMETRIC() ),
|
||||
activeUnits( UnitSystem::newMETRIC() ),
|
||||
m_dataFile("")
|
||||
m_dataFile(""),
|
||||
input_path("")
|
||||
{
|
||||
/*
|
||||
* If multiple unit systems are requested, metric is preferred over
|
||||
@@ -169,8 +169,8 @@ namespace Opm {
|
||||
keywordList( d.keywordList ),
|
||||
defaultUnits( d.defaultUnits ),
|
||||
activeUnits( d.activeUnits ),
|
||||
m_dataFile( d.m_dataFile ) {
|
||||
|
||||
m_dataFile( d.m_dataFile ),
|
||||
input_path( d.input_path ) {
|
||||
this->reinit(this->keywordList.begin(), this->keywordList.end());
|
||||
}
|
||||
|
||||
@@ -209,12 +209,22 @@ namespace Opm {
|
||||
return this->activeUnits;
|
||||
}
|
||||
|
||||
const std::string Deck::getDataFile() const {
|
||||
const std::string& Deck::getDataFile() const {
|
||||
return m_dataFile;
|
||||
}
|
||||
|
||||
const std::string& Deck::getInputPath() const {
|
||||
return this->input_path;
|
||||
}
|
||||
|
||||
void Deck::setDataFile(const std::string& dataFile) {
|
||||
m_dataFile = dataFile;
|
||||
this->m_dataFile = dataFile;
|
||||
|
||||
auto slash_pos = dataFile.find_last_of("/\\");
|
||||
if (slash_pos == std::string::npos)
|
||||
this->input_path = "";
|
||||
else
|
||||
this->input_path = dataFile.substr(0, slash_pos);
|
||||
}
|
||||
|
||||
Deck::iterator Deck::begin() {
|
||||
@@ -237,7 +247,7 @@ namespace Opm {
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Deck& deck) {
|
||||
DeckOutput out( os );
|
||||
DeckOutput out( os, 10 );
|
||||
deck.write( out );
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -24,13 +24,25 @@
|
||||
|
||||
namespace Opm {
|
||||
|
||||
DeckOutput::DeckOutput( std::ostream& s) :
|
||||
DeckOutput::DeckOutput( std::ostream& s, int precision) :
|
||||
os( s ),
|
||||
default_count( 0 ),
|
||||
row_count( 0 ),
|
||||
record_on( false )
|
||||
record_on( false ),
|
||||
org_precision( os.precision(precision) )
|
||||
{}
|
||||
|
||||
|
||||
DeckOutput::~DeckOutput() {
|
||||
this->set_precision(this->org_precision);
|
||||
}
|
||||
|
||||
|
||||
void DeckOutput::set_precision(int precision) {
|
||||
this->os.precision(precision);
|
||||
}
|
||||
|
||||
|
||||
void DeckOutput::endl() {
|
||||
this->os << std::endl;
|
||||
}
|
||||
|
||||
@@ -31,17 +31,18 @@ namespace Opm {
|
||||
for (auto& aquctRecord : aquctKeyword){
|
||||
|
||||
AquiferCT::AQUCT_data data;
|
||||
|
||||
|
||||
data.c1 = 1.0;
|
||||
data.c2 = 6.283; // Value of C2 used by E100 (for METRIC, PVT-M and LAB unit systems)
|
||||
data.aquiferID = aquctRecord.getItem("AQUIFER_ID").template get<int>(0);
|
||||
data.h = aquctRecord.getItem("THICKNESS_AQ").getSIDouble(0);
|
||||
data.p0 = aquctRecord.getItem("P_INI").getSIDouble(0);
|
||||
data.phi_aq = aquctRecord.getItem("PORO_AQ").getSIDouble(0);
|
||||
data.d0 = aquctRecord.getItem("DAT_DEPTH").getSIDouble(0);
|
||||
data.C_t = aquctRecord.getItem("C_T").getSIDouble(0);
|
||||
data.r_o = aquctRecord.getItem("RAD").getSIDouble(0);
|
||||
data.k_a = aquctRecord.getItem("PERM_AQ").getSIDouble(0);
|
||||
data.theta = aquctRecord.getItem("INFLUENCE_ANGLE").getSIDouble(0);
|
||||
data.c1 = 0.008527; // We are using SI
|
||||
data.c2 = 6.283;
|
||||
data.theta = aquctRecord.getItem("INFLUENCE_ANGLE").getSIDouble(0)/360.0;
|
||||
data.inftableID = aquctRecord.getItem("TABLE_NUM_INFLUENCE_FN").template get<int>(0);
|
||||
data.pvttableID = aquctRecord.getItem("TABLE_NUM_WATER_PRESS").template get<int>(0);
|
||||
|
||||
|
||||
@@ -443,6 +443,20 @@ namespace Opm {
|
||||
return supportedDoubleKeywords;
|
||||
}
|
||||
|
||||
Eclipse3DProperties::Eclipse3DProperties( UnitSystem unit_system,
|
||||
const TableManager& tableManager,
|
||||
const EclipseGrid& eclipseGrid):
|
||||
m_defaultRegion("FLUXNUM"),
|
||||
m_deckUnitSystem(unit_system),
|
||||
// Note that the variants of grid keywords for radial grids are not
|
||||
// supported. (and hopefully never will be)
|
||||
// register the grid properties
|
||||
m_intGridProperties(eclipseGrid, makeSupportedIntKeywords()),
|
||||
m_doubleGridProperties(eclipseGrid, &unit_system,
|
||||
makeSupportedDoubleKeywords(&tableManager, &eclipseGrid, &m_intGridProperties))
|
||||
{
|
||||
}
|
||||
|
||||
Eclipse3DProperties::Eclipse3DProperties( const Deck& deck,
|
||||
const TableManager& tableManager,
|
||||
const EclipseGrid& eclipseGrid)
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Opm {
|
||||
m_inputNnc( deck ),
|
||||
m_inputGrid( deck, nullptr ),
|
||||
m_eclipseProperties( deck, m_tables, m_inputGrid ),
|
||||
m_simulationConfig( deck, m_eclipseProperties ),
|
||||
m_simulationConfig( m_eclipseConfig.getInitConfig().restartRequested(), deck, m_eclipseProperties ),
|
||||
m_transMult( GridDims(deck), deck, m_eclipseProperties )
|
||||
{
|
||||
m_inputGrid.resetACTNUM(m_eclipseProperties.getIntGridProperty("ACTNUM").getData().data());
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <functional>
|
||||
|
||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||
#include <opm/common/utility/numeric/calculateCellVol.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Deck/Section.hpp>
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
@@ -47,7 +48,7 @@
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
|
||||
#include <ert/ecl/ecl_grid.h>
|
||||
#include <ert/ecl/ecl_grid.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
@@ -57,11 +58,13 @@ namespace Opm {
|
||||
const std::vector<double>& zcorn ,
|
||||
const int * actnum,
|
||||
const double * mapaxes)
|
||||
: m_minpvValue(0),
|
||||
: GridDims(dims),
|
||||
m_minpvValue(0),
|
||||
m_minpvMode(MinpvMode::ModeEnum::Inactive),
|
||||
m_pinch("PINCH"),
|
||||
m_pinchoutMode(PinchMode::ModeEnum::TOPBOT),
|
||||
m_multzMode(PinchMode::ModeEnum::TOP)
|
||||
m_multzMode(PinchMode::ModeEnum::TOP),
|
||||
volume_cache(dims[0] * dims[1] * dims[2], -1.0)
|
||||
{
|
||||
initCornerPointGrid( dims, coord , zcorn , actnum , mapaxes );
|
||||
}
|
||||
@@ -89,6 +92,8 @@ namespace Opm {
|
||||
m_nx = ecl_grid_get_nx( c_ptr() );
|
||||
m_ny = ecl_grid_get_ny( c_ptr() );
|
||||
m_nz = ecl_grid_get_nz( c_ptr() );
|
||||
|
||||
volume_cache.resize(m_nx * m_ny * m_nz, -1.0);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +105,7 @@ namespace Opm {
|
||||
m_pinch("PINCH"),
|
||||
m_pinchoutMode(PinchMode::ModeEnum::TOPBOT),
|
||||
m_multzMode(PinchMode::ModeEnum::TOP),
|
||||
volume_cache(nx * ny * nz, -1.0),
|
||||
m_grid( ecl_grid_alloc_rectangular(nx, ny, nz, dx, dy, dz, NULL) )
|
||||
{
|
||||
}
|
||||
@@ -110,7 +116,8 @@ namespace Opm {
|
||||
m_minpvMode( src.m_minpvMode ),
|
||||
m_pinch( src.m_pinch ),
|
||||
m_pinchoutMode( src.m_pinchoutMode ),
|
||||
m_multzMode( src.m_multzMode )
|
||||
m_multzMode( src.m_multzMode ),
|
||||
volume_cache(src.volume_cache.size(), -1.0)
|
||||
{
|
||||
const int * actnum_data = (actnum.empty()) ? nullptr : actnum.data();
|
||||
m_grid.reset( ecl_grid_alloc_processed_copy( src.c_ptr(), zcorn , actnum_data ));
|
||||
@@ -163,7 +170,8 @@ namespace Opm {
|
||||
m_minpvMode(MinpvMode::ModeEnum::Inactive),
|
||||
m_pinch("PINCH"),
|
||||
m_pinchoutMode(PinchMode::ModeEnum::TOPBOT),
|
||||
m_multzMode(PinchMode::ModeEnum::TOP)
|
||||
m_multzMode(PinchMode::ModeEnum::TOP),
|
||||
volume_cache(m_nx * m_ny * m_nz, -1.0)
|
||||
{
|
||||
|
||||
const std::array<int, 3> dims = getNXYZ();
|
||||
@@ -445,8 +453,6 @@ namespace Opm {
|
||||
const int * actnum,
|
||||
const double * mapaxes)
|
||||
{
|
||||
const std::vector<float> zcorn_float( zcorn.begin() , zcorn.end() );
|
||||
const std::vector<float> coord_float( coord.begin() , coord.end() );
|
||||
float * mapaxes_float = nullptr;
|
||||
if (mapaxes) {
|
||||
mapaxes_float = new float[6];
|
||||
@@ -454,14 +460,14 @@ namespace Opm {
|
||||
mapaxes_float[i] = mapaxes[i];
|
||||
}
|
||||
|
||||
m_grid.reset( ecl_grid_alloc_GRDECL_data(dims[0] ,
|
||||
dims[1] ,
|
||||
dims[2] ,
|
||||
zcorn_float.data() ,
|
||||
coord_float.data() ,
|
||||
actnum ,
|
||||
false, // We do not apply the MAPAXES transformations
|
||||
mapaxes_float) );
|
||||
m_grid.reset( ecl::ecl_grid_alloc_GRDECL_data(dims[0] ,
|
||||
dims[1] ,
|
||||
dims[2] ,
|
||||
zcorn.data() ,
|
||||
coord.data() ,
|
||||
actnum ,
|
||||
false, // We do not apply the MAPAXES transformations
|
||||
mapaxes_float) );
|
||||
|
||||
if (mapaxes)
|
||||
delete[] mapaxes_float;
|
||||
@@ -730,13 +736,23 @@ namespace Opm {
|
||||
|
||||
double EclipseGrid::getCellVolume(size_t globalIndex) const {
|
||||
assertGlobalIndex( globalIndex );
|
||||
return ecl_grid_get_cell_volume1( c_ptr() , static_cast<int>(globalIndex));
|
||||
if (volume_cache[globalIndex] < 0.0) {
|
||||
// Calculate cell volume and put it in the cache.
|
||||
std::vector<double> x(8,0);
|
||||
std::vector<double> y(8,0);
|
||||
std::vector<double> z(8,0);
|
||||
for (int i=0; i < 8; i++) {
|
||||
ecl_grid_get_cell_corner_xyz1(c_ptr(), static_cast<int>(globalIndex), i, &x[i], &y[i], &z[i]);
|
||||
}
|
||||
volume_cache[globalIndex] = calculateCellVol(x,y,z);
|
||||
}
|
||||
return volume_cache[globalIndex];
|
||||
}
|
||||
|
||||
|
||||
double EclipseGrid::getCellVolume(size_t i , size_t j , size_t k) const {
|
||||
assertIJK(i,j,k);
|
||||
return ecl_grid_get_cell_volume3( c_ptr() , static_cast<int>(i),static_cast<int>(j),static_cast<int>(k));
|
||||
return getCellVolume(getGlobalIndex(i, j, k));
|
||||
}
|
||||
|
||||
double EclipseGrid::getCellThicknes(size_t i , size_t j , size_t k) const {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user