Compare commits

...

89 Commits

Author SHA1 Message Date
Arne Morten Kvarving
8f297e2079 bump versions for final 2018-10-24 13:35:03 +02:00
Arne Morten Kvarving
1e77807ff0 correct packaging versions 2018-10-04 06:06:01 +02:00
Joakim Hove
a732ddeb50 Merge pull request #512 from joakim-hove/bump-versions
Bump versions to 2018.10-rc1
2018-10-02 15:50:58 +02:00
Joakim Hove
4768b5cd95 Bump versions to 2018.10-rc1 2018-10-02 15:27:41 +02:00
Joakim Hove
c81e5027c9 Merge pull request #510 from bska/difftime
TimeMap: Use difftime() for Time Deltas as double
2018-10-02 14:44:44 +02:00
Bård Skaflestad
23950403f1 TimeMap: Use difftime() for Time Deltas as double
Reduces the amount of explicit arithmetic on std::time_t values and
thereby, implicitly, the assumption of targeting Posix systems only.
2018-10-02 13:11:02 +02:00
Bård Skaflestad
33372a3337 Merge pull request #506 from jalvestad/flow-flow-restart
EclipseRestart-improvements
2018-10-02 13:05:43 +02:00
Jostein Alvestad
c067e48276 Additional improvement and correction for writing of eclipse compatible restart file 2018-09-28 15:39:25 +02:00
Jostein Alvestad
5d398565c2 Improved the code structure - current improvement 2018-09-28 11:23:42 +02:00
Jostein Alvestad
a9a82e3814 Minor correction to previous commit rseg [39] was not properly assigned 2018-09-28 09:56:03 +02:00
Jostein Alvestad
3f94b580a2 Added changes to improve treatment of multi segment wells in Eclipse Restart
Added flowing well bottom hole pressure to item[8] and [39] plus adjusted item[9]
2018-09-28 09:48:03 +02:00
Jostein Alvestad
cfc1b29c08 Added improvements and corrections to handle writing of eclipse compatible restart file
for more general well data
2018-09-27 16:23:34 +02:00
Jostein Alvestad
264d451d56 Added additional changes to handle repeated read of COMPDAT
for same grid i,j,k cell.
Corrections for handling wells with only 1 connection
Correction for XWEL - BG being NaN
2018-09-27 16:23:32 +02:00
Jostein Alvestad
21eddfbdf2 Added changes to handle repeated read of COMPDAT for same grid cells 2018-09-27 16:23:31 +02:00
Joakim Hove
34b9cbcaa4 Merge pull request #502 from GitPaean/alq_unit_wcon
not converting the unit of ALQ value in VFPPROD
2018-09-26 20:16:42 +02:00
Kai Bao
8721385104 not converting the unit of ALQ value in VFPPROD
since the ALQ value in WCON* keywords are not converted based on the
unit of ALQ in the VFPPROD keyword. Easiest fix is not to convert either
of them.
2018-09-26 13:01:29 +02:00
Arne Morten Kvarving
fa85844a9b Merge pull request #500 from akva2/bash_completion
added: cmake glue for adding bash tab completion for an installed product
2018-09-25 12:32:03 +02:00
Arne Morten Kvarving
e3bc8a6ad7 fixed: fail build in jenkins scripts if installation target fails 2018-09-25 12:31:11 +02:00
Arne Morten Kvarving
564f064392 added: cmake glue for adding bash tab completion for an installed product 2018-09-25 12:31:11 +02:00
Arne Morten Kvarving
5477711420 Merge pull request #504 from akva2/restart_fixups
Fixups after restart merge
2018-09-25 10:58:21 +02:00
Arne Morten Kvarving
23c1aa9308 changed: use memcpy to avoid aliasing warnings 2018-09-25 10:04:39 +02:00
Arne Morten Kvarving
0e2dbf737e fixed: do not try to append size_t to string using + 2018-09-25 10:04:39 +02:00
Arne Morten Kvarving
5a2eec25b2 fixed: change to signed loop counters
avoids signed/unsigned comparison warnings
2018-09-25 10:04:39 +02:00
Arne Morten Kvarving
ae7c7fdf74 changed: flip comparison to avoid warnings
warning: assuming signed overflow does not occur when assuming that (X +
c) < X is always false [-Wstrict-overflow]
2018-09-25 10:04:39 +02:00
Arne Morten Kvarving
ddf6f153f7 fixed: use constructor argument instead of (broken) init loop 2018-09-25 10:04:39 +02:00
Arne Morten Kvarving
9f7b9be7f4 changed: make unsigned to avoid narrowing warnings/errors 2018-09-25 10:04:39 +02:00
Arne Morten Kvarving
0b85652c35 remove unused symbols 2018-09-25 10:04:39 +02:00
Arne Morten Kvarving
4bb0ede6b4 Merge pull request #503 from rolk/503_warncompat
Do not warn if just def'ed HAVE_ vars are set to 1
2018-09-24 08:54:54 +02:00
Roland Kaufmann
d847e10d96 Do not warn if just def'ed HAVE_ vars are set to 1
Some configuration scripts probe and just set HAVE_FOO without any
values, whereas others set it explicitly to 1. If these two are mixed,
for instance that the same package is used by two of our prerequisites,
but in different manner, then we get compatibility warnings when we try
to run the configuration script, even though there is no real conflict.

dune-fem, dune-alugrid and dune-localfunctions have this problem (around
release 2018.04).

This patch special-code the test so if the old value was previously
either just defined or explicitly set to the value 1, a warning will not
be issued if then suddenly the other variant is used.
2018-09-21 13:49:39 +02:00
Atgeirr Flø Rasmussen
5fb0c91c05 Merge pull request #454 from jalvestad/restart-group+mswell
Restart group+mswell
2018-09-21 10:14:47 +02:00
Bård Skaflestad
ff53a2334c Merge pull request #499 from totto82/fix_save_keywords
BugFix size of save_keywords
2018-09-20 17:59:30 +02:00
Tor Harald Sandve
776d851b26 Fix size of save_keywords 2018-09-20 13:50:23 +02:00
Bård Skaflestad
b03ccdc6e1 SWEL/XWEL: Guard Against Missing Summary Vectors
Commit 36af2aad (PR #496) switched to not calculating the well's
summary vectors in the case of outputting the initial condition
(SEQNUM=0).  Account for this possibility when creating SWEL and
XWEL.
2018-09-19 16:02:17 +02:00
Jostein Alvestad
fa9275f1af Added correction to treatment of multisegment wells in preparation for writing of eclipse
compatible restart file
2018-09-19 16:02:17 +02:00
Jostein Alvestad
ef6e0b084d Corrected merge conflicts with upstream master
Write cumulative production / injection only in eclipse compatible mode
2018-09-19 16:02:17 +02:00
Bård Skaflestad
a3b37eee4f Support Retrieving Well Vectors from {I,X}{WEL,CON}
This commit extends function RestartIO::load() to retrieve most of
the well restart data (aggregate flow rates per well connection,
or per well) from the standard ECL restart vectors IWEL, XWEL, ICON,
and XCON.  We still prefer the dedicated OPM_* variants if
available, but this commit brings us closer to being able to retire
OPM_XWEL.

While here, also add WELLDIMS to FIRST_SIM_THPRES to restore the
STORE_THPRES unit test.
2018-09-19 16:02:16 +02:00
Bård Skaflestad
980f55271f Connection Data: Write Flow Rates to XCON
This commit adds a simple facility for outputting surface rates of
the oil, gas, and water components for each well connection, as well
as total reservoir voidage rate per well connection if available in
the data::Connection object.
2018-09-19 16:02:16 +02:00
Bård Skaflestad
335b070564 Aggregate Connection Data: Use Named Indices
This commit introduces a new set of named indices pertaining to the
*CON vectors (ICON, SCON, XCON).  Use these where appropriate in
ICON and SCON.
2018-09-19 16:02:15 +02:00
Bård Skaflestad
d42c98223c Refactor Implementation of RestartIO::save()
In particular, reimplement write_kw() in terms of vector<T> rather
than EclKW<T> to simplify callers.  While here, also move some file
handling operations out to separate helper functions to make control
flow more linear in the body of RestartIO::save(), and prune unused
arguments from other helper functions.
2018-09-19 16:02:15 +02:00
Bård Skaflestad
2f868a7325 Split RestartIO into Separate Load/Save Files
This is in preparation of introducing support for loading most
well-related solution items from the regular vectors IWEL, XWEL,
ICON, and XCON.
2018-09-19 16:02:14 +02:00
Jostein Alvestad
96f2528083 Added changes to CMakeLists_files.cmake to correct for rebase 2018-09-19 16:02:14 +02:00
Bård Skaflestad
38c4d07282 Aggregate Well Data: Miscellaneous Cleanup
Fix a few white-space issues and use 'atm' unit of measurement for
the default lower BHP limit of producers.
2018-09-19 16:02:14 +02:00
Bård Skaflestad
77904d6aab Aggregate Well Data: Fix SWEL UoM for Injectors
Unit of measurement for non-gas injectors must be liquid surface
rate for O/W injectors and 'rate' (reservoir voidage rate) for RESV
injectors.
2018-09-19 16:02:13 +02:00
Bård Skaflestad
6688a9286f Unit Tests: Fix Comparison Values 2018-09-19 16:02:13 +02:00
Bård Skaflestad
9637109ca8 Test Data: Add WELLDIMS for Restart Purposes
The new restart code depends on having WELLDIMS available in order
to allocate appropriately sized output vectors.
2018-09-19 16:02:13 +02:00
Bård Skaflestad
41d0a56967 Test Restart: Use Non-Default SummaryState Values
Needed by the new restart code.
2018-09-19 16:02:12 +02:00
Jostein Alvestad
9d32793796 Added improvements to connection data ICON (account for inactive cells) etc. 2018-09-19 16:02:12 +02:00
Jostein Alvestad
13e849140c Added changes to identify issues for improving ICON 2018-09-19 16:02:11 +02:00
Jostein Alvestad
0e1e4e08e7 Added changes to improve handling of ICON 2018-09-19 16:02:11 +02:00
Jostein Alvestad
3fb7149226 Added change to rseg item 11 2018-09-19 16:02:10 +02:00
Jostein Alvestad
2889a829f8 Additional corrections to restart file (iseg, rseg, icon and scon) 2018-09-19 16:02:10 +02:00
Jostein Alvestad
ccb223521f Added corrections to construction of ISEG for more general segmented well trajectories 2018-09-19 16:02:09 +02:00
Jostein Alvestad
409a497396 Added corrections to code to generate Eclipse compatible Restart file: i) two changes to intehead, [49] and [50] -> 1 (based on tests), ii) corrections to ISEG mainly for multisegmented wells and iii) change to ICON to allow for default saturation table implying ICON[6] and [9] = 0 2018-09-19 16:02:09 +02:00
Jostein Alvestad
5cf35e03c7 Added other correction to account for compatibility with Eclipse 2017 and not 2014 2018-09-19 16:02:08 +02:00
Jostein Alvestad
4f9f952e77 Added corrections to SWEL and ISEG plus InteHead[179] to 146 2018-09-19 16:02:08 +02:00
Jostein Alvestad
a41596004a Added correction for writing of unformatted restart 2018-09-19 16:02:07 +02:00
Jostein Alvestad
6ea83724d6 corrected code for write of unformatted restart 2018-09-19 16:02:07 +02:00
Jostein Alvestad
0a96fc012e Corrected code for differences in buffer size for read from restart files 2018-09-19 16:02:06 +02:00
Jostein Alvestad
5d860f8b03 corrected default injector and producer bhp pressures for restart file 2018-09-19 16:02:06 +02:00
Jostein Alvestad
9ea6c034e2 Disable extra flow restart output that Eclipse cannot handle in a Restart run
As of now we are able to run an ECL restart from a flow generated restart file for
a specific realistic model test case
2018-09-19 16:02:06 +02:00
Jostein Alvestad
17966d098b Added unit conversion for MSW data pluss correctin for complum 2018-09-19 16:02:05 +02:00
Jostein Alvestad
9d0604ad99 additions to handle segmented wells for ICON and SCON 2018-09-19 16:02:05 +02:00
Jostein Alvestad
36de4a4a31 Added changes needed to provide connection index for restart file 2018-09-19 16:02:04 +02:00
Jostein Alvestad
690fe11e58 Additional changes for restart writing og well and connection data 2018-09-19 16:02:03 +02:00
Jostein Alvestad
bce55f7087 Added changes to remove debug print plus some code comments 2018-09-19 16:02:03 +02:00
Jostein Alvestad
dc64b6eb86 Add correction due to non-resolved conflict during rebase operation 2018-09-19 16:02:02 +02:00
Jostein Alvestad
c720c48ba0 Added correction for IGRP array 2018-09-19 16:02:02 +02:00
Jostein Alvestad
5b1ec7b5b0 Added code to write restart data for groups and segmented wells to restart file - consistent with Eclipse 100 2018-09-19 16:02:02 +02:00
Jostein Alvestad
439bc30ea3 Final changes for first "beta" version of segmented well ++ for restart 2018-09-19 16:02:01 +02:00
Jostein Alvestad
888326b32c Initial changes to add group data to restart output plus adding changes to include no of groups in inteHEAD 2018-09-19 16:02:01 +02:00
Jostein Alvestad
6ed9c356a9 Final changes for first "beta" version of segmented well ++ for restart 2018-09-19 16:02:00 +02:00
Jostein Alvestad
d9adf7ccc2 Further changes to include iSeg and rSeg data to Restart file 2018-09-19 16:01:59 +02:00
Jostein Alvestad
c5a1b30dc1 Added code to finalize writing of group data to restart file 2018-09-19 16:01:59 +02:00
Jostein Alvestad
cedadaf649 Added code to implement writing XGRP to the restart file. 2018-09-19 16:01:58 +02:00
Jostein Alvestad
949fb3d944 Add summary vectors for group and field for restart 2018-09-19 16:01:58 +02:00
Jostein Alvestad
86ca704d75 Further changes to implement group output to the restart file.
Starting to use the SummaryState class to include summary data
2018-09-19 16:01:57 +02:00
Jostein Alvestad
53d19e8a44 Further changes to implement group data (IGRP and SGRP)
Plus updating source code to the latest github version of the rest of the OPM code
2018-09-19 16:01:57 +02:00
Jostein Alvestad
f7d975920b Added changes to serialize IGRP and SGRP and write to restart file 2018-09-19 16:01:56 +02:00
Jostein Alvestad
531581762f Further additions and changes to implement preparation and writing of group data to the restart file 2018-09-19 16:01:56 +02:00
Jostein Alvestad
402a5f0965 Initial changes to implement group data into writing of restart file 2018-09-19 16:01:55 +02:00
Jostein Alvestad
79d0081369 Added changes to include no of groups in InteHEAD 2018-09-19 16:01:55 +02:00
Jostein Alvestad
0f26e2e958 Initial changes to add group data to restart output
While here also add changes to include no of groups in InteHEAD
2018-09-19 16:01:55 +02:00
Jostein Alvestad
9cf9bf310d Added changes to serialize IGPR and SGRP and write to restart file
Well info at correct step for save & load RESTART

Retrieve number of wells and completions at the beginning of the
simulated step. Otherwise a well introduced at the same time step as the
report will be included - even though there doesn't exist any simulated
data yet.

This issue would trigger a throw if WRFTPLT was added at the same time
step as a well is introduced in the schedule section.

Removed one DATES item in FIRST_SIM.DATA. The
EclipseReadWriteWellStateData in test_Restart compared state at T1,
which did not include any well data as it was. No other tests were
affected.

Added new implementation of serialize_ICON

The new function has been added to the file WriteRestartHelpers, and
intended to take over for the local function 'serialize_ICON' in
`restartIO.cpp` when `restartIO::save()` is to be updated.  The purpose
of the new implementation is to be compatible with Eclipse.

Handle wildcard in group keywords

Added function getGroups(pattern) to allow records with wildcard.

Included the functionality for GCONPROD, GCONINJE and GEFAC - currently
the only group keywords that should accept wildcards.

Add key string to RestartKey

Pass dimension information for extra fields in restart

Verify that the extra container has THPRES
2018-09-19 16:01:54 +02:00
Jostein Alvestad
a284acc3ed Further additions and changes to implement preparation and writing of group data to the restart file 2018-09-19 16:01:54 +02:00
Jostein Alvestad
19bb0e0077 Additional changes to create restart group data in general and igrp data in particular 2018-09-19 16:01:53 +02:00
Jostein Alvestad
89b11dfd26 Further changes to write group data to restart file 2018-09-19 16:01:53 +02:00
Jostein Alvestad
2552750bed Initial changes to implement group data into writing of restart file 2018-09-19 16:01:52 +02:00
Jostein Alvestad
7b2c36bde5 Added changes to include no of groups in InteHEAD 2018-09-19 16:01:52 +02:00
Jostein Alvestad
b9bb0ae60a Initial changes to add group data to restart output plus adding changes to include no of groups in inteHEAD 2018-09-19 16:01:51 +02:00
71 changed files with 9786 additions and 923 deletions

View File

@@ -161,3 +161,6 @@ endif()
# Install build system files
install(DIRECTORY cmake DESTINATION share/opm)
# Install tab completion skeleton
install(FILES etc/opm_bash_completion.sh.in DESTINATION share/opm/etc)

View File

@@ -135,6 +135,9 @@ if(ENABLE_ECL_INPUT)
endif()
if(ENABLE_ECL_OUTPUT)
list( APPEND MAIN_SOURCE_FILES
src/opm/output/eclipse/AggregateConnectionData.cpp
src/opm/output/eclipse/AggregateGroupData.cpp
src/opm/output/eclipse/AggregateMSWData.cpp
src/opm/output/eclipse/AggregateWellData.cpp
src/opm/output/eclipse/CreateDoubHead.cpp
src/opm/output/eclipse/CreateInteHead.cpp
@@ -144,7 +147,9 @@ if(ENABLE_ECL_OUTPUT)
src/opm/output/eclipse/EclipseGridInspector.cpp
src/opm/output/eclipse/EclipseIO.cpp
src/opm/output/eclipse/InteHEAD.cpp
src/opm/output/eclipse/libECLRestart.cpp
src/opm/output/eclipse/LinearisedOutputTable.cpp
src/opm/output/eclipse/LoadRestart.cpp
src/opm/output/eclipse/LogiHEAD.cpp
src/opm/output/eclipse/RestartIO.cpp
src/opm/output/eclipse/Summary.cpp
@@ -481,8 +486,12 @@ if(ENABLE_ECL_OUTPUT)
opm/output/data/Cells.hpp
opm/output/data/Solution.hpp
opm/output/data/Wells.hpp
opm/output/eclipse/VectorItems/connection.hpp
opm/output/eclipse/VectorItems/intehead.hpp
opm/output/eclipse/VectorItems/well.hpp
opm/output/eclipse/AggregateGroupData.hpp
opm/output/eclipse/AggregateConnectionData.hpp
opm/output/eclipse/AggregateMSWData.hpp
opm/output/eclipse/AggregateWellData.hpp
opm/output/eclipse/CharArrayNullTerm.hpp
opm/output/eclipse/DoubHEAD.hpp
@@ -490,8 +499,9 @@ if(ENABLE_ECL_OUTPUT)
opm/output/eclipse/EclipseIO.hpp
opm/output/eclipse/EclipseIOUtil.hpp
opm/output/eclipse/InteHEAD.hpp
opm/output/eclipse/LogiHEAD.hpp
opm/output/eclipse/libECLRestart.hpp
opm/output/eclipse/LinearisedOutputTable.hpp
opm/output/eclipse/LogiHEAD.hpp
opm/output/eclipse/RegionCache.hpp
opm/output/eclipse/RestartIO.hpp
opm/output/eclipse/RestartValue.hpp

View File

@@ -78,7 +78,17 @@ function (configure_vars obj syntax filename verb)
# write a CMake statements that warns if the value has changed
if ("${syntax}" STREQUAL "CMAKE")
set (_db "\${") # to avoid parsing problems
file (APPEND "${filename}" "if (DEFINED ${_var} AND NOT \"${_db}${_var}}\" STREQUAL \"${${_var}}\")\n")
# special case: if we have a truth variable HAVE_ and this is
# either just defined (as is), or set to 1 explicitly, then both
# of these count as "true", so put in a check that also accepts
# both of these values.
if (("${_var}" MATCHES "^HAVE_.*") AND
(("${${_var}}" STREQUAL "") OR ("${${_var}}" STREQUAL "1")))
set (_cond "(\"${_db}${_var}}\" STREQUAL \"\") OR (\"${_db}${_var}}\" STREQUAL \"1\")")
else ()
set (_cond "\"${_db}${_var}}\" STREQUAL \"${${_var}}\"")
endif ()
file (APPEND "${filename}" "if (DEFINED ${_var} AND NOT (${_cond}))\n")
file (APPEND "${filename}" "\tmessage (WARNING \"Incompatible value \\\"${_db}${_var}}\\\" of variable \\\"${_var}\\\"\")\n")
file (APPEND "${filename}" "endif ()\n")
endif ()

View File

@@ -0,0 +1,6 @@
# Installs bash tab completion for a product
macro(opm_add_bash_completion binary)
set(PRODUCT ${binary})
configure_file(${OPM_MACROS_ROOT}/etc/opm_bash_completion.sh.in ${binary}_bash_completion.sh @ONLY)
install(FILES ${PROJECT_BINARY_DIR}/${binary}_bash_completion.sh DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/bash_completion.d)
endmacro()

2
debian/changelog vendored
View File

@@ -1,4 +1,4 @@
opm-common (2015.10-1~trusty) trusty; urgency=medium
opm-common (2018.10-rfinal-2~xenial) xenial; urgency=medium
* New release

View File

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

View File

@@ -0,0 +1,60 @@
# this snippet enables parameter completion via the tabulator key
# for bash for opm products.
# this is a bash readline completer for the case where a binary is
# already known to be an eWoms simulator.
_ewoms_parameter_completor()
{
if test "$COMP_WORDS" == ""; then
return 0
fi
cmd="${COMP_WORDS[0]}"
cur="${COMP_WORDS[COMP_CWORD]}"
fullcmd="$(which "$cmd")"
ALL_OPTS=$("$fullcmd" --help 2> /dev/null | grep '^ *--' | sed 's/ *\(--[a-zA-Z0-9\-]*\)=.*/\1=/')
ALL_OPTS=$(echo "$ALL_OPTS" | sed 's/^ *--help.*/--help/')
COMPREPLY=( $(compgen -A file -W "$ALL_OPTS" -- "${cur}") )
}
# this is a bash readline default completer which attempts to find out
# if a given binary is an eWoms simulation. this needs to be set as a
# default completer because the name of eWoms binaries cannot be known
# a-priori.
_ewoms_generic_parameter_completor()
{
if test "$COMP_WORDS" == ""; then
return 0
fi
COMPREPLY=()
local cmd cur ALL_OPTS
cmd="${COMP_WORDS[0]}"
cur="${COMP_WORDS[COMP_CWORD]}"
fullcmd="$(which "$cmd")"
if test -z "$fullcmd" || \
! test -x "$fullcmd" || \
(! test -f "$fullcmd" && ! test -h "$fullcmd" ) || \
! test -r "$fullcmd" || \
! grep -q "Ewoms[a-zA-Z0-9]*Simulator[a-zA-Z0-0]" "$fullcmd"
then
if test -n "$DEFAULT_COMPLETION_LOADER"; then
"$DEFAULT_COMPLETION_LOADER" $@
elif type -t _completion_loader 2>&1 > /dev/null; then
# the default DEFAULT_COMPLETION_LOADER variable has not
# been set and the _completion_loader function exists, so
# we use _completion_loader as the default completer.
_completion_loader $@
else
return 1
fi
return $?
fi
_ewoms_parameter_completor $@
return 0
}
complete -o nospace -F _ewoms_parameter_completor @PRODUCT@

View File

@@ -112,6 +112,7 @@ function build_module {
else
cmake --build . --target install
fi
test $? -eq 0 || exit 3
fi
}

View File

@@ -0,0 +1,75 @@
/*
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_AGGREGATE_CONNECTION_DATA_HPP
#define OPM_AGGREGATE_CONNECTION_DATA_HPP
#include <opm/output/eclipse/WindowedArray.hpp>
#include <cstddef>
#include <string>
#include <vector>
namespace Opm {
class EclipseGrid;
class Schedule;
class UnitSystem;
} // Opm
namespace Opm { namespace data {
class WellRates;
}}
namespace Opm { namespace RestartIO { namespace Helpers {
class AggregateConnectionData
{
public:
explicit AggregateConnectionData(const std::vector<int>& inteHead);
void captureDeclaredConnData(const Opm::Schedule& sched,
const Opm::EclipseGrid& grid,
const Opm::UnitSystem& units,
const Opm::data::WellRates& xw,
const std::size_t sim_step);
const std::vector<int>& getIConn() const
{
return this->iConn_.data();
}
const std::vector<float>& getSConn() const
{
return this->sConn_.data();
}
const std::vector<double>& getXConn() const
{
return this->xConn_.data();
}
private:
WindowedMatrix<int> iConn_;
WindowedMatrix<float> sConn_;
WindowedMatrix<double> xConn_;
};
}}} // Opm::RestartIO::Helpers
#endif // OPM_AGGREGATE_CONNECTION_DATA_HPP

View File

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

View File

@@ -0,0 +1,105 @@
/*
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_MSW_DATA_HPP
#define OPM_AGGREGATE_MSW_DATA_HPP
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/output/eclipse/CharArrayNullTerm.hpp>
#include <opm/output/eclipse/WindowedArray.hpp>
#include <string>
#include <vector>
namespace Opm {
class Phases;
class Schedule;
class EclipseGrid;
class UnitSystem;
class SummaryState;
} // Opm
namespace Opm { namespace RestartIO { namespace Helpers {
struct BranchSegmentPar {
int outletS;
int noSegInBranch;
int firstSeg;
int lastSeg;
int branch;
};
class AggregateMSWData
{
public:
explicit AggregateMSWData(const std::vector<int>& inteHead);
void captureDeclaredMSWData(const Opm::Schedule& sched,
const std::size_t rptStep,
const Opm::UnitSystem& units,
const std::vector<int>& inteHead,
const Opm::EclipseGrid& grid,
const ::Opm::SummaryState& smry
);
/// Retrieve Integer Multisegment well data Array.
const std::vector<int>& getISeg() const
{
return this->iSeg_.data();
}
/// Retrieve Double precision segment data Array.
const std::vector<double>& getRSeg() const
{
return this->rSeg_.data();
}
/// Retrieve Integer multisegment well data Array for lateral branches (ILBS)
const std::vector<int>& getILBs() const
{
return this->iLBS_.data();
}
/// Retrieve Integer multisegment well data Array for lateral branches (ILBR)
const std::vector<int>& getILBr() const
{
return this->iLBR_.data();
}
private:
/// Aggregate 'ISEG' array (Integer) for all multisegment wells
WindowedArray<int> iSeg_;
/// Aggregate 'RSEG' array (Double) for all multisegment wells
WindowedArray<double> rSeg_;
/// Aggregate 'ILBS' array (Integer) for all multisegment wells
WindowedArray<int> iLBS_;
/// Aggregate 'ILBR' array (Integer) for all multisegment wells
WindowedArray<int> iLBR_;
};
}}} // Opm::RestartIO::Helpers
#endif // OPM_AGGREGATE_WELL_DATA_HPP

View File

@@ -44,12 +44,15 @@ namespace Opm { namespace RestartIO { namespace Helpers {
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 captureDeclaredWellData(const Schedule& sched,
const UnitSystem& units,
const std::size_t sim_step,
const ::Opm::SummaryState& smry,
const std::vector<int>& inteHead);
void captureDynamicWellData(const Opm::Schedule& sched,
const std::size_t sim_step,
const bool ecl_compatible_rst,
const Opm::data::WellRates& xw,
const Opm::SummaryState& smry);
@@ -77,6 +80,8 @@ namespace Opm { namespace RestartIO { namespace Helpers {
return this->zWell_.data();
}
private:
/// Aggregate 'IWEL' array (Integer) for all wells.
WindowedArray<int> iWell_;

View File

@@ -35,6 +35,7 @@
#include <opm/output/data/Solution.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/RestartValue.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
namespace Opm {
@@ -177,7 +178,7 @@ public:
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,
bool write_double = false);
const bool write_double = false);
/*

View File

@@ -85,6 +85,10 @@ namespace Opm { namespace RestartIO {
int mxwsit;
int mxwpit;
};
struct Group {
int ngroups;
};
InteHEAD();
~InteHEAD() = default;
@@ -112,6 +116,7 @@ namespace Opm { namespace RestartIO {
InteHEAD& variousParam(const int version, const int iprog);
InteHEAD& wellSegDimensions(const WellSegDims& wsdim);
InteHEAD& regionDimensions(const RegDims& rdim);
InteHEAD& ngroups(const Group& gr);
const std::vector<int>& data() const
{

View File

@@ -46,6 +46,7 @@ class EclipseGrid;
class EclipseState;
class Phases;
class Schedule;
class SummaryState;
namespace RestartIO {
@@ -72,6 +73,17 @@ namespace RestartIO {
the report step argument '99'.
*/
/*void save(const std::string& filename,
int report_step,
double seconds_elapsed,
data::Solution cells,
data::Wells wells,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
std::map<std::string, std::vector<double>> extra_data = {},
bool write_double = false);
*/
void save(const std::string& filename,
int report_step,
double seconds_elapsed,
@@ -79,9 +91,9 @@ void save(const std::string& filename,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const SummaryState& sumState,
bool write_double = false);
RestartValue load( const std::string& filename,
int report_step,
const std::vector<RestartKey>& solution_keys,

View File

@@ -71,6 +71,9 @@ namespace Opm {
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;
void convertFromSI(const UnitSystem& units);
void convertToSI(const UnitSystem& units);
};
}

View File

@@ -0,0 +1,74 @@
/*
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_CONNECTION_HPP
#define OPM_OUTPUT_ECLIPSE_VECTOR_CONNECTION_HPP
#include <vector>
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
namespace IConn {
enum index : std::vector<int>::size_type {
SeqIndex = 0, // Connection sequence index
CellI = 1, // I-location (1-based cell index) of connection
CellJ = 2, // J-location (1-based cell index) of connection
CellK = 3, // K-location (1-based cell index) of connection
ConnStat = 5, // Connection status.
// > 0 => open, shut otherwise
Drainage = 6, // Saturation function (table ID) for drainage
Imbibition = 9, // Saturation function (table ID) for imbibition
ComplNum = 12, // Completion ID (1-based)
ConnDir = 13, // Penetration direction (1:X, 2:Y, 3:Z)
Segment = 14, // Segment ID of connection
// 0 for regular connections, > 0 for MSW.
};
} // IConn
namespace SConn {
enum index : std::vector<float>::size_type {
ConnTrans = 0, // Connection transmissibility factor
Depth = 1, // Connection centre depth
Diameter = 2, // Connection diameter
EffectiveKH = 3, // Effective Kh product of connection
item12 = 11, // Unknown
SegDistEnd = 20, // Distance to end of connection in segment
SegDistStart = 21, // Distance to start of connection in segment
item30 = 29, // Unknown
item31 = 30, // Unknown
};
} // SConn
namespace XConn {
enum index : std::vector<double>::size_type {
OilRate = 0, // Surface flow rate (oil)
WaterRate = 1, // Surface flow rate (water)
GasRate = 2, // Surface Flow rate (gas)
ResVRate = 49, // Reservoir voidage rate
};
} // XConn
}}}} // Opm::RestartIO::Helpers::VectorItems
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_CONNECTION_HPP

View File

@@ -42,7 +42,7 @@ namespace 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,
@@ -57,12 +57,12 @@ namespace Opm { namespace RestartIO { namespace Helpers {
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.
const int lookup_step); // The integer index used to look up dynamic properties, e.g. the number of well.
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.

File diff suppressed because it is too large Load Diff

View File

@@ -75,7 +75,12 @@ public:
return this->nGMax;
}
int maxWellsInField() const
{
return this->nWMax;
}
private:
int nWMax { 0 };
int nCWMax { 0 };
int nWGMax { 0 };
int nGMax { 0 };

View File

@@ -22,15 +22,16 @@
#define COMPLETION_HPP_
#include <array>
#include <cstddef>
#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>
namespace Opm {
class DeckKeyword;
@@ -46,7 +47,12 @@ namespace Opm {
double Kh,
double rw,
const int satTableId,
const WellCompletion::DirectionEnum direction);
const WellCompletion::DirectionEnum direction,
const std::size_t seqIndex,
const double segDistStart,
const double segDistEnd,
const bool defaultSatTabId
);
bool attachedToSegment() const;
@@ -68,7 +74,16 @@ namespace Opm {
void setState(WellCompletion::StateEnum state);
void setComplnum(int compnum);
void scaleWellPi(double wellPi);
void updateSegment(int segment_number, double center_depth);
void updateSegment(int segment_number, double center_depth, std::size_t seqIndex);
const std::size_t& getSeqIndex() const;
const bool& getDefaultSatTabId() const;
const std::size_t& getCompSegSeqIndex() const;
void setCompSegSeqIndex(std::size_t index);
void setDefaultSatTabId(bool id);
const double& getSegDistStart() const;
const double& getSegDistEnd() const;
void setSegDistStart(const double& distStart);
void setSegDistEnd(const double& distEnd);
bool operator==( const Connection& ) const;
bool operator!=( const Connection& ) const;
@@ -83,6 +98,11 @@ namespace Opm {
double m_rw;
std::array<int,3> ijk;
std::size_t m_seqIndex;
double m_segDistStart;
double m_segDistEnd;
bool m_defaultSatTabId;
std::size_t m_compSeg_seqIndex=0;
// related segment number
// -1 means the completion is not related to segment
@@ -91,7 +111,5 @@ namespace Opm {
};
}
#endif /* COMPLETION_HPP_ */

View File

@@ -24,6 +24,7 @@
#include <memory>
#include <set>
#include <string>
#include <stddef.h>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
@@ -66,9 +67,10 @@ namespace Opm {
class Group {
public:
Group(const std::string& name, const TimeMap& timeMap , size_t creationTimeStep);
Group(const std::string& name, const size_t& seqIndex, const TimeMap& timeMap , size_t creationTimeStep);
bool hasBeenDefined(size_t timeStep) const;
const std::string& name() const;
const size_t& seqIndex() const;
bool isProductionGroup(size_t timeStep) const;
bool isInjectionGroup(size_t timeStep) const;
void setProductionGroup(size_t timeStep, bool isProductionGroup);
@@ -133,6 +135,7 @@ namespace Opm {
private:
size_t m_creationTimeStep;
std::string m_name;
size_t m_seqIndex;
GroupInjection::InjectionData m_injection;
GroupProduction::ProductionData m_production;
DynamicState< std::set< std::string > > m_wells;

View File

@@ -22,17 +22,21 @@
#include <string>
#include <vector>
#include <map>
namespace Opm {
class GroupTree {
public:
void update( const std::string& name );
void update( const std::string& name, const std::string& parent );
void update( const std::string& name);
void update( const std::string& name, const std::string& parent);
void updateSeqIndex( const std::string& name, const std::string& other_parent);
bool exists( const std::string& group ) const;
const std::string& parent( const std::string& name ) const;
std::vector< std::string > children( const std::string& parent ) const;
const std::map<const std::string , size_t>& nameSeqIndMap() const;
const std::map<size_t, const std::string >& seqIndNameMap() const;
size_t groupTreeSize();
bool operator==( const GroupTree& ) const;
bool operator!=( const GroupTree& ) const;
@@ -53,6 +57,8 @@ class GroupTree {
std::vector< group > groups = { group { "FIELD", "" } };
friend bool operator<( const std::string&, const group& );
std::vector< group >::iterator find( const std::string& );
std::map<const std::string , size_t> m_nameSeqIndMap;
std::map<size_t, const std::string > m_seqIndNameMap;
};
}

View File

@@ -24,9 +24,11 @@
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
namespace Opm {
WellConnections * newConnectionsWithSegments(const DeckKeyword& compsegs, const WellConnections& input_connections, const WellSegments& segments);
WellConnections * newConnectionsWithSegments(const DeckKeyword& compsegs, const WellConnections& input_connections,
const WellSegments& segments, const EclipseGrid& grid, std::size_t& totNC);
}
#endif

View File

@@ -94,8 +94,11 @@ namespace Opm
is an inefficient way to get all the wells defined at time
't'.
*/
*/
//std::vector< const Group& > getChildGroups(const std::string& group_name, size_t timeStep) const;
std::vector< const Group* > getChildGroups(const std::string& group_name, size_t timeStep) const;
std::vector< const Well* > getWells(const std::string& group, size_t timeStep) const;
std::vector< const Well* > getChildWells(const std::string& group_name, size_t timeStep) const;
std::vector< const Well* > getWellsMatching( const std::string& ) const;
const OilVaporizationProperties& getOilVaporizationProperties(size_t timestep) const;
@@ -103,9 +106,11 @@ namespace Opm
const GroupTree& getGroupTree(size_t t) const;
size_t numGroups() const;
size_t numGroups(size_t timeStep) const;
bool hasGroup(const std::string& groupName) const;
const Group& getGroup(const std::string& groupName) const;
std::vector< const Group* > getGroups() const;
std::vector< const Group* > getGroups(size_t timeStep) const;
const Tuning& getTuning() const;
const MessageLimits& getMessageLimits() const;
void invalidNamePattern (const std::string& namePattern, const ParseContext& parseContext, const DeckKeyword& keyword) const;
@@ -159,7 +164,7 @@ namespace Opm
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 handleCOMPSEGS( const DeckKeyword& keyword, size_t currentStep, const EclipseGrid& grid);
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);

View File

@@ -182,9 +182,6 @@ private:
static void convertGFRToSI(const GFR_TYPE& type,
std::vector<double>& values,
const UnitSystem& unit_system);
static void convertALQToSI(const ALQ_TYPE& type,
std::vector<double>& values,
const UnitSystem& unit_system);
};

View File

@@ -35,6 +35,7 @@
#include <opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
namespace Opm {
@@ -49,13 +50,15 @@ namespace Opm {
class Well {
public:
Well(const std::string& name, int headI,
Well(const std::string& name, const size_t& seqIndex, int headI,
int headJ, double refDepth, Phase preferredPhase,
const TimeMap& timeMap, size_t creationTimeStep,
WellCompletion::CompletionOrderEnum completionOrdering = WellCompletion::TRACK,
bool allowCrossFlow = true, bool automaticShutIn = true);
const std::string& name() const;
const size_t& seqIndex() const;
const std::size_t getTotNoConn() const;
void setTotNoConn(std::size_t noConn);
bool hasBeenDefined(size_t timeStep) const;
const std::string getGroupName(size_t timeStep) const;
void setGroupName(size_t timeStep , const std::string& groupName);
@@ -184,7 +187,7 @@ namespace Opm {
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 handleCOMPSEGS(const DeckKeyword& keyword, const EclipseGrid& grid, 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);
@@ -198,7 +201,9 @@ namespace Opm {
private:
size_t m_creationTimeStep;
std::string m_name;
std::size_t m_seqIndex;
std::size_t m_totNoConn=0;
DynamicState< WellCommon::StatusEnum > m_status;
DynamicState< int > m_isAvailableForGroupControl;

View File

@@ -39,8 +39,12 @@ namespace Opm {
double Kh,
double rw,
const int satTableId,
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z);
void loadCOMPDAT(const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties);
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z,
const std::size_t seqIndex = 0,
const double segDistStart= 0.0,
const double segDistEnd= 0.0,
const bool defaultSatTabId = true);
void loadCOMPDAT(const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties, std::size_t& totNC);
using const_iterator = std::vector< Connection >::const_iterator;
@@ -53,6 +57,9 @@ namespace Opm {
const_iterator begin() const { return this->m_connections.begin(); }
const_iterator end() const { return this->m_connections.end(); }
std::size_t totNoConn() const { return this->m_connections.size(); }
void filter(const EclipseGrid& grid);
bool allConnectionsShut() const;
/// Order connections irrespective of input order.
@@ -81,7 +88,11 @@ namespace Opm {
double Kh,
double rw,
const int satTableId,
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z);
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z,
const std::size_t seqIndex = 0,
const double segDistStart= 0.0,
const double segDistEnd= 0.0,
const bool defaultSatTabId = true);
std::vector< Connection > m_connections;
size_t findClosestConnection(int oi, int oj, double oz, size_t start_pos);

View File

@@ -5,7 +5,7 @@
%define tag final
Name: opm-common
Version: 2018.04
Version: 2018.10
Release: 0
Summary: Open Porous Media - common helpers and buildsystem
License: GPL-3.0

View File

@@ -0,0 +1,325 @@
/*
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/AggregateConnectionData.hpp>
#include <opm/output/eclipse/VectorItems/connection.hpp>
#include <opm/output/eclipse/VectorItems/intehead.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.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 <cassert>
#include <cstddef>
#include <iostream>
#include <cmath>
namespace VI = Opm::RestartIO::Helpers::VectorItems;
// #####################################################################
// Class Opm::RestartIO::Helpers::AggregateConnectionData
// ---------------------------------------------------------------------
namespace {
std::size_t numWells(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NWELLS];
}
std::size_t maxNumConn(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NCWMAX];
}
std::map <std::size_t, const Opm::Connection*> mapSeqIndexToConnection(const Opm::WellConnections& conns)
{
// make seqIndex to Connection map
std::map <std::size_t, const Opm::Connection*> seqIndConnMap;
for (const auto & conn : conns) {
std::size_t sI = conn.getSeqIndex();
seqIndConnMap.insert(std::make_pair(sI, &conn));
}
return seqIndConnMap;
}
std::map <std::size_t, const Opm::Connection*> mapCompSegSeqIndexToConnection(const Opm::WellConnections& conns)
{
// make CompSegSeqIndex to Connection map
std::map <std::size_t, const Opm::Connection*> cs_seqIndConnMap;
for (const auto & conn : conns) {
std::size_t sI = conn.getCompSegSeqIndex();
cs_seqIndConnMap.insert(std::make_pair(sI, &conn));
}
return cs_seqIndConnMap;
}
template <class ConnOp>
void connectionLoop(const std::vector<const Opm::Well*>& wells,
const Opm::EclipseGrid& grid,
const std::size_t sim_step,
ConnOp&& connOp)
{
for (auto nWell = wells.size(), wellID = 0*nWell;
wellID < nWell; ++wellID)
{
const auto* well = wells[wellID];
if (well == nullptr) { continue; }
const auto& conns = well->getActiveConnections(sim_step, grid);
const int niSI = static_cast<int>(well->getTotNoConn());
std::map <std::size_t, const Opm::Connection*> sIToConn;
//Branch according to MSW well or not and
//sort active connections according to appropriate seqIndex
if (well->isMultiSegment(sim_step)) {
//sort connections according to input sequence in COMPSEGS
sIToConn = mapCompSegSeqIndexToConnection(conns);
} else
{
//sort connections according to input sequence in COMPDAT
sIToConn = mapSeqIndexToConnection(conns);
}
std::vector<const Opm::Connection*> connSI;
for (int iSI = 0; iSI < niSI; iSI++) {
const auto searchSI = sIToConn.find(static_cast<std::size_t>(iSI));
if (searchSI != sIToConn.end()) {
connSI.push_back(searchSI->second);
}
}
for (auto nConn = connSI.size(), connID = 0*nConn;
connID < nConn; ++connID)
{
connOp(*well, wellID, *(connSI[connID]), connID);
}
}
}
namespace IConn {
std::size_t entriesPerConn(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NICONZ];
}
Opm::RestartIO::Helpers::WindowedMatrix<int>
allocate(const std::vector<int>& inteHead)
{
using WM = Opm::RestartIO::Helpers::WindowedMatrix<int>;
return WM {
WM::NumRows { numWells(inteHead) },
WM::NumCols { maxNumConn(inteHead) },
WM::WindowSize{ entriesPerConn(inteHead) }
};
}
template <class IConnArray>
void staticContrib(const Opm::Connection& conn,
const std::size_t connID,
IConnArray& iConn)
{
using ConnState = ::Opm::WellCompletion::StateEnum;
using Ix = ::Opm::RestartIO::Helpers::VectorItems::IConn::index;
iConn[Ix::SeqIndex] = connID + 1;
iConn[Ix::CellI] = conn.getI() + 1;
iConn[Ix::CellJ] = conn.getJ() + 1;
iConn[Ix::CellK] = conn.getK() + 1;
iConn[Ix::ConnStat] = (conn.state() == ConnState::OPEN)
? 1 : -1000;
iConn[Ix::Drainage] = conn.getDefaultSatTabId()
? 0 : conn.satTableId();
// Don't support differing sat-func tables for
// draining and imbibition curves at connections.
iConn[Ix::Imbibition] = iConn[Ix::Drainage];
iConn[Ix::ComplNum] = std::abs(conn.complnum());
//iConn[Ix::ComplNum] = iConn[Ix::SeqIndex];
iConn[Ix::ConnDir] = conn.dir();
iConn[Ix::Segment] = conn.attachedToSegment()
? conn.segment() : 0;
}
} // IConn
namespace SConn {
std::size_t entriesPerConn(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NSCONZ];
}
Opm::RestartIO::Helpers::WindowedMatrix<float>
allocate(const std::vector<int>& inteHead)
{
using WM = Opm::RestartIO::Helpers::WindowedMatrix<float>;
return WM {
WM::NumRows { numWells(inteHead) },
WM::NumCols { maxNumConn(inteHead) },
WM::WindowSize{ entriesPerConn(inteHead) }
};
}
template <class SConnArray>
void staticContrib(const Opm::Connection& conn,
const Opm::UnitSystem& units,
SConnArray& sConn)
{
using M = ::Opm::UnitSystem::measure;
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SConn::index;
auto scprop = [&units](const M u, const double x) -> float
{
return static_cast<float>(units.from_si(u, x));
};
sConn[Ix::ConnTrans] =
scprop(M::transmissibility, conn.CF());
sConn[Ix::Depth] = scprop(M::length, conn.depth());
sConn[Ix::Diameter] = scprop(M::length, 2*conn.rw());
sConn[Ix::EffectiveKH] =
scprop(M::effective_Kh, conn.Kh());
sConn[Ix::item12] = sConn[Ix::ConnTrans];
sConn[Ix::SegDistEnd] = scprop(M::length, conn.getSegDistEnd());
sConn[Ix::SegDistStart] = scprop(M::length, conn.getSegDistStart());
sConn[Ix::item30] = -1.0e+20f;
sConn[Ix::item31] = -1.0e+20f;
}
} // SConn
namespace XConn {
std::size_t entriesPerConn(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NXCONZ];
}
Opm::RestartIO::Helpers::WindowedMatrix<double>
allocate(const std::vector<int>& inteHead)
{
using WM = Opm::RestartIO::Helpers::WindowedMatrix<double>;
return WM {
WM::NumRows { numWells(inteHead) },
WM::NumCols { maxNumConn(inteHead) },
WM::WindowSize{ entriesPerConn(inteHead) }
};
}
template <class XConnArray>
void dynamicContrib(const Opm::data::Connection& x,
const Opm::UnitSystem& units,
XConnArray& xConn)
{
using M = ::Opm::UnitSystem::measure;
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XConn::index;
using R = ::Opm::data::Rates::opt;
// Note flow rate sign. Treat production rates as positive.
const auto& Q = x.rates;
if (Q.has(R::oil)) {
xConn[Ix::OilRate] =
- units.from_si(M::liquid_surface_rate, Q.get(R::oil));
}
if (Q.has(R::wat)) {
xConn[Ix::WaterRate] =
- units.from_si(M::liquid_surface_rate, Q.get(R::wat));
}
if (Q.has(R::gas)) {
xConn[Ix::WaterRate] =
- units.from_si(M::gas_surface_rate, Q.get(R::gas));
}
xConn[Ix::ResVRate] = 0.0;
if (Q.has(R::reservoir_oil)) {
xConn[Ix::ResVRate] -=
units.from_si(M::rate, Q.get(R::reservoir_oil));
}
if (Q.has(R::reservoir_water)) {
xConn[Ix::ResVRate] -=
units.from_si(M::rate, Q.get(R::reservoir_water));
}
if (Q.has(R::reservoir_gas)) {
xConn[Ix::ResVRate] -=
units.from_si(M::rate, Q.get(R::reservoir_gas));
}
}
} // XConn
} // Anonymous
Opm::RestartIO::Helpers::AggregateConnectionData::
AggregateConnectionData(const std::vector<int>& inteHead)
: iConn_(IConn::allocate(inteHead))
, sConn_(SConn::allocate(inteHead))
, xConn_(XConn::allocate(inteHead))
{}
// ---------------------------------------------------------------------
void
Opm::RestartIO::Helpers::AggregateConnectionData::
captureDeclaredConnData(const Schedule& sched,
const EclipseGrid& grid,
const UnitSystem& units,
const data::WellRates& xw,
const std::size_t sim_step)
{
const auto& wells = sched.getWells(sim_step);
connectionLoop(wells, grid, sim_step, [&units, &xw, this]
(const Well& well, const std::size_t wellID,
const Connection& conn, const std::size_t connID) -> void
{
auto ic = this->iConn_(wellID, connID);
auto sc = this->sConn_(wellID, connID);
IConn::staticContrib(conn, connID, ic);
SConn::staticContrib(conn, units, sc);
auto xi = xw.find(well.name());
if ((xi != xw.end()) &&
(connID < xi->second.connections.size()))
{
auto xc = this->xConn_(wellID, connID);
XConn::dynamicContrib(xi->second.connections[connID],
units, xc);
}
});
}

View File

@@ -0,0 +1,556 @@
/*
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/AggregateGroupData.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/output/eclipse/WriteRestartHelpers.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/EclipseState/Schedule/GroupTree.hpp>
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <string>
#include <iostream>
// #####################################################################
// Class Opm::RestartIO::Helpers::AggregateGroupData
// ---------------------------------------------------------------------
namespace {
// maximum number of groups
std::size_t ngmaxz(const std::vector<int>& inteHead)
{
return inteHead[20];
}
// maximum number of wells in any group
int nwgmax(const std::vector<int>& inteHead)
{
return inteHead[19];
}
const int groupType(const Opm::Schedule& sched,
const Opm::Group& group,
const std::size_t simStep)
{
const std::string& groupName = group.name();
if (!sched.hasGroup(groupName))
throw std::invalid_argument("No such group: " + groupName);
{
if (group.hasBeenDefined( simStep )) {
const auto& groupTree = sched.getGroupTree( simStep );
const auto& childGroups = groupTree.children( groupName );
if (childGroups.size()) {
return 1;
}
else {
return 0;
}
}
return 0;
}
}
template <typename GroupOp>
void groupLoop(const std::vector<const Opm::Group*>& groups,
GroupOp&& groupOp)
{
auto groupID = std::size_t{0};
for (const auto* group : groups) {
groupID += 1;
if (group == nullptr) { continue; }
groupOp(*group, groupID - 1);
}
}
std::map <size_t, const Opm::Group*> currentGroupMapIndexGroup(const Opm::Schedule& sched, const size_t simStep, const std::vector<int>& inteHead)
{
const auto& groups = sched.getGroups(simStep);
// make group index for current report step
std::map <size_t, const Opm::Group*> indexGroupMap;
for (const auto* group : groups) {
int ind = (group->name() == "FIELD")
? ngmaxz(inteHead)-1 : group->seqIndex()-1;
const std::pair<size_t, const Opm::Group*> groupPair = std::make_pair(static_cast<size_t>(ind), group);
indexGroupMap.insert(groupPair);
}
return indexGroupMap;
}
std::map <const std::string, size_t> currentGroupMapNameIndex(const Opm::Schedule& sched, const size_t simStep, const std::vector<int>& inteHead)
{
const auto& groups = sched.getGroups(simStep);
// make group name to index map for the current time step
std::map <const std::string, size_t> groupIndexMap;
for (const auto* group : groups) {
int ind = (group->name() == "FIELD")
? ngmaxz(inteHead)-1 : group->seqIndex()-1;
std::pair<const std::string, size_t> groupPair = std::make_pair(group->name(), ind);
groupIndexMap.insert(groupPair);
}
return groupIndexMap;
}
const int currentGroupLevel(const Opm::Schedule& sched, const Opm::Group& group, const size_t simStep)
{
int level = 0;
const std::vector< const Opm::Group* > groups = sched.getGroups(simStep);
const std::string& groupName = group.name();
if (!sched.hasGroup(groupName))
throw std::invalid_argument("No such group: " + groupName);
{
if (group.hasBeenDefined( simStep )) {
const auto& groupTree = sched.getGroupTree( simStep );
//find group level - field level is 0
std::string tstGrpName = groupName;
while (((tstGrpName.size())>0) && (!(tstGrpName=="FIELD"))) {
std::string curParent = groupTree.parent(tstGrpName);
level+=1;
tstGrpName = curParent;
}
return level;
}
else {
std::stringstream str;
str << "actual group has not been defined at report time: " << simStep;
throw std::invalid_argument(str.str());
}
}
return level;
}
namespace IGrp {
std::size_t entriesPerGroup(const std::vector<int>& inteHead)
{
// INTEHEAD[36] = NIGRPZ
return inteHead[36];
}
Opm::RestartIO::Helpers::WindowedArray<int>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<int>;
return WV {
WV::NumWindows{ ngmaxz(inteHead) },
WV::WindowSize{ entriesPerGroup(inteHead) }
};
}
template <class IGrpArray>
void staticContrib(const Opm::Schedule& sched,
const Opm::Group& group,
const int nwgmax,
const int ngmaxz,
const std::size_t simStep,
IGrpArray& iGrp,
const std::vector<int>& inteHead)
{
// find the number of wells or child groups belonging to a group and store in
// location nwgmax +1 in the iGrp array
const auto childGroups = sched.getChildGroups(group.name(), simStep);
const auto childWells = sched.getChildWells(group.name(), simStep);
const auto groupMapNameIndex = currentGroupMapNameIndex(sched, simStep, inteHead);
const auto mapIndexGroup = currentGroupMapIndexGroup(sched, simStep, inteHead);
if ((childGroups.size() != 0) && (childWells.size()!=0))
throw std::invalid_argument("group has both wells and child groups" + group.name());
int igrpCount = 0;
if (childWells.size() != 0) {
//group has child wells
for ( auto it = childWells.begin() ; it != childWells.end(); it++) {
iGrp[igrpCount] = (*it)->seqIndex()+1;
igrpCount+=1;
}
}
else if (childGroups.size() != 0) {
//group has child groups
//The field group always has seqIndex = 0 because it is always defined first
//Hence the all groups except the Field group uses the seqIndex assigned
std::vector<size_t> childGroupIndex;
Opm::RestartIO::Helpers::groupMaps groupMap;
groupMap.currentGrpTreeNameSeqIndMap(sched, simStep, groupMapNameIndex,mapIndexGroup);
const auto indGroupMap = groupMap.indexGroupMap();
const auto gNameIndMap = groupMap.groupNameIndexMap();
for (auto* grp : childGroups) {
auto groupName = grp->name();
auto searchGTName = gNameIndMap.find(groupName);
if (searchGTName != gNameIndMap.end()) {
childGroupIndex.push_back(searchGTName->second);
}
else {
throw std::invalid_argument( "Invalid group name" );
}
}
std::sort(childGroupIndex.begin(), childGroupIndex.end());
for (auto groupTreeIndex : childGroupIndex) {
auto searchGTIterator = indGroupMap.find(groupTreeIndex);
if (searchGTIterator != indGroupMap.end()) {
auto gname = (searchGTIterator->second)->name();
auto gSeqNoItr = groupMapNameIndex.find(gname);
if (gSeqNoItr != groupMapNameIndex.end()) {
iGrp[igrpCount] = (gSeqNoItr->second) + 1;
igrpCount+=1;
}
else {
std::cout << "AggregateGroupData, ChildGroups - Group name: groupMapNameIndex: " << gSeqNoItr->first << std::endl;
throw std::invalid_argument( "Invalid group name" );
}
}
else {
std::cout << "AggregateGroupData, ChildGroups - GroupTreeIndex: " << groupTreeIndex << std::endl;
throw std::invalid_argument( "Invalid GroupTree index" );
}
}
}
//assign the number of child wells or child groups to
// location nwgmax
iGrp[nwgmax] = (childGroups.size() == 0)
? childWells.size() : childGroups.size();
// find the group type (well group (type 0) or node group (type 1) and store the type in
// location nwgmax + 26
const auto grpType = groupType(sched, group, simStep);
iGrp[nwgmax+26] = grpType;
//find group level ("FIELD" is level 0) and store the level in
//location nwgmax + 27
const auto grpLevel = currentGroupLevel(sched, group, simStep);
iGrp[nwgmax+27] = grpLevel;
// set values for group probably connected to GCONPROD settings
//
if (group.name() != "FIELD")
{
iGrp[nwgmax+ 5] = -1;
iGrp[nwgmax+12] = -1;
iGrp[nwgmax+17] = -1;
iGrp[nwgmax+22] = -1;
//assign values to group number (according to group sequence)
iGrp[nwgmax+88] = group.seqIndex();
iGrp[nwgmax+89] = group.seqIndex();
iGrp[nwgmax+95] = group.seqIndex();
iGrp[nwgmax+96] = group.seqIndex();
}
else
{
//assign values to group number (according to group sequence)
iGrp[nwgmax+88] = ngmaxz;
iGrp[nwgmax+89] = ngmaxz;
iGrp[nwgmax+95] = ngmaxz;
iGrp[nwgmax+96] = ngmaxz;
}
//find parent group and store index of parent group in
//location nwgmax + 28
const auto& groupTree = sched.getGroupTree( simStep );
const std::string& parent = groupTree.parent(group.name());
if (group.name() == "FIELD")
iGrp[nwgmax+28] = 0;
else {
if (parent.size() == 0)
throw std::invalid_argument("parent group does not exist" + group.name());
const auto itr = groupMapNameIndex.find(parent);
iGrp[nwgmax+28] = (itr->second)+1;
}
}
} // Igrp
namespace SGrp {
std::size_t entriesPerGroup(const std::vector<int>& inteHead)
{
// INTEHEAD[37] = NSGRPZ
return inteHead[37];
}
Opm::RestartIO::Helpers::WindowedArray<float>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<float>;
return WV {
WV::NumWindows{ ngmaxz(inteHead) },
WV::WindowSize{ entriesPerGroup(inteHead) }
};
}
template <class SGrpArray>
void staticContrib(SGrpArray& sGrp)
{
const auto dflt = -1.0e+20f;
const auto dflt_2 = -2.0e+20f;
const auto infty = 1.0e+20f;
const auto zero = 0.0f;
const auto one = 1.0f;
const auto init = std::vector<float> { // 112 Items (0..111)
// 0 1 2 3 4
infty, infty, dflt , infty, zero , // 0.. 4 ( 0)
zero , infty, infty, infty , infty, // 5.. 9 ( 1)
infty, infty, infty, infty , dflt , // 10.. 14 ( 2)
infty, infty, infty, infty , dflt , // 15.. 19 ( 3)
infty, infty, infty, infty , dflt , // 20.. 24 ( 4)
zero , zero , zero , dflt_2, zero , // 24.. 29 ( 5)
zero , zero , zero , zero , zero , // 30.. 34 ( 6)
infty ,zero , zero , zero , infty, // 35.. 39 ( 7)
zero , zero , zero , zero , zero , // 40.. 44 ( 8)
zero , zero , zero , zero , zero , // 45.. 49 ( 9)
zero , infty, infty, infty , infty, // 50.. 54 (10)
infty, infty, infty, infty , infty, // 55.. 59 (11)
infty, infty, infty, infty , infty, // 60.. 64 (12)
infty, infty, infty, infty , zero , // 65.. 69 (13)
zero , zero , zero , zero , zero , // 70.. 74 (14)
zero , zero , zero , zero , infty, // 75.. 79 (15)
infty, zero , infty, zero , zero , // 80.. 84 (16)
zero , zero , zero , zero , zero , // 85.. 89 (17)
zero , zero , one , zero , zero , // 90.. 94 (18)
zero , zero , zero , zero , zero , // 95.. 99 (19)
zero , zero , zero , zero , zero , // 100..104 (20)
zero , zero , zero , zero , zero , // 105..109 (21)
zero , zero // 110..111 (22)
};
const auto sz = static_cast<
decltype(init.size())>(sGrp.size());
auto b = std::begin(init);
auto e = b + std::min(init.size(), sz);
std::copy(b, e, std::begin(sGrp));
}
} // SGrp
namespace XGrp {
std::size_t entriesPerGroup(const std::vector<int>& inteHead)
{
// INTEHEAD[38] = NXGRPZ
return inteHead[38];
}
Opm::RestartIO::Helpers::WindowedArray<double>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<double>;
return WV {
WV::NumWindows{ ngmaxz(inteHead) },
WV::WindowSize{ entriesPerGroup(inteHead) }
};
}
std::vector<std::string>
filter_cumulative(const bool ecl_compatible_rst,
const std::vector<std::string>& keys)
{
if (ecl_compatible_rst) {
// User wants ECLIPSE-compatible output. Write all vectors.
return keys;
}
auto ret = std::vector<std::string>{};
ret.reserve(keys.size());
for (const auto& key : keys) {
if ((key[3] == 'T') && ((key[2] == 'I') || (key[2] == 'P'))) {
// Don't write cumulative quantities in case of
continue;
}
ret.push_back(key);
}
return ret;
}
// here define the dynamic group quantities to be written to the restart file
template <class XGrpArray>
void dynamicContrib(const std::vector<std::string>& restart_group_keys,
const std::vector<std::string>& restart_field_keys,
const std::map<std::string, size_t>& groupKeyToIndex,
const std::map<std::string, size_t>& fieldKeyToIndex,
const Opm::Group& group,
const Opm::SummaryState& sumState,
const bool ecl_compatible_rst,
XGrpArray& xGrp)
{
std::string groupName = group.name();
const std::vector<std::string>& keys = (groupName == "FIELD")
? restart_field_keys : restart_group_keys;
const std::map<std::string, size_t>& keyToIndex = (groupName == "FIELD")
? fieldKeyToIndex : groupKeyToIndex;
for (const auto key : filter_cumulative(ecl_compatible_rst,keys)) {
std::string compKey = (groupName == "FIELD")
? key : key + ":" + groupName;
if (sumState.has(compKey)) {
double keyValue = sumState.get(compKey);
const auto itr = keyToIndex.find(key);
xGrp[itr->second] = keyValue;
}
/*else {
std::cout << "AggregateGroupData_compkey: " << compKey << std::endl;
std::cout << "AggregateGroupData, empty " << std::endl;
//throw std::invalid_argument("No such keyword: " + compKey);
}*/
}
}
}
namespace ZGrp {
std::size_t entriesPerGroup(const std::vector<int>& inteHead)
{
// INTEHEAD[39] = NZGRPZ
return inteHead[39];
}
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{ ngmaxz(inteHead) },
WV::WindowSize{ entriesPerGroup(inteHead) }
};
}
}
} // Anonymous
void
Opm::RestartIO::Helpers::groupMaps::
currentGrpTreeNameSeqIndMap(const Opm::Schedule& sched,
const size_t simStep,
const std::map<const std::string , size_t>& GnIMap,
const std::map<size_t, const Opm::Group*>& IGMap)
{
const auto& grpTreeNSIMap = (sched.getGroupTree(simStep)).nameSeqIndMap();
// make group index for current report step
for (auto itr = IGMap.begin(); itr != IGMap.end(); itr++) {
auto name = (itr->second)->name();
auto srchGN = grpTreeNSIMap.find(name);
if (srchGN != grpTreeNSIMap.end()) {
//come here if group is in gruptree
this->m_indexGroupMap.insert(std::make_pair(srchGN->second, itr->second));
this->m_groupNameIndexMap.insert(std::make_pair(srchGN->first, srchGN->second));
}
else {
//come here if group is not in gruptree to put in from global group list
this->m_indexGroupMap.insert(std::make_pair(itr->first, itr->second));
this->m_groupNameIndexMap.insert(std::make_pair(name, itr->first));
}
}
}
const std::map <size_t, const Opm::Group*>&
Opm::RestartIO::Helpers::groupMaps::indexGroupMap() const
{
return this->m_indexGroupMap;
}
const std::map <const std::string, size_t>&
Opm::RestartIO::Helpers::groupMaps::groupNameIndexMap() const
{
return this->m_groupNameIndexMap;
}
// =====================================================================
Opm::RestartIO::Helpers::AggregateGroupData::
AggregateGroupData(const std::vector<int>& inteHead)
: iGroup_ (IGrp::allocate(inteHead))
, sGroup_ (SGrp::allocate(inteHead))
, xGroup_ (XGrp::allocate(inteHead))
, zGroup_ (ZGrp::allocate(inteHead))
, nWGMax_ (nwgmax(inteHead))
, nGMaxz_ (ngmaxz(inteHead))
{}
// ---------------------------------------------------------------------
void
Opm::RestartIO::Helpers::AggregateGroupData::
captureDeclaredGroupData(const Opm::Schedule& sched,
const std::vector<std::string>& restart_group_keys,
const std::vector<std::string>& restart_field_keys,
const std::map<std::string, size_t>& groupKeyToIndex,
const std::map<std::string, size_t>& fieldKeyToIndex,
const bool ecl_compatible_rst,
const std::size_t simStep,
const Opm::SummaryState& sumState,
const std::vector<int>& inteHead)
{
const auto indexGroupMap = currentGroupMapIndexGroup(sched, simStep, inteHead);
const auto nameIndexMap = currentGroupMapNameIndex(sched, simStep, inteHead);
std::vector<const Opm::Group*> curGroups(ngmaxz(inteHead), nullptr);
auto it = indexGroupMap.begin();
while (it != indexGroupMap.end())
{
curGroups[static_cast<int>(it->first)] = it->second;
it++;
}
{
groupLoop(curGroups, [sched, simStep, inteHead, this]
(const Group& group, const std::size_t groupID) -> void
{
auto ig = this->iGroup_[groupID];
IGrp::staticContrib(sched, group, this->nWGMax_, this->nGMaxz_, simStep, ig, inteHead);
});
}
// Define Static Contributions to SGrp Array.
groupLoop(curGroups,
[this](const Group& group, const std::size_t groupID) -> void
{
auto sw = this->sGroup_[groupID];
SGrp::staticContrib(sw);
});
// Define DynamicContributions to XGrp Array.
groupLoop(curGroups,
[restart_group_keys, restart_field_keys, groupKeyToIndex, fieldKeyToIndex, ecl_compatible_rst, sumState, this]
(const Group& group, const std::size_t groupID) -> void
{
auto xg = this->xGroup_[groupID];
XGrp::dynamicContrib( restart_group_keys, restart_field_keys, groupKeyToIndex, fieldKeyToIndex, group, sumState, ecl_compatible_rst, xg);
});
}
// ---------------------------------------------------------------------

View File

@@ -0,0 +1,639 @@
/*
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/AggregateMSWData.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.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/EclipseState/Schedule/Connection.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
//#include <opm/output/data/Wells.hpp>
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <string>
#include <iostream>
#include <limits>
// #####################################################################
// Class Opm::RestartIO::Helpers::AggregateMSWData
// ---------------------------------------------------------------------
namespace {
std::size_t nswlmx(const std::vector<int>& inteHead)
{
// inteHead(175) = NSWLMX
return inteHead[175];
}
std::size_t nisegz(const std::vector<int>& inteHead)
{
// inteHead(178) = NISEGZ
return inteHead[178];
}
std::size_t nrsegz(const std::vector<int>& inteHead)
{
// inteHead(179) = NRSEGZ
return inteHead[179];
}
std::size_t nilbrz(const std::vector<int>& inteHead)
{
// inteHead(180) = NILBRZ
return inteHead[180];
}
Opm::RestartIO::Helpers::BranchSegmentPar
getBranchSegmentParam(const Opm::WellSegments& segSet, const int branch)
{
int noSegInBranch = 0;
int firstSeg = -1;
int lastSeg = -1;
int outletS = 0;
for (int segNo = 1; segNo <= segSet.size(); segNo++) {
auto segInd = segSet.segmentNumberToIndex(segNo);
auto i_branch = segSet[segInd].branchNumber();
auto i_outS = segSet[segInd].outletSegment();
if (i_branch == branch) {
noSegInBranch +=1;
if (firstSeg < 0) {
firstSeg = segNo;
outletS = (branch > 1) ? i_outS : 0;
}
lastSeg = segNo;
}
}
return {
outletS,
noSegInBranch,
firstSeg,
lastSeg,
branch
};
}
std::vector<std::size_t> SegmentSetBranches(const Opm::WellSegments& segSet) {
std::vector<std::size_t> branches;
for (int segNo = 1; segNo <= segSet.size(); segNo++) {
auto segInd = segSet.segmentNumberToIndex(segNo);
auto i_branch = segSet[segInd].branchNumber();
if (std::find(branches.begin(), branches.end(), i_branch) == branches.end()) {
branches.push_back(i_branch);
}
}
return branches;
}
int firstSegmentInBranch(const Opm::WellSegments& segSet, const int branch) {
int firstSegNo = 0;
int segNo = 0;
while ((segNo <= segSet.size()) && (firstSegNo == 0)) {
segNo+=1;
auto segInd = segSet.segmentNumberToIndex(segNo);
auto i_branch = segSet[segInd].branchNumber();
if (branch == i_branch) {
firstSegNo = segNo;
}
}
return firstSegNo;
}
int noConnectionsSegment(const Opm::WellConnections& compSet,
const Opm::WellSegments& segSet,
const std::size_t segIndex)
{
auto segNumber = segSet[segIndex].segmentNumber();
int noConnections = 0;
for (auto it : compSet) {
auto cSegment = it.segment();
if (segNumber == cSegment) {
noConnections+=1;
}
}
return noConnections;
}
int sumConnectionsSegment(const Opm::WellConnections& compSet,
const Opm::WellSegments& segSet,
const std::size_t segIndex)
{
// This function returns (for a given segment) the sum of number of connections for each segment
// with lower segment index than the currnet segment
// If the segment contains no connections, the number returned is zero.
int sumConn = 0;
if (noConnectionsSegment(compSet, segSet, segIndex) > 0) {
// add up the number of connections for å segments with lower segment index than current segment
auto segNumber = segSet[segIndex].segmentNumber();
for (int i_seg = 1; i_seg <= segNumber; i_seg++) {
auto ind = segSet.segmentNumberToIndex(i_seg);
int addCon = (ind == static_cast<int>(segIndex)) ? 1 : noConnectionsSegment(compSet, segSet, ind);
sumConn += addCon;
}
}
return sumConn;
}
std::vector<std::size_t>
inflowSegmentsIndex(const Opm::WellSegments& segSet, std::size_t segIndex) {
auto segNumber = segSet[segIndex].segmentNumber();
std::vector<std::size_t> inFlowSegNum;
for (int ind = 0; ind < segSet.size(); ind++) {
auto i_outletSeg = segSet[ind].outletSegment();
if (segNumber == i_outletSeg) {
inFlowSegNum.push_back(ind);
}
}
return inFlowSegNum;
}
int noInFlowBranches(const Opm::WellSegments& segSet, std::size_t segIndex) {
auto segNumber = segSet[segIndex].segmentNumber();
auto branch = segSet[segIndex].branchNumber();
int noIFBr = 0;
for (int ind = 0; ind < segSet.size(); ind++) {
auto o_segNum = segSet[ind].outletSegment();
auto i_branch = segSet[ind].branchNumber();
if ((segNumber == o_segNum) && (branch != i_branch)){
noIFBr+=1;
}
}
return noIFBr;
}
//find the number of inflow branches (different from the current branch)
int sumNoInFlowBranches(const Opm::WellSegments& segSet, std::size_t segIndex) {
int sumIFB = 0;
auto segBranch = segSet[segIndex].branchNumber();
const auto iSInd = inflowSegmentsIndex(segSet, segIndex);
for (auto ind : iSInd) {
auto inflowBranch = segSet[ind].branchNumber();
// if inflow segment belongs to different branch add contribution
if (segBranch != inflowBranch) {
sumIFB+=1;
// search recursively down this branch to find more inflow branches
sumIFB += sumNoInFlowBranches(segSet, ind);
}
}
return sumIFB;
}
std::vector<std::size_t> segmentOrder(const Opm::WellSegments& segSet, const std::size_t segIndex) {
std::vector<std::size_t> ordSegNumber;
std::vector<std::size_t> tempOrdVect;
std::vector<std::size_t> segIndCB;
// Store "heel" segment since that will not always be at the end of the list
segIndCB.push_back(segIndex);
int newSInd = segIndex;
auto origBranchNo = segSet[segIndex].branchNumber();
bool endOrigBranch = true;
// loop down branch to find all segments in branch and number from "toe" to "heel"
while (newSInd < segSet.size()) {
endOrigBranch = true;
const auto iSInd = inflowSegmentsIndex(segSet, newSInd);
for (auto isi : iSInd ) {
auto inflowBranch = segSet[isi].branchNumber();
if (origBranchNo == inflowBranch) {
endOrigBranch = false;
}
}
if (iSInd.size() > 0) {
for (auto ind : iSInd) {
auto inflowBranch = segSet[ind].branchNumber();
if (origBranchNo == inflowBranch) {
// if inflow segment belongs to same branch add contribution
segIndCB.insert(segIndCB.begin(), ind);
// search recursively down this branch to find more inflow branches
newSInd = ind;
}
else {
// if inflow segment belongs to different branch, start new search
auto nSOrd = segmentOrder(segSet, ind);
// copy the segments already found and indexed into the total ordered segment vector
for (std::size_t indOS = 0; indOS < nSOrd.size(); indOS++) {
ordSegNumber.push_back(nSOrd[indOS]);
}
if (endOrigBranch) {
newSInd = segSet.size();
}
// increment the local branch sequence number counter
}
}
}
if (endOrigBranch || (iSInd.size()==0)) {
// have come to toe of current branch - store segment indicies of current branch
for (std::size_t indOS = 0; indOS < segIndCB.size(); indOS++) {
ordSegNumber.push_back(segIndCB[indOS]);
}
// set new index to exit while loop
newSInd = segSet.size();
}
//}
}
if (origBranchNo == 1) {
// make the vector of ordered segments
tempOrdVect.resize(ordSegNumber.size());
for (std::size_t ov_ind = 0; ov_ind < ordSegNumber.size(); ov_ind++) {
tempOrdVect[ordSegNumber[ov_ind]] = ov_ind+1;
}
return tempOrdVect;
} else {
return ordSegNumber;
}
}
int inflowSegmentCurBranch(const Opm::WellSegments& segSet, std::size_t segIndex) {
auto branch = segSet[segIndex].branchNumber();
auto segNumber = segSet[segIndex].segmentNumber();
int inFlowSegNum = 0;
for (int ind = 0; ind < segSet.size(); ind++) {
auto i_segNum = segSet[ind].segmentNumber();
auto i_branch = segSet[ind].branchNumber();
auto i_outFlowSeg = segSet[ind].outletSegment();
if ((branch == i_branch) && (segNumber == i_outFlowSeg)) {
if (inFlowSegNum == 0) {
inFlowSegNum = i_segNum;
}
else {
std::cout << "Non-unique inflow segment in same branch, Well: " << segSet.wellName() << std::endl;
std::cout << "Segment number: " << segNumber << std::endl;
std::cout << "Branch number: " << branch << std::endl;
std::cout << "Inflow segment number 1: " << inFlowSegNum << std::endl;
std::cout << "Inflow segment number 2: " << segSet[ind].segmentNumber() << std::endl;
throw std::invalid_argument("Non-unique inflow segment in same branch, Well " + segSet.wellName());
}
}
}
return inFlowSegNum;
}
template <typename MSWOp>
void MSWLoop(const std::vector<const Opm::Well*>& wells,
MSWOp&& mswOp)
{
auto mswID = std::size_t{0};
for (const auto* well : wells) {
mswID += 1;
if (well == nullptr) { continue; }
mswOp(*well, mswID - 1);
}
}
namespace ISeg {
std::size_t entriesPerMSW(const std::vector<int>& inteHead)
{
// inteHead(176) = NSEGMX
// inteHead(178) = NISEGZ
return inteHead[176] * inteHead[178];
}
Opm::RestartIO::Helpers::WindowedArray<int>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<int>;
return WV {
WV::NumWindows{ nswlmx(inteHead) },
WV::WindowSize{ entriesPerMSW(inteHead) }
};
}
template <class ISegArray>
void staticContrib(const Opm::Well& well,
const std::size_t rptStep,
const std::vector<int>& inteHead,
const Opm::EclipseGrid& grid,
ISegArray& iSeg
)
{
if (well.isMultiSegment(rptStep)) {
//loop over segment set and print out information
auto welSegSet = well.getWellSegments(rptStep);
auto completionSet = well.getConnections(rptStep);
auto noElmSeg = nisegz(inteHead);
std::size_t segmentInd = 0;
auto orderedSegmentNo = segmentOrder(welSegSet, segmentInd);
for (int ind_seg = 1; ind_seg <= welSegSet.size(); ind_seg++) {
auto ind = welSegSet.segmentNumberToIndex(ind_seg);
auto iS = (ind_seg-1)*noElmSeg;
iSeg[iS + 0] = orderedSegmentNo[ind];
iSeg[iS + 1] = welSegSet[ind].outletSegment();
iSeg[iS + 2] = inflowSegmentCurBranch(welSegSet, ind);
iSeg[iS + 3] = welSegSet[ind].branchNumber();
iSeg[iS + 4] = noInFlowBranches(welSegSet, ind);
iSeg[iS + 5] = sumNoInFlowBranches(welSegSet, ind);
iSeg[iS + 6] = noConnectionsSegment(completionSet, welSegSet, ind);
iSeg[iS + 7] = sumConnectionsSegment(completionSet, welSegSet, ind);
iSeg[iS + 8] = iSeg[iS+0];
}
}
else {
throw std::invalid_argument("No such multisegment well: " + well.name());
}
}
} // ISeg
namespace RSeg {
std::size_t entriesPerMSW(const std::vector<int>& inteHead)
{
// inteHead(176) = NSEGMX
// inteHead(179) = NRSEGZ
return inteHead[176] * inteHead[179];
}
Opm::RestartIO::Helpers::WindowedArray<double>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<double>;
return WV {
WV::NumWindows{ nswlmx(inteHead) },
WV::WindowSize{ entriesPerMSW(inteHead) }
};
}
template <class RSegArray>
void staticContrib(const Opm::Well& well,
const std::size_t rptStep,
const std::vector<int>& inteHead,
const Opm::UnitSystem& units,
const ::Opm::SummaryState& smry,
RSegArray& rSeg)
{
if (well.isMultiSegment(rptStep)) {
using M = ::Opm::UnitSystem::measure;
//loop over segment set and print out information
auto welSegSet = well.getWellSegments(rptStep);
auto completionSet = well.getCompletions(rptStep);
auto noElmSeg = nrsegz(inteHead);
auto& wname = well.name();
std::string bhpKey = "WBHP:" + wname;
//treat the top segment individually
rSeg[0] = units.from_si(M::length, welSegSet.lengthTopSegment());
rSeg[1] = units.from_si(M::length, welSegSet.depthTopSegment());
rSeg[5] = units.from_si(M::volume, welSegSet.volumeTopSegment());
rSeg[6] = rSeg[0];
rSeg[7] = rSeg[1];
//Item 8: should be some segment cumulative flow rate, use a constant value for now
rSeg[8] = 200.;
//Item ind+9: not sure what this parameter is, the current value works well for tests on E100
rSeg[9] = 0.01;
// set item ind + 10 to 0.5 based on tests on E100
rSeg[10] = 0.5;
//Item 11 should be segment pressure - use flowing bottom hole pressure temporarily
//if (smry.has( bhpKey)) {
// rSeg[11] = smry.get(bhpKey);
//}
// use default value for now
rSeg[11] = 0.;
// segment pressure - set equal to item 8
rSeg[ 39] = rSeg[11];
//Default values
//rSeg[ 39] = 1.0;
rSeg[105] = 1.0;
rSeg[106] = 1.0;
rSeg[107] = 1.0;
rSeg[108] = 1.0;
rSeg[109] = 1.0;
rSeg[110] = 1.0;
//Treat subsequent segments
for (int ind_seg = 2; ind_seg <= welSegSet.size(); ind_seg++) {
// set the elements of the rSeg array
auto ind = welSegSet.segmentNumberToIndex(ind_seg);
auto outSeg = welSegSet[ind].outletSegment();
auto ind_ofs = welSegSet.segmentNumberToIndex(outSeg);
auto iS = (ind_seg-1)*noElmSeg;
rSeg[iS + 0] = units.from_si(M::length, (welSegSet[ind].totalLength() - welSegSet[ind_ofs].totalLength()));
rSeg[iS + 1] = units.from_si(M::length, (welSegSet[ind].depth() - welSegSet[ind_ofs].depth()));
rSeg[iS + 2] = units.from_si(M::length, (welSegSet[ind].internalDiameter()));
rSeg[iS + 3] = units.from_si(M::length, (welSegSet[ind].roughness()));
rSeg[iS + 4] = units.from_si(M::length, (welSegSet[ind].crossArea()));
//repeat unit conversion to convert for area instead of length
rSeg[iS + 4] = units.from_si(M::length, rSeg[iS + 4]);
rSeg[iS + 5] = units.from_si(M::volume, (welSegSet[ind].volume()));
rSeg[iS + 6] = units.from_si(M::length, (welSegSet[ind].totalLength()));
rSeg[iS + 7] = units.from_si(M::length, (welSegSet[ind].depth()));
//Item ind+8: should be some segment cumulative flow rate, use a constant value for now
rSeg[iS + 8] = 200.;
//Item ind+9: not sure what this parameter is, the current value works well for tests on E100
rSeg[iS + 9] = 0.01;
// set item ind + 10 to 0.5 based on tests on E100
rSeg[iS + 10] = 0.5;
// segment pressure (to be added!!)
rSeg[iS + 11] = rSeg[11];
//Default values
rSeg[iS + 39] = rSeg[iS + 11];
rSeg[iS + 105] = 1.0;
rSeg[iS + 106] = 1.0;
rSeg[iS + 107] = 1.0;
rSeg[iS + 108] = 1.0;
rSeg[iS + 109] = 1.0;
rSeg[iS + 110] = 1.0;
}
}
else {
throw std::invalid_argument("No such multisegment well: " + well.name());
}
}
} // RSeg
namespace ILBS {
std::size_t entriesPerMSW(const std::vector<int>& inteHead)
{
// inteHead(177) = NLBRMX
return inteHead[177];
}
Opm::RestartIO::Helpers::WindowedArray<int>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<int>;
return WV {
WV::NumWindows{ nswlmx(inteHead) },
WV::WindowSize{ entriesPerMSW(inteHead) }
};
}
template <class ILBSArray>
void staticContrib(const Opm::Well& well,
const std::size_t rptStep,
ILBSArray& iLBS)
{
if (well.isMultiSegment(rptStep)) {
//
auto welSegSet = well.getWellSegments(rptStep);
auto branches = SegmentSetBranches(welSegSet);
for (auto it = branches.begin()+1; it != branches.end(); it++){
iLBS[*it-2] = firstSegmentInBranch(welSegSet, *it);
}
}
else {
throw std::invalid_argument("No such multisegment well: " + well.name());
}
}
} // ILBS
namespace ILBR {
std::size_t entriesPerMSW(const std::vector<int>& inteHead)
{
// inteHead(177) = NLBRMX
// inteHead(180) = NILBRZ
return inteHead[177] * inteHead[180];
}
Opm::RestartIO::Helpers::WindowedArray<int>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<int>;
return WV {
WV::NumWindows{ nswlmx(inteHead) },
WV::WindowSize{ entriesPerMSW(inteHead) }
};
}
template <class ILBRArray>
void staticContrib(const Opm::Well& well,
const std::size_t rptStep,
const std::vector<int>& inteHead,
ILBRArray& iLBR)
{
if (well.isMultiSegment(rptStep)) {
//
auto welSegSet = well.getWellSegments(rptStep);
auto branches = SegmentSetBranches(welSegSet);
auto noElmBranch = nilbrz(inteHead);
for (auto it = branches.begin(); it != branches.end(); it++){
auto iB = (*it-1)*noElmBranch;
auto branchParam = getBranchSegmentParam(welSegSet, *it);
iLBR[iB ] = branchParam.outletS;
iLBR[iB+1] = branchParam.noSegInBranch;
iLBR[iB+2] = branchParam.firstSeg;
iLBR[iB+3] = branchParam.lastSeg;
iLBR[iB+4] = branchParam.branch - 1;
}
}
else {
throw std::invalid_argument("No such multisegment well: " + well.name());
}
}
} // ILBR
} // Anonymous
// =====================================================================
Opm::RestartIO::Helpers::AggregateMSWData::
AggregateMSWData(const std::vector<int>& inteHead)
: iSeg_ (ISeg::allocate(inteHead))
, rSeg_ (RSeg::allocate(inteHead))
, iLBS_ (ILBS::allocate(inteHead))
, iLBR_ (ILBR::allocate(inteHead))
{}
// ---------------------------------------------------------------------
void
Opm::RestartIO::Helpers::AggregateMSWData::
captureDeclaredMSWData(const Schedule& sched,
const std::size_t rptStep,
const Opm::UnitSystem& units,
const std::vector<int>& inteHead,
const Opm::EclipseGrid& grid,
const ::Opm::SummaryState& smry
)
{
const auto& wells = sched.getWells(rptStep);
auto msw = std::vector<const Opm::Well*>{};
//msw.reserve(wells.size());
for (const auto well : wells) {
if (well->isMultiSegment(rptStep)) msw.push_back(well);
}
// Extract Contributions to ISeg Array
{
MSWLoop(msw, [rptStep, inteHead, grid, this]
(const Well& well, const std::size_t mswID) -> void
{
auto imsw = this->iSeg_[mswID];
ISeg::staticContrib(well, rptStep, inteHead, grid, imsw);
});
}
// Extract Contributions to RSeg Array
{
MSWLoop(msw, [&units, rptStep, inteHead, &smry, this]
(const Well& well, const std::size_t mswID) -> void
{
auto rmsw = this->rSeg_[mswID];
RSeg::staticContrib(well, rptStep, inteHead, units, smry, rmsw);
});
}
// Extract Contributions to ILBS Array
{
MSWLoop(msw, [rptStep, this]
(const Well& well, const std::size_t mswID) -> void
{
auto ilbs_msw = this->iLBS_[mswID];
ILBS::staticContrib(well, rptStep, ilbs_msw);
});
}
// Extract Contributions to ILBR Array
{
MSWLoop(msw, [rptStep, inteHead, this]
(const Well& well, const std::size_t mswID) -> void
{
auto ilbr_msw = this->iLBR_[mswID];
ILBR::staticContrib(well, rptStep, inteHead, ilbr_msw);
});
}
}

View File

@@ -31,6 +31,7 @@
#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/output/data/Wells.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/Units/Units.hpp>
@@ -74,19 +75,6 @@ namespace {
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)
@@ -119,7 +107,37 @@ namespace {
};
}
int groupIndex(const std::string& grpName,
std::map <const std::string, size_t> currentGroupMapNameIndex(const Opm::Schedule& sched, const size_t simStep, const std::vector<int>& inteHead)
{
const auto& groups = sched.getGroups(simStep);
// make group name to index map for the current time step
std::map <const std::string, size_t> groupIndexMap;
for (const auto* group : groups) {
int ind = (group->name() == "FIELD")
? inteHead[VI::intehead::NGMAXZ]-1 : group->seqIndex()-1;
std::pair<const std::string, size_t> groupPair = std::make_pair(group->name(), ind);
groupIndexMap.insert(groupPair);
}
return groupIndexMap;
}
int groupIndex(const std::string& grpName,
const std::map <const std::string, size_t>& currentGroupMapNameIndex)
{
int ind = 0;
auto searchGTName = currentGroupMapNameIndex.find(grpName);
if (searchGTName != currentGroupMapNameIndex.end())
{
ind = searchGTName->second + 1;
}
else
{
std::cout << "group Name: " << grpName << std::endl;
throw std::invalid_argument( "Invalid group name" );
}
return ind;
}
/*int groupIndex(const std::string& grpName,
const std::vector<std::string>& groupNames,
const int maxGroups)
{
@@ -141,7 +159,7 @@ namespace {
// One-based indexing.
return std::distance(b, i) + 1;
}
} */
int wellType(const Opm::Well& well,
const std::size_t sim_step)
@@ -264,7 +282,8 @@ namespace {
template <class IWellArray>
void staticContrib(const Opm::Well& well,
const std::size_t msWellID,
const std::vector<std::string>& groupNames,
const std::map <const std::string, size_t>& GroupMapNameInd,
/*const std::vector<std::string>& groupNames,*/
const int maxGroups,
const std::size_t sim_step,
IWellArray& iWell)
@@ -279,16 +298,26 @@ namespace {
const auto& conn = well.getConnections(sim_step);
iWell[Ix::NConn] = static_cast<int>(conn.size());
iWell[Ix::FirstK] = (iWell[Ix::NConn] == 0)
if (well.isMultiSegment(sim_step))
{
// Set top and bottom connections to zero for multi segment wells
iWell[Ix::FirstK] = 0;
iWell[Ix::LastK] = 0;
}
else
{
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::LastK] = (iWell[Ix::NConn] == 0)
? 0 : conn.get(conn.size() - 1).getK() + 1;
}
}
iWell[Ix::Group] =
groupIndex(trim(well.getGroupName(sim_step)),
groupNames, maxGroups);
groupIndex(trim(well.getGroupName(sim_step)),
GroupMapNameInd);
iWell[Ix::WType] = wellType (well, sim_step);
iWell[Ix::WCtrl] = ctrlMode (well, sim_step);
@@ -433,6 +462,7 @@ namespace {
void staticContrib(const Opm::Well& well,
const Opm::UnitSystem& units,
const std::size_t sim_step,
const ::Opm::SummaryState& smry,
SWellArray& sWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SWell::index;
@@ -442,58 +472,77 @@ namespace {
{
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)) {
if (pp.OilRate != 0.0) {
sWell[Ix::OilRateTarget] =
swprop(M::liquid_surface_rate, pp.OilRate);
}
}
if (pp.hasProductionControl(PP::WRAT)) {
if (pp.WaterRate != 0.0) {
sWell[Ix::WatRateTarget] =
swprop(M::liquid_surface_rate, pp.WaterRate);
}
if (pp.hasProductionControl(PP::GRAT)) {
if (pp.GasRate != 0.0) {
sWell[Ix::GasRateTarget] =
swprop(M::gas_surface_rate, pp.GasRate);
}
if (pp.hasProductionControl(PP::LRAT)) {
if (pp.LiquidRate != 0.0) {
sWell[Ix::LiqRateTarget] =
swprop(M::liquid_surface_rate, pp.LiquidRate);
}
else if (pp.hasProductionControl(PP::ORAT) &&
pp.hasProductionControl(PP::WRAT))
{
else {
sWell[Ix::LiqRateTarget] =
swprop(M::liquid_surface_rate, pp.OilRate + pp.WaterRate);
}
if (pp.hasProductionControl(PP::RESV)) {
if (pp.ResVRate != 0.0) {
sWell[Ix::ResVRateTarget] =
swprop(M::rate, pp.ResVRate);
}
else if (smry.has("WVPR:" + well.name())) {
// Write out summary voidage production rate if
// target/limit is not set
sWell[Ix::ResVRateTarget] =
static_cast<float>(smry.get("WVPR:" + well.name()));
}
if (pp.hasProductionControl(PP::THP)) {
if (pp.THPLimit != 0.0) {
sWell[Ix::THPTarget] =
swprop(M::pressure, pp.THPLimit);
}
sWell[Ix::BHPTarget] = pp.hasProductionControl(PP::BHP)
sWell[Ix::BHPTarget] = pp.BHPLimit != 0.0
? swprop(M::pressure, pp.BHPLimit)
: swprop(M::pressure, 100.0e3*::Opm::unit::psia);
: swprop(M::pressure, 1.0*::Opm::unit::atm);
}
else if (well.isInjector(sim_step)) {
const auto& ip = well.getInjectionProperties(sim_step);
using IP = ::Opm::WellInjector::ControlModeEnum;
using IT = ::Opm::WellInjector::TypeEnum;
if (ip.hasInjectionControl(IP::RATE)) {
if (ip.injectorType == IT::OIL) {
sWell[Ix::OilRateTarget] = swprop(M::liquid_surface_rate, ip.surfaceInjectionRate);
}
if (ip.injectorType == IT::WATER) {
sWell[Ix::WatRateTarget] = swprop(M::liquid_surface_rate, ip.surfaceInjectionRate);
}
if (ip.injectorType == IT::GAS) {
sWell[Ix::GasRateTarget] = swprop(M::gas_surface_rate, ip.surfaceInjectionRate);
}
}
if (ip.hasInjectionControl(IP::RESV)) {
sWell[Ix::ResVRateTarget] = swprop(M::rate, ip.reservoirInjectionRate);
}
if (ip.hasInjectionControl(IP::THP)) {
sWell[Ix::THPTarget] = swprop(M::pressure, ip.THPLimit);
@@ -501,7 +550,7 @@ namespace {
sWell[Ix::BHPTarget] = ip.hasInjectionControl(IP::BHP)
? swprop(M::pressure, ip.BHPLimit)
: swprop(M::pressure, 1.0*::Opm::unit::atm);
: swprop(M::pressure, 1.0E05*::Opm::unit::psia);
}
sWell[Ix::DatumDepth] =
@@ -548,13 +597,16 @@ namespace {
template <class XWellArray>
void assignProducer(const std::string& well,
const ::Opm::SummaryState& smry,
const bool ecl_compatible_rst,
XWellArray& xWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
auto get = [&smry, &well](const std::string& vector)
{
return smry.get(vector + ':' + well);
const auto key = vector + ':' + well;
return smry.has(key) ? smry.get(key) : 0.0;
};
xWell[Ix::OilPrRate] = get("WOPR");
@@ -570,11 +622,12 @@ namespace {
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");
if (ecl_compatible_rst) {
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];
@@ -583,13 +636,16 @@ namespace {
template <class XWellArray>
void assignWaterInjector(const std::string& well,
const ::Opm::SummaryState& smry,
const bool ecl_compatible_rst,
XWellArray& xWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
auto get = [&smry, &well](const std::string& vector)
{
return smry.get(vector + ':' + well);
const auto key = vector + ':' + well;
return smry.has(key) ? smry.get(key) : 0.0;
};
// Injection rates reported as negative, cumulative
@@ -598,8 +654,10 @@ namespace {
xWell[Ix::LiqPrRate] = xWell[Ix::WatPrRate];
xWell[Ix::FlowBHP] = get("WBHP");
xWell[Ix::WatInjTotal] = get("WWIT");
if (ecl_compatible_rst) {
xWell[Ix::WatInjTotal] = get("WWIT");
}
xWell[Ix::item37] = xWell[Ix::WatPrRate];
xWell[Ix::item82] = xWell[Ix::WatInjTotal];
@@ -610,13 +668,16 @@ namespace {
template <class XWellArray>
void assignGasInjector(const std::string& well,
const ::Opm::SummaryState& smry,
const bool ecl_compatible_rst,
XWellArray& xWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
auto get = [&smry, &well](const std::string& vector)
{
return smry.get(vector + ':' + well);
const auto key = vector + ':' + well;
return smry.has(key) ? smry.get(key) : 0.0;
};
// Injection rates reported as negative production rates,
@@ -626,11 +687,16 @@ namespace {
xWell[Ix::FlowBHP] = get("WBHP");
xWell[Ix::GasInjTotal] = get("WGIT");
xWell[Ix::GasFVF] = xWell[Ix::VoidPrRate]
/ xWell[Ix::GasPrRate];
if (ecl_compatible_rst) {
xWell[Ix::GasInjTotal] = get("WGIT");
}
xWell[Ix::GasFVF] = (std::abs(xWell[Ix::GasPrRate]) > 0.0)
? xWell[Ix::VoidPrRate] / xWell[Ix::GasPrRate]
: 0.0;
if (std::isnan(xWell[Ix::GasFVF])) xWell[Ix::GasFVF] = 0.;
// Not fully characterised.
xWell[Ix::item38] = xWell[Ix::GasPrRate];
xWell[Ix::item83] = xWell[Ix::GasInjTotal];
@@ -642,10 +708,11 @@ namespace {
void dynamicContrib(const ::Opm::Well& well,
const ::Opm::SummaryState& smry,
const std::size_t sim_step,
const bool ecl_compatible_rst,
XWellArray& xWell)
{
if (well.isProducer(sim_step)) {
assignProducer(well.name(), smry, xWell);
assignProducer(well.name(), smry, ecl_compatible_rst, xWell);
}
else if (well.isInjector(sim_step)) {
using IType = ::Opm::WellInjector::TypeEnum;
@@ -659,16 +726,16 @@ namespace {
break;
case IType::WATER:
assignWaterInjector(well.name(), smry, xWell);
assignWaterInjector(well.name(), smry, ecl_compatible_rst, xWell);
break;
case IType::GAS:
assignGasInjector(well.name(), smry, xWell);
assignGasInjector(well.name(), smry, ecl_compatible_rst, xWell);
break;
case IType::MULTI:
assignWaterInjector(well.name(), smry, xWell);
assignGasInjector (well.name(), smry, xWell);
assignWaterInjector(well.name(), smry, ecl_compatible_rst, xWell);
assignGasInjector (well.name(), smry, ecl_compatible_rst, xWell);
break;
}
}
@@ -726,33 +793,36 @@ void
Opm::RestartIO::Helpers::AggregateWellData::
captureDeclaredWellData(const Schedule& sched,
const UnitSystem& units,
const std::size_t sim_step)
const std::size_t sim_step,
const ::Opm::SummaryState& smry,
const std::vector<int>& inteHead)
{
const auto& wells = sched.getWells(sim_step);
// Static contributions to IWEL array.
{
const auto grpNames = groupNames(sched.getGroups());
//const auto grpNames = groupNames(sched.getGroups());
const auto groupMapNameIndex = IWell::currentGroupMapNameIndex(sched, sim_step, inteHead);
auto msWellID = std::size_t{0};
wellLoop(wells, [&grpNames, &msWellID, sim_step, this]
wellLoop(wells, [&groupMapNameIndex, &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,
IWell::staticContrib(well, msWellID, groupMapNameIndex,
this->nWGMax_, sim_step, iw);
});
}
// Static contributions to SWEL array.
wellLoop(wells, [&units, sim_step, this]
wellLoop(wells, [&units, sim_step, &smry, this]
(const Well& well, const std::size_t wellID) -> void
{
auto sw = this->sWell_[wellID];
SWell::staticContrib(well, units, sim_step, sw);
SWell::staticContrib(well, units, sim_step, smry, sw);
});
// Static contributions to XWEL array.
@@ -780,6 +850,7 @@ void
Opm::RestartIO::Helpers::AggregateWellData::
captureDynamicWellData(const Schedule& sched,
const std::size_t sim_step,
const bool ecl_compatible_rst,
const Opm::data::WellRates& xw,
const ::Opm::SummaryState& smry)
{
@@ -801,11 +872,11 @@ captureDynamicWellData(const Schedule& sched,
});
// Dynamic contributions to XWEL array.
wellLoop(wells, [this, sim_step, &smry]
wellLoop(wells, [this, sim_step, ecl_compatible_rst, &smry]
(const Well& well, const std::size_t wellID) -> void
{
auto xw = this->xWell_[wellID];
XWell::dynamicContrib(well, smry, sim_step, xw);
XWell::dynamicContrib(well, smry, sim_step, ecl_compatible_rst, xw);
});
}

View File

@@ -145,7 +145,7 @@ namespace {
const ::Opm::Schedule& sched,
const std::size_t lookup_step)
{
const auto& wsd = rspec.wellSegmentDimensions();
const auto& wsd = rspec.wellSegmentDimensions();
const auto& sched_wells = sched.getWells(lookup_step);
@@ -160,7 +160,7 @@ namespace {
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 nrsegz = 146; // Number of entries per segment in RSEG array. (Eclipse v.2017)
const auto nilbrz = 10; // Number of entries per segment in ILBR array.
return {
@@ -192,6 +192,18 @@ namespace {
static_cast<int>(nplmix),
};
}
Opm::RestartIO::InteHEAD::Group
getNoGroups(const ::Opm::Schedule& sched,
const std::size_t step)
{
const auto ngroups = sched.numGroups(step)-1;
return {
int(ngroups)
};
}
} // Anonymous
// #####################################################################
@@ -205,8 +217,8 @@ createInteHead(const EclipseState& es,
const Schedule& sched,
const double simTime,
const int num_solver_steps,
const int lookup_step,
const int report_step)
const int lookup_step
)
{
const auto& rspec = es.runspec();
const auto& tdim = es.getTableManager();
@@ -229,11 +241,12 @@ createInteHead(const EclipseState& es,
// 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)
.stepParam (num_solver_steps, lookup_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.
.ngroups(getNoGroups(sched, lookup_step))
.variousParam (201702, 100) // Output should be compatible with Eclipse 100, 2017.02 version.
;
return ih.data();

View File

@@ -375,7 +375,8 @@ namespace {
// ---------------------------------------------------------------------
Opm::RestartIO::DoubHEAD::DoubHEAD()
: data_(Index::NUMBER_OF_ITEMS, -1.0e20)
: data_(Index::NUMBER_OF_ITEMS, 0.0)
//: 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.

View File

@@ -20,8 +20,6 @@
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <unordered_map>
#include "config.h"
#include <opm/output/eclipse/EclipseIO.hpp>
@@ -38,12 +36,15 @@
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
#include <opm/parser/eclipse/Utility/Functional.hpp>
#include <opm/output/eclipse/Summary.hpp>
#include <opm/output/eclipse/Tables.hpp>
#include <opm/output/eclipse/RestartIO.hpp>
#include <opm/output/eclipse/Summary.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/output/eclipse/Tables.hpp>
#include <cstdlib>
#include <memory> // unique_ptr
#include <unordered_map>
#include <utility> // move
#include <ert/ecl/EclKW.hpp>
@@ -422,7 +423,7 @@ void EclipseIO::writeTimeStep(int report_step,
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,
bool write_double)
const bool write_double)
{
if( !this->impl->output_enabled )
@@ -454,7 +455,6 @@ void EclipseIO::writeTimeStep(int report_step,
this->impl->summary.write();
}
/*
Current implementation will not write restart files for substep,
but there is an unsupported option to the RPTSCHED keyword which
@@ -467,8 +467,8 @@ void EclipseIO::writeTimeStep(int report_step,
ioConfig.getUNIFOUT() ? ECL_UNIFIED_RESTART_FILE : ECL_RESTART_FILE,
report_step,
ioConfig.getFMTOUT() );
RestartIO::save( filename , report_step, secs_elapsed, value, es , grid , schedule, write_double);
RestartIO::save(filename, report_step, secs_elapsed, value, es, grid, schedule,
this->impl->summary.get_restart_vectors(), write_double);
}

View File

@@ -37,7 +37,7 @@ enum index : std::vector<int>::size_type {
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
NGRP = 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
@@ -68,8 +68,8 @@ enum index : std::vector<int>::size_type {
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_049 = 49 , // 1 // has been determined by testing
ih_050 = 50 , // 1 // has been determined by testing
ih_051 = 51 , // 0 0
ih_052 = 52 , // 0 0
ih_053 = 53 , // 0 0
@@ -198,7 +198,7 @@ enum index : std::vector<int>::size_type {
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
NRSEGZ = VI::intehead::NRSEGZ , // 146 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
@@ -593,12 +593,10 @@ params_NAAQZ(const int ncamax,
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::
stepParam(const int num_solver_steps, const int report_step)
stepParam(const int num_solver_steps, const int sim_step)
{
this -> data_[NUM_SOLVER_STEPS] = num_solver_steps;
this -> data_[REPORT_STEP] = report_step;
this -> data_[REPORT_STEP] = sim_step + 1;
return *this;
}
@@ -622,14 +620,27 @@ Opm::RestartIO::InteHEAD::variousParam(const int version,
{
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_049: Usage unknown, value fixed across reference cases
this->data_[ih_049] = 1;
// ih_050: Usage unknown, value fixed across reference cases
this->data_[ih_050] = 1;
// 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;
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;
this->data_[ih_200] = 1;
return *this;
}
@@ -657,6 +668,16 @@ Opm::RestartIO::InteHEAD::regionDimensions(const RegDims& rdim)
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::
ngroups(const Group& gr)
{
this -> data_[NGRP] = gr.ngroups;
return *this;
}
// =====================================================================
// Free functions (calendar/time utilities)
// =====================================================================

View File

@@ -0,0 +1,648 @@
/*
Copyright (c) 2016 Statoil ASA
Copyright (c) 2013-2015 Andreas Lauser
Copyright (c) 2013 SINTEF ICT, Applied Mathematics.
Copyright (c) 2013 Uni Research AS
Copyright (c) 2015 IRIS AS
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/RestartIO.hpp>
#include <opm/output/eclipse/RestartValue.hpp>
#include <opm/output/eclipse/VectorItems/connection.hpp>
#include <opm/output/eclipse/VectorItems/intehead.hpp>
#include <opm/output/eclipse/VectorItems/well.hpp>
#include <opm/output/eclipse/libECLRestart.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <exception>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
class RestartFileView
{
public:
explicit RestartFileView(const std::string& filename,
const int report_step);
~RestartFileView() = default;
RestartFileView(const RestartFileView& rhs) = delete;
RestartFileView(RestartFileView&& rhs);
RestartFileView& operator=(const RestartFileView& rhs) = delete;
RestartFileView& operator=(RestartFileView&& rhs);
std::size_t simStep() const
{
return this->sim_step_;
}
operator const Opm::RestartIO::ecl_file_view_type*() const
{
return this->step_view_;
}
const Opm::RestartIO::ecl_kw_type* getKeyword(const char* kw) const
{
namespace Load = Opm::RestartIO;
// Main grid only. Does not handle/support LGR.
return Load::ecl_file_view_has_kw (*this, kw)
? Load::ecl_file_view_iget_named_kw(*this, kw, 0)
: nullptr;
}
private:
using RstFile = Opm::RestartIO::ert_unique_ptr<
Opm::RestartIO::ecl_file_type,
Opm::RestartIO::ecl_file_close>;
std::size_t sim_step_;
RstFile rst_file_;
Opm::RestartIO::ecl_file_view_type* step_view_ = nullptr;
operator Opm::RestartIO::ecl_file_type*()
{
return this->rst_file_.get();
}
operator const Opm::RestartIO::ecl_file_type*() const
{
return this->rst_file_.get();
}
};
RestartFileView::RestartFileView(const std::string& filename,
const int report_step)
: sim_step_(std::max(report_step - 1, 0))
, rst_file_(Opm::RestartIO::ecl_file_open(filename.c_str(), 0))
{
namespace Load = Opm::RestartIO;
if (this->rst_file_ == nullptr) {
throw std::invalid_argument {
"Unable to open Restart File '" + filename
+ "' at Report Step " + std::to_string(report_step)
};
}
this->step_view_ =
(Load::EclFiletype(filename) == Load::ECL_UNIFIED_RESTART_FILE)
? Load::ecl_file_get_restart_view(*this, -1, report_step, -1, -1)
: Load::ecl_file_get_global_view (*this); // Separate
if (this->step_view_ == nullptr) {
throw std::runtime_error {
"Unable to acquire restart information for report step "
+ std::to_string(report_step)
};
}
}
RestartFileView::RestartFileView(RestartFileView&& rhs)
: sim_step_ (rhs.sim_step_) // Scalar (size_t)
, rst_file_ (std::move(rhs.rst_file_))
, step_view_(rhs.step_view_) // Pointer
{}
RestartFileView& RestartFileView::operator=(RestartFileView&& rhs)
{
this->sim_step_ = rhs.sim_step_; // Scalar (size_t)
this->rst_file_ = std::move(rhs.rst_file_);
this->step_view_ = rhs.step_view_; // Pointer copy
return *this;
}
namespace {
void throwIfMissingRequired(const Opm::RestartKey& rst_key)
{
if (rst_key.required) {
throw std::runtime_error {
"Requisite restart vector '"
+ rst_key.key +
"' is not available in restart file"
};
}
}
std::vector<double>
double_vector(const ::Opm::RestartIO::ecl_kw_type* ecl_kw)
{
namespace Load = ::Opm::RestartIO;
const auto size = static_cast<std::size_t>(
Load::ecl_kw_get_size(ecl_kw));
if (Load::ecl_type_get_type(Load::ecl_kw_get_data_type(ecl_kw)) == Load::ECL_DOUBLE_TYPE) {
const double* ecl_data = Load::ecl_kw_get_type_ptr<double>(ecl_kw, Load::ECL_DOUBLE_TYPE);
return { ecl_data , ecl_data + size };
}
else {
const float* ecl_data = Load::ecl_kw_get_type_ptr<float>(ecl_kw, Load::ECL_FLOAT_TYPE);
return { ecl_data , ecl_data + size };
}
}
Opm::data::Solution
restoreSOLUTION(const RestartFileView& rst_view,
const std::vector<Opm::RestartKey>& solution_keys,
const int numcells)
{
Opm::data::Solution sol(/* init_si = */ false);
for (const auto& value : solution_keys) {
const auto& vector = value.key;
const auto* kw = rst_view.getKeyword(vector.c_str());
if (kw == nullptr) {
throwIfMissingRequired(value);
// Requested vector not available, but caller does not
// actually require the vector for restart purposes.
// Skip this.
continue;
}
if (Opm::RestartIO::ecl_kw_get_size(kw) != numcells) {
throw std::runtime_error {
"Restart file: Could not restore "
+ std::string(Opm::RestartIO::ecl_kw_get_header(kw))
+ ", mismatched number of cells"
};
}
sol.insert(vector, value.dim, double_vector(kw),
Opm::data::TargetType::RESTART_SOLUTION);
}
return sol;
}
void restoreExtra(const RestartFileView& rst_view,
const std::vector<Opm::RestartKey>& extra_keys,
const Opm::UnitSystem& usys,
Opm::RestartValue& rst_value)
{
for (const auto& extra : extra_keys) {
const auto& vector = extra.key;
const auto* kw = rst_view.getKeyword(vector.c_str());
if (kw == nullptr) {
throwIfMissingRequired(extra);
// Requested vector not available, but caller does not
// actually require the vector for restart purposes.
// Skip this.
continue;
}
// Requisite vector available in result set. Recover data.
rst_value.addExtra(vector, extra.dim, double_vector(kw));
}
for (auto& extra_value : rst_value.extra) {
const auto& restart_key = extra_value.first;
auto& data = extra_value.second;
usys.to_si(restart_key.dim, data);
}
}
void checkWellVectorSizes(const ::Opm::RestartIO::ecl_kw_type* opm_xwel,
const ::Opm::RestartIO::ecl_kw_type* opm_iwel,
const int sim_step,
const std::vector<Opm::data::Rates::opt>& phases,
const std::vector<const Opm::Well*>& sched_wells)
{
const auto expected_xwel_size =
std::accumulate(sched_wells.begin(), sched_wells.end(),
std::size_t(0),
[&phases, sim_step](const std::size_t acc, const Opm::Well* w)
-> std::size_t
{
return acc
+ 2 + phases.size()
+ (w->getConnections(sim_step).size()
* (phases.size() + Opm::data::Connection::restart_size));
});
if (static_cast<std::size_t>(::Opm::RestartIO::ecl_kw_get_size(opm_xwel)) != expected_xwel_size)
{
throw std::runtime_error {
"Mismatch between OPM_XWEL and deck; "
"OPM_XWEL size was " + std::to_string(::Opm::RestartIO::ecl_kw_get_size(opm_xwel)) +
", expected " + std::to_string(expected_xwel_size)
};
}
if (::Opm::RestartIO::ecl_kw_get_size(opm_iwel) != int(sched_wells.size())) {
throw std::runtime_error {
"Mismatch between OPM_IWEL and deck; "
"OPM_IWEL size was " + std::to_string(::Opm::RestartIO::ecl_kw_get_size(opm_iwel)) +
", expected " + std::to_string(sched_wells.size())
};
}
}
Opm::data::Wells
restore_wells_opm(const RestartFileView& rst_view,
const ::Opm::EclipseState& es,
const ::Opm::EclipseGrid& grid,
const ::Opm::Schedule& schedule)
{
namespace Load = ::Opm::RestartIO;
const auto* opm_iwel = rst_view.getKeyword("OPM_IWEL");
const auto* opm_xwel = rst_view.getKeyword("OPM_XWEL");
if ((opm_xwel == nullptr) || (opm_iwel == nullptr)) {
return {};
}
using rt = Opm::data::Rates::opt;
const auto& sched_wells = schedule.getWells(rst_view.simStep());
std::vector<rt> phases;
{
const auto& phase = es.runspec().phases();
if (phase.active(Opm::Phase::WATER)) { phases.push_back(rt::wat); }
if (phase.active(Opm::Phase::OIL)) { phases.push_back(rt::oil); }
if (phase.active(Opm::Phase::GAS)) { phases.push_back(rt::gas); }
}
checkWellVectorSizes(opm_xwel, opm_iwel,
rst_view.simStep(),
phases, sched_wells);
Opm::data::Wells wells;
const auto* opm_xwel_data = Load::ecl_kw_get_type_ptr<double>(opm_xwel, Load::ECL_DOUBLE_TYPE);
const auto* opm_iwel_data = Load::ecl_kw_get_type_ptr<int>(opm_iwel, Load::ECL_INT_TYPE);
for (const auto* sched_well : sched_wells) {
auto& well = wells[ sched_well->name() ];
well.bhp = *opm_xwel_data++;
well.temperature = *opm_xwel_data++;
well.control = *opm_iwel_data++;
for (const auto& phase : phases) {
well.rates.set(phase, *opm_xwel_data++);
}
for (const auto& sc : sched_well->getConnections(rst_view.simStep())) {
const auto i = sc.getI(), j = sc.getJ(), k = sc.getK();
if (!grid.cellActive(i, j, k) || sc.state() == Opm::WellCompletion::SHUT) {
opm_xwel_data += Opm::data::Connection::restart_size + phases.size();
continue;
}
const auto active_index = grid.activeIndex(i, j, k);
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 (const auto& phase : phases) {
connection.rates.set(phase, *opm_xwel_data++);
}
}
}
return wells;
}
template <typename T>
const T* getPtr(const ::Opm::RestartIO::ecl_kw_type* kw)
{
return (kw == nullptr) ? nullptr
: static_cast<const T*>(ecl_kw_iget_ptr(kw /* <- ADL */, 0));
}
int getInteHeadElem(const ::Opm::RestartIO::ecl_kw_type* intehead,
const std::vector<int>::size_type i)
{
return getPtr<int>(intehead)[i];
}
struct WellArrayDim
{
explicit WellArrayDim(const ::Opm::RestartIO::ecl_kw_type* intehead);
std::size_t maxConnPerWell;
std::size_t numIWelElem;
std::size_t numXWelElem;
std::size_t numIConElm;
std::size_t numXConElm;
};
WellArrayDim::WellArrayDim(const ::Opm::RestartIO::ecl_kw_type* intehead)
: maxConnPerWell(getInteHeadElem(intehead, VI::intehead::NCWMAX))
, numIWelElem (getInteHeadElem(intehead, VI::intehead::NIWELZ))
, numXWelElem (getInteHeadElem(intehead, VI::intehead::NXWELZ))
, numIConElm (getInteHeadElem(intehead, VI::intehead::NICONZ))
, numXConElm (getInteHeadElem(intehead, VI::intehead::NXCONZ))
{}
template <typename T>
boost::iterator_range<const T*>
getDataWindow(const T* arr,
const std::size_t windowSize,
const std::size_t well,
const std::size_t conn = 0,
const std::size_t maxConnPerWell = 1)
{
const auto off = windowSize * (conn + maxConnPerWell*well);
const auto* begin = arr + off;
const auto* end = begin + windowSize;
return { begin, end };
}
boost::iterator_range<const int*>
getIWelWindow(const int* iwel,
const WellArrayDim& wdim,
const std::size_t well)
{
return getDataWindow(iwel, wdim.numIWelElem, well);
}
boost::iterator_range<const double*>
getXWelWindow(const double* xwel,
const WellArrayDim& wdim,
const std::size_t well)
{
return getDataWindow(xwel, wdim.numXWelElem, well);
}
boost::iterator_range<const int*>
getIConWindow(const int* icon,
const WellArrayDim& wdim,
const std::size_t well,
const std::size_t conn)
{
return getDataWindow(icon, wdim.numIConElm, well,
conn, wdim.maxConnPerWell);
}
boost::iterator_range<const double*>
getXConWindow(const double* xcon,
const WellArrayDim& wdim,
const std::size_t well,
const std::size_t conn)
{
return getDataWindow(xcon, wdim.numXConElm, well,
conn, wdim.maxConnPerWell);
}
std::unordered_map<std::size_t, boost::iterator_range<const double*>::size_type>
seqID_to_resID(const WellArrayDim& wdim,
const std::size_t wellID,
const std::size_t nConn,
const int* icon_full)
{
using SizeT = boost::iterator_range<const double*>::size_type;
auto seqToRes = std::unordered_map<std::size_t, SizeT>{};
for (auto connID = 0*nConn; connID < nConn; ++connID) {
const auto icon =
getIConWindow(icon_full, wdim, wellID, connID);
seqToRes.emplace(icon[VI::IConn::index::SeqIndex] - 1, connID);
}
return seqToRes;
}
void restoreConnRates(const Opm::Well& well,
const std::size_t wellID,
const std::size_t sim_step,
const Opm::EclipseGrid& grid,
const WellArrayDim& wdim,
const Opm::UnitSystem& usys,
const Opm::Phases& phases,
const int* iwel_full,
const int* icon_full,
const double* xcon_full,
Opm::data::Well& xw)
{
using M = ::Opm::UnitSystem::measure;
const auto iwel = getIWelWindow(iwel_full, wdim, wellID);
const auto nConn = static_cast<std::size_t>(
iwel[VI::IWell::index::NConn]);
xw.connections.resize(nConn, Opm::data::Connection{});
if ((icon_full == nullptr) || (xcon_full == nullptr)) {
// Result set does not provide certain pieces of
// information which are needed to reconstruct
// connection flow rates. Nothing to do here.
return;
}
const auto oil = phases.active(Opm::Phase::OIL);
const auto gas = phases.active(Opm::Phase::GAS);
const auto wat = phases.active(Opm::Phase::WATER);
const auto conns = well.getActiveConnections(sim_step, grid);
const auto seq_to_res =
seqID_to_resID(wdim, wellID, nConn, icon_full);
auto linConnID = std::size_t{0};
for (const auto& conn : conns) {
const auto connID = seq_to_res.at(conn.getSeqIndex());
const auto xcon =
getXConWindow(xcon_full, wdim, wellID, connID);
auto& xc = xw.connections[linConnID++];
if (wat) {
xc.rates.set(Opm::data::Rates::opt::wat,
- usys.to_si(M::liquid_surface_rate,
xcon[VI::XConn::index::WaterRate]));
}
if (oil) {
xc.rates.set(Opm::data::Rates::opt::oil,
- usys.to_si(M::liquid_surface_rate,
xcon[VI::XConn::index::OilRate]));
}
if (gas) {
xc.rates.set(Opm::data::Rates::opt::gas,
- usys.to_si(M::gas_surface_rate,
xcon[VI::XConn::index::GasRate]));
}
}
}
Opm::data::Well
restore_well(const Opm::Well& well,
const std::size_t wellID,
const std::size_t sim_step,
const Opm::EclipseGrid& grid,
const WellArrayDim& wdim,
const Opm::UnitSystem& usys,
const Opm::Phases& phases,
const int* iwel_full,
const double* xwel_full,
const int* icon_full,
const double* xcon_full)
{
if ((iwel_full == nullptr) || (xwel_full == nullptr)) {
// Result set does not provide well information.
// No wells? In any case, nothing to do here.
return {};
}
using M = ::Opm::UnitSystem::measure;
const auto xwel = getXWelWindow(xwel_full, wdim, wellID);
const auto oil = phases.active(Opm::Phase::OIL);
const auto gas = phases.active(Opm::Phase::GAS);
const auto wat = phases.active(Opm::Phase::WATER);
auto xw = ::Opm::data::Well{};
// 1) Restore well rates (xw.rates)
if (wat) {
xw.rates.set(Opm::data::Rates::opt::wat,
- usys.to_si(M::liquid_surface_rate,
xwel[VI::XWell::index::WatPrRate]));
}
if (oil) {
xw.rates.set(Opm::data::Rates::opt::oil,
- usys.to_si(M::liquid_surface_rate,
xwel[VI::XWell::index::OilPrRate]));
}
if (gas) {
xw.rates.set(Opm::data::Rates::opt::gas,
- usys.to_si(M::gas_surface_rate,
xwel[VI::XWell::index::GasPrRate]));
}
// 2) Restore other well quantities (really only xw.bhp)
xw.bhp = usys.to_si(M::pressure, xwel[VI::XWell::index::FlowBHP]);
xw.thp = xw.temperature = 0.0;
// 3) Restore connection flow rates (xw.connections[i].rates)
restoreConnRates(well, wellID, sim_step, grid, wdim, usys, phases,
iwel_full, icon_full, xcon_full, xw);
return xw;
}
Opm::data::Wells
restore_wells_ecl(const RestartFileView& rst_view,
const ::Opm::EclipseState& es,
const ::Opm::EclipseGrid& grid,
const ::Opm::Schedule& schedule)
{
auto soln = ::Opm::data::Wells{};
const auto* intehead = rst_view.getKeyword("INTEHEAD");
if (intehead == nullptr) {
// Result set does not provide indexing information.
// Can't do anything here.
return soln;
}
const auto wdim = WellArrayDim{ intehead };
const auto& units = es.getUnits();
const auto& phases = es.runspec().phases();
const auto* iwel_full = getPtr<int> (rst_view.getKeyword("IWEL"));
const auto* xwel_full = getPtr<double>(rst_view.getKeyword("XWEL"));
const auto* icon_full = getPtr<int> (rst_view.getKeyword("ICON"));
const auto* xcon_full = getPtr<double>(rst_view.getKeyword("XCON"));
const auto sim_step = rst_view.simStep();
const auto& wells = schedule.getWells(sim_step);
for (auto nWells = wells.size(), wellID = 0*nWells;
wellID < nWells; ++wellID)
{
const auto* well = wells[wellID];
soln[well->name()] =
restore_well(*well, wellID, sim_step, grid, wdim, units, phases,
iwel_full, xwel_full, icon_full, xcon_full);
}
return soln;
}
} // Anonymous namespace
namespace Opm { namespace RestartIO {
RestartValue
load(const std::string& filename,
int report_step,
const std::vector<RestartKey>& solution_keys,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const std::vector<RestartKey>& extra_keys)
{
const auto rst_view = RestartFileView{ filename, report_step };
auto xr = restoreSOLUTION(rst_view, solution_keys,
grid.getNumActive());
xr.convertToSI(es.getUnits());
auto xw = Opm::RestartIO::ecl_file_view_has_kw(rst_view, "OPM_XWEL")
? restore_wells_opm(rst_view, es, grid, schedule)
: restore_wells_ecl(rst_view, es, grid, schedule);
auto rst_value = RestartValue{ std::move(xr), std::move(xw) };
if (! extra_keys.empty()) {
restoreExtra(rst_view, extra_keys, es.getUnits(), rst_value);
}
return rst_value;
}
}} // Opm::RestartIO

View File

@@ -148,18 +148,18 @@ variousParam(const bool e300_radial, const bool e100_radial, const int nswlmx)
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_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;
//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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -81,5 +81,25 @@ namespace Opm {
this->addExtra(key, UnitSystem::measure::identity, std::move(data));
}
void RestartValue::convertFromSI(const UnitSystem& units) {
this->solution.convertFromSI(units);
for (auto & extra_value : this->extra) {
const auto& restart_key = extra_value.first;
auto & data = extra_value.second;
units.from_si(restart_key.dim, data);
}
}
void RestartValue::convertToSI(const UnitSystem& units) {
this->solution.convertToSI(units);
for (auto & extra_value : this->extra) {
const auto& restart_key = extra_value.first;
auto & data = extra_value.second;
units.to_si(restart_key.dim, data);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -397,14 +397,15 @@ void RestartConfig::handleScheduleSection(const SCHEDULESection& schedule) {
continue;
}
if( this->m_timemap.size() <= current_step ) continue;
if (name == "SAVE") {
this->save_keywords[current_step] = true;
this->save_keywords.at(current_step) = true;
} else {
this->save_keywords[current_step]= false;
this->save_keywords.at(current_step) = false;
}
if( !( name == "RPTRST" || name == "RPTSCHED" ) ) continue;
if( this->m_timemap.size() <= current_step ) continue;
const bool is_RPTRST = name == "RPTRST";
const auto& prev_sched = this->restart_schedule.back();
@@ -483,7 +484,7 @@ void RestartConfig::handleScheduleSection(const SCHEDULESection& schedule) {
m_first_restart_step( -1 ),
restart_schedule( m_timemap, { 0, 0, 1 } ),
restart_keywords( m_timemap, {} ),
save_keywords( m_timemap.numTimesteps(), false )
save_keywords( m_timemap.size(), false )
{
handleSolutionSection( solution );
handleScheduleSection( schedule );

View File

@@ -90,6 +90,7 @@ Welldims::Welldims(const Deck& deck)
//
// i.e., the maximum of item 1 and item 4 here.
this->nGMax = wd.getItem("MAXGROUPS").get<int>(0);
this->nWMax = wd.getItem("MAXWELLS").get<int>(0);
}
}

View File

@@ -44,7 +44,12 @@ namespace Opm {
double Kh,
double rw,
const int satTableId,
const WellCompletion::DirectionEnum direction)
const WellCompletion::DirectionEnum direction,
const std::size_t seqIndex,
const double segDistStart,
const double segDistEnd,
const bool defaultSatTabId
)
: direction(direction),
center_depth(depth),
open_state(stateArg),
@@ -53,9 +58,22 @@ namespace Opm {
m_CF(CF),
m_Kh(Kh),
m_rw(rw),
ijk({i,j,k})
ijk({i,j,k}),
m_seqIndex(seqIndex),
m_segDistStart(segDistStart),
m_segDistEnd(segDistEnd),
m_defaultSatTabId(defaultSatTabId)
{}
/*bool Connection::sameCoordinate(const Connection& other) const {
if ((m_i == other.m_i) &&
(m_j == other.m_j) &&
(m_k == other.m_k))
return true;
else
return false;
}*/
bool Connection::sameCoordinate(const int i, const int j, const int k) const {
if ((ijk[0] == i) && (ijk[1] == j) && (ijk[2] == k)) {
return true;
@@ -81,11 +99,48 @@ namespace Opm {
bool Connection::attachedToSegment() const {
return (segment_number > 0);
}
const std::size_t& Connection::getSeqIndex() const {
return m_seqIndex;
}
const bool& Connection::getDefaultSatTabId() const {
return m_defaultSatTabId;
}
const std::size_t& Connection::getCompSegSeqIndex() const {
return m_compSeg_seqIndex;
}
WellCompletion::DirectionEnum Connection::dir() const {
return this->direction;
}
const double& Connection::getSegDistStart() const {
return m_segDistStart;
}
const double& Connection::getSegDistEnd() const {
return m_segDistEnd;
}
void Connection::setCompSegSeqIndex(std::size_t index) {
m_compSeg_seqIndex = index;
}
void Connection::setDefaultSatTabId(bool id) {
m_defaultSatTabId = id;
}
void Connection::setSegDistStart(const double& distStart) {
m_segDistStart = distStart;
}
void Connection::setSegDistEnd(const double& distEnd) {
m_segDistEnd = distEnd;
}
double Connection::depth() const {
return this->center_depth;
}
@@ -122,9 +177,10 @@ namespace Opm {
this->open_state = state;
}
void Connection::updateSegment(int segment_number, double center_depth) {
void Connection::updateSegment(int segment_number, double center_depth, std::size_t seqIndex) {
this->segment_number = segment_number;
this->center_depth = center_depth;
this->m_seqIndex = seqIndex;
}
int Connection::segment() const {
@@ -150,12 +206,11 @@ namespace Opm {
&& this->open_state == rhs.open_state
&& this->direction == rhs.direction
&& this->segment_number == rhs.segment_number
&& this->center_depth == rhs.center_depth;
&& this->center_depth == rhs.center_depth
&& this->m_seqIndex == rhs.m_seqIndex;
}
bool Connection::operator!=( const Connection& rhs ) const {
return !( *this == rhs );
}
}

View File

@@ -50,9 +50,10 @@ namespace Opm {
/*****************************************************************/
Group::Group(const std::string& name_, const TimeMap& timeMap , size_t creationTimeStep) :
Group::Group(const std::string& name_, const size_t& seqIndex_, const TimeMap& timeMap , size_t creationTimeStep) :
m_creationTimeStep( creationTimeStep ),
m_name( name_ ),
m_seqIndex( seqIndex_),
m_injection( timeMap ),
m_production( timeMap ),
m_wells( timeMap, {} ),
@@ -68,6 +69,9 @@ namespace Opm {
return m_name;
}
const size_t& Group::seqIndex() const {
return m_seqIndex;
}
bool Group::hasBeenDefined(size_t timeStep) const {
if (timeStep < m_creationTimeStep)

View File

@@ -19,13 +19,14 @@
#include <algorithm>
#include <stdexcept>
#include <iostream>
#include <opm/parser/eclipse/EclipseState/Schedule/GroupTree.hpp>
namespace Opm {
void GroupTree::update( const std::string& name ) {
this->update( name, "FIELD" );
void GroupTree::update( const std::string& name) {
this->update( name, "FIELD");
}
/*
@@ -35,8 +36,16 @@ void GroupTree::update( const std::string& name ) {
* this grouptree class is just meta data for the actual group objects (stored
* and represented elsewhere)
*/
const std::map<const std::string , size_t>& GroupTree::nameSeqIndMap() const {
return m_nameSeqIndMap;
}
void GroupTree::update( const std::string& name, const std::string& other_parent ) {
const std::map<size_t, const std::string >& GroupTree::seqIndNameMap() const {
return m_seqIndNameMap;
}
void GroupTree::update( const std::string& name, const std::string& other_parent) {
if( name == "FIELD" )
throw std::invalid_argument( "The FIELD group name is reserved." );
@@ -44,12 +53,10 @@ void GroupTree::update( const std::string& name, const std::string& other_parent
throw std::invalid_argument( "Parent group must have a name." );
auto root = this->find( other_parent );
if( root == this->groups.end() || root->name != other_parent )
if( root == this->groups.end() || root->name != other_parent )
this->groups.insert( root, 1, group { other_parent, "FIELD" } );
auto node = this->find( name );
if( node == this->groups.end() || node->name != name ) {
this->groups.insert( node, 1, group { name, other_parent } );
return;
@@ -58,6 +65,30 @@ void GroupTree::update( const std::string& name, const std::string& other_parent
node->parent = other_parent;
}
void GroupTree::updateSeqIndex( const std::string& name, const std::string& other_parent) {
if( name == "FIELD" )
throw std::invalid_argument( "The FIELD group name is reserved." );
if( other_parent.empty() )
throw std::invalid_argument( "Parent group must have a name." );
// add code to set an index that determine the sequence of the groups
// defined in the group tree
size_t index = this->m_nameSeqIndMap.size();
auto name_itr = this->m_nameSeqIndMap.find(name);
if (name_itr == this->m_nameSeqIndMap.end()) {
this->m_nameSeqIndMap.insert(std::make_pair(name, index));
this->m_seqIndNameMap.insert(std::make_pair(index, name));
index +=1;
}
auto parent_itr = this->m_nameSeqIndMap.find(other_parent);
if (parent_itr == this->m_nameSeqIndMap.end()) {
this->m_nameSeqIndMap.insert(std::make_pair(other_parent, index));
this->m_seqIndNameMap.insert(std::make_pair(index, other_parent));
}
}
bool GroupTree::exists( const std::string& name ) const {
return std::binary_search( this->groups.begin(),
this->groups.end(),
@@ -78,10 +109,15 @@ std::vector< std::string > GroupTree::children( const std::string& other_parent
throw std::out_of_range( "Node '" + other_parent + "' does not exist." );
std::vector< std::string > kids;
for( const auto& node : this->groups ) {
/* for( const auto& node : this->groups ) {
if( node.parent != other_parent ) continue;
kids.push_back( node.name );
}
*/
for( auto it = this->groups.begin(); it != this->groups.end(); it++ ) {
if( (*it).parent != other_parent ) continue;
kids.push_back( (*it).name );
}
return kids;
}

View File

@@ -18,6 +18,7 @@
*/
#include <cmath>
#include <iostream>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
@@ -33,7 +34,7 @@ namespace Opm {
Compsegs::Compsegs(int i_in, int j_in, int k_in, int branch_number_in, double distance_start_in, double distance_end_in,
WellCompletion::DirectionEnum dir_in, double center_depth_in, int segment_number_in)
WellCompletion::DirectionEnum dir_in, double center_depth_in, int segment_number_in, size_t seqIndex_in)
: m_i(i_in),
m_j(j_in),
m_k(k_in),
@@ -42,11 +43,12 @@ namespace Opm {
m_distance_end(distance_end_in),
m_dir(dir_in),
center_depth(center_depth_in),
segment_number(segment_number_in)
segment_number(segment_number_in),
m_seqIndex(seqIndex_in)
{
}
std::vector< Compsegs > Compsegs::compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword ) {
std::vector< Compsegs > Compsegs::compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword, const EclipseGrid& grid, std::size_t& totNC ) {
// only handle the second record here
// The first record here only contains the well name
@@ -119,14 +121,20 @@ namespace Opm {
segment_number = 0;
// will decide the segment number based on the distance in a process later.
}
if (!record.getItem<ParserKeywords::COMPSEGS::END_IJK>().hasValue(0)) { // only one compsegs
compsegs.emplace_back( I, J, K,
branch,
distance_start, distance_end,
direction,
center_depth,
segment_number );
if (grid.cellActive(I, J, K)) {
std::size_t seqIndex = compsegs.size();
totNC = seqIndex+1;
compsegs.emplace_back( I, J, K,
branch,
distance_start, distance_end,
direction,
center_depth,
segment_number,
seqIndex
);
}
} else { // a range is defined. genrate a range of Compsegs
throw std::runtime_error("entering COMPSEGS entries with a range is not supported yet!");
}
@@ -231,15 +239,22 @@ namespace Opm {
}
void Compsegs::updateConnectionsWithSegment(const std::vector< Compsegs >& compsegs,
const EclipseGrid& grid,
WellConnections& connection_set) {
for( const auto& compseg : compsegs ) {
const int i = compseg.m_i;
const int j = compseg.m_j;
const int k = compseg.m_k;
if (grid.cellActive(i, j, k)) {
Connection& connection = connection_set.getFromIJK( i, j, k );
connection.updateSegment(compseg.segment_number, compseg.center_depth,compseg.m_seqIndex);
Connection& connection = connection_set.getFromIJK( i, j, k );
connection.updateSegment(compseg.segment_number, compseg.center_depth);
//keep connection sequence number from input sequence
connection.setCompSegSeqIndex(compseg.m_seqIndex);
connection.setSegDistStart(compseg.m_distance_start);
connection.setSegDistEnd(compseg.m_distance_end);
}
}
for (size_t ic = 0; ic < connection_set.size(); ++ic) {

View File

@@ -25,12 +25,15 @@
#include <string>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
namespace Opm {
class WellConnections;
class DeckKeyword;
class WellSegments;
class EclipseGrid;
struct Compsegs {
int m_i;
@@ -48,19 +51,21 @@ namespace Opm {
// we do not handle thermal length for the moment
// double m_thermal_length;
int segment_number;
std::size_t m_seqIndex;
Compsegs(int i_in, int j_in, int k_in, int branch_number_in, double distance_start_in, double distance_end_in,
WellCompletion::DirectionEnum dir_in, double center_depth_in, int segment_number_in);
WellCompletion::DirectionEnum dir_in, double center_depth_in, int segment_number_in, std::size_t seqIndex_in);
void calculateCenterDepthWithSegments(const WellSegments& segment_set);
static std::vector< Compsegs > compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword );
static std::vector< Compsegs > compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword, const EclipseGrid& grid, std::size_t& totNC );
// get the segment number information and depth information based on the information from WellSegments
static void processCOMPSEGS(std::vector< Compsegs >& compsegs, const WellSegments& segment_set );
// update the segment related information for Connections
static void updateConnectionsWithSegment(const std::vector< Compsegs >& compsegs,
const EclipseGrid& grid,
WellConnections& connection_set);
};

View File

@@ -18,19 +18,23 @@
*/
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/updatingConnectionsWithSegments.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include "Compsegs.hpp"
namespace Opm {
WellConnections * newConnectionsWithSegments(const DeckKeyword& compsegs,
const WellConnections& input_connections,
const WellSegments& segment_set)
const WellSegments& segment_set,
const EclipseGrid& grid,
std::size_t& totNC
)
{
WellConnections * new_connection_set = new WellConnections(input_connections);
std::vector<Compsegs> compsegs_vector = Compsegs::compsegsFromCOMPSEGSKeyword( compsegs );
std::vector<Compsegs> compsegs_vector = Compsegs::compsegsFromCOMPSEGSKeyword( compsegs, grid, totNC );
Compsegs::processCOMPSEGS(compsegs_vector, segment_set);
Compsegs::updateConnectionsWithSegment(compsegs_vector, *new_connection_set);
Compsegs::updateConnectionsWithSegment(compsegs_vector, grid, *new_connection_set);
return new_connection_set;
}
}

View File

@@ -20,6 +20,7 @@
#include <string>
#include <vector>
#include <stdexcept>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
@@ -106,6 +107,9 @@ namespace Opm {
{}
std::time_t Schedule::getStartTime() const {
return this->posixStartTime( );
}
@@ -205,7 +209,7 @@ namespace Opm {
handleWELSEGS(keyword, currentStep);
else if (keyword.name() == "COMPSEGS")
handleCOMPSEGS(keyword, currentStep);
handleCOMPSEGS(keyword, currentStep, grid);
else if (keyword.name() == "WELOPEN")
handleWELOPEN(keyword, currentStep, parseContext);
@@ -1348,11 +1352,11 @@ namespace Opm {
well.handleWELSEGS(keyword, currentStep);WellSegments newSegmentset;
}
void Schedule::handleCOMPSEGS( const DeckKeyword& keyword, size_t currentStep) {
void Schedule::handleCOMPSEGS( const DeckKeyword& keyword, size_t currentStep, const EclipseGrid& grid) {
const auto& record1 = keyword.getRecord(0);
const std::string& well_name = record1.getItem("WELL").getTrimmedString(0);
auto& well = this->m_wells.get( well_name );
well.handleCOMPSEGS(keyword, currentStep);
well.handleCOMPSEGS(keyword, grid, currentStep);
}
void Schedule::handleWGRUPCON( const DeckKeyword& keyword, size_t currentStep) {
@@ -1382,6 +1386,7 @@ namespace Opm {
const std::string& childName = record.getItem("CHILD_GROUP").getTrimmedString(0);
const std::string& parentName = record.getItem("PARENT_GROUP").getTrimmedString(0);
newTree.update(childName, parentName);
newTree.updateSeqIndex(childName, parentName);
if (!hasGroup(parentName))
addGroup( parentName , currentStep );
@@ -1473,8 +1478,10 @@ namespace Opm {
if (automaticShutInStr == "STOP") {
automaticShutIn = false;
}
Well well(wellName,
const size_t wseqIndex = m_wells.size();
Well well(wellName, wseqIndex,
headI, headJ, refDepth,
preferredPhase, m_timeMap,
timeStep,
@@ -1530,6 +1537,51 @@ namespace Opm {
}
}
std::vector< const Group* > Schedule::getChildGroups(const std::string& group_name, size_t timeStep) const {
if (!hasGroup(group_name))
throw std::invalid_argument("No such group: " + group_name);
{
const auto& group = getGroup( group_name );
std::vector<const Group*> child_groups;
if (group.hasBeenDefined( timeStep )) {
const GroupTree& group_tree = getGroupTree( timeStep );
const auto& ch_grps = group_tree.children( group_name );
//for (const std::string& group_name : ch_grps) {
for ( auto it = ch_grps.begin() ; it != ch_grps.end(); it++) {
child_groups.push_back( &getGroup(*it));
}
}
return child_groups;
}
}
std::vector< const Well* > Schedule::getChildWells(const std::string& group_name, size_t timeStep) const {
if (!hasGroup(group_name))
throw std::invalid_argument("No such group: " + group_name);
{
const auto& group = getGroup( group_name );
std::vector<const Well*> wells;
if (group.hasBeenDefined( timeStep )) {
const GroupTree& group_tree = getGroupTree( timeStep );
const auto& child_groups = group_tree.children( group_name );
if (!child_groups.size()) {
//for (const auto& well_name : group.getWells( timeStep )) {
const auto& ch_wells = group.getWells( timeStep );
for (auto it= ch_wells.begin(); it != ch_wells.end(); it++) {
wells.push_back( getWell( *it ));
}
}
}
return wells;
}
}
std::vector< const Well* > Schedule::getWells(size_t timeStep) const {
if (timeStep >= m_timeMap.size()) {
throw std::invalid_argument("Timestep to large");
@@ -1598,13 +1650,17 @@ namespace Opm {
}
void Schedule::addGroup(const std::string& groupName, size_t timeStep) {
m_groups.insert( groupName, Group { groupName, m_timeMap, timeStep } );
const size_t gseqIndex = m_groups.size();
m_groups.insert( groupName, Group { groupName, gseqIndex, m_timeMap, timeStep } );
m_events.addEvent( ScheduleEvents::NEW_GROUP , timeStep );
}
size_t Schedule::numGroups() const {
return m_groups.size();
}
size_t Schedule::numGroups(size_t timeStep) const {
return this->getGroups( timeStep ).size();
}
bool Schedule::hasGroup(const std::string& groupName) const {
return m_groups.hasKey(groupName);
@@ -1645,6 +1701,25 @@ namespace Opm {
return groups;
}
std::vector< const Group* > Schedule::getGroups(size_t timeStep) const {
if (timeStep >= m_timeMap.size()) {
throw std::invalid_argument("Timestep to large");
}
auto defined = [=]( const Group& g ) {
return g.hasBeenDefined( timeStep );
};
std::vector< const Group* > groups;
for( const auto& group : m_groups ) {
if( !defined( group ) ) continue;
groups.push_back( &group );
}
return groups;
}
void Schedule::addWellToGroup( Group& newGroup, Well& well , size_t timeStep) {
const std::string currentGroupName = well.getGroupName(timeStep);
if (currentGroupName != "") {

View File

@@ -85,8 +85,9 @@ namespace Opm {
{
if (m_timeList.size() < 2)
return 0.0;
const time_t deltaT = m_timeList.back() - m_timeList.front();
return static_cast<double>(deltaT);
return std::difftime(this->m_timeList.back(),
this->m_timeList.front());
}
void TimeMap::addTime(std::time_t newTime) {
@@ -196,19 +197,17 @@ namespace Opm {
double TimeMap::getTimeStepLength(size_t tStepIdx) const
{
assert(tStepIdx < numTimesteps());
const std::time_t t1 = m_timeList[tStepIdx];
const std::time_t t2 = m_timeList[tStepIdx + 1];
const std::time_t deltaT = t2 - t1;
return static_cast<double>(deltaT);
return std::difftime(this->m_timeList[tStepIdx + 1],
this->m_timeList[tStepIdx + 0]);
}
double TimeMap::getTimePassedUntil(size_t tLevelIdx) const
{
assert(tLevelIdx < m_timeList.size());
const std::time_t t1 = m_timeList.front();
const std::time_t t2 = m_timeList[tLevelIdx];
const std::time_t deltaT = t2 - t1;
return static_cast<double>(deltaT);
return std::difftime(this->m_timeList[tLevelIdx],
this->m_timeList.front());
}

View File

@@ -258,7 +258,6 @@ VFPProdTable::VFPProdTable( const DeckKeyword& table, const UnitSystem& deck_uni
//Get actual gas fraction values
m_alq_data = table.getRecord(5).getItem<VFPPROD::ALQ_VALUES>().getData< double >();
convertALQToSI(m_alq_type, m_alq_data, deck_unit_system);
//Finally, read the actual table itself.
size_t nt = m_thp_data.size();
@@ -515,34 +514,4 @@ void VFPProdTable::convertGFRToSI(const GFR_TYPE& type,
scaleValues(values, scaling_factor);
}
void VFPProdTable::convertALQToSI(const ALQ_TYPE& type,
std::vector<double>& values,
const UnitSystem& unit_system) {
double scaling_factor = 1.0;
switch (type) {
case ALQ_GRAT:
scaling_factor = unit_system.parse("GasSurfaceVolume/Time").getSIScaling();
break;
case ALQ_IGLR:
case ALQ_TGLR:
scaling_factor = unit_system.parse("GasSurfaceVolume/LiquidSurfaceVolume").getSIScaling();
break;
case ALQ_PUMP:
case ALQ_COMP:
case ALQ_BEAN:
case ALQ_UNDEF:
break;
default:
throw std::logic_error("Invalid FLO type");
}
scaleValues(values, scaling_factor);
}
} //Namespace opm

View File

@@ -33,13 +33,14 @@
namespace Opm {
Well::Well(const std::string& name_, int headI,
Well::Well(const std::string& name_, const size_t& seqIndex_, int headI,
int headJ, double refDepth , Phase preferredPhase,
const TimeMap& timeMap, size_t creationTimeStep,
WellCompletion::CompletionOrderEnum completionOrdering,
bool allowCrossFlow, bool automaticShutIn)
: m_creationTimeStep( creationTimeStep ),
m_name( name_ ),
m_seqIndex( seqIndex_),
m_status( timeMap, WellCommon::SHUT ),
m_isAvailableForGroupControl( timeMap, true ),
m_guideRate( timeMap, -1.0 ),
@@ -74,6 +75,10 @@ namespace Opm {
return m_name;
}
const size_t& Well::seqIndex() const {
return m_seqIndex;
}
void Well::switchToProducer( size_t timeStep) {
WellInjectionProperties p = getInjectionPropertiesCopy(timeStep);
@@ -376,6 +381,14 @@ namespace Opm {
return *m_completions.back();
}
const std::size_t Well::getTotNoConn() const {
return this->m_totNoConn;
}
void Well::setTotNoConn(std::size_t noConn) {
m_totNoConn = noConn;
}
const std::string Well::getGroupName(size_t time_step) const {
return m_groupName.get(time_step);
}
@@ -676,15 +689,23 @@ namespace Opm {
void Well::handleCOMPDAT(size_t time_step, const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties) {
WellConnections * connections = new WellConnections(this->getConnections(time_step));
connections->loadCOMPDAT(record, grid, eclipseProperties);
std::size_t totNC = 0;
connections->loadCOMPDAT(record, grid, eclipseProperties, totNC);
if (totNC > 0) {
this->setTotNoConn(totNC);
}
this->updateWellConnections(time_step, connections);
}
void Well::handleCOMPSEGS(const DeckKeyword& keyword, size_t time_step) {
void Well::handleCOMPSEGS(const DeckKeyword& keyword, const EclipseGrid& grid, size_t time_step) {
const auto& segment_set = this->getWellSegments(time_step);
const auto& completion_set = this->getConnections( time_step );
WellConnections * new_connection_set = newConnectionsWithSegments(keyword, completion_set, segment_set);
std::size_t totNC = 0;
WellConnections * new_connection_set = newConnectionsWithSegments(keyword, completion_set, segment_set, grid, totNC);
if (totNC > 0) {
this->setTotNoConn(totNC);
}
this->updateWellConnections(time_step, new_connection_set);
}

View File

@@ -20,6 +20,7 @@
#include <cassert>
#include <cmath>
#include <limits>
#include <iostream>
#include <opm/parser/eclipse/Units/Units.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
@@ -137,11 +138,15 @@ namespace {
double Kh,
double rw,
const int satTableId,
const WellCompletion::DirectionEnum direction)
const WellCompletion::DirectionEnum direction,
const std::size_t seqIndex,
const double segDistStart,
const double segDistEnd,
const bool defaultSatTabId)
{
int conn_i = (i < 0) ? this->headI : i;
int conn_j = (j < 0) ? this->headJ : j;
Connection conn(conn_i, conn_j, k, complnum, depth, state, CF, Kh, rw, satTableId, direction);
Connection conn(conn_i, conn_j, k, complnum, depth, state, CF, Kh, rw, satTableId, direction, seqIndex, segDistStart, segDistEnd, defaultSatTabId);
this->add(conn);
}
@@ -154,7 +159,11 @@ namespace {
double Kh,
double rw,
const int satTableId,
const WellCompletion::DirectionEnum direction)
const WellCompletion::DirectionEnum direction,
const std::size_t seqIndex,
const double segDistStart,
const double segDistEnd,
const bool defaultSatTabId)
{
int complnum = -(this->m_connections.size() + 1);
this->addConnection(i,
@@ -167,10 +176,14 @@ namespace {
Kh,
rw,
satTableId,
direction);
direction,
seqIndex,
segDistStart,
segDistEnd,
defaultSatTabId);
}
void WellConnections::loadCOMPDAT(const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties) {
void WellConnections::loadCOMPDAT(const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties, std::size_t& totNC) {
const auto& permx = eclipseProperties.getDoubleGridProperty("PERMX").getData();
const auto& permy = eclipseProperties.getDoubleGridProperty("PERMY").getData();
const auto& permz = eclipseProperties.getDoubleGridProperty("PERMZ").getData();
@@ -272,21 +285,33 @@ namespace {
auto prev = std::find_if( this->m_connections.begin(),
this->m_connections.end(),
same_ijk );
if (prev == this->m_connections.end()) {
this->addConnection(I,J,k,
// Only add connection for active grid cells
if (grid.cellActive(I, J, k)) {
if (prev == this->m_connections.end()) {
std::size_t noConn = this->m_connections.size();
totNC = noConn+1;
this->addConnection(I,J,k,
grid.getCellDepth( I,J,k ),
state,
CF,
Kh,
rw,
satTableId,
direction );
} else {
// The complnum value carries over; the rest of the state is fully specified by
// the current COMPDAT keyword.
int complnum = prev->complnum();
*prev = Connection(I,J,k,
direction,
noConn, 0., 0., defaultSatTable);
}
else {
std::size_t noConn = prev->getSeqIndex();
// The complnum value carries over; the rest of the state is fully specified by
// the current COMPDAT keyword.
int complnum = prev->complnum();
std::size_t css_ind = prev->getCompSegSeqIndex();
int conSegNo = prev->segment();
std::size_t con_SIndex = prev->getSeqIndex();
double conCDepth = prev->depth();
double conSDStart = prev->getSegDistStart();
double conSDEnd = prev->getSegDistEnd();
*prev = Connection(I,J,k,
complnum,
grid.getCellDepth(I,J,k),
state,
@@ -294,14 +319,17 @@ namespace {
Kh,
rw,
satTableId,
direction );
}
}
direction,
noConn, conSDStart, conSDEnd, defaultSatTable);
prev->setCompSegSeqIndex(css_ind);
prev->updateSegment(conSegNo, conCDepth, con_SIndex);
}
}
}
}
size_t WellConnections::size() const {
return m_connections.size();
}

View File

@@ -9,6 +9,15 @@ UNIFIN
DIMENS
10 10 10 /
WELLDIMS
-- Item 1: NWMAX (Maximum number of wells in model)
-- Item 2: NCWMAX (Maximum number of connections per well)
-- Item 3: NGMAX (Maximum number of groups in model--excluding FIELD)
-- Item 4: NWGMAX (Maximum number of wells or child groups per group)
-- NWMAX NCWMAX NGMAX NWGMAX
6 3 1 6
/
GRID
DXV
10*0.25 /

View File

@@ -13,10 +13,18 @@ UNIFIN
DIMENS
10 10 10 /
WELLDIMS
-- Item 1: NWMAX (Maximum number of wells in model)
-- Item 2: NCWMAX (Maximum number of connections per well)
-- Item 3: NGMAX (Maximum number of groups in model--excluding FIELD)
-- Item 4: NWGMAX (Maximum number of wells or child groups per group)
-- NWMAX NCWMAX NGMAX NWGMAX
6 3 1 6
/
EQLDIMS
10 /
GRID
DXV
10*0.25 /

View File

@@ -12,6 +12,15 @@ DIMENS
REGDIMS
10 /
WELLDIMS
-- Item 1: NWMAX (Maximum number of wells in model)
-- Item 2: NCWMAX (Maximum number of connections per well)
-- Item 3: NGMAX (Maximum number of groups in model--excluding FIELD)
-- Item 4: NWGMAX (Maximum number of wells or child groups per group)
-- NWMAX NCWMAX NGMAX NWGMAX
3 2 5 2
/
OIL
GAS
WATER

View File

@@ -69,9 +69,9 @@ BOOST_AUTO_TEST_CASE(CreateWellConnectionsOK) {
BOOST_AUTO_TEST_CASE(AddCompletionSizeCorrect) {
Opm::WellCompletion::DirectionEnum dir = Opm::WellCompletion::DirectionEnum::Z;
Opm::WellConnections completionSet;
Opm::Connection completion1( 10,10,10, 1, 0.0, Opm::WellCompletion::OPEN , 99.88, 355.113, 0.25, 0, dir);
Opm::Connection completion2( 10,10,11, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir);
completionSet.add( completion1 );
Opm::Connection completion1( 10,10,10, 1, 0.0, Opm::WellCompletion::OPEN , 99.88, 355.113, 0.25, 0, dir,0, 0., 0., true);
Opm::Connection completion2( 10,10,11, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir,0, 0., 0., true);
completionSet.add( completion1 );
BOOST_CHECK_EQUAL( 1U , completionSet.size() );
completionSet.add( completion2 );
@@ -83,8 +83,8 @@ completionSet.add( completion1 );
BOOST_AUTO_TEST_CASE(WellConnectionsGetOutOfRangeThrows) {
Opm::WellCompletion::DirectionEnum dir = Opm::WellCompletion::DirectionEnum::Z;
Opm::Connection completion1( 10,10,10, 1, 0.0, Opm::WellCompletion::OPEN , 99.88, 355.113, 0.25, 0, dir);
Opm::Connection completion2( 10,10,11, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir);
Opm::Connection completion1( 10,10,10, 1, 0.0, Opm::WellCompletion::OPEN , 99.88, 355.113, 0.25, 0, dir,0,0., 0., true);
Opm::Connection completion2( 10,10,11, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir,0,0., 0., true);
Opm::WellConnections completionSet;
completionSet.add( completion1 );
BOOST_CHECK_EQUAL( 1U , completionSet.size() );
@@ -103,9 +103,9 @@ BOOST_AUTO_TEST_CASE(AddCompletionCopy) {
Opm::WellConnections completionSet;
Opm::WellCompletion::DirectionEnum dir = Opm::WellCompletion::DirectionEnum::Z;
Opm::Connection completion1( 10,10,10, 1, 0.0, Opm::WellCompletion::OPEN , 99.88, 355.113, 0.25, 0, dir);
Opm::Connection completion2( 10,10,11, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir);
Opm::Connection completion3( 10,10,12, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir);
Opm::Connection completion1( 10,10,10, 1, 0.0, Opm::WellCompletion::OPEN , 99.88, 355.113, 0.25, 0, dir,0,0., 0., true);
Opm::Connection completion2( 10,10,11, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir,0,0., 0., true);
Opm::Connection completion3( 10,10,12, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir,0,0., 0., true);
completionSet.add( completion1 );
completionSet.add( completion2 );
@@ -125,9 +125,9 @@ BOOST_AUTO_TEST_CASE(ActiveCompletions) {
Opm::EclipseGrid grid(10,20,20);
Opm::WellCompletion::DirectionEnum dir = Opm::WellCompletion::DirectionEnum::Z;
Opm::WellConnections completions;
Opm::Connection completion1( 0,0,0, 1, 0.0, Opm::WellCompletion::OPEN , 99.88, 355.113, 0.25, 0, dir);
Opm::Connection completion2( 0,0,1, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir);
Opm::Connection completion3( 0,0,2, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir);
Opm::Connection completion1( 0,0,0, 1, 0.0, Opm::WellCompletion::OPEN , 99.88, 355.113, 0.25, 0, dir,0,0., 0., true);
Opm::Connection completion2( 0,0,1, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir,0,0., 0., true);
Opm::Connection completion3( 0,0,2, 1, 0.0, Opm::WellCompletion::SHUT , 99.88, 355.113, 0.25, 0, dir,0,0., 0., true);
completions.add( completion1 );
completions.add( completion2 );
@@ -151,8 +151,9 @@ Opm::WellConnections loadCOMPDAT(const std::string& compdat_keyword) {
Opm::Eclipse3DProperties props(deck, tables, grid );
const auto& keyword = deck.getKeyword("COMPDAT", 0);
Opm::WellConnections connections;
std::size_t totnc = 0;
for (const auto& rec : keyword)
connections.loadCOMPDAT(rec, grid, props);
connections.loadCOMPDAT(rec, grid, props, totnc);
return connections;
}

View File

@@ -49,14 +49,14 @@ static TimeMap createXDaysTimeMap(size_t numDays) {
BOOST_AUTO_TEST_CASE(CreateGroup_CorrectNameAndDefaultValues) {
auto timeMap = createXDaysTimeMap(10);
Opm::Group group("G1" , timeMap , 0);
Opm::Group group("G1" , 1, timeMap , 0);
BOOST_CHECK_EQUAL( "G1" , group.name() );
}
BOOST_AUTO_TEST_CASE(CreateGroupCreateTimeOK) {
auto timeMap = createXDaysTimeMap(10);
Opm::Group group("G1" , timeMap , 5);
Opm::Group group("G1" , 1, timeMap , 5);
BOOST_CHECK_EQUAL( false, group.hasBeenDefined( 4 ));
BOOST_CHECK_EQUAL( true, group.hasBeenDefined( 5 ));
BOOST_CHECK_EQUAL( true, group.hasBeenDefined( 6 ));
@@ -66,8 +66,8 @@ BOOST_AUTO_TEST_CASE(CreateGroupCreateTimeOK) {
BOOST_AUTO_TEST_CASE(CreateGroup_SetInjectorProducer_CorrectStatusSet) {
auto timeMap = createXDaysTimeMap(10);
Opm::Group group1("IGROUP" , timeMap , 0);
Opm::Group group2("PGROUP" , timeMap , 0);
Opm::Group group1("IGROUP" , 1, timeMap , 0);
Opm::Group group2("PGROUP" , 2, timeMap , 0);
group1.setProductionGroup(0, true);
BOOST_CHECK(group1.isProductionGroup(1));
@@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(CreateGroup_SetInjectorProducer_CorrectStatusSet) {
BOOST_AUTO_TEST_CASE(InjectRateOK) {
auto timeMap = createXDaysTimeMap(10);
Opm::Group group("G1" , timeMap , 0);
Opm::Group group("G1" , 1, timeMap , 0);
BOOST_CHECK_EQUAL( 0 , group.getInjectionRate( 0 ));
group.setInjectionRate( 2 , 100 );
BOOST_CHECK_EQUAL( 100 , group.getInjectionRate( 2 ));
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(InjectRateOK) {
BOOST_AUTO_TEST_CASE(ControlModeOK) {
auto timeMap = createXDaysTimeMap(10);
Opm::Group group("G1" , timeMap , 0);
Opm::Group group("G1" , 1, timeMap , 0);
BOOST_CHECK_EQUAL( Opm::GroupInjection::NONE , group.getInjectionControlMode( 0 ));
group.setInjectionControlMode( 2 , Opm::GroupInjection::RESV );
BOOST_CHECK_EQUAL( Opm::GroupInjection::RESV , group.getInjectionControlMode( 2 ));
@@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE(ControlModeOK) {
BOOST_AUTO_TEST_CASE(GroupChangePhaseSameTimeThrows) {
auto timeMap = createXDaysTimeMap(10);
Opm::Group group("G1" , timeMap , 0);
Opm::Group group("G1" , 1, timeMap , 0);
BOOST_CHECK_EQUAL( Opm::Phase::WATER , group.getInjectionPhase( 0 )); // Default phase - assumed WATER
group.setInjectionPhase( 5, Opm::Phase::WATER );
group.setInjectionPhase( 5, Opm::Phase::WATER );
@@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(GroupChangePhaseSameTimeThrows) {
BOOST_AUTO_TEST_CASE(GroupMiscInjection) {
auto timeMap = createXDaysTimeMap(10);
Opm::Group group("G1" , timeMap , 0);
Opm::Group group("G1" , 1, timeMap , 0);
group.setSurfaceMaxRate( 3 , 100 );
BOOST_CHECK_EQUAL( 100 , group.getSurfaceMaxRate( 5 ));
@@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(GroupMiscInjection) {
BOOST_AUTO_TEST_CASE(GroupDoesNotHaveWell) {
auto timeMap = createXDaysTimeMap(10);
Opm::Group group("G1" , timeMap , 0);
Opm::Group group("G1" , 1, timeMap , 0);
BOOST_CHECK_EQUAL(false , group.hasWell("NO", 2));
BOOST_CHECK_EQUAL(0U , group.numWells(2));
@@ -155,9 +155,9 @@ BOOST_AUTO_TEST_CASE(GroupDoesNotHaveWell) {
BOOST_AUTO_TEST_CASE(GroupAddWell) {
auto timeMap = createXDaysTimeMap( 10 );
Opm::Group group("G1" , timeMap , 0);
auto well1 = std::make_shared< Well >("WELL1", 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
auto well2 = std::make_shared< Well >("WELL2", 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
Opm::Group group("G1" , 1, timeMap , 0);
auto well1 = std::make_shared< Well >("WELL1", 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
auto well2 = std::make_shared< Well >("WELL2", 2, 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
BOOST_CHECK_EQUAL(0U , group.numWells(2));
group.addWell( 3 , well1.get() );
@@ -192,9 +192,9 @@ BOOST_AUTO_TEST_CASE(GroupAddWell) {
BOOST_AUTO_TEST_CASE(GroupAddAndDelWell) {
auto timeMap = createXDaysTimeMap( 10 );
Opm::Group group("G1" , timeMap , 0);
auto well1 = std::make_shared< Well >("WELL1", 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
auto well2 = std::make_shared< Well >("WELL2", 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
Opm::Group group("G1" , 1, timeMap , 0);
auto well1 = std::make_shared< Well >("WELL1", 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
auto well2 = std::make_shared< Well >("WELL2", 2, 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
BOOST_CHECK_EQUAL(0U , group.numWells(2));
group.addWell( 3 , well1.get() );
@@ -225,9 +225,9 @@ BOOST_AUTO_TEST_CASE(GroupAddAndDelWell) {
BOOST_AUTO_TEST_CASE(getWells) {
auto timeMap = createXDaysTimeMap( 10 );
Opm::Group group("G1" , timeMap , 0);
auto well1 = std::make_shared< Well >("WELL1", 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
auto well2 = std::make_shared< Well >("WELL2", 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
Opm::Group group("G1" , 1, timeMap , 0);
auto well1 = std::make_shared< Well >("WELL1", 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
auto well2 = std::make_shared< Well >("WELL2", 2, 0, 0, 0.0, Opm::Phase::OIL, timeMap, 0);
group.addWell( 2 , well1.get() );
group.addWell( 3 , well1.get() );

View File

@@ -44,14 +44,15 @@
BOOST_AUTO_TEST_CASE(MultisegmentWellTest) {
Opm::WellCompletion::DirectionEnum dir = Opm::WellCompletion::DirectionEnum::Z;
Opm::WellConnections connection_set;
connection_set.add(Opm::Connection( 19, 0, 0, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, dir) );
connection_set.add(Opm::Connection( 19, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, dir) );
connection_set.add(Opm::Connection( 19, 0, 2, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, dir) );
Opm::EclipseGrid grid(20,20,20);
connection_set.add(Opm::Connection( 19, 0, 0, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, dir,0, 0., 0., true) );
connection_set.add(Opm::Connection( 19, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, dir,0, 0., 0., true) );
connection_set.add(Opm::Connection( 19, 0, 2, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, dir,0, 0., 0., true) );
connection_set.add(Opm::Connection( 18, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, Opm::WellCompletion::DirectionEnum::X) );
connection_set.add(Opm::Connection( 17, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, Opm::WellCompletion::DirectionEnum::X) );
connection_set.add(Opm::Connection( 16, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, Opm::WellCompletion::DirectionEnum::X) );
connection_set.add(Opm::Connection( 15, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, Opm::WellCompletion::DirectionEnum::X) );
connection_set.add(Opm::Connection( 18, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, Opm::WellCompletion::DirectionEnum::X,0, 0., 0., true) );
connection_set.add(Opm::Connection( 17, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, Opm::WellCompletion::DirectionEnum::X,0, 0., 0., true) );
connection_set.add(Opm::Connection( 16, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, Opm::WellCompletion::DirectionEnum::X,0, 0., 0., true) );
connection_set.add(Opm::Connection( 15, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , 200, 17.29, 0.25, 0, Opm::WellCompletion::DirectionEnum::X,0, 0., 0., true) );
BOOST_CHECK_EQUAL( 7U , connection_set.size() );
@@ -87,8 +88,8 @@ BOOST_AUTO_TEST_CASE(MultisegmentWellTest) {
segment_set.loadWELSEGS(welsegs);
BOOST_CHECK_EQUAL(6U, segment_set.size());
const Opm::WellConnections * new_connection_set = Opm::newConnectionsWithSegments(compsegs, connection_set, segment_set);
std::size_t totNC = 0;
const Opm::WellConnections * new_connection_set = Opm::newConnectionsWithSegments(compsegs, connection_set, segment_set, grid, totNC);
BOOST_CHECK_EQUAL(7U, new_connection_set->size());

View File

@@ -712,4 +712,4 @@ BOOST_AUTO_TEST_CASE( test_invalid_wtemplate_config ) {
BOOST_CHECK_THROW( Schedule( deckUnSupported , grid , eclipseProperties, Phases(true, true, true) , parseContext), std::invalid_argument );
}
}
}

View File

@@ -63,7 +63,7 @@ inline std::ostream& operator<<( std::ostream& stream, const Well& well ) {
BOOST_AUTO_TEST_CASE(CreateWell_CorrectNameAndDefaultValues) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
BOOST_CHECK_EQUAL( "WELL1" , well.name() );
BOOST_CHECK_EQUAL(0.0 , well.getProductionPropertiesCopy(5).OilRate);
}
@@ -71,10 +71,10 @@ BOOST_AUTO_TEST_CASE(CreateWell_CorrectNameAndDefaultValues) {
BOOST_AUTO_TEST_CASE(CreateWell_Equals) {
auto timeMap = createXDaysTimeMap(10);
auto timeMap2 = createXDaysTimeMap(11);
Opm::Well well1("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well2("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well3("WELL3" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well4("WELL3" , 0, 0, 0.0, Opm::Phase::OIL, timeMap2 , 0);
Opm::Well well1("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well2("WELL1" , 2, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well3("WELL3" , 3, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well4("WELL3" , 4, 0, 0, 0.0, Opm::Phase::OIL, timeMap2 , 0);
BOOST_CHECK_EQUAL( well1, well1 );
BOOST_CHECK_EQUAL( well2, well1 );
BOOST_CHECK( well1 == well2 );
@@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(CreateWell_Equals) {
BOOST_AUTO_TEST_CASE(CreateWell_GetProductionPropertiesShouldReturnSameObject) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
BOOST_CHECK_EQUAL(&(well.getProductionProperties(5)), &(well.getProductionProperties(5)));
BOOST_CHECK_EQUAL(&(well.getProductionProperties(8)), &(well.getProductionProperties(8)));
@@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(CreateWell_GetProductionPropertiesShouldReturnSameObject) {
BOOST_AUTO_TEST_CASE(CreateWell_GetInjectionPropertiesShouldReturnSameObject) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
BOOST_CHECK_EQUAL(&(well.getInjectionProperties(5)), &(well.getInjectionProperties(5)));
BOOST_CHECK_EQUAL(&(well.getInjectionProperties(8)), &(well.getInjectionProperties(8)));
@@ -105,7 +105,7 @@ BOOST_AUTO_TEST_CASE(CreateWell_GetInjectionPropertiesShouldReturnSameObject) {
BOOST_AUTO_TEST_CASE(CreateWellCreateTimeStepOK) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 5);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 5);
BOOST_CHECK_EQUAL( false , well.hasBeenDefined(0) );
BOOST_CHECK_EQUAL( false , well.hasBeenDefined(4) );
BOOST_CHECK_EQUAL( true , well.hasBeenDefined(5) );
@@ -116,7 +116,7 @@ BOOST_AUTO_TEST_CASE(CreateWellCreateTimeStepOK) {
BOOST_AUTO_TEST_CASE(setWellProductionProperties_PropertiesSetCorrect) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
BOOST_CHECK_EQUAL(0.0 , well.getProductionPropertiesCopy( 5 ).OilRate);
Opm::WellProductionProperties props;
@@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(setWellProductionProperties_PropertiesSetCorrect) {
BOOST_AUTO_TEST_CASE(setOilRate_RateSetCorrect) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
BOOST_CHECK_EQUAL(0.0 , well.getProductionPropertiesCopy(5).OilRate);
Opm::WellProductionProperties props;
@@ -161,7 +161,7 @@ BOOST_AUTO_TEST_CASE(setOilRate_RateSetCorrect) {
BOOST_AUTO_TEST_CASE(seLiquidRate_RateSetCorrect) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
BOOST_CHECK_EQUAL(0.0 , well.getProductionPropertiesCopy(5).LiquidRate);
Opm::WellProductionProperties props;
@@ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(seLiquidRate_RateSetCorrect) {
BOOST_AUTO_TEST_CASE(setPredictionModeProduction_ModeSetCorrect) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
BOOST_CHECK_EQUAL( true, well.getProductionPropertiesCopy(5).predictionMode);
Opm::WellProductionProperties props;
@@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(setPredictionModeProduction_ModeSetCorrect) {
BOOST_AUTO_TEST_CASE(setpredictionModeInjection_ModeSetCorrect) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
BOOST_CHECK_EQUAL( true, well.getInjectionPropertiesCopy(5).predictionMode);
Opm::WellInjectionProperties props;
@@ -333,28 +333,13 @@ BOOST_AUTO_TEST_CASE(WellCOMPDATtestINPUT) {
BOOST_AUTO_TEST_CASE(NewWellZeroCompletions) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap , 0);
BOOST_CHECK_EQUAL( 0U , well.getConnections( 0 ).size() );
}
// Helper function for CompletionOrder test.
inline Opm::Connection connection( int i, int j, int k, int complnum = 1 ) {
return Opm::Connection { i, j, k,
complnum,
k*1.0,
Opm::WellCompletion::AUTO,
99.88,
17.29,
0.25,
0,
Opm::WellCompletion::DirectionEnum::Z };
}
BOOST_AUTO_TEST_CASE(setGasRate_RateSetCorrect) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::GAS, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::GAS, timeMap , 0);
BOOST_CHECK_EQUAL(0.0 , well.getProductionPropertiesCopy(5).GasRate);
Opm::WellProductionProperties properties;
@@ -368,7 +353,7 @@ BOOST_AUTO_TEST_CASE(setGasRate_RateSetCorrect) {
BOOST_AUTO_TEST_CASE(setWaterRate_RateSetCorrect) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
BOOST_CHECK_EQUAL(0.0 , well.getProductionPropertiesCopy(5).WaterRate);
Opm::WellProductionProperties properties;
@@ -381,7 +366,7 @@ BOOST_AUTO_TEST_CASE(setWaterRate_RateSetCorrect) {
BOOST_AUTO_TEST_CASE(setSurfaceInjectionRate_RateSetCorrect) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
BOOST_CHECK_EQUAL(0.0 , well.getInjectionPropertiesCopy(5).surfaceInjectionRate);
Opm::WellInjectionProperties props(well.getInjectionPropertiesCopy(5));
@@ -400,7 +385,7 @@ BOOST_AUTO_TEST_CASE(setSurfaceInjectionRate_RateSetCorrect) {
BOOST_AUTO_TEST_CASE(setReservoirInjectionRate_RateSetCorrect) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::WATER, timeMap , 0);
BOOST_CHECK_EQUAL(0.0 , well.getInjectionPropertiesCopy(5).reservoirInjectionRate);
Opm::WellInjectionProperties properties(well.getInjectionPropertiesCopy(5));
@@ -415,7 +400,7 @@ BOOST_AUTO_TEST_CASE(isProducerCorrectlySet) {
// HACK: This test checks correctly setting of isProducer/isInjector. This property depends on which of
// WellProductionProperties/WellInjectionProperties is set last, independent of actual values.
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::OIL, timeMap ,0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::OIL, timeMap ,0);
/* 1: Well is created as producer */
BOOST_CHECK_EQUAL( false , well.isInjector(0));
@@ -471,7 +456,7 @@ BOOST_AUTO_TEST_CASE(isProducerCorrectlySet) {
BOOST_AUTO_TEST_CASE(GroupnameCorretlySet) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1" , 0, 0, 0.0, Opm::Phase::WATER, timeMap ,0);
Opm::Well well("WELL1" , 1, 0, 0, 0.0, Opm::Phase::WATER, timeMap ,0);
BOOST_CHECK_EQUAL("" , well.getGroupName(2));
@@ -485,7 +470,7 @@ BOOST_AUTO_TEST_CASE(GroupnameCorretlySet) {
BOOST_AUTO_TEST_CASE(addWELSPECS_setData_dataSet) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1", 23, 42, 2334.32, Opm::Phase::WATER, timeMap, 3);
Opm::Well well("WELL1", 1, 23, 42, 2334.32, Opm::Phase::WATER, timeMap, 3);
BOOST_CHECK(!well.hasBeenDefined(2));
BOOST_CHECK(well.hasBeenDefined(3));
@@ -498,7 +483,7 @@ BOOST_AUTO_TEST_CASE(addWELSPECS_setData_dataSet) {
BOOST_AUTO_TEST_CASE(XHPLimitDefault) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1", 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::Well well("WELL1", 1, 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::WellProductionProperties productionProps(well.getProductionPropertiesCopy(1));
@@ -519,7 +504,7 @@ BOOST_AUTO_TEST_CASE(XHPLimitDefault) {
BOOST_AUTO_TEST_CASE(InjectorType) {
auto timeMap = createXDaysTimeMap(10);
Opm::Well well("WELL1", 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::Well well("WELL1", 1, 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::WellInjectionProperties injectionProps(well.getInjectionPropertiesCopy(1));
injectionProps.injectorType = Opm::WellInjector::WATER;
@@ -531,15 +516,13 @@ BOOST_AUTO_TEST_CASE(InjectorType) {
/*****************************************************************/
BOOST_AUTO_TEST_CASE(WellHaveProductionControlLimit) {
auto timeMap = createXDaysTimeMap(20);
Opm::Well well("WELL1", 1, 2, 2334.32, Opm::Phase::OIL, timeMap, 0);
Opm::Well well("WELL1", 1, 1, 2, 2334.32, Opm::Phase::OIL, timeMap, 0);
BOOST_CHECK( !well.getProductionPropertiesCopy(1).hasProductionControl( Opm::WellProducer::ORAT ));
@@ -589,7 +572,7 @@ BOOST_AUTO_TEST_CASE(WellHaveProductionControlLimit) {
BOOST_AUTO_TEST_CASE(WellHaveInjectionControlLimit) {
auto timeMap = createXDaysTimeMap(20);
Opm::Well well("WELL1", 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::Well well("WELL1", 1, 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
BOOST_CHECK( !well.getInjectionPropertiesCopy(1).hasInjectionControl( Opm::WellInjector::RATE ));
BOOST_CHECK( !well.getInjectionPropertiesCopy(1).hasInjectionControl( Opm::WellInjector::RESV ));
@@ -633,7 +616,7 @@ BOOST_AUTO_TEST_CASE(WellHaveInjectionControlLimit) {
BOOST_AUTO_TEST_CASE(WellSetAvailableForGroupControl_ControlSet) {
auto timeMap = createXDaysTimeMap(20);
Opm::Well well("WELL1", 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::Well well("WELL1", 1, 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
BOOST_CHECK(well.isAvailableForGroupControl(10));
well.setAvailableForGroupControl(12, false);
@@ -644,7 +627,7 @@ BOOST_AUTO_TEST_CASE(WellSetAvailableForGroupControl_ControlSet) {
BOOST_AUTO_TEST_CASE(WellSetGuideRate_GuideRateSet) {
auto timeMap = createXDaysTimeMap(20);
Opm::Well well("WELL1", 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::Well well("WELL1", 1, 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
BOOST_CHECK_LT(well.getGuideRate(0), 0);
well.setGuideRate(1, 32.2);
@@ -654,7 +637,7 @@ BOOST_AUTO_TEST_CASE(WellSetGuideRate_GuideRateSet) {
BOOST_AUTO_TEST_CASE(WellGuideRatePhase_GuideRatePhaseSet) {
auto timeMap = createXDaysTimeMap(20);
Opm::Well well("WELL1", 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::Well well("WELL1", 1, 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
BOOST_CHECK_EQUAL(Opm::GuideRate::UNDEFINED, well.getGuideRatePhase(0));
well.setGuideRatePhase(3, Opm::GuideRate::RAT);
BOOST_CHECK_EQUAL(Opm::GuideRate::UNDEFINED, well.getGuideRatePhase(2));
@@ -663,7 +646,7 @@ BOOST_AUTO_TEST_CASE(WellGuideRatePhase_GuideRatePhaseSet) {
BOOST_AUTO_TEST_CASE(WellEfficiencyFactorSet) {
auto timeMap = createXDaysTimeMap(20);
Opm::Well well("WELL1", 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::Well well("WELL1", 1, 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
BOOST_CHECK_EQUAL(1.0, well.getEfficiencyFactor(0));
well.setEfficiencyFactor(3, 0.9);
BOOST_CHECK_EQUAL(1.0, well.getEfficiencyFactor(0));
@@ -672,7 +655,7 @@ BOOST_AUTO_TEST_CASE(WellEfficiencyFactorSet) {
BOOST_AUTO_TEST_CASE(WellSetScalingFactor_ScalingFactorSetSet) {
auto timeMap = createXDaysTimeMap(20);
Opm::Well well("WELL1", 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
Opm::Well well("WELL1", 1, 1, 2, 2334.32, Opm::Phase::WATER, timeMap, 0);
BOOST_CHECK_EQUAL(1.0, well.getGuideRateScalingFactor(0));
well.setGuideRateScalingFactor(4, 0.6);
BOOST_CHECK_EQUAL(1.0, well.getGuideRateScalingFactor(3));

View File

@@ -17,6 +17,15 @@ DIMENS
REGDIMS
10 /
WELLDIMS
-- Item 1: NWMAX (Maximum number of wells in model)
-- Item 2: NCWMAX (Maximum number of connections per well)
-- Item 3: NGMAX (Maximum number of groups in model--excluding FIELD)
-- Item 4: NWGMAX (Maximum number of wells or child groups per group)
-- NWMAX NCWMAX NGMAX NWGMAX
5 2 3 2
/
OIL
GAS
WATER

View File

@@ -21,6 +21,15 @@ OIL
GAS
WATER
WELLDIMS
-- Item 1: NWMAX (Maximum number of wells in model)
-- Item 2: NCWMAX (Maximum number of connections per well)
-- Item 3: NGMAX (Maximum number of groups in model--excluding FIELD)
-- Item 4: NWGMAX (Maximum number of wells or child groups per group)
-- NWMAX NCWMAX NGMAX NWGMAX
4 2 3 2
/
GRID
DX

View File

@@ -370,9 +370,10 @@ BOOST_AUTO_TEST_CASE (Declared_Well_Data)
BOOST_CHECK_EQUAL(ih.nwells, MockIH::Sz{2});
const auto smry = sim_state();
auto awd = Opm::RestartIO::Helpers::AggregateWellData{ih.value};
awd.captureDeclaredWellData(simCase.sched,
simCase.es.getUnits(), rptStep);
simCase.es.getUnits(), rptStep, smry, ih.value);
// IWEL (OP_1)
{
@@ -427,15 +428,24 @@ BOOST_AUTO_TEST_CASE (Declared_Well_Data)
const auto i0 = 0*ih.nswelz;
const auto& swell = awd.getSWell();
BOOST_CHECK_CLOSE(swell[i0 + Ix::OilRateTarget] , 20.0e3f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::WatRateTarget] , 1.0e20f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::GasRateTarget] , 1.0e20f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::LiqRateTarget] , 1.0e20f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::ResVRateTarget], 1.0e20f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::THPTarget] , 1.0e20f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::BHPTarget] , 1000.0f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::OilRateTarget], 20.0e3f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::DatumDepth] , 0.375f, 1.0e-7f);
// No WRAT limit
BOOST_CHECK_CLOSE(swell[i0 + Ix::WatRateTarget], 1.0e20f, 1.0e-7f);
// No GRAT limit
BOOST_CHECK_CLOSE(swell[i0 + Ix::GasRateTarget], 1.0e20f, 1.0e-7f);
// LRAT limit derived from ORAT + WRAT (= ORAT + 0.0)
BOOST_CHECK_CLOSE(swell[i0 + Ix::LiqRateTarget], 20.0e3f, 1.0e-7f);
// No direct limit, extract value from 'smry' (WVPR:OP_1)
BOOST_CHECK_CLOSE(swell[i0 + Ix::ResVRateTarget], 4.0f, 1.0e-7f);
// No THP limit
BOOST_CHECK_CLOSE(swell[i0 + Ix::THPTarget] , 1.0e20f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::BHPTarget] , 1000.0f, 1.0e-7f);
BOOST_CHECK_CLOSE(swell[i0 + Ix::DatumDepth], 0.375f, 1.0e-7f);
}
// SWEL (OP_2)
@@ -513,7 +523,7 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step1)
const auto smry = sim_state();
auto awd = Opm::RestartIO::Helpers::AggregateWellData{ih.value};
awd.captureDynamicWellData(simCase.sched, rptStep, xw, smry);
awd.captureDynamicWellData(simCase.sched, rptStep, true, xw, smry);
// IWEL (OP_1)
{
@@ -609,7 +619,7 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step2)
const auto smry = sim_state();
auto awd = Opm::RestartIO::Helpers::AggregateWellData{ih.value};
awd.captureDynamicWellData(simCase.sched, rptStep, xw, smry);
awd.captureDynamicWellData(simCase.sched, rptStep, true, xw, smry);
// IWEL (OP_1) -- closed producer
{

View File

@@ -328,8 +328,8 @@ BOOST_AUTO_TEST_CASE(Time_and_report_step)
const auto& v = ih.data();
BOOST_CHECK_EQUAL(v[67], 12); // TSTEP
BOOST_CHECK_EQUAL(v[68], 2); // REP_STEP
BOOST_CHECK_EQUAL(v[67], 12); // TSTEP
BOOST_CHECK_EQUAL(v[68], 2 + 1); // REP_STEP (= sim_step + 1)
}
BOOST_AUTO_TEST_CASE(Tuning_param)
@@ -415,6 +415,17 @@ BOOST_AUTO_TEST_CASE(regionDimensions)
BOOST_CHECK_EQUAL(v[99], nmfipr); // NMFIPR
}
BOOST_AUTO_TEST_CASE(ngroups)
{
const auto ngroup = 8;
const auto ih = Opm::RestartIO::InteHEAD{}
.ngroups({ ngroup });
const auto& v = ih.data();
BOOST_CHECK_EQUAL(v[18], ngroup); // NGRP
}
BOOST_AUTO_TEST_CASE(SimulationDate)
{
const auto input = std::string { R"(

View File

@@ -39,18 +39,7 @@ BOOST_AUTO_TEST_CASE(Radial_Settings_and_Init)
BOOST_CHECK_EQUAL(v[ 1], true); //
BOOST_CHECK_EQUAL(v[ 3], false); // E300 Radial
BOOST_CHECK_EQUAL(v[ 4], true); // E100 Radial
BOOST_CHECK_EQUAL(v[ 16], true); //
BOOST_CHECK_EQUAL(v[ 18], true); //
BOOST_CHECK_EQUAL(v[ 31], true); //
BOOST_CHECK_EQUAL(v[ 44], true); //
BOOST_CHECK_EQUAL(v[ 75], true); // MS Well Simulation Case
BOOST_CHECK_EQUAL(v[ 76], true); //
BOOST_CHECK_EQUAL(v[ 87], true); //
BOOST_CHECK_EQUAL(v[ 99], true); //
BOOST_CHECK_EQUAL(v[113], true); //
BOOST_CHECK_EQUAL(v[114], true); //
BOOST_CHECK_EQUAL(v[115], true); //
BOOST_CHECK_EQUAL(v[117], true); //
BOOST_CHECK_EQUAL(v[ 75], true); // MS Well Simulation Case
}
BOOST_AUTO_TEST_SUITE_END()

View File

@@ -346,6 +346,66 @@ data::Solution mkSolution( int numCells ) {
return sol;
}
Opm::SummaryState sim_state()
{
auto state = Opm::SummaryState{};
state.add("WOPR:OP_1" , 1.0);
state.add("WWPR:OP_1" , 2.0);
state.add("WGPR:OP_1" , 3.0);
state.add("WVPR:OP_1" , 4.0);
state.add("WOPT:OP_1" , 10.0);
state.add("WWPT:OP_1" , 20.0);
state.add("WGPT:OP_1" , 30.0);
state.add("WVPT:OP_1" , 40.0);
state.add("WWIR:OP_1" , 0.0);
state.add("WGIR:OP_1" , 0.0);
state.add("WWIT:OP_1" , 0.0);
state.add("WGIT:OP_1" , 0.0);
state.add("WWCT:OP_1" , 0.625);
state.add("WGOR:OP_1" , 234.5);
state.add("WBHP:OP_1" , 314.15);
state.add("WGVIR:OP_1", 0.0);
state.add("WWVIR:OP_1", 0.0);
state.add("WOPR:OP_2" , 0.0);
state.add("WWPR:OP_2" , 0.0);
state.add("WGPR:OP_2" , 0.0);
state.add("WVPR:OP_2" , 0.0);
state.add("WOPT:OP_2" , 0.0);
state.add("WWPT:OP_2" , 0.0);
state.add("WGPT:OP_2" , 0.0);
state.add("WVPT:OP_2" , 0.0);
state.add("WWIR:OP_2" , 100.0);
state.add("WGIR:OP_2" , 200.0);
state.add("WWIT:OP_2" , 1000.0);
state.add("WGIT:OP_2" , 2000.0);
state.add("WWCT:OP_2" , 0.0);
state.add("WGOR:OP_2" , 0.0);
state.add("WBHP:OP_2" , 400.6);
state.add("WGVIR:OP_2", 1234.0);
state.add("WWVIR:OP_2", 4321.0);
state.add("WOPR:OP_3" , 11.0);
state.add("WWPR:OP_3" , 12.0);
state.add("WGPR:OP_3" , 13.0);
state.add("WVPR:OP_3" , 14.0);
state.add("WOPT:OP_3" , 110.0);
state.add("WWPT:OP_3" , 120.0);
state.add("WGPT:OP_3" , 130.0);
state.add("WVPT:OP_3" , 140.0);
state.add("WWIR:OP_3" , 0.0);
state.add("WGIR:OP_3" , 0.0);
state.add("WWIT:OP_3" , 0.0);
state.add("WGIT:OP_3" , 0.0);
state.add("WWCT:OP_3" , 0.0625);
state.add("WGOR:OP_3" , 1234.5);
state.add("WBHP:OP_3" , 314.15);
state.add("WGVIR:OP_3", 0.0);
state.add("WWVIR:OP_3", 43.21);
return state;
}
RestartValue first_sim(const EclipseState& es, EclipseIO& eclWriter, bool write_double) {
const auto& grid = es.getInputGrid();
@@ -362,7 +422,7 @@ RestartValue first_sim(const EclipseState& es, EclipseIO& eclWriter, bool write_
false,
first_step - start_time,
restart_value,
{}, {}, {}, write_double);
{}, {}, {}, write_double);
return restart_value;
}
@@ -443,6 +503,7 @@ BOOST_AUTO_TEST_CASE(ECL_FORMATTED) {
auto num_cells = setup.grid.getNumActive( );
auto cells = mkSolution( num_cells );
auto wells = mkWells();
auto sumState = sim_state();
{
RestartValue restart_value(cells, wells);
@@ -454,6 +515,7 @@ BOOST_AUTO_TEST_CASE(ECL_FORMATTED) {
setup.es,
setup.grid,
setup.schedule,
sumState,
true);
{
@@ -472,6 +534,7 @@ BOOST_AUTO_TEST_CASE(ECL_FORMATTED) {
setup.es,
setup.grid,
setup.schedule,
sumState,
true);
{
ecl_file_type * rst_file = ecl_file_open( "ECL_FILE.UNRST" , 0 );
@@ -540,13 +603,15 @@ BOOST_AUTO_TEST_CASE(WriteWrongSOlutionSize) {
auto num_cells = setup.grid.getNumActive( ) + 1;
auto cells = mkSolution( num_cells );
auto wells = mkWells();
Opm::SummaryState sumState;
BOOST_CHECK_THROW( RestartIO::save("FILE.UNRST", 1 ,
100,
RestartValue(cells, wells),
setup.es,
setup.grid ,
setup.schedule),
setup.schedule,
sumState),
std::runtime_error);
}
test_work_area_free(test_area);
@@ -583,14 +648,17 @@ BOOST_AUTO_TEST_CASE(ExtraData_content) {
const auto& units = setup.es.getUnits();
{
RestartValue restart_value(cells, wells);
const auto sumState = sim_state();
restart_value.addExtra("EXTRA", UnitSystem::measure::pressure, {10,1,2,3});
RestartIO::save("FILE.UNRST", 1 ,
100,
restart_value,
setup.es,
setup.grid,
setup.schedule);
setup.schedule,
sumState);
{
ecl_file_type * f = ecl_file_open( "FILE.UNRST" , 0 );
@@ -600,8 +668,8 @@ BOOST_AUTO_TEST_CASE(ExtraData_content) {
BOOST_CHECK_EQUAL( ecl_kw_get_header( ex) , "EXTRA" );
BOOST_CHECK_EQUAL( 4 , ecl_kw_get_size( ex ));
BOOST_CHECK_CLOSE( 10 , units.to_si( UnitSystem::measure::pressure, ecl_kw_iget_double( ex, 0 )), 0.00001);
BOOST_CHECK_CLOSE( units.from_si( UnitSystem::measure::pressure, 3) , ecl_kw_iget_double( ex, 3 ), 0.00001);
BOOST_CHECK_CLOSE( 10 , units.to_si( UnitSystem::measure::pressure, ecl_kw_iget_double( ex, 0 )), 0.00001);
BOOST_CHECK_CLOSE( units.from_si( UnitSystem::measure::pressure, 3), ecl_kw_iget_double( ex, 3 ), 0.00001);
}
ecl_file_close( f );
}
@@ -609,11 +677,17 @@ BOOST_AUTO_TEST_CASE(ExtraData_content) {
BOOST_CHECK_THROW( RestartIO::load( "FILE.UNRST" , 1 , {}, setup.es, setup.grid , setup.schedule,
{{"NOT-THIS", UnitSystem::measure::identity, true}}) , std::runtime_error );
{
const auto rst_value = RestartIO::load( "FILE.UNRST" , 1 , { RestartKey("SWAT", UnitSystem::measure::identity),
RestartKey("NO", UnitSystem::measure::identity, false)},
setup.es, setup.grid , setup.schedule,
{{"EXTRA", UnitSystem::measure::pressure, true},
{"EXTRA2", UnitSystem::measure::identity, false}});
const auto rst_value = RestartIO::load(
"FILE.UNRST" , 1 ,
/* solution_keys = */ {
RestartKey("SWAT", UnitSystem::measure::identity),
RestartKey("NO" , UnitSystem::measure::identity, false)
},
setup.es, setup.grid , setup.schedule,
/* extra_keys = */ {
{"EXTRA" , UnitSystem::measure::pressure, true} ,
{"EXTRA2", UnitSystem::measure::identity, false}
});
BOOST_CHECK(!rst_value.hasExtra("EXTRA2"));
BOOST_CHECK( rst_value.hasExtra("EXTRA"));
@@ -656,13 +730,16 @@ BOOST_AUTO_TEST_CASE(STORE_THPRES) {
*/
restart_value.addExtra("THRESHPR", UnitSystem::measure::pressure, {0,1});
const auto sumState = sim_state();
/* THPRES data has wrong size in extra container. */
BOOST_CHECK_THROW( RestartIO::save("FILE.UNRST", 1 ,
100,
restart_value,
setup.es,
setup.grid,
setup.schedule), std::runtime_error);
setup.schedule,
sumState), std::runtime_error);
int num_regions = setup.es.getTableManager().getEqldims().getNumEquilRegions();
std::vector<double> thpres(num_regions * num_regions, 78);
@@ -674,7 +751,7 @@ BOOST_AUTO_TEST_CASE(STORE_THPRES) {
restart_value2,
setup.es,
setup.grid,
setup.schedule);
setup.schedule, sumState);
{
ecl_file_type * rst_file = ecl_file_open("FILE2.UNRST", 0);

View File

@@ -19,6 +19,10 @@
#include <config.h>
#include <iostream> // @@
#include <algorithm> // @@
#include <iterator> // @@
#define BOOST_TEST_MODULE serialize_ICON_TEST
#include <boost/test/unit_test.hpp>
@@ -84,6 +88,11 @@ BOOST_AUTO_TEST_CASE( serialize_icon_test )
}
w_offset += (ICONZ * ncwmax);
}
}
};
std::copy(icondata.begin(),
icondata.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
BOOST_CHECK_EQUAL(1, 1);// @@@
}
}

View File

@@ -17,6 +17,15 @@ METRIC
DIMENS
10 10 10 /
WELLDIMS
-- Item 1: NWMAX (Maximum number of wells in model)
-- Item 2: NCWMAX (Maximum number of connections per well)
-- Item 3: NGMAX (Maximum number of groups in model--excluding FIELD)
-- Item 4: NWGMAX (Maximum number of wells or child groups per group)
-- NWMAX NCWMAX NGMAX NWGMAX
9 10 2 6
/
GRID
DXV
10*10 /