Compare commits

..

219 Commits

Author SHA1 Message Date
Atgeirr Flø Rasmussen
ef3ef3142a Merge pull request #465 from joakim-hove/opm-pack
Add application opmpack to load a deck and dump it again as one stream
2018-08-01 08:16:03 +02:00
Joakim Hove
9c6a0cc5d9 Add application opmpack to load a deck and dump it again as one stream 2018-07-31 15:05:34 +02:00
Markus Blatt
6d58f519fd Merge pull request #459 from blattms/search-deps-in-prereqs
Search for the prerequisites from package configuration file.
2018-07-16 14:32:23 +02:00
Markus Blatt
4a5333887b Research for software if we search for COMPONENTS.
Otherwise we will never search for e.g. Boost multiple
times and the upmost module in the hierarchy will dictate
the components to be used. That does not work for downstream
modules.

Therefore with this change we check whether there is an argument
COMPONENTS passed to find_package and make sure there will be
another call to it if that is the case.
2018-07-13 16:10:32 +02:00
Markus Blatt
760d0d70b4 Export ENABLE_ECL_INPUT as it is used in opm-common-prereq.cmake 2018-07-12 12:25:21 +02:00
Markus Blatt
563c053d3a Set only ecl_LIBRARIES and nothing else for ecl. 2018-07-12 12:25:21 +02:00
Markus Blatt
cbd44ff67a Remove unneeded opm_common_processed variable.
As we now process the prerequisites in the package configuration file
one search for opm-common is fully sufficient.
2018-07-12 12:25:21 +02:00
Markus Blatt
32dabd6572 Handle prerequisites at the end of package configuration file.
The code in @opm-project_NAME@-prereqs uses macros from OpmPackage.cmake. At
the previous location that file was not yet included for the module opm-common
as this is done in the section @OPM_PROJECT_EXTRA_CODE@, which also sets
CMAKE_MODULE_PATH.
2018-07-12 12:24:43 +02:00
Bård Skaflestad
3d61162e29 Merge pull request #451 from bska/restart-xWELL-output
Revise Infrastructure for Well Arrays in Restart Files
2018-07-12 11:57:37 +02:00
Markus Blatt
3fabf2aad3 Unify handling of package dependency.
There was one macro to do that and one inline code in another
macro. With these changes we always use the macro for this.
2018-07-12 10:45:08 +02:00
Bård Skaflestad
3fa0064e5b VectorItems/well.hpp: Annotate More Items
In particular recognize that the 'item*' indices represent values
that aren't fully characterised yet.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
62f267cf89 INTEHEAD: Document Inter-Module Relations
In particular, the index list in InteHEAD.cpp must use public values
from VectorItems/intehead.hpp if available.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
f16b45eeed SWEL Array: Use L=O+W if LRAT Limit Unavailable
As an alternative source for LRAT data.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
7b301cb300 Aggregate Well Data: Report Default BHP Limits if Defaulted
Use E100 default values.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
34b1b3a073 xWEL Restart Vectors: Switch to Using Named Indexes
While here, also update pertinent unit tests to use the same vector
identfication scheme.

Suggested by: [at]joakim-hove and [at]atgeirr.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
20d0565220 Char Array Unit Test: Introduce Convenience Type Alias
Mostly for shortening constructor calls.

Suggested by: [at]atgeirr.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
1695dfe78b Char-Array Unit Test: Prune Duplicate Check
Identified by [at]atgeirr.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
387be05c77 WindowedArray: Add Doxygen-Style Reference Documentation
Requested by: [at]atgeirr
2018-07-12 10:44:27 +02:00
Bård Skaflestad
349ee4657e WindowedArray: Switch to Explicitly Using vector<T>
Suggested by: [at]joakim-hove and [at]atgeirr
2018-07-12 10:44:27 +02:00
Bård Skaflestad
7d7ec8efca WindowedArray: Rename Include Guards
Original name was a remnant of an earlier implementation.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
5c1aa3657d String Trim: Fix Inverted Logic for Blank String
Thanks to: [at]atgeirr.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
bf58a16e33 Rewrite 'wellLoop()' in Terms of Iteration Counter
Suggested by [at]atgeirr.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
84739c3bed InteHEAD: Publish Index of Common Size Items
Use these in implementation of InteHEAD and AggregateWellData.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
1c21ec9d5c Restart *WEL Arrays: Add Facility for Aggregating Vectors
This commit adds a new class that aggregates the *WEL vectors for
restart purposes.  Using the data sources

    - Simulation run's "Schedule" object
    - Simulation run's "UnitSystem" object
    - Current simulation step ("sim_step")
    - WellRates object from simulator at the end of sim_step
    - SummaryState object from Summary class at the end of sim_step

this class will fill in the (presently) known elements of the IWEL
(integers), SWEL (Real/float), XWEL (double precision), and ZWEL
arrays for output to a restart file.  We distinguish contributions
of data sources extracted directly from the simulation deck from
those computed dynamically by the simulator--mostly to separate
concerns and to enable independent testing.  If this introduces too
much computational overhead in actual simulation runs we can fuse
the member functions

    AggregateWellData::captureDeclaredWellData()
    AggregateWellData::captureDynamicWellData()

to reduce the number of loops over active wells.

The overall structure of this facility is that we have a single
templated function, wellLoop(), that calls user-defined "operations"
on each active well.  Each of these operations in turn define a
subset of one of the {I,S,X,Z}WEL arrays pertaining to the
particular well.  We furthermore put implementation functions into
namespaces according to the pertinent arrays.

Many thanks to my Equinor collaborators.
2018-07-12 10:44:27 +02:00
Bård Skaflestad
03b3be48b0 Restart *WEL Arrays: Add Foundational Helper Classes
This commit adds new helper classes,

    Opm::RestartIO::Helpers::CharArrayNullTerm<NChar>
    Opm::RestartIO::Helpers::WindowedArray<T>
    Opm::RestartIO::Helpers::WindowedMatrix<T>

the first of which represents a nul-terminated character string of
'NChar' user data (total array size is NChar + 1).  Mainly intended
for representing Fortran-compatible characters arrays--especially
for ZWEL and similar restart vectors (e.g., ZGRP).

The second two simplify working with subsets of large linear arrays,
particularly those that represent N items per well, group, or
segment.  The WindowedArray is a linear array of windows (N items
per window) packed into a std::vector<T> and the WindowedMatrix
additionally imposes a Row-by-Colum structure which is useful for
the case of N windows (each of size K) for each of M entities (e.g.,
K items for each of N connections for each of M wells).
2018-07-12 10:44:27 +02:00
Bård Skaflestad
b9c68bdc6e InteHEAD: Prune Duplicate Assignments 2018-07-12 10:44:27 +02:00
Bård Skaflestad
7680d1900f Merge pull request #461 from bska/extra-conn-props
Provide Effective Kh Product as an Extra Connection Property
2018-07-12 10:36:01 +02:00
Bård Skaflestad
0be3f2c76f Unit Tests: Supply Enough Parameters for data::Connection
We must provide cell_pressure, cell_saturation_water,
cell_saturation_gas, and effective_Kh.

Forgotten in commit 687f108.
2018-07-12 00:46:46 +02:00
Bård Skaflestad
d4c49398c5 Recognize Effective Kh in INPUT Unit System
Forgotten in commit 687f108

Pointy Hat: [at]bska
2018-07-12 00:03:01 +02:00
Bård Skaflestad
687f108285 Unit System: Recognize Units for Effective Kh Product
While here, also add check for all (current) unit conversion
constants for METRIC, FIELD, and LAB unit conventions and extend the
existing PVT-M checks to cover effective Kh too.
2018-07-11 22:07:38 +02:00
Bård Skaflestad
48047f8c7a Restart Output (Wells): Store Effective 'Kh' Product
Mostly to forward to SCON array.

While here, also fix 'Missing initializer' warnings in the
'get_completions' unit test.
2018-07-10 17:37:49 +02:00
Bård Skaflestad
3466776c1a Connection: Capture Effective 'Kh' Value from COMPDAT
Needed for restart output (especially, SCON), and also useful for
computing the connection transmissibility factor (WI) in some cases
if not supplied in COMPDAT.
2018-07-10 17:23:04 +02:00
Markus Blatt
efb2904beb Rephrase comment into more proper English 2018-07-10 15:57:10 +02:00
Markus Blatt
d7c855906f Search for the prerequisites from package configuration file.
That is the way it is done in other modules, too. We need this
at least for libecl as this target is used in opm-common_LIBRARIES
and not defined if there was no find_package(ecl) call. That call
is now made during execution of find_package_deps(opm-common).
2018-07-10 15:41:58 +02:00
Joakim Hove
19afcbf769 Merge pull request #458 from joakim-hove/ACTIONX
Add schema for ACTIONX keyword
2018-07-10 10:59:26 +02:00
Joakim Hove
e4d39dc722 Add schema for ACTIONX keyword 2018-07-10 09:35:13 +02:00
Arne Morten Kvarving
c7c2480c01 Merge pull request #455 from blattms/make-calling-prereq-function-possible-without-fuss
Make calling prereq function possible without fuss
2018-07-09 14:40:33 +02:00
Markus Blatt
90cbad1163 Better mark extra code section in opm-project-config.cmake.in 2018-07-06 11:02:50 +02:00
Markus Blatt
5b5d895380 Fix calling function from OpmPackage in package configuration file.
Find package_deps is called from <opm-module-name>-prereqs.cmake that is
included in our package configuration files. So it has to be defined early on.
We do this in the package confguration file of opm-common which needs to
be found before any other OPM module.

This fixes the CMake Error seen be e.g. dumux:
CMake Error at opm-grid/opm-grid-prereqs.cmake:37 (find_package_deps):
  Unknown CMake command "find_package_deps".
2018-07-06 11:02:15 +02:00
Atgeirr Flø Rasmussen
c38100a491 Merge pull request #453 from GitPaean/support_whistctl
handling the over-writing control part of WHISTCTL
2018-07-04 16:17:13 +02:00
Kai Bao
b5ff9bc393 handling the over-writing control part of WHISTCTL
for producers. The termination flag part is not handled yet.
2018-07-04 14:50:08 +02:00
Arne Morten Kvarving
3186a2d01a Merge pull request #449 from dr-robertk/PR/have-suitesparse-umfpack
[bugfix][Finddune-istl] Add HAVE_SUITESPARSE_UMFPACK for newer dune-istl versions.
2018-07-02 16:01:03 +02:00
Robert Kloefkorn
13d1ce4fbf [bugfix][Finddune-istl] Add HAVE_SUITESPARSE_UMFPACK for newer dune-istl
versions.
2018-07-02 15:56:03 +02:00
Joakim Hove
4144d761dd Merge pull request #431 from lars-petter-hauge/support_polymer_keys
Support polymer keys
2018-07-02 09:39:35 +02:00
Bård Skaflestad
71961c21b4 Merge pull request #446 from atgeirr/use-opm-cellvolumes
Use OPM cell volume calculations.
2018-07-02 09:26:22 +02:00
Atgeirr Flø Rasmussen
1b8e1b3197 Fix test failure by reinstating IJK check. 2018-07-02 00:08:36 +02:00
Atgeirr Flø Rasmussen
1e4e565380 Address review comment: do not call data() needlessly. 2018-07-02 00:08:16 +02:00
Joakim Hove
fa002c4408 Merge pull request #445 from atgeirr/improve-performance-of-MULTREGTScanner
Massively improve the startup time for Flow
2018-07-01 17:42:09 +02:00
Atgeirr Flø Rasmussen
9d5a43d4e6 Use const reference instead of copying map.
Also use at() instead of operator[], the at() is
guaranteed to succeed by the checks of the lines above it.
2018-07-01 14:07:28 +02:00
Atgeirr Flø Rasmussen
6eb363e8e1 Also use OPM cell volume calc in comparison program. 2018-06-29 15:57:15 +02:00
Atgeirr Flø Rasmussen
98e3bbcf1d Changes to make the code compile and run. 2018-06-29 15:57:15 +02:00
Joakim Hove
976bfdab35 Use opm-internal algorithm for volume calculation 2018-06-29 15:57:15 +02:00
Bård Skaflestad
ca79b16b26 Merge pull request #443 from atgeirr/error-and-warning-fixes
Error and warning fixes
2018-06-29 15:50:37 +02:00
Atgeirr Flø Rasmussen
65639b0a03 Make it possible to create Input unit systems, add test. 2018-06-29 10:56:34 +02:00
Atgeirr Flø Rasmussen
986abc1bdc Silence various warnings (shadowing, unused args or funcs). 2018-06-29 10:56:13 +02:00
Lars Petter Øren Hauge
5c68a0aaa8 Support CCI(R/T) 2018-06-29 09:45:14 +02:00
Lars Petter Øren Hauge
7a91bebd61 Support FCI(R/T) 2018-06-29 09:45:14 +02:00
Lars Petter Øren Hauge
102bd6b728 Support GCI(R/T) 2018-06-29 09:45:14 +02:00
Lars Petter Øren Hauge
fc3bc714fc Support WCI(R/T) 2018-06-29 09:45:14 +02:00
Atgeirr Flø Rasmussen
89e95b0789 Segment class: fix warnings and operator!= bug.
While silencing warnings in this class, it became apparent that
operator!=() was buggy, it was just a copy of operator==().
2018-06-28 17:01:27 +02:00
Atgeirr Flø Rasmussen
ffa4a8ef7b Include required <array> header. 2018-06-28 14:45:30 +02:00
Joakim Hove
1f7a2d5459 Merge pull request #435 from joakim-hove/completion-support2
Completion support2
2018-06-28 09:58:36 +02:00
Atgeirr Flø Rasmussen
3ffcff1773 Merge pull request #442 from atgeirr/make-volume-check-optional
Add more flexibility to compareECL.
2018-06-27 18:55:06 +02:00
Atgeirr Flø Rasmussen
cfb3d34467 Add more flexibility to compareECL.
In particular:
 - Grid comparison will now also check that the active cells are the same,
   not just that the number of active cells is identical.
 - In the grid comparison, checking volumes is now optional, from compareECL
   this feature is used by passing the '-V' option on the command line.
2018-06-27 15:22:55 +02:00
Joakim Hove
b109ab7822 Merge pull request #423 from akva2/codegen_rebuilds
changed: use a two-tiered process for code gen
2018-06-27 13:27:33 +02:00
Joakim Hove
5c55957718 Merge pull request #437 from rolk/0437_isatty
Include vendor-specific header for isatty function
2018-06-27 11:22:45 +02:00
Joakim Hove
4d3c143af4 Silnce warning 2018-06-26 12:36:49 +02:00
Joakim Hove
3a46555b6d Reorder connection members to quell warning 2018-06-26 12:36:49 +02:00
Joakim Hove
a5cc1cfe48 Remove stale private functions 2018-06-26 12:36:49 +02:00
Joakim Hove
6095fda39f Access connection direction directly 2018-06-26 12:36:49 +02:00
Joakim Hove
a8d1545947 Acces Connection sat table id directly 2018-06-26 12:36:49 +02:00
Joakim Hove
c212af9253 Remove stale function Connection::sameCoordinate() 2018-06-26 12:36:49 +02:00
Joakim Hove
6461cc2a81 Remove stale function Connection::fixDefaultIJ() 2018-06-26 12:36:49 +02:00
Joakim Hove
8895ee171a Remove function Connection::shift_complnum() 2018-06-26 12:36:49 +02:00
Joakim Hove
90f6b46837 Remove stale method Well::addConnections( ) 2018-06-26 12:36:49 +02:00
Joakim Hove
04a3a9ada5 WIP: cleaun up access methods 2018-06-26 12:36:49 +02:00
Joakim Hove
7a790a33bb Remove stale forwards 2018-06-26 12:36:49 +02:00
Joakim Hove
d72c45cd62 Remove unused construtors 2018-06-26 12:36:49 +02:00
Joakim Hove
bcfb195a83 Rename completionIdx -> complnum and size_t -> int 2018-06-26 12:36:49 +02:00
Joakim Hove
0327393951 Add function to get completions 2018-06-26 12:35:30 +02:00
Joakim Hove
15dd449354 Changed WELSEGS implementation 2018-06-26 12:35:30 +02:00
Joakim Hove
ad2af10c5a New implementation of WELLPI 2018-06-26 12:35:30 +02:00
Joakim Hove
5bce16c4e9 Reenable COMPLUMP tests 2018-06-26 12:35:30 +02:00
Joakim Hove
9d16cc8ec4 New implementation of WELOPEN 2018-06-26 12:35:30 +02:00
Joakim Hove
1f1ecebec5 New implementation of COMPLUMP 2018-06-26 12:35:30 +02:00
Joakim Hove
fd3000cd31 WellConnections::add() does not inspect IJK 2018-06-26 12:35:30 +02:00
Joakim Hove
363b8589e6 Change handleCOMPDAT implementation 2018-06-26 12:35:30 +02:00
Joakim Hove
93f7f50eb7 Temporarily disable COMPLUMP test 2018-06-26 12:35:30 +02:00
Joakim Hove
f3d82437fd Using shared_ptr to manage connections 2018-06-26 12:35:30 +02:00
Joakim Hove
d52d4cc3a6 Add method WellConnections::addConnection() 2018-06-26 12:35:30 +02:00
Joakim Hove
7332ee4b18 Remove intializer list ctx + stale test 2018-06-26 12:35:30 +02:00
Joakim Hove
2cb5f62591 Add mutable WellConnections::getFromIJK() 2018-06-26 12:35:30 +02:00
Atgeirr Flø Rasmussen
08994de897 Merge pull request #436 from akva2/again_pass_by_ref
fixed: pass string by const ref
2018-06-26 10:57:38 +02:00
Joakim Hove
b8605532f4 Merge pull request #438 from rolk/0438_libtool
Improve status message when libtool is not present
2018-06-26 10:03:34 +02:00
Roland Kaufmann
2356cc35e5 Improve status message when libtool is not present
Libtool uses libtool archive files (.la) to determine how to do a
platform-specific link. To generate these files, it is necessary to have
libtool installed on the system, since it will only accept files with
its own particular version number embedded. If libtool is not installed,
you probably don't need the libtool archive files either, so no .la is
generated. However, the status message sounded like libtool was probed
but not found, and that this was something that you should install.

This patch modifies the status message to make it more clear way libtool
was probed, and what the consequence of a missing libtool is (i.e. no
.la file for you).
2018-06-26 09:22:03 +02:00
Roland Kaufmann
83b63213f4 Include vendor-specific header for isatty function
MS Windows doesn't contain POSIX functions in unistd.h, but rather has
its own versions in io.h.
2018-06-26 09:14:12 +02:00
Arne Morten Kvarving
32722f3b9c fixed: pass string by const ref 2018-06-26 08:39:34 +02:00
Bård Skaflestad
d0580c2180 Merge pull request #434 from bska/calculate-all-sumvec-for-restart
Summary: Calculate Independent Set of Vectors for Restart
2018-06-25 16:41:11 +02:00
Bård Skaflestad
c3a11a2fb5 Summary: Calculate Independent Set of Vectors for Restart
This commit ensures that the following set of vectors are stored/updated in

    Summary::add_timestep()

for all active wells and well groups (including FIELD):

    - Production rates for Oil, Water, Gas, and Reservoir Volume
      (i.e., (O|W|G|V)PR).

    - Cumulative production totals for Oil, Water, Gas, and
      Reservoir Volume (i.e., (O|W|G|V)PT).

    - Injection rates for Water and Gas (i.e., (W|G)IR).

    - Cumulative injection totals for Water and Gas ((W|G)IT).

    - Producing Water Cut (WCT).

    - Producing Gas/Oil ratio (GOR).

We additionally capture the well bottom-hole pressure (WBHP) for all
wells that are active at the pertinent simulation step (sim_step).

Add an accessor function

    const SummaryState& Summary::get_restart_vectors() const

that returns the 'prev_state' which contains these summary vectors
and add a set of unit tests to exercise the new interface.
2018-06-25 14:04:11 +02:00
Joakim Hove
a50c823873 Merge pull request #432 from joakim-hove/no-deck-ctx
Add no deck constructor to Eclipse3DProperties
2018-06-22 16:52:06 +02:00
Joakim Hove
ba04fbb1ad Add no deck constructor to Eclipse3DProperties 2018-06-22 13:27:19 +02:00
Arne Morten Kvarving
acef0e411d further adjustments to redhat packaging
nightly builds broke
2018-06-21 09:02:36 +02:00
Joakim Hove
aa04fee73f Merge pull request #426 from joakim-hove/rename-connection-set
Rename connectionset and wellset
2018-06-21 08:14:08 +02:00
Joakim Hove
fa3d6029b3 Merge pull request #430 from rolk/0430_unassigned
Add catch-all else clause to satisfy compiler
2018-06-20 17:32:32 +02:00
Joakim Hove
f7950ca458 Merge pull request #429 from akva2/quell_sgn_usgn_war
quell signed/unsigned comparison warnings
2018-06-20 14:59:43 +02:00
Joakim Hove
197b34d9ec Merge pull request #428 from akva2/pass_const_ref
fixed: pass by const ref
2018-06-20 14:53:31 +02:00
Roland Kaufmann
c839f8dac7 Add catch-all else clause to satisfy compiler
Some compilers (notably GCC 5.4.0; default in Ubuntu 16.04) does not
do sufficient static analysis to determine that 'vect' is actually
exhaustively defined due to all indices being enumerated, and issue
a (spurious) warning that an unassigned value may be used.

This patch provides a default branch for the if-statements so that
'vect' is always assigned to, even in the eyes of the compiler. Since
entering this branch is unequivocally a bug, an assert is added so that
the null value is not mistakenly used.
2018-06-20 14:27:12 +02:00
Arne Morten Kvarving
7cedf056d7 quell signed/unsigned comparison warnings 2018-06-20 13:38:52 +02:00
Arne Morten Kvarving
261f6ac270 fixed: pass by const ref 2018-06-20 12:56:10 +02:00
Arne Morten Kvarving
d1d9e214ce Merge pull request #427 from akva2/add_mpich
add mpich packages to redhat
2018-06-20 12:41:41 +02:00
Arne Morten Kvarving
d2d9128e6a add mpich packages to redhat 2018-06-20 12:30:45 +02:00
Joakim Hove
b22e00b92d Rename WellSegment::numberSegment() WellSegment::size() 2018-06-20 11:48:02 +02:00
Joakim Hove
6c7f6d7afb Rename SegmentSet -> WellSegments 2018-06-20 11:36:50 +02:00
Joakim Hove
dc318f731f Rename ConnectionSet > WellConnections 2018-06-20 11:35:11 +02:00
Joakim Hove
d4d2b813dd Merge pull request #425 from joakim-hove/completion-refactor
Completion refactor
2018-06-20 11:00:42 +02:00
Joakim Hove
501b1dc760 Remove stale test 2018-06-20 09:27:02 +02:00
Joakim Hove
bfbcd3e470 Minor refactor JFunc + TableManager 2018-06-20 09:26:50 +02:00
Joakim Hove
2574dc7542 Merge pull request #424 from totto82/addCompletionsToTestState
Add posibility to store closed completions in wellTestState
2018-06-19 20:54:13 +02:00
Tor Harald Sandve
fb0272f343 Add posibility to store closed completions in wellTestState 2018-06-19 10:37:44 +02:00
Arne Morten Kvarving
3085243117 Merge pull request #302 from blattms/allow-dune-to-find-dune.module
Allow DUNE modules to locate the dune.module files during CMake run.
2018-06-18 13:46:10 +02:00
Markus Blatt
c6536c0b2f Allow DUNE modules to locate the dune.module files during CMake run.
For this we need to set <dune-module>_PREFIX either to where the module
is installed to or the source directory for a build with uninstalled
modules.
2018-06-18 12:47:53 +02:00
Arne Morten Kvarving
5dba20496a changed: use a two-tiered process for code gen
to avoid some unwanted rebuilds
2018-06-18 10:07:52 +02:00
Joakim Hove
97bb1c3413 Merge pull request #422 from alfbr/master
The MESSAGES keyword needs a thirteenth item
2018-06-18 08:55:34 +02:00
Alf B. Rustad
0d0e123735 Fixed Json syntax 2018-06-18 08:47:02 +02:00
Alf B. Rustad
768326527a The MESSAGES keyword needs a thirteenth item 2018-06-15 13:05:04 +02:00
Atgeirr Flø Rasmussen
df289d455b Merge pull request #418 from joakim-hove/grdecl-double
Use double overload for eclGrid
2018-06-15 12:32:16 +02:00
Joakim Hove
6b9e0c5ef8 Merge pull request #419 from joakim-hove/rename-completion
Rename Completion -> Connection
2018-06-12 13:22:48 +02:00
Joakim Hove
3975db2ff3 Rename CompletionSet -> ConnectionSet 2018-06-11 14:03:32 +02:00
Joakim Hove
d39db2f0db Rename Completion -> Connection 2018-06-11 10:40:59 +02:00
Joakim Hove
b3eb6b58eb Use double overload for eclGrid 2018-06-08 14:04:59 +02:00
Joakim Hove
088ba8a19a Merge pull request #413 from joakim-hove/restart-icon-skip-inactive
Restart icon skip inactive
2018-06-08 12:49:37 +02:00
Joakim Hove
d168e9ff67 Merge pull request #414 from joakim-hove/welltest-state
Add WellTestState object to keep track of automatically closed wells
2018-06-07 12:41:05 +02:00
Joakim Hove
46ab6dd8e1 Merge pull request #416 from OPM/revert-415-welltest
Revert "Add method for getting all the wells in the WellTestConfig"
2018-06-07 12:40:54 +02:00
Joakim Hove
66de108c68 Revert "Add method for getting all the wells in the WellTestConfig" 2018-06-07 07:48:44 +02:00
Joakim Hove
58e4e5263e Add WellTestState object to keep track of automatically closed wells 2018-06-07 07:42:03 +02:00
Joakim Hove
8fda1e036a Merge pull request #415 from totto82/welltest
Add method for getting all the wells in the WellTestConfig
2018-06-06 15:45:06 +02:00
Tor Harald Sandve
3327d17c3f Add method for getting all the wells in the WellTestConfig 2018-06-06 15:22:14 +02:00
Joakim Hove
d299e003b7 Merge pull request #411 from GitPaean/adding_vfp_numbers
VFP related needs to be processed even without THP target/limit
2018-06-05 17:34:29 +02:00
Joakim Hove
37da204eb6 Merge pull request #412 from atgeirr/fix-forgotten-include
Fix forgotten <string> include.
2018-06-05 13:20:03 +02:00
Joakim Hove
ccb7e5df3e Use active completions when writng restart files. 2018-06-05 12:31:00 +02:00
Joakim Hove
1ee597206c Add CompletionsSet constructor including only active connections. 2018-06-05 12:25:20 +02:00
Joakim Hove
163c3d435a Remove unused test file 2018-06-05 12:25:17 +02:00
Atgeirr Flø Rasmussen
3ad0b1c5ca Fix forgotten <string> include. 2018-06-04 15:05:09 +02:00
Joakim Hove
476bfa1046 Merge pull request #410 from joakim-hove/restart-THPRES
Ignore THPRES input for restart runs
2018-06-01 11:46:39 +02:00
Joakim Hove
24f28e8a5d Ignore THPRES input for restart runs 2018-05-31 17:15:34 +02:00
Kai Bao
59bb98d312 adding tests related to VFP table number 2018-05-30 15:15:02 +02:00
Kai Bao
f945032405 VFP table number related to history macthing mode
tests are failed.
2018-05-30 13:26:51 +02:00
Kai Bao
62c7706f30 VFP number is always read for WCONINJE
and a zero-value THP limit for WCONPROD will not be treated as a THP
limit.
2018-05-30 11:58:04 +02:00
Joakim Hove
a7ec8b1d53 Merge pull request #407 from joakim-hove/GNETINJE
Add keyword GNETINJE
2018-05-29 14:33:52 +02:00
Joakim Hove
d39ba17190 Add keyword GNETINJE 2018-05-29 11:00:21 +02:00
Arne Morten Kvarving
e654cba898 Merge pull request #409 from akva2/revert_pr_401
Revert #401
2018-05-29 09:33:09 +02:00
Arne Morten Kvarving
47d06c526f Revert "changed: manually merge pr's to work around slow updating merge refs on github"
This reverts commit b338e56730.

Causes too much problems to be worth the gains
2018-05-29 09:23:11 +02:00
Arne Morten Kvarving
61b7977406 Merge pull request #406 from akva2/revert_set_e
revert 'set -e' addition in jenkins script
2018-05-25 15:39:03 +02:00
Joakim Hove
0b4f830d28 Merge pull request #377 from nairr/aquctconversions
Handle conversion of constants in parser
2018-05-24 16:34:02 +02:00
Arne Morten Kvarving
f6c795bed0 revert 'set -e' addition in jenkins script
had some more consequences than expected, not all of them desired
2018-05-24 10:36:38 +02:00
Joakim Hove
ab365481a7 Merge pull request #403 from joakim-hove/summary_state
Add SummaryState class to hold on to summary state.
2018-05-23 19:32:55 +02:00
Joakim Hove
6883c8ae21 Merge pull request #401 from akva2/slow_updates
changed: manually merge pr's to work around slow updating merge refs
2018-05-23 09:11:42 +02:00
Arne Morten Kvarving
b338e56730 changed: manually merge pr's to work around slow updating merge refs on github 2018-05-23 09:00:00 +02:00
Joakim Hove
28b7781017 Merge pull request #404 from akva2/rh6_update
fix redhat 6 packaging
2018-05-23 08:31:06 +02:00
Arne Morten Kvarving
56da8cd8f9 fix redhat 6 packaging
cmake28 -> cmake3
2018-05-23 08:26:37 +02:00
Joakim Hove
6168a35512 Add SummaryState class to hold on to summary state. 2018-05-23 06:49:23 +02:00
Rohith Nair
9a17457e6f comment on C2 2018-05-22 16:02:38 +02:00
Rohith Nair
aecf3f6470 Handle conversion of constants in parser
Adds conversion factors for constants to SI units

edit

use p0_defaulted within aquiferCT

conversion based on unitsystem

edit
2018-05-22 14:28:34 +02:00
Joakim Hove
3b84678db5 Merge pull request #398 from joakim-hove/welltest-config
Add WTEST configuration
2018-05-18 09:10:00 +02:00
Joakim Hove
23ca927249 Merge pull request #391 from joakim-hove/use-restart-value
Save and load THPRES
2018-05-18 08:57:15 +02:00
Joakim Hove
7163807296 Change method names 2018-05-16 12:31:14 +02:00
Joakim Hove
5008501318 Add WellTestConfiguration to Schedule 2018-05-16 00:57:54 +02:00
Joakim Hove
3c18add696 Verify that the extra container has THPRES 2018-05-15 23:08:30 +02:00
Joakim Hove
b9d2a08930 Add WellTestConfig implementation to support WTEST keyword 2018-05-15 19:23:56 +02:00
Joakim Hove
eb001a1e67 Add runtime check that THPRES is saved 2018-05-14 16:12:52 +02:00
Joakim Hove
593af1c678 Pass dimension information for extra fields in restart 2018-05-14 16:12:52 +02:00
Joakim Hove
e6f318aa28 Add key string to RestartKey 2018-05-14 16:12:52 +02:00
Joakim Hove
d078a96eae Use RestartValue container for Eclipse output 2018-05-14 16:12:52 +02:00
Joakim Hove
fea57c5031 Merge pull request #387 from lars-petter-hauge/invalid_wells_context
Invalid wells context
2018-05-14 15:22:00 +02:00
Arne Morten Kvarving
fadab53590 Merge pull request #402 from akva2/master
update redhat packaging
2018-05-14 13:33:39 +02:00
Joakim Hove
b4ef14dfc0 Merge pull request #400 from atgeirr/serialize_SCON
Added implementation of serialize_SCON
2018-05-14 13:26:21 +02:00
Atgeirr Flø Rasmussen
b28527c0ec Update after review.
In particular:
 - correct path for test deck,
 - use unit system to convert output correctly,
 - handle and warn for the case where we do not have an explicit
   connection transmissibility factor from the deck.
2018-05-14 11:30:51 +02:00
Lars Petter Øren Hauge
429c4e475c Remove deprecated comment
The handling of `time step - 1` was changed in
62b9548167
2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
fcbcc9cda4 Add INVALID_NAME to GCONPROD, GCONINJE & GEFAC 2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
675858f1e0 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.
2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
427833b089 Add INVALID_WELLS to WECON & WEFAC 2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
ba573b5834 Add INVALID_WELLS to WELOPEN & WELTARG 2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
6a8e7a9a05 Add INVALID_WELL context to WPOLYMER & WSOLVENT 2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
580a64563f Add INVALID_WELL context to W(INJ)TEMP
Handle well template (e.g. W*) in the .DATA file for WTEMP and WINJTEMP
and add INVALID_WELL_CONTEXT
2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
e6b57fa422 Handle well template for COMPDAT
Allow well template (e.g 'W*') when defining completion records in the
.DATA file under COMPDAT
2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
ba107498a1 Add INVALID_WELL context for WCONINJ(E/H) 2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
183fd4eabb Add INVALID_WELL context for WCONPROD
Handle invalid wellpatterns for WCONPROD.

Given a deck with:

----
WELSPECS
  'PROD' 'G1'  10 10 8400 'OIL' /
/
COMPDAT
  'PROD' 10 10 3 3 'OPEN' 1* 1* 0.5 /
/
WCONPROD
  'SOMETHINGELSE' 'OPEN' 'ORAT' 20000 4* 1000 /
 /
----

OPM will now by default abort and inform the user that no well match
"SOMETHINGELSE".
2018-05-14 09:26:22 +02:00
Lars Petter Øren Hauge
f2cb5fe9de Add INVALID_WELL parse context
Handle invalid wellpatterns for COMPDAT.

Given a deck with:

----
WELSPECS
  'PROD' 'G1'  10 10 8400 'OIL' /
/
COMPDAT
  'SOMETHINGELSE' 10 10 3 3 'OPEN' 1* 1* 0.5 /
/
----

OPM will now by default abort and inform the user that no well match
"SOMETHINGELSE".
2018-05-14 09:26:21 +02:00
Lars Petter Øren Hauge
5dd34b1308 Removed dead code in from::COMPDAT
The "prev_compls" was initialized with preadded completions, such that
new records in COMPDAT would append in the correct order.

However the order is maintained without the need of including the check
in Completion::fromCOMPDAT.

Tests exist in ScheduleTests.cpp to verify completion order for both
TRACK and INPUT mode.

Completion order will affect the print in RFT data. A simple case which
will have changes for completion order was simulated and the output was
verified (with both INPUT and TRACK order).
2018-05-14 09:26:21 +02:00
Odd
8cfd477d3e Added implementation of serialize_SCON
The value 'Kh' (effective for connection) is not directly available from
the Connection interface.  For the time being, a dummy value is used.

Computing the correct value for 'Kh' involves using the connection
transmissibility factor (avaliable), the well diameter (available), as
well as information about grid geometry (not immediately available), well
angle through connection cell (not immediately available, as far as I
can tell), and possibly a conversion factor.
2018-05-14 09:26:03 +02:00
Atgeirr Flø Rasmussen
bfb6553828 Merge pull request #399 from atgeirr/Oddan-odd-devel
Added new implementation of serialize_ICON
2018-05-14 07:39:39 +02:00
Atgeirr Flø Rasmussen
49edd1e54d Minor fixes from review.
In particular:
 - replace tabs -> spaces,
 - use the term "lookup_step",
 - document interface better,
 - use correct path (no path...) for test deck.
2018-05-13 22:48:14 +02:00
Odd Andersen
6b78115229 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.
2018-05-13 21:43:35 +02:00
Atgeirr Flø Rasmussen
901a44e92b Merge pull request #397 from atgeirr/restart-xHEAD-keywords
Add Initial Implementation of Correctly Sized Header Vectors for Restart
2018-05-11 20:54:20 +02:00
Atgeirr Flø Rasmussen
01f87ea750 Use 2001 instead of 1901 in toDateNum().
This is because the toDateNum() calls makeUTCTime(), which calls
mktime(), which can fail for dates before epoch.
2018-05-10 08:51:02 +02:00
Atgeirr Flø Rasmussen
9303771a73 Fix typo: calender -> calendar. 2018-05-10 07:09:47 +02:00
Atgeirr Flø Rasmussen
be9744ef68 Add extra consistency test, that is independent of dates used. 2018-05-10 07:01:40 +02:00
Atgeirr Flø Rasmussen
6ec82f8947 Update test to match intended change in behaviour. 2018-05-10 07:01:04 +02:00
Atgeirr Flø Rasmussen
ef29518fab Documented some literals used in INTEHEAD implementation. 2018-05-09 16:48:52 +02:00
Atgeirr Flø Rasmussen
cd9afa6aec Merge branch 'restart-xHEAD-keywords' of https://github.com/joakim-hove/opm-common into joakim-hove-restart-xHEAD-keywords 2018-05-09 14:06:22 +02:00
Arne Morten Kvarving
bdef0ddfb0 update redhat packaging 2018-05-08 14:06:43 +02:00
Joakim Hove
e79b5bbc8c Merge pull request #395 from totto82/fix_fnpt
fix fnpt rates
2018-05-08 13:39:54 +02:00
Tor Harald Sandve
d0979638bc fix fnpt rates 2018-05-08 11:25:47 +02:00
Joakim Hove
38640bffd6 Merge pull request #394 from akva2/data_to_tests
opm-data -> opm-tests
2018-05-08 10:51:05 +02:00
Arne Morten Kvarving
464d557c80 fixed: opm-data -> opm-tests 2018-05-08 10:40:49 +02:00
Joakim Hove
1d02191178 Use lookup_step and report_step consistently 2018-05-03 08:57:05 +02:00
Bård Skaflestad
51933168eb Build System: Sort List of Public Headers for ECL_OUTPUT 2018-05-02 17:10:58 +02:00
Bård Skaflestad
d0542ba9fe Restart Headers: Add Support for DOUBHEAD Keyword
In particular, implement logic for "datenum" of start point in
addition to elapsed time (in days) and "datenum" of current time
point (start + elapsed).
2018-05-02 17:10:58 +02:00
Bård Skaflestad
a2f27bd62d InteHEAD: Expose Time-Point Handling as Utility
This commit allows clients to derive an InteHEAD::TimePoint (renamed
from InteHEAD::Date) from a calendrical start point (std::time_t)
and an elapsed time in seconds.  This is generally useful for
restart purposes which needs to fill in Y-m-d H:M:S information in
INTEHEAD and has other uses as well.  Demonstrate utility in a new
unit test that also shows leap year handling.

While here, also add fractional second resolution to the time-point
handling.  INTEHEAD(411) already has microsecond precision and we
should leverage that support.
2018-05-02 17:10:58 +02:00
Jostein Alvestad
17767fab3a Completed INTEHEAD vector-data, added LOGIHEAD vector data. 2018-05-02 17:10:58 +02:00
Jostein Alvestad
ce1f66b4e5 Skeleton for INTEHEAD Writing
Based on reverse-engineering of several ECL runs.
2018-05-02 17:10:58 +02:00
Arne Morten Kvarving
e864031bf4 Merge pull request #389 from andlaus/update_version
dune.module: update version to 2018.10-pre
2018-04-27 10:45:03 +02:00
Andreas Lauser
76f678bf82 dune.module: update version to 2018.10-pre 2018-04-26 17:48:37 +02:00
Joakim Hove
b5a2454d2c Merge pull request #383 from lars-petter-hauge/restart_timestep
Well info at correct step for save & load RESTART
2018-04-23 16:30:51 +02:00
Joakim Hove
36c166cdc9 Merge pull request #386 from GitPaean/fixing_vfp_running
return std::map of std::shared_ptr for getVFPxTables()
2018-04-23 16:30:26 +02:00
Joakim Hove
122158d713 Merge pull request #385 from joakim-hove/compare-header-keywords
Utility to compare keywords: check if grid parameter
2018-04-20 11:48:29 +02:00
Kai Bao
a1e587ef09 return std::map of std::shared_ptr for getVFPxTables()
in Schedule.
2018-04-20 11:27:26 +02:00
Joakim Hove
a4228efc66 Utility to compare keywords: check if grid parameter 2018-04-20 10:40:00 +02:00
Lars Petter Øren Hauge
62b9548167 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.
2018-04-17 14:58:00 +02:00
142 changed files with 11154 additions and 2356 deletions

View File

@@ -23,11 +23,17 @@ macro (dir_hook)
endmacro (dir_hook)
# We need to define this variable in the installed cmake config file.
set(OPM_PROJECT_EXTRA_CODE_INSTALLED "set(OPM_MACROS_ROOT ${CMAKE_INSTALL_PREFIX}/share/opm)
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)")
set(OPM_PROJECT_EXTRA_CODE_INSTALLED "#ENABLE_ECL_INPUT is needed by opm-common-prereq.cmake
set(ENABLE_ECL_INPUT ${ENABLE_ECL_INPUT})
set(OPM_MACROS_ROOT ${CMAKE_INSTALL_PREFIX}/share/opm)
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)
include(OpmPackage) #Make macros availabe after find_package(opm-common)")
set(OPM_PROJECT_EXTRA_CODE_INTREE "set(OPM_MACROS_ROOT ${OPM_MACROS_ROOT})
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)")
set(OPM_PROJECT_EXTRA_CODE_INTREE "#ENABLE_ECL_INPUT is needed by opm-common-prereq.cmake
set(ENABLE_ECL_INPUT ${ENABLE_ECL_INPUT})
set(OPM_MACROS_ROOT ${OPM_MACROS_ROOT})
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)
include(OpmPackage) #Make macros availabe after find_package(opm-common)")
if(ENABLE_ECL_OUTPUT)
set(OPM_PROJECT_EXTRA_CODE_INSTALLED "${OPM_PROJECT_EXTRA_CODE_INSTALLED}
set(COMPARE_SUMMARY_COMMAND ${CMAKE_INSTALL_PREFIX}/bin${${name}_VER_DIR}/compareSummary)

View File

@@ -73,16 +73,16 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp
src/opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.cpp
src/opm/parser/eclipse/EclipseState/Runspec.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Completion.cpp
src/opm/parser/eclipse/EclipseState/Schedule/CompletionSet.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Connection.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellConnections.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Events.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group.cpp
src/opm/parser/eclipse/EclipseState/Schedule/GroupTree.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MessageLimits.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/updatingConnectionsWithSegments.cpp
src/opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp
src/opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.cpp
@@ -93,6 +93,8 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/Schedule/WellInjectionProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellTestState.cpp
src/opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.cpp
src/opm/parser/eclipse/EclipseState/SimulationConfig/ThresholdPressure.cpp
src/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp
@@ -136,13 +138,23 @@ if(ENABLE_ECL_OUTPUT)
src/opm/test_util/summaryRegressionTest.cpp
src/opm/test_util/summaryComparator.cpp
src/opm/test_util/EclFilesComparator.cpp
src/opm/output/eclipse/AggregateWellData.cpp
src/opm/output/eclipse/CreateDoubHead.cpp
src/opm/output/eclipse/CreateInteHead.cpp
src/opm/output/eclipse/CreateLogiHead.cpp
src/opm/output/eclipse/WellDataSerializers.cpp
src/opm/output/eclipse/DoubHEAD.cpp
src/opm/output/eclipse/EclipseGridInspector.cpp
src/opm/output/eclipse/EclipseIO.cpp
src/opm/output/eclipse/InteHEAD.cpp
src/opm/output/eclipse/LinearisedOutputTable.cpp
src/opm/output/eclipse/LogiHEAD.cpp
src/opm/output/eclipse/RestartIO.cpp
src/opm/output/eclipse/Summary.cpp
src/opm/output/eclipse/SummaryState.cpp
src/opm/output/eclipse/Tables.cpp
src/opm/output/eclipse/RegionCache.cpp
src/opm/output/eclipse/RestartValue.cpp
src/opm/output/data/Solution.cpp
)
endif()
@@ -167,7 +179,7 @@ if(ENABLE_ECL_INPUT)
tests/parser/AquanconTests.cpp
tests/parser/BoxTests.cpp
tests/parser/ColumnSchemaTests.cpp
tests/parser/CompletionTests.cpp
tests/parser/ConnectionTests.cpp
tests/parser/COMPSEGUnits.cpp
tests/parser/CopyRegTests.cpp
tests/parser/DeckTests.cpp
@@ -216,22 +228,31 @@ if(ENABLE_ECL_INPUT)
tests/parser/UnitTests.cpp
tests/parser/ValueTests.cpp
tests/parser/WellSolventTests.cpp
tests/parser/WellTests.cpp)
tests/parser/WellTests.cpp
tests/parser/WTEST.cpp)
endif()
if(ENABLE_ECL_OUTPUT)
list (APPEND TEST_SOURCE_FILES
tests/test_AggregateWellData.cpp
tests/test_CharArrayNullTerm.cpp
tests/test_compareSummary.cpp
tests/test_EclFilesComparator.cpp
tests/test_EclipseIO.cpp
tests/test_DoubHEAD.cpp
tests/test_InteHEAD.cpp
tests/test_LinearisedOutputTable.cpp
tests/test_LogiHEAD.cpp
tests/test_regionCache.cpp
tests/test_Restart.cpp
tests/test_RFT.cpp
tests/test_Solution.cpp
tests/test_Summary.cpp
tests/test_Tables.cpp
tests/test_Wells.cpp
tests/test_WindowedArray.cpp
tests/test_writenumwells.cpp
tests/test_Solution.cpp
tests/test_regionCache.cpp
tests/test_serialize_ICON.cpp
tests/test_serialize_SCON.cpp
)
endif()
@@ -241,6 +262,7 @@ list (APPEND TEST_DATA_FILES
if(ENABLE_ECL_OUTPUT)
list (APPEND TEST_DATA_FILES
tests/FIRST_SIM.DATA
tests/FIRST_SIM_THPRES.DATA
tests/summary_deck.DATA
tests/group_group.DATA
tests/testblackoilstate3.DATA
@@ -256,6 +278,7 @@ list (APPEND EXAMPLE_SOURCE_FILES
if(ENABLE_ECL_INPUT)
list (APPEND EXAMPLE_SOURCE_FILES
examples/opmi.cpp
examples/opmpack.cpp
)
endif()
if(ENABLE_ECL_OUTPUT)
@@ -272,6 +295,7 @@ list (APPEND PROGRAM_SOURCE_FILES
if(ENABLE_ECL_INPUT)
list (APPEND PROGRAM_SOURCE_FILES
examples/opmi.cpp
examples/opmpack.cpp
)
endif()
if(ENABLE_ECL_OUTPUT)
@@ -435,13 +459,15 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp
opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/GroupTree.hpp
opm/parser/eclipse/EclipseState/Schedule/Completion.hpp
opm/parser/eclipse/EclipseState/Schedule/Connection.hpp
opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp
opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp
opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp
opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.hpp
opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp
opm/parser/eclipse/EclipseState/Schedule/MSW/updatingConnectionsWithSegments.hpp
opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.hpp
opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp
opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp
opm/parser/eclipse/EclipseState/Schedule/WellTestState.hpp
opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp
opm/parser/eclipse/EclipseState/SimulationConfig/ThresholdPressure.hpp
opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.hpp
opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp
@@ -465,23 +491,32 @@ if(ENABLE_ECL_INPUT)
endif()
if(ENABLE_ECL_OUTPUT)
list(APPEND PUBLIC_HEADER_FILES
opm/output/OutputWriter.hpp
opm/output/data/Wells.hpp
opm/output/data/Cells.hpp
opm/test_util/summaryRegressionTest.hpp
opm/test_util/summaryIntegrationTest.hpp
opm/test_util/summaryComparator.hpp
opm/output/data/Solution.hpp
opm/output/data/Wells.hpp
opm/output/eclipse/VectorItems/intehead.hpp
opm/output/eclipse/VectorItems/well.hpp
opm/output/eclipse/AggregateWellData.hpp
opm/output/eclipse/CharArrayNullTerm.hpp
opm/output/eclipse/DoubHEAD.hpp
opm/output/eclipse/EclipseGridInspector.hpp
opm/output/eclipse/EclipseIOUtil.hpp
opm/output/eclipse/EclipseIO.hpp
opm/output/eclipse/EclipseIOUtil.hpp
opm/output/eclipse/InteHEAD.hpp
opm/output/eclipse/LogiHEAD.hpp
opm/output/eclipse/LinearisedOutputTable.hpp
opm/output/eclipse/RegionCache.hpp
opm/output/eclipse/RestartIO.hpp
opm/output/eclipse/RestartValue.hpp
opm/output/eclipse/Summary.hpp
opm/output/eclipse/SummaryState.hpp
opm/output/eclipse/Tables.hpp
opm/output/eclipse/RegionCache.hpp
opm/output/data/Solution.hpp
opm/output/eclipse/WindowedArray.hpp
opm/output/eclipse/WriteRestartHelpers.hpp
opm/output/OutputWriter.hpp
opm/test_util/EclFilesComparator.hpp
opm/test_util/summaryComparator.hpp
opm/test_util/summaryIntegrationTest.hpp
opm/test_util/summaryRegressionTest.hpp
opm/test_util/summaryComparator.hpp)
)
endif()

21
CopyHeaders.cmake Normal file
View File

@@ -0,0 +1,21 @@
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
${BASE_DIR}/tmp_gen/ParserKeywords.cpp
${BASE_DIR}/ParserKeywords.cpp)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
${BASE_DIR}/tmp_gen/inlinekw.cpp
${BASE_DIR}/inlinekw.cpp)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
${BASE_DIR}/tmp_gen/include/opm/parser/eclipse/Parser/ParserKeywords.hpp
${BASE_DIR}/include/opm/parser/eclipse/Parser/ParserKeywords.hpp)
file(GLOB HDRS ${BASE_DIR}/tmp_gen/include/opm/parser/eclipse/Parser/ParserKeywords/*.hpp)
foreach(HDR ${HDRS})
file(RELATIVE_PATH hdr ${BASE_DIR}/tmp_gen/include/opm/parser/eclipse/Parser/ParserKeywords ${HDR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
${HDR}
${BASE_DIR}/include/opm/parser/eclipse/Parser/ParserKeywords/${hdr})
endforeach()

View File

@@ -48,7 +48,6 @@ list(APPEND EXTRA_TESTS EclipseStateTests)
foreach (test BoxTest
CheckDeckValidity
CompletionsFromDeck
EclipseGridCreateFromDeck
IncludeTest
IntegrationTests

View File

@@ -38,11 +38,17 @@ configure_file(src/opm/parser/eclipse/keyword_list.argv.in keyword_list.argv)
# Generate keyword source
add_custom_command(
OUTPUT ${PROJECT_BINARY_DIR}/ParserKeywords.cpp ${PROJECT_BINARY_DIR}/inlinekw.cpp
OUTPUT ${PROJECT_BINARY_DIR}/tmp_gen/ParserKeywords.cpp ${PROJECT_BINARY_DIR}/tmp_gen/inlinekw.cpp
COMMAND genkw keyword_list.argv
${PROJECT_BINARY_DIR}/ParserKeywords.cpp
${PROJECT_BINARY_DIR}/include/
${PROJECT_BINARY_DIR}/tmp_gen/ParserKeywords.cpp
${PROJECT_BINARY_DIR}/tmp_gen/include/
opm/parser/eclipse/Parser/ParserKeywords
${PROJECT_BINARY_DIR}/inlinekw.cpp
${PROJECT_BINARY_DIR}/tmp_gen/inlinekw.cpp
DEPENDS genkw ${keyword_files} src/opm/parser/eclipse/share/keywords/keyword_list.cmake
)
# To avoid some rebuilds
add_custom_command(OUTPUT ParserKeywords.cpp inlinekw.cpp
DEPENDS ${PROJECT_BINARY_DIR}/tmp_gen/ParserKeywords.cpp
COMMAND ${CMAKE_COMMAND} -DBASE_DIR=${PROJECT_BINARY_DIR}
-P ${PROJECT_SOURCE_DIR}/CopyHeaders.cmake)

View File

@@ -52,6 +52,7 @@ int main (void) {
HAVE_PARMETIS;
HAVE_SUPERLU;
HAVE_UMFPACK;
HAVE_SUITESPARSE_UMFPACK;
SUPERLU_INT_TYPE;
HAVE_SLU_CDEFS_H;
HAVE_SLU_DDEFS_H;

View File

@@ -123,7 +123,7 @@ function (configure_la name target)
mark_as_advanced (libtool_MAIN)
# notify the user if it not found after we explicitly searched
if (NOT libtool_MAIN)
message (STATUS "Libtool not found!")
message (STATUS "Not generating libtool archive (.la) since libtool was not found")
endif (NOT libtool_MAIN)
endif (NOT libtool_MAIN)
if (libtool_MAIN)

View File

@@ -139,6 +139,12 @@ macro (find_and_append_package_to prefix name)
set (${name}_FOUND FALSE)
set (${NAME}_FOUND FALSE)
else ()
# List of components might differ for every module. Therefore we will
# need to research for a library multiple times. _search_components
# will hold the index of the string COMPONENTS in the list
set(_ARGN_LIST ${ARGN}) # Create a real list to use with list commands
list(FIND _ARGN_LIST "COMPONENTS" _search_components)
# using config mode is better than using module (aka. find) mode
# because then the package has already done all its probes and
# stored them in the config file for us
@@ -147,8 +153,8 @@ macro (find_and_append_package_to prefix name)
# We even need to repeat the search for opm-common once as this is done
# in the top most CMakeLists.txt without querying defines, setting dependencies
# and the likes which is only done via opm_find_package
if (NOT DEFINED ${name}_FOUND AND NOT DEFINED ${NAME}_FOUND
OR ("${name}" STREQUAL "opm-common" AND NOT _opm_common_deps_processed))
if ( (NOT DEFINED ${name}_FOUND AND NOT DEFINED ${NAME}_FOUND )
OR _search_components GREATER -1)
string(REGEX MATCH "(dune|opm)-.*" _is_opm ${name})
if(NOT _is_opm)
string(REGEX MATCH "ewoms" _is_opm ${name})
@@ -164,11 +170,8 @@ macro (find_and_append_package_to prefix name)
find_package (${name} ${ARGN_NO_REQUIRED} NO_CMAKE_SYSTEM_PACKAGE_REGISTRY NO_CMAKE_PACKAGE_REGISTRY)
if(TARGET ecl)
# Need to grab from target to enable transitional depends
get_target_property(ecl_INCLUDE_DIRS ecl INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(ecl_LIBRARIES ecl INTERFACE_LINK_LIBRARIES)
get_target_property(ecl_lib ecl LOCATION)
set(ecl_LIBRARIES ecl ${ecl_lib} ${ecl_LIBRARIES})
set(ecl_FOUND 1)
#get_target_property(ecl_INCLUDE_DIRS ecl INTERFACE_INCLUDE_DIRECTORIES)
set(ecl_LIBRARIES ecl)
set(HAVE_ERT 1)
endif()
elseif(_${name}_exempted LESS 0 AND NOT _is_opm)
@@ -197,10 +200,6 @@ macro (find_and_append_package_to prefix name)
if (NOT DEFINED ${NAME}_FOUND)
set (${NAME}_FOUND "${${name}_FOUND}")
endif ()
if("${name}" STREQUAL "opm-common")
set(_opm_common_deps_processed ON)
endif()
endif ()
# the variable "NAME" may be replaced during find_package (as this is

View File

@@ -59,11 +59,7 @@ macro (find_opm_package module deps header lib defs prog conf)
# top most CMakeLists.txt but we still need to search for its
# dependencies
if (${MODULE}_FOUND OR ${module}_FOUND)
if (${module} STREQUAL "opm-common" AND NOT _opm_common_deps_processed)
set(_opm_common_deps_processed ON)
else()
return ()
endif()
endif ()
# variables to pass on to other packages
@@ -84,31 +80,11 @@ macro (find_opm_package module deps header lib defs prog conf)
# ${module}_CONFIG_VARS for dune modules.
find_package(${module} ${_${module}_quiet} ${_${module}_required} CONFIG)
# period because it should be something that evaluates to true
# in find_package_handle_standard_args
set (${module}_ALL_PREREQS ".")
foreach (_dep IN ITEMS ${deps})
separate_arguments (_${module}_args UNIX_COMMAND ${_dep})
if (_${module}_args)
# keep REQUIRED in the arguments only if we were required ourself
# "required-ness" is not transitive as far as CMake is concerned
# (i.e. if an optional package requests a package to be required,
# the build will fail if it's not found)
string (REPLACE "REQUIRED" "${_${module}_required}" _args_req "${_${module}_args}")
find_and_append_package_to (${module} ${_args_req} ${_${module}_quiet})
list (GET _${module}_args 0 _name_only)
string (TOUPPER "${_name_only}" _NAME_ONLY)
string (REPLACE "-" "_" _NAME_ONLY "${_NAME_ONLY}")
# check manually if it was found if REQUIRED; otherwise poison the
# dependency list which is checked later (so that it will fail)
if (("${_${module}_args}" MATCHES "REQUIRED") AND NOT (${_name_only}_FOUND OR ${_NAME_ONLY}_FOUND))
list (APPEND ${module}_ALL_PREREQS "${_name_only}-NOTFOUND")
endif ()
else ()
message (WARNING "Empty dependency in find module for ${module} (check for trailing semi-colon)")
endif ()
endforeach (_dep)
if(NOT ${module}_DEPS)
# set the dependencies used in find_package_deps
set(${module}_DEPS "${deps}")
endif()
find_package_deps(${module})
# since find_and_append_package_to is a macro, this variable have
# probably been overwritten (due to its common name); it is now
@@ -181,6 +157,11 @@ macro (find_package_deps module)
foreach (_dep IN ITEMS ${${module}_DEPS})
separate_arguments (_${module}_args UNIX_COMMAND "${_dep}")
if (_${module}_args)
# keep REQUIRED in the arguments only if we were required ourself
# "required-ness" is not transitive as far as CMake is concerned
# (i.e. if an optional package requests a package to be required,
# the build will fail if it's not found)
string (REPLACE "REQUIRED" "${_${module}_required}" _args_req "${_${module}_args}")
if(_dep MATCHES "opm-" OR _dep MATCHES "ewoms")
set(deplist ${_dep})
string(STRIP "${_dep}" _dep)

View File

@@ -76,6 +76,7 @@ function (opm_cmake_config name)
set (template_dir "${OPM_MACROS_ROOT}/cmake/Templates")
# write configuration file to locate library
set(DUNE_PREFIX ${PROJECT_SOURCE_DIR})
set(OPM_PROJECT_EXTRA_CODE ${OPM_PROJECT_EXTRA_CODE_INTREE})
set(PREREQ_LOCATION "${PROJECT_SOURCE_DIR}")
configure_cmake_file (${name} "config" "")
@@ -123,6 +124,7 @@ function (opm_cmake_config name)
# of the build directory (using the same input template)
set(OPM_PROJECT_EXTRA_CODE ${OPM_PROJECT_EXTRA_CODE_INSTALLED})
set(PREREQ_LOCATION "${CMAKE_INSTALL_PREFIX}/share/opm/cmake/Modules")
set(DUNE_PREFIX ${CMAKE_INSTALL_PREFIX})
configure_cmake_file (${name} "install" "")
configure_vars (
FILE CMAKE "${PROJECT_BINARY_DIR}/${${name}_NAME}-install.cmake"

View File

@@ -21,9 +21,8 @@
# Prevent multiple inclusions
if(NOT @opm-project_NAME@_FOUND)
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" @PREREQ_LOCATION@)
include(@opm-project_NAME@-prereqs)
# propagate these properties from one build system to the other
set (@opm-project_NAME@_PREFIX "@DUNE_PREFIX@")
set (@opm-project_NAME@_VERSION "@opm-project_VERSION@")
set (@opm-project_NAME@_DEFINITIONS "@opm-project_DEFINITIONS@")
set (@opm-project_NAME@_INCLUDE_DIRS "@opm-project_INCLUDE_DIRS@")
@@ -72,6 +71,12 @@ if(NOT @opm-project_NAME@_FOUND)
# this is the contents of config.h as far as our probes can tell:
# extra code
# extra code from variable OPM_PROJECT_EXTRA_CODE
@OPM_PROJECT_EXTRA_CODE@
# end extra code
# This call is at the bottom as we need to include
# the OpmPackage Macros.
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" @PREREQ_LOCATION@)
include(@opm-project_NAME@-prereqs)
endif()

2
debian/changelog vendored
View File

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

View File

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

108
examples/opmpack.cpp Normal file
View File

@@ -0,0 +1,108 @@
/*
Copyright 2018 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <getopt.h>
#include <boost/filesystem.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/InputErrorAction.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
inline void pack_deck( const char * deck_file, std::ostream& os) {
Opm::ParseContext parseContext(Opm::InputError::WARN);
Opm::Parser parser;
auto deck = parser.parseFile(deck_file, parseContext);
os << deck;
}
void print_help_and_exit() {
const char * help_text = R"(
The opmpack program will load a deck, resolve all include
files and then print it out again on stdout. All comments
will be stripped and the value types will be validated.
By passing the option -o you can redirect the output to a file
or a directory.
Print on stdout:
opmpack /path/to/case/CASE.DATA
Print MY_CASE.DATA in /tmp:
opmpack -o /tmp /path/to/MY_CASE.DATA
Print NEW_CASE in cwd:
opmpack -o NEW_CASE.DATA path/to/MY_CASE.DATA
)";
std::cerr << help_text << std::endl;
exit(1);
}
int main(int argc, char** argv) {
int arg_offset = 1;
bool stdout_output = true;
const char * coutput_arg;
while (true) {
int c;
c = getopt(argc, argv, "o:");
if (c == -1)
break;
switch(c) {
case 'o':
stdout_output = false;
coutput_arg = optarg;
break;
}
}
arg_offset = optind;
if (arg_offset >= argc)
print_help_and_exit();
if (stdout_output)
pack_deck(argv[arg_offset], std::cout);
else {
std::ofstream os;
using path = boost::filesystem::path;
path input_arg(argv[arg_offset]);
path output_arg(coutput_arg);
if (boost::filesystem::is_directory(output_arg)) {
path output_path = output_arg / input_arg.filename();
os.open(output_path.string());
} else
os.open(output_arg.string());
pack_deck(argv[arg_offset], os);
}
}

View File

@@ -114,11 +114,12 @@ int main(int argc, char** argv) {
bool specificKeyword = false;
bool specificFileType = false;
bool throwOnError = true;
bool volumecheck = true;
char* keyword = nullptr;
char* fileTypeCstr = nullptr;
int c = 0;
while ((c = getopt(argc, argv, "hiIk:lnpPt:")) != -1) {
while ((c = getopt(argc, argv, "hiIk:lnpPt:V")) != -1) {
switch (c) {
case 'h':
printHelp();
@@ -150,6 +151,9 @@ int main(int argc, char** argv) {
specificFileType = true;
fileTypeCstr = optarg;
break;
case 'V':
volumecheck = false;
break;
case '?':
if (optopt == 'k') {
std::cerr << "Option k requires a keyword as argument, see manual (-h) for more information." << std::endl;
@@ -254,11 +258,11 @@ int main(int argc, char** argv) {
comparator.setOnlyLastOccurrence(true);
}
if (specificKeyword) {
comparator.gridCompare();
comparator.gridCompare(volumecheck);
comparator.resultsForKeyword(keyword);
}
else {
comparator.gridCompare();
comparator.gridCompare(volumecheck);
comparator.results();
}
if (comparator.getNoErrors() > 0)

View File

@@ -81,7 +81,7 @@ then
PRNUMBER=${rev//[!0-9]/}
DATA_PR=`curl -X GET https://api.github.com/repos/OPM/opm-tests/pulls?head=jenkins4opm:$BRANCH_NAME | grep '"number":' | awk -F ':' '{print $2}' | sed -e 's/,//' -e 's/ //'`
git push -u jenkins4opm $BRANCH_NAME -f
curl -d "{ \"body\": \"Existing PR https://github.com/OPM/opm-data/pull/$DATA_PR was updated\" }" -X POST https://api.github.com/repos/OPM/$MAIN_REPO/issues/$PRNUMBER/comments?access_token=$GH_TOKEN
curl -d "{ \"body\": \"Existing PR https://github.com/OPM/opm-tests/pull/$DATA_PR was updated\" }" -X POST https://api.github.com/repos/OPM/$MAIN_REPO/issues/$PRNUMBER/comments?access_token=$GH_TOKEN
else
git-open-pull -u jenkins4opm --base-account OPM --base-repo opm-tests -r /tmp/cmsg $BRANCH_NAME
fi

View File

@@ -25,3 +25,7 @@ else()
"Boost 1.44.0
COMPONENTS system unit_test_framework REQUIRED")
endif()
# We need a defined target for libecl when linking.
# The definition of the target is done implicitly below when
# libecl is searched for.
find_package_deps(opm-common)

View File

@@ -101,7 +101,7 @@ namespace Opm {
double reservoir_gas = 0.0;
};
struct Completion {
struct Connection {
using global_index = size_t;
static const constexpr int restart_size = 2;
@@ -112,6 +112,7 @@ namespace Opm {
double cell_pressure;
double cell_saturation_water;
double cell_saturation_gas;
double effective_Kh;
template <class MessageBufferType>
void write(MessageBufferType& buffer) const;
@@ -125,7 +126,7 @@ namespace Opm {
double thp;
double temperature;
int control;
std::vector< Completion > completions;
std::vector< Connection > connections;
inline bool flowing() const noexcept;
template <class MessageBufferType>
@@ -146,20 +147,20 @@ namespace Opm {
}
double get(const std::string& well_name , Completion::global_index completion_grid_index, Rates::opt m) const {
double get(const std::string& well_name , Connection::global_index connection_grid_index, Rates::opt m) const {
const auto& witr = this->find( well_name );
if( witr == this->end() ) return 0.0;
const auto& well = witr->second;
const auto& completion = std::find_if( well.completions.begin() ,
well.completions.end() ,
[=]( const Completion& c ) {
return c.index == completion_grid_index; });
const auto& connection = std::find_if( well.connections.begin() ,
well.connections.end() ,
[=]( const Connection& c ) {
return c.index == connection_grid_index; });
if( completion == well.completions.end() )
if( connection == well.connections.end() )
return 0.0;
return completion->rates.get( m, 0.0 );
return connection->rates.get( m, 0.0 );
}
template <class MessageBufferType>
@@ -288,7 +289,7 @@ namespace Opm {
}
template <class MessageBufferType>
void Completion::write(MessageBufferType& buffer) const {
void Connection::write(MessageBufferType& buffer) const {
buffer.write(this->index);
this->rates.write(buffer);
buffer.write(this->pressure);
@@ -296,6 +297,7 @@ namespace Opm {
buffer.write(this->cell_pressure);
buffer.write(this->cell_saturation_water);
buffer.write(this->cell_saturation_gas);
buffer.write(this->effective_Kh);
}
template <class MessageBufferType>
@@ -305,9 +307,9 @@ namespace Opm {
buffer.write(this->thp);
buffer.write(this->temperature);
buffer.write(this->control);
unsigned int size = this->completions.size();
unsigned int size = this->connections.size();
buffer.write(size);
for (const Completion& comp : this->completions)
for (const Connection& comp : this->connections)
comp.write(buffer);
}
@@ -328,7 +330,7 @@ namespace Opm {
}
template <class MessageBufferType>
void Completion::read(MessageBufferType& buffer) {
void Connection::read(MessageBufferType& buffer) {
buffer.read(this->index);
this->rates.read(buffer);
buffer.read(this->pressure);
@@ -336,6 +338,7 @@ namespace Opm {
buffer.read(this->cell_pressure);
buffer.read(this->cell_saturation_water);
buffer.read(this->cell_saturation_gas);
buffer.read(this->effective_Kh);
}
template <class MessageBufferType>
@@ -345,12 +348,12 @@ namespace Opm {
buffer.read(this->thp);
buffer.read(this->temperature);
buffer.read(this->control);
unsigned int size = 0.0; //this->completions.size();
unsigned int size = 0.0; //this->connections.size();
buffer.read(size);
this->completions.resize(size);
this->connections.resize(size);
for (size_t i = 0; i < size; ++i)
{
auto& comp = this->completions[ i ];
auto& comp = this->connections[ i ];
comp.read(buffer);
}
}

View File

@@ -0,0 +1,99 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_AGGREGATE_WELL_DATA_HPP
#define OPM_AGGREGATE_WELL_DATA_HPP
#include <opm/output/eclipse/CharArrayNullTerm.hpp>
#include <opm/output/eclipse/WindowedArray.hpp>
#include <cstddef>
#include <string>
#include <vector>
namespace Opm {
class Schedule;
class SummaryState;
class UnitSystem;
} // Opm
namespace Opm { namespace data {
class WellRates;
}} // Opm::data
namespace Opm { namespace RestartIO { namespace Helpers {
class AggregateWellData
{
public:
explicit AggregateWellData(const std::vector<int>& inteHead);
void captureDeclaredWellData(const Opm::Schedule& sched,
const Opm::UnitSystem& units,
const std::size_t sim_step);
void captureDynamicWellData(const Opm::Schedule& sched,
const std::size_t sim_step,
const Opm::data::WellRates& xw,
const Opm::SummaryState& smry);
/// Retrieve Integer Well Data Array.
const std::vector<int>& getIWell() const
{
return this->iWell_.data();
}
/// Retrieve Floating-Point (Real) Well Data Array.
const std::vector<float>& getSWell() const
{
return this->sWell_.data();
}
/// Retrieve Floating-Point (Double Precision) Well Data Array.
const std::vector<double>& getXWell() const
{
return this->xWell_.data();
}
/// Retrieve Character Well Data Array.
const std::vector<CharArrayNullTerm<8>>& getZWell() const
{
return this->zWell_.data();
}
private:
/// Aggregate 'IWEL' array (Integer) for all wells.
WindowedArray<int> iWell_;
/// Aggregate 'SWEL' array (Real) for all wells.
WindowedArray<float> sWell_;
/// Aggregate 'XWEL' array (Double Precision) for all wells.
WindowedArray<double> xWell_;
/// Aggregate 'ZWEL' array (Character) for all wells.
WindowedArray<CharArrayNullTerm<8>> zWell_;
/// Maximum number of groups in model.
int nWGMax_;
};
}}} // Opm::RestartIO::Helpers
#endif // OPM_AGGREGATE_WELL_DATA_HPP

View File

@@ -0,0 +1,103 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_CHARARRAY_HEADER_HPP
#define OPM_CHARARRAY_HEADER_HPP
#include <algorithm>
#include <array>
#include <cstring>
#include <cstddef>
#include <string>
namespace Opm { namespace RestartIO { namespace Helpers {
/// Null-terminated, left adjusted, space padded array of N characters.
///
/// Simple container of character data. Exists solely for purpose of
/// outputting std::string (or types convertible to std::string) as
/// Fortran-style \code character (len=N) \endcode values.
///
/// \tparam N Number of characters.
template <std::size_t N>
class CharArrayNullTerm
{
public:
CharArrayNullTerm()
{
this->clear();
}
explicit CharArrayNullTerm(const std::string& s)
: CharArrayNullTerm()
{
this->copy_in(s.c_str(), s.size());
}
~CharArrayNullTerm() = default;
CharArrayNullTerm(const CharArrayNullTerm& rhs) = default;
CharArrayNullTerm(CharArrayNullTerm&& rhs) = default;
CharArrayNullTerm& operator=(const CharArrayNullTerm& rhs) = default;
CharArrayNullTerm& operator=(CharArrayNullTerm&& rhs) = default;
/// Assign from \code std::string \endcode.
CharArrayNullTerm& operator=(const std::string& s)
{
this->clear();
this->copy_in(s.data(), s.size());
return *this;
}
const char* c_str() const
{
return this->s_.data();
}
private:
enum : typename std::array<char, N + 1>::size_type { NChar = N };
std::array<char, NChar + 1> s_;
/// Clear contents of internal array (fill with ' ').
void clear()
{
this->s_.fill(' ');
this->s_[NChar] = '\0';
}
/// Assign new value to internal array (left adjusted, space padded
/// and null-terminated).
void copy_in(const char* s,
const typename std::array<char, NChar + 1>::size_type len)
{
const auto ncpy = std::min(len, static_cast<decltype(len)>(NChar));
// Note: Not strcpy() or strncpy() here. The former has no bounds
// checking, the latter writes a null-terminator at position 'ncpy'
// (s_[ncpy]) which violates the post condition if ncpy < NChar.
std::memcpy(this->s_.data(), s,
ncpy * sizeof *this->s_.data());
}
};
}}} // Opm::RestartIO::Helpers
#endif // CHARARRAY_HEADER

71
opm/output/eclipse/DoubHEAD.hpp Executable file
View File

@@ -0,0 +1,71 @@
/*
Copyright 2018 Statoil ASA.
This file is part of the Open Porous Media Project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_DOUBHEAD_HEADER_INCLUDED
#define OPM_DOUBHEAD_HEADER_INCLUDED
#include <chrono>
#include <cstddef>
#include <vector>
namespace Opm {
class Tuning;
class Schedule;
}
namespace Opm { namespace RestartIO {
class DoubHEAD
{
public:
struct TimeStamp {
std::chrono::time_point<std::chrono::system_clock> start;
std::chrono::duration<double, std::chrono::seconds::period> elapsed;
};
DoubHEAD();
~DoubHEAD() = default;
DoubHEAD(const DoubHEAD& rhs) = default;
DoubHEAD(DoubHEAD&& rhs) = default;
DoubHEAD& operator=(const DoubHEAD& rhs) = default;
DoubHEAD& operator=(DoubHEAD&& rhs) = default;
DoubHEAD& tuningParameters(const Tuning& tuning,
const std::size_t lookup_step,
const double cnvT);
DoubHEAD& timeStamp(const TimeStamp& ts);
DoubHEAD& drsdt(const Schedule& sched,
const std::size_t lookup_step);
const std::vector<double>& data() const
{
return this->data_;
}
private:
std::vector<double> data_;
};
}} // Opm::RestartIO
#endif // OPM_DOUBHEAD_HEADER_INCLUDED

View File

@@ -173,12 +173,10 @@ public:
void writeTimeStep( int report_step,
bool isSubstep,
double seconds_elapsed,
data::Solution,
data::Wells,
RestartValue value,
const std::map<std::string, double>& single_summary_values,
const std::map<std::string, std::vector<double>>& region_summary_values,
const std::map<std::pair<std::string, int>, double>& block_summary_values,
const std::map<std::string, std::vector<double>>& extra_restart = {},
bool write_double = false);
@@ -220,7 +218,7 @@ public:
missing, if the bool is false missing keywords will be ignored
(there will *not* be an empty vector in the return value).
*/
RestartValue loadRestart(const std::map<std::string, RestartKey>& keys, const std::map<std::string, bool>& extra_keys = {}) const;
RestartValue loadRestart(const std::vector<RestartKey>& solution_keys, const std::vector<RestartKey>& extra_keys = {}) const;
EclipseIO( const EclipseIO& ) = delete;

132
opm/output/eclipse/InteHEAD.hpp Executable file
View File

@@ -0,0 +1,132 @@
/*
Copyright 2016, 2017, 2018 Statoil ASA.
This file is part of the Open Porous Media Project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_INTEHEAD_HEADER_INCLUDED
#define OPM_INTEHEAD_HEADER_INCLUDED
#include <array>
#include <ctime>
#include <memory>
#include <vector>
namespace Opm { namespace RestartIO {
class InteHEAD
{
public:
enum class UnitSystem {
Metric, Field, Lab, PVT_M
};
struct WellTableDim {
int numWells;
int maxPerf;
int maxWellInGroup;
int maxGroupInField;
};
struct WellSegDims {
int nsegwl;
int nswlmx;
int nsegmx;
int nlbrmx;
int nisegz;
int nrsegz;
int nilbrz;
};
struct RegDims {
int ntfip;
int nmfipr;
int nrfreg;
int ntfreg;
int nplmix;
};
struct TimePoint {
int year;
int month; // 1..12
int day; // 1..31
int hour; // 0..23
int minute; // 0..59
int second; // 0..59
int microseconds; // 0..999999
};
struct Phases {
int oil;
int water;
int gas;
};
struct TuningPar {
int newtmx;
int newtmn;
int litmax;
int litmin;
int mxwsit;
int mxwpit;
};
InteHEAD();
~InteHEAD() = default;
InteHEAD(const InteHEAD& rhs) = default;
InteHEAD(InteHEAD&& rhs) = default;
InteHEAD& operator=(const InteHEAD& rhs) = default;
InteHEAD& operator=(InteHEAD&& rhs) = default;
InteHEAD& dimensions(const int nx, const int ny, const int nz);
InteHEAD& dimensions(const std::array<int,3>& cartDims);
InteHEAD& numActive(const int nactive);
InteHEAD& unitConventions(const UnitSystem& usys);
InteHEAD& wellTableDimensions(const WellTableDim& wtdim);
InteHEAD& calendarDate(const TimePoint& date);
InteHEAD& activePhases(const Phases& phases);
InteHEAD& params_NWELZ(const int niwelz, const int nswelz, const int nxwelz, const int nzwelz);
InteHEAD& params_NCON(const int niconz, const int nsconz, const int nxconz);
InteHEAD& params_GRPZ(const std::array<int, 4>& grpz);
InteHEAD& params_NAAQZ(const int ncamax, const int niaaqz, const int nsaaqz, const int nxaaqz, const int nicaqz, const int nscaqz, const int nacaqz);
InteHEAD& stepParam(const int tstep, const int report_step);
InteHEAD& tuningParam(const TuningPar& tunpar);
InteHEAD& variousParam(const int version, const int iprog);
InteHEAD& wellSegDimensions(const WellSegDims& wsdim);
InteHEAD& regionDimensions(const RegDims& rdim);
const std::vector<int>& data() const
{
return this->data_;
}
private:
std::vector<int> data_;
};
std::time_t makeUTCTime(const std::tm& timePoint);
InteHEAD::TimePoint
getSimulationTimePoint(const std::time_t start,
const double elapsed);
}} // Opm::RestartIO
#endif // OPM_INTEHEAD_HEADER_INCLUDED

View File

@@ -0,0 +1,54 @@
/*
Copyright 2016, 2017 Statoil ASA.
This file is part of the Open Porous Media Project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_LOGIHEAD_HEADER_INCLUDED
#define OPM_LOGIHEAD_HEADER_INCLUDED
#include <vector>
namespace Opm { namespace RestartIO {
class LogiHEAD
{
public:
LogiHEAD();
~LogiHEAD() = default;
LogiHEAD(const LogiHEAD& rhs) = default;
LogiHEAD(LogiHEAD&& rhs) = default;
LogiHEAD& operator=(const LogiHEAD& rhs) = default;
LogiHEAD& operator=(LogiHEAD&& rhs) = default;
LogiHEAD& variousParam(const bool e300_radial,
const bool e100_radial,
const int nswlmx);
const std::vector<bool>& data() const
{
return this->data_;
}
private:
std::vector<bool> data_;
};
}} // Opm::RestartIO
#endif // OPM_LOGIHEAD_HEADER_INCLUDED

View File

@@ -32,12 +32,12 @@ namespace out {
public:
RegionCache() = default;
RegionCache(const Eclipse3DProperties& properties, const EclipseGrid& grid, const Schedule& schedule);
const std::vector<std::pair<std::string,size_t>>& completions( int region_id ) const;
const std::vector<std::pair<std::string,size_t>>& connections( int region_id ) const;
private:
std::vector<std::pair<std::string,size_t>> completions_empty;
std::vector<std::pair<std::string,size_t>> connections_empty;
std::map<int , std::vector<std::pair<std::string,size_t>>> completion_map;
std::map<int , std::vector<std::pair<std::string,size_t>>> connection_map;
};
}
}

View File

@@ -75,22 +75,20 @@ namespace RestartIO {
void save(const std::string& filename,
int report_step,
double seconds_elapsed,
data::Solution cells,
data::Wells wells,
RestartValue value,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
std::map<std::string, std::vector<double>> extra_data = {},
bool write_double = false);
bool write_double = false);
RestartValue load( const std::string& filename,
int report_step,
const std::map<std::string, RestartKey>& keys,
const std::vector<RestartKey>& solution_keys,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const std::map<std::string, bool>& extra_keys = {});
const std::vector<RestartKey>& extra_keys = {});
}
}

View File

@@ -22,39 +22,30 @@
#include <map>
#include <vector>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/output/data/Solution.hpp>
#include <opm/output/data/Wells.hpp>
namespace Opm {
/*
Small convenience class used in the map passed to the
RestartIO::load( ) function. A class instance can be constructed
from a UnitSystem::measure value, which will default to a
required key, but it can also be constructed from a
two-parameter constructor, and then the required/not required
can controlled explicitly:
RestartIO::load(..., {{"PRESSURE" , UnitSystem::measure::pressure},
{"MAX_SWAT" , {UnitSystem::measure::identity, false}} )
The RestartKey( ) for pressure is implicitly created from
UnitSystem::measure::pressure and will be required, whereas the
MAX_SWAT keyword is optional.
*/
class RestartKey {
public:
std::string key;
UnitSystem::measure dim;
bool required = true;
bool required;
explicit RestartKey( UnitSystem::measure _dim)
: dim(_dim)
RestartKey( const std::string& _key, UnitSystem::measure _dim)
: key(_key),
dim(_dim),
required(true)
{}
RestartKey( UnitSystem::measure _dim, bool _required)
: dim(_dim),
RestartKey( const std::string& _key, UnitSystem::measure _dim, bool _required)
: key(_key),
dim(_dim),
required(_required)
{}
@@ -62,32 +53,24 @@ namespace Opm {
/*
A simple struct - the only purpose is to facilitate return by value from the
RestartIO::load( ) function.
A simple class used to communicate values between the simulator and the
RestartIO function.
*/
struct RestartValue {
class RestartValue {
public:
using ExtraVector = std::vector<std::pair<RestartKey, std::vector<double>>>;
data::Solution solution;
data::Wells wells;
std::map<std::string,std::vector<double>> extra = {};
ExtraVector extra;
RestartValue(data::Solution sol, data::Wells wells_arg);
RestartValue(data::Solution sol, data::Wells wells_arg, std::map<std::string, std::vector<double>> extra_arg) :
solution(std::move(sol)),
wells(std::move(wells_arg)),
extra(std::move(extra_arg))
{
}
RestartValue(data::Solution sol, data::Wells wells_arg) :
solution(std::move(sol)),
wells(std::move(wells_arg))
{
}
bool hasExtra(const std::string& key) const;
void addExtra(const std::string& key, UnitSystem::measure dimension, std::vector<double> data);
void addExtra(const std::string& key, std::vector<double> data);
const std::vector<double>& getExtra(const std::string& key) const;
};
}

View File

@@ -29,6 +29,7 @@
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/RegionCache.hpp>
@@ -61,6 +62,8 @@ class Summary {
~Summary();
const SummaryState& get_restart_vectors() const;
private:
class keyword_handlers;
@@ -68,8 +71,8 @@ class Summary {
out::RegionCache regionCache;
ERT::ert_unique_ptr< ecl_sum_type, ecl_sum_free > ecl_sum;
std::unique_ptr< keyword_handlers > handlers;
const ecl_sum_tstep_type* prev_tstep = nullptr;
double prev_time_elapsed = 0;
SummaryState prev_state;
};
}

View File

@@ -0,0 +1,50 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SUMMARY_STATE_H
#define SUMMARY_STATE_H
#include <string>
#include <unordered_map>
namespace Opm{
/*
The purpose of this class is to serve as a small container object for
computed, ready to use summary values. The values will typically be used by
the UDQ, WTEST and ACTIONX calculations. Observe that all value *have been
converted to the correct output units*.
*/
class SummaryState {
public:
typedef std::unordered_map<std::string, double>::const_iterator const_iterator;
void add(const std::string& key, double value);
double get(const std::string&) const;
bool has(const std::string& key) const;
const_iterator begin() const;
const_iterator end() const;
private:
std::unordered_map<std::string,double> values;
};
}
#endif

View File

@@ -0,0 +1,90 @@
/*
Copyright (c) 2018 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_OUTPUT_ECLIPSE_VECTOR_INTEHEAD_HPP
#define OPM_OUTPUT_ECLIPSE_VECTOR_INTEHEAD_HPP
#include <vector>
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
// This is a subset of the items in src/opm/output/eclipse/InteHEAD.cpp .
// Promote items from that list to this in order to make them public.
enum intehead : std::vector<int>::size_type {
ISNUM = 0, // An encoded integer corresponding to the
// time the file was created. For files not
// originating from ECLIPSE, this value may
// be set to zero.
VERSION = 1, // Simulator version
UNIT = 2, // Units convention
// 1: METRIC, 2: FIELD, 3: LAB, 4: PVT-M
NX = 8, // #cells in X direction (Cartesian)
NY = 9, // #cells in Y direction (Cartesian)
NZ = 10, // #cells in Z direction (Cartesian)
NACTIV = 11, // Number of active cells
PHASE = 14, // Phase indicator:
// 1: oil, 2: water, 3: O/W, 4: gas,
// 5: G/O, 6: G/W, 7: O/G/W
NWELLS = 16, // Number of wells
NCWMAX = 17, // Maximum number of completions per well
NWGMAX = 19, // Maximum number of wells in any well group
NGMAXZ = 20, // Maximum number of groups in field
NIWELZ = 24, // Number of data elements per well in IWEL array
// (default 97 for ECLIPSE, 94 for ECLIPSE 300).
NSWELZ = 25, // Number of data elements per well in SWEL array
NXWELZ = 26, // Number of delements per well in XWEL array
NZWELZ = 27, // Number of 8-character words per well in ZWEL array
NICONZ = 32, // Number of data elements per completion
// in ICON array (default 19)
NSCONZ = 33, // Number of data elements per completion in SCON array
NXCONZ = 34, // Number of data elements per completion in XCON array
NIGRPZ = 36, // Number of data elements per group in IGRP array
NSGRPZ = 37, // Number of data elements per group in SGRP array
NXGRPZ = 38, // Number of data elements per group in XGRP array
NZGRPZ = 39, // Number of data elements per group in ZGRP array
NCAMAX = 41, // Maximum number of analytic aquifer connections
NIAAQZ = 42, // Number of data elements per aquifer in IAAQ array
NSAAQZ = 43, // Number of data elements per aquifer in SAAQ array
NXAAQZ = 44, // Number of data elements per aquifer in XAAQ array
NICAQZ = 45, // Number of data elements per aquifer connection in ICAQ array
NSCAQZ = 46, // Number of data elements per aquifer connection in SCAQ array
NACAQZ = 47, // Number of data elements per aquifer connection in ACAQ array
NSEGWL = 174, // Number of multisegment wells defined with WELSEG
NSWLMX = 175, // Maximum number of segmented wells (item 1 ofWSEGDIMS)
NSEGMX = 176, // Maximum number of segments per well (item 2 of WSEGDIMS)
NLBRMX = 177, // Maximum number of lateral branches (item 3 of WSEGDIMS)
NISEGZ = 178, // Number of entries per segment in ISEG array
NRSEGZ = 179, // Number of entries per segment in RSEG array
NILBRZ = 180, // Number of entries per segment in ILBR array
};
}}}} // Opm::RestartIO::Helpers::VectorItems
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_INTEHEAD_HPP

View File

@@ -0,0 +1,164 @@
/*
Copyright (c) 2018 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_OUTPUT_ECLIPSE_VECTOR_WELL_HPP
#define OPM_OUTPUT_ECLIPSE_VECTOR_WELL_HPP
#include <vector>
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
namespace IWell {
enum index : std::vector<int>::size_type {
IHead = 0, // I-location (one-based) of well head
JHead = 1, // J-location (one-based) of well head
FirstK = 2, // Layer ID (one-based) of top/first connection
LastK = 3, // Layer ID (one-based) of bottom/last connection
NConn = 4, // Number of active cells connected to well
Group = 5, // Index (one-based) of well's current group
WType = 6, // Well type
WCtrl = 7, // Well control
item9 = 8, // Unknown
item11 = 10, // Unknown
VFPTab = 11, // ID (one-based) of well's current VFP table
item18 = 17, // Unknown
item25 = 24, // Unknown
item32 = 31, // Unknown
item48 = 47, // Unknown
item50 = 49, // Unknown
MsWID = 70, // Multisegment well ID
// Value 0 for regular wells
// Value 1..#MS wells for MS wells
NWseg = 71, // Number of well segments
// Value 0 for regular wells
// Value #segments for MS wells
CompOrd = 98, // Well's completion ordering scheme.
};
namespace Value {
enum WellType : int {
WTUnk = 0, // Unknown well type (OPM only)
Producer = 1, // Well is producer
OilInj = 2, // Well is oil injector
WatInj = 3, // Well is water injector
GasInj = 4, // Well is gas injector
};
enum WellCtrlMode : int {
WMCtlUnk = -10, // Unknown well control mode (OPM only)
Group = - 1, // Well under group control
Shut = 0, // Well is shut
OilRate = 1, // Well controlled by oil rate
WatRate = 2, // Well controlled by water rate
GasRate = 3, // Well controlled by gas rate
LiqRate = 4, // Well controlled by liquid rate
ResVRate = 5, // Well controlled by
// reservoir voidage rate
THP = 6, // Well controlled by
// tubing head pressure target
BHP = 7, // Well controlled by
// bottom-hole pressure target
CombRate = 9, // Well controlled by linearly
// combined rate target
};
enum CompOrder : int {
Track = 0, // Connections ordered along
// well track (increasing MD)
Depth = 1, // Connections ordered by inceasing
// true vertical depth. Not really
// supported in OPM Flow.
Input = 2, // Connections listed in order of
// appearance in simulation model's
// COMPDAT keyword.
};
} // Value
} // IWell
namespace SWell {
enum index : std::vector<float>::size_type {
OilRateTarget = 0, // Well's current oil rate production target
WatRateTarget = 1, // Well's current water rate production target
GasRateTarget = 2, // Well's current gas rate production target
LiqRateTarget = 3, // Well's current liquid rate production target
ResVRateTarget = 4, // Well's current reservoir voidate rate
// production target
THPTarget = 5, // Well's tubing head pressure target
BHPTarget = 6, // Well's bottom hole pressure target
DatumDepth = 9, // Well's reference depth for BHP
};
} // SWell
namespace XWell {
enum index : std::vector<double>::size_type {
OilPrRate = 0, // Well's oil production rate
WatPrRate = 1, // Well's water production rate
GasPrRate = 2, // Well's gas production rate
LiqPrRate = 3, // Well's liquid production rate
VoidPrRate = 4, // Well's reservoir voidage production rate
FlowBHP = 6, // Well's flowing/producing bottom hole pressure
WatCut = 7, // Well's producing water cut
GORatio = 8, // Well's producing gas/oil ratio
OilPrTotal = 18, // Well's total cumulative oil production
WatPrTotal = 19, // Well's total cumulative water production
GasPrTotal = 20, // Well's total cumulative gas production
VoidPrTotal = 21, // Well's total cumulative reservoir
// voidage production
WatInjTotal = 23, // Well's total cumulative water injection
GasInjTotal = 24, // Well's total cumulative gas injection
GasFVF = 34, // Well's producing gas formation volume factor.
item37 = 36, // Unknown
item38 = 37, // Unknown
BHPTarget = 41, // Well's current BHP Target/Limit
item82 = 81, // Unknown
item83 = 82, // Unknown
WatVoidPrRate = 122, // Well's voidage production rate
GasVoidPrRate = 123, // Well's voidage production rate
};
} // XWell
namespace ZWell {
enum index : std::vector<const char*>::size_type {
WellName = 0, // Well name
};
} // ZWell
}}}} // Opm::RestartIO::Helpers::VectorItems
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_WELL_HPP

View File

@@ -0,0 +1,262 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_WINDOWED_ARRAY_HPP
#define OPM_WINDOWED_ARRAY_HPP
#include <cassert>
#include <iterator>
#include <type_traits>
#include <vector>
#include <boost/range/iterator_range.hpp>
/// \file
///
/// Provide facilities to simplify constructing restart vectors
/// such as IWEL or RSEG.
namespace Opm { namespace RestartIO { namespace Helpers {
/// Provide read-only and read/write access to constantly sized
/// portions/windows of a linearised buffer with an implied
/// 1D array structure.
///
/// Intended as backing store for vectors that have a constant
/// number of items per entity (e.g., N integer data items for
/// each active group at a report step).
///
/// \tparam T Element type for underlying data items.
template <typename T>
class WindowedArray
{
public:
/// Read/write access.
using WriteWindow = boost::iterator_range<
typename std::vector<T>::iterator>;
/// Read-only access.
using ReadWindow = boost::iterator_range<
typename std::vector<T>::const_iterator>;
using Idx = typename std::vector<T>::size_type;
/// Distinct compile-time type for number of windows in
/// underlying storage.
struct NumWindows { Idx value; };
/// Distinct compile-time type for size of windows
/// (number of data items per window.)
struct WindowSize { Idx value; };
/// Constructor.
///
/// \param[in] n Number of windows.
/// \param[in] sz Number of data items per window.
explicit WindowedArray(const NumWindows n, const WindowSize sz)
: x_ (n.value * sz.value)
, windowSize_(sz.value)
{}
/// Retrieve number of windows allocated for this array.
Idx numWindows() const
{
return this->x_.size() / this->windowSize_;
}
/// Retrieve number of data items per windows.
Idx windowSize() const
{
return this->windowSize_;
}
/// Request read/write access to individual window.
///
/// \param[in] window Numeric ID of particular read/write window.
/// Must be in range \code [0 .. numWindows()-1] \endcode.
WriteWindow operator[](const Idx window)
{
assert ((window < this->numWindows()) &&
"Window ID Out of Bounds");
auto b = std::begin(this->x_) + window*this->windowSize_;
auto e = b + this->windowSize_;
return { b, e };
}
/// Request read-only access to individual window.
///
/// \param[in] window Numeric ID of particular read-only window.
/// Must be in range \code [0 .. numWindows()-1] \endcode.
ReadWindow operator[](const Idx window) const
{
assert ((window < this->numWindows()) &&
"Window ID Out of Bounds");
auto b = std::begin(this->x_) + window*this->windowSize_;
auto e = b + this->windowSize_;
return { b, e };
}
/// Get read-only access to full, linearised data items for
/// all windows.
const std::vector<T>& data() const
{
return this->x_;
}
/// Extract full, linearised data items for all windows.
///
/// Destroys the internal state of the \c WindowedArray.
std::vector<T> getDataDestructively()
{
return std::move(this->x_);
}
private:
std::vector<T> x_;
Idx windowSize_;
};
/// Provide read-only and read/write access to constantly sized
/// portions/windows of a linearised buffer with an implied
/// row/column matrix (2D array) structure.
///
/// Intended as backing store for vectors that have a constant
/// number of items per sub-entity of a fixed number of containing
/// entities (e.g., K double precision data items for each of N
/// maximum well connections for each of M maximum active wells at
/// a particular report step).
///
/// \tparam T Element type for underlying data items.
template <typename T>
class WindowedMatrix
{
private:
using NumWindows = typename WindowedArray<T>::NumWindows;
public:
using WriteWindow = typename WindowedArray<T>::WriteWindow;
using ReadWindow = typename WindowedArray<T>::ReadWindow;
using WindowSize = typename WindowedArray<T>::WindowSize;
using Idx = typename WindowedArray<T>::Idx;
/// Distinct compile-time type for number of matrix rows
/// in underlying storage.
struct NumRows { Idx value; };
/// Distinct compile-time type for number of matrix columns
/// in underlying storage.
struct NumCols { Idx value; };
/// Constructor.
///
/// \param[in] nRows Number of rows.
/// \param[in] nCols Number of columns.
/// \param[in] sz Number of data items per (row,column) window.
explicit WindowedMatrix(const NumRows& nRows,
const NumCols& nCols,
const WindowSize& sz)
: data_ (NumWindows{ nRows.value * nCols.value }, sz)
, numCols_(nCols.value)
{}
/// Retrieve number of columns allocated for this matrix.
Idx numCols() const
{
return this->numCols_;
}
/// Retrieve number of rows allocated for this matrix.
Idx numRows() const
{
return this->data_.numWindows() / this->numCols();
}
/// Retrieve number of data items per windows.
Idx windowSize() const
{
return this->data_.windowSize();
}
/// Request read/write access to individual window.
///
/// \param[in] row Numeric ID of particular row in matrix.
/// Must be in range \code [0 .. numRows()-1] \endcode.
///
/// \param[in] col Numeric ID of particular column in matrix.
/// Must be in range \code [0 .. numCols()-1] \endcode.
///
/// \return Read/write window at position \code (row,col) \endcode.
WriteWindow operator()(const Idx row, const Idx col)
{
return this->data_[ this->i(row, col) ];
}
/// Request read-only access to individual window.
///
/// \param[in] row Numeric ID of particular row in matrix.
/// Must be in range \code [0 .. numRows()-1] \endcode.
///
/// \param[in] col Numeric ID of particular column in matrix.
/// Must be in range \code [0 .. numCols()-1] \endcode.
///
/// \return Read-only window at position \code (row,col) \endcode.
ReadWindow operator()(const Idx row, const Idx col) const
{
return this->data_[ this->i(row, col) ];
}
/// Get read-only access to full, linearised data items for
/// all windows.
auto data() const
-> decltype(std::declval<const WindowedArray<T>>().data())
{
return this->data_.data();
}
/// Extract full, linearised data items for all windows.
///
/// Destroys the internal state of the \c WindowedMatrix.
auto getDataDestructively()
-> decltype(std::declval<WindowedArray<T>>()
.getDataDestructively())
{
return this->data_.getDataDestructively();
}
private:
WindowedArray<T> data_;
Idx numCols_;
/// Row major (C) order.
Idx i(const Idx row, const Idx col) const
{
return row*this->numCols() + col;
}
};
}}} // Opm::RestartIO::Helpers
#endif // OPM_WINDOW_ARRAY_HPP

View File

@@ -0,0 +1,79 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_WRITE_RESTART_HELPERS_HPP
#define OPM_WRITE_RESTART_HELPERS_HPP
#include <vector>
// Missing definitions (really belong in ert/ecl_well/well_const.h, but not
// defined there)
#define SCON_KH_INDEX 3
// Forward declarations
namespace Opm {
class EclipseGrid;
class EclipseState;
class Schedule;
class Well;
class UnitSystem;
} // Opm
namespace Opm { namespace RestartIO { namespace Helpers {
const double UNIMPLEMENTED_VALUE = 1e-100; // placeholder for values not yet available
std::vector<double>
createDoubHead(const EclipseState& es,
const Schedule& sched,
const std::size_t lookup_step,
const double simTime);
std::vector<int>
createInteHead(const EclipseState& es,
const EclipseGrid& grid,
const Schedule& sched,
const double simTime,
const int num_solver_steps,
const int lookup_step, // The integer index used to look up dynamic properties, e.g. the number of well.
const int report_step); // The integer number this INTEHEAD keyword will be saved to, typically report_step = lookup_step + 1.
std::vector<bool>
createLogiHead(const EclipseState& es);
std::vector<int> serialize_ICON(int lookup_step, // The integer index used to look up dynamic properties, e.g. the number of well.
int ncwmax, // Max number of completions per well, should be entry 17 from createInteHead.
int niconz, // Number of elements per completion in ICON, should be entry 32 from createInteHead.
const std::vector<const Well*>& sched_wells);
std::vector<double> serialize_SCON(int lookup_step, // The integer index used to look up dynamic properties, e.g. the number of well.
int ncwmax, // Max number of completions per well, should be entry 17 from createInteHead.
int nsconz, // Number of elements per completion in SCON, should be entry 33 from createInteHead.
const std::vector<const Well*>& sched_wells,
const UnitSystem& units);
}}} // Opm::RestartIO::Helpers
#endif // OPM_WRITE_RESTART_HELPERS_HPP

View File

@@ -36,6 +36,7 @@
#include <opm/parser/eclipse/EclipseState/Tables/TableContainer.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/AqutabTable.hpp>
#include <boost/concept_check.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
namespace Opm {
@@ -57,9 +58,10 @@ namespace Opm {
k_a , //aquifer permeability
c1, // 0.008527 (METRIC, PVT-M); 0.006328 (FIELD); 3.6 (LAB)
h , //aquifer thickness
p0, //Initial aquifer pressure at datum depth, d0
theta , //angle subtended by the aquifer boundary
c2 ; //6.283 (METRIC, PVT-M); 1.1191 (FIELD); 6.283 (LAB).
std::vector<double> td, pi;
};

View File

@@ -49,10 +49,14 @@ namespace Opm {
public:
Eclipse3DProperties() = default;
Eclipse3DProperties(const Deck& deck,
const TableManager& tableManager,
const EclipseGrid& eclipseGrid);
Eclipse3DProperties( UnitSystem unit_system,
const TableManager& tableManager,
const EclipseGrid& eclipseGrid);
std::vector< int > getRegions( const std::string& keyword ) const;
std::string getDefaultRegionKeyword() const;

View File

@@ -181,9 +181,9 @@ namespace Opm {
Value<double> m_pinch;
PinchMode::ModeEnum m_pinchoutMode;
PinchMode::ModeEnum m_multzMode;
mutable std::vector<double> volume_cache;
mutable std::vector< int > activeMap;
bool m_circle = false;
/*
The internal class grid_ptr is a a std::unique_ptr with
special copy semantics. The purpose of implementing this is

View File

@@ -1,71 +0,0 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef COMPLETIONSET_HPP_
#define COMPLETIONSET_HPP_
#include <opm/parser/eclipse/EclipseState/Schedule/Completion.hpp>
namespace Opm {
class EclipseGrid;
class CompletionSet {
public:
CompletionSet() = default;
// cppcheck-suppress noExplicitConstructor
CompletionSet( std::initializer_list< Completion > );
using const_iterator = std::vector< Completion >::const_iterator;
void add( Completion );
size_t size() const;
const Completion& get(size_t index) const;
const Completion& getFromIJK(const int i, const int j, const int k) const;
const_iterator begin() const { return this->m_completions.begin(); }
const_iterator end() const { return this->m_completions.end(); }
void filter(const EclipseGrid& grid);
bool allCompletionsShut() const;
/// Order completions irrespective of input order.
/// The algorithm used is the following:
/// 1. The completion nearest to the given (well_i, well_j)
/// coordinates in terms of the completion's (i, j) is chosen
/// to be the first completion. If non-unique, choose one with
/// lowest z-depth (shallowest).
/// 2. Choose next completion to be nearest to current in (i, j) sense.
/// If non-unique choose closest in z-depth (not logical cartesian k).
///
/// \param[in] well_i logical cartesian i-coordinate of well head
/// \param[in] well_j logical cartesian j-coordinate of well head
/// \param[in] grid EclipseGrid object, used for cell depths
void orderCompletions(size_t well_i, size_t well_j);
bool operator==( const CompletionSet& ) const;
bool operator!=( const CompletionSet& ) const;
private:
std::vector< Completion > m_completions;
size_t findClosestCompletion(int oi, int oj, double oz, size_t start_pos);
};
}
#endif

View File

@@ -21,11 +21,12 @@
#ifndef COMPLETION_HPP_
#define COMPLETION_HPP_
#include <array>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Util/Value.hpp>
@@ -34,74 +35,53 @@ namespace Opm {
class DeckKeyword;
class DeckRecord;
class Well;
class EclipseGrid;
class Eclipse3DProperties;
class Completion {
class Connection {
public:
Completion(int i, int j , int k ,
Connection(int i, int j , int k ,
int complnum,
double depth,
WellCompletion::StateEnum state ,
const Value<double>& connectionTransmissibilityFactor,
const Value<double>& diameter,
const Value<double>& skinFactor,
const Value<double>& Kh,
const int satTableId,
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z);
const WellCompletion::DirectionEnum direction);
Completion(const Completion&, WellCompletion::StateEnum newStatus);
Completion(const Completion&, double wellPi);
Completion(const Completion&, int complnum );
Completion(const Completion& completion_initial, int segment_number, double center_depth);
bool sameCoordinate(const Completion& other) const;
bool sameCoordinate(const int i, const int j, const int k) const;
int getI() const;
int getJ() const;
int getK() const;
int complnum() const;
WellCompletion::StateEnum getState() const;
double getConnectionTransmissibilityFactor() const;
double getWellPi() const;
const Value<double>& getConnectionTransmissibilityFactorAsValueObject() const;
double getDiameter() const;
double getSkinFactor() const;
int getSatTableId() const;
void fixDefaultIJ(int wellHeadI , int wellHeadJ);
void shift_complnum( int );
int getSegmentNumber() const;
double getCenterDepth() const;
bool attachedToSegment() const;
const Value<double>& getConnectionTransmissibilityFactorAsValueObject() const;
const Value<double>& getEffectiveKhAsValueObject() const;
WellCompletion::DirectionEnum getDirection() const;
bool operator==( const Connection& ) const;
bool operator!=( const Connection& ) const;
static std::map< std::string, std::vector< Completion > >
fromCOMPDAT( const EclipseGrid& grid,
const Eclipse3DProperties& eclipseProperties,
const DeckKeyword& compdatKeyword,
const std::vector< const Well* >& );
bool operator==( const Completion& ) const;
bool operator!=( const Completion& ) const;
WellCompletion::DirectionEnum dir;
double center_depth;
WellCompletion::StateEnum state;
int sat_tableId;
int complnum;
private:
int m_i, m_j, m_k;
int m_complnum;
std::array<int,3> ijk;
Value<double> m_diameter;
Value<double> m_connectionTransmissibilityFactor;
double m_wellPi;
Value<double> m_skinFactor;
int m_satTableId;
WellCompletion::StateEnum m_state;
WellCompletion::DirectionEnum m_direction;
Value<double> getDiameterAsValueObject() const;
Value<double> getSkinFactorAsValueObject() const;
Value<double> m_Kh;
public:
// related segment number
// -1 means the completion is not related to segment
int m_segment_number = -1;
double m_center_depth;
int segment_number = -1;
double wellPi = 1.0;
};
}

View File

@@ -120,6 +120,7 @@ namespace Opm {
bool getTransferGroupEfficiencyFactor(size_t time_step) const;
void setGroupNetVFPTable(size_t time_step, int table);
int getGroupNetVFPTable(size_t time_step) const;
static bool groupNameInGroupNamePattern(const std::string& groupName, const std::string& groupNamePattern);
/*****************************************************************/

View File

@@ -30,13 +30,13 @@ namespace Opm {
class DeckKeyword;
class SegmentSet {
class WellSegments {
public:
SegmentSet() = default;
WellSegments() = default;
std::string wellName() const;
int numberBranch() const;
int numberSegment() const;
int size() const;
double depthTopSegment() const;
double lengthTopSegment() const;
double volumeTopSegment() const;
@@ -50,7 +50,7 @@ namespace Opm {
void addSegment(Segment new_segment);
void segmentsFromWELSEGSKeyword( const DeckKeyword& welsegsKeyword);
void loadWELSEGS( const DeckKeyword& welsegsKeyword);
const Segment& getFromSegmentNumber(const int segment_number) const;
@@ -59,8 +59,8 @@ namespace Opm {
void processABS();
void processINC(const bool first_time);
bool operator==( const SegmentSet& ) const;
bool operator!=( const SegmentSet& ) const;
bool operator==( const WellSegments& ) const;
bool operator!=( const WellSegments& ) const;
private:
@@ -91,7 +91,7 @@ namespace Opm {
std::vector< Segment > m_segments;
// the mapping from the segment number to the
// storage index in the vector
std::map<int, int> m_segment_number_to_index;
std::map<int, int> segment_number_to_index;
};
}

View File

@@ -17,16 +17,16 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UPDATING_COMPLETIONS_WITH_SEGMENTS
#define UPDATING_COMPLETIONS_WITH_SEGMENTS
#ifndef UPDATING_CONNECTIONS_WITH_SEGMENTS
#define UPDATING_CONNECTIONS_WITH_SEGMENTS
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
namespace Opm {
CompletionSet updatingCompletionsWithSegments(const DeckKeyword& compsegs, const CompletionSet& input_completions, const SegmentSet& segments);
WellConnections * newConnectionsWithSegments(const DeckKeyword& compsegs, const WellConnections& input_connections, const WellSegments& segments);
}
#endif

View File

@@ -39,6 +39,7 @@
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp>
namespace Opm
{
@@ -64,7 +65,7 @@ namespace Opm
Schedule(const Deck& deck,
const EclipseState& es,
const ParseContext& parseContext = ParseContext());
/*
* If the input deck does not specify a start time, Eclipse's 1. Jan
* 1983 is defaulted
@@ -78,7 +79,7 @@ namespace Opm
size_t numWells() const;
size_t numWells(size_t timestep) const;
size_t getMaxNumCompletionsForWells(size_t timestep) const;
size_t getMaxNumConnectionsForWells(size_t timestep) const;
bool hasWell(const std::string& wellName) const;
const Well* getWell(const std::string& wellName) const;
std::vector< const Well* > getOpenWells(size_t timeStep) const;
@@ -98,6 +99,8 @@ namespace Opm
std::vector< const Well* > getWellsMatching( const std::string& ) const;
const OilVaporizationProperties& getOilVaporizationProperties(size_t timestep) const;
const WellTestConfig& wtestConfig(size_t timestep) const;
const GroupTree& getGroupTree(size_t t) const;
size_t numGroups() const;
bool hasGroup(const std::string& groupName) const;
@@ -105,19 +108,20 @@ namespace Opm
std::vector< const Group* > getGroups() const;
const Tuning& getTuning() const;
const MessageLimits& getMessageLimits() const;
void invalidNamePattern (const std::string& namePattern, const ParseContext& parseContext, const DeckKeyword& keyword) const;
const Events& getEvents() const;
const Deck& getModifierDeck(size_t timeStep) const;
bool hasOilVaporizationProperties() const;
const VFPProdTable& getVFPProdTable(int table_id, size_t timeStep) const;
const VFPInjTable& getVFPInjTable(int table_id, size_t timeStep) const;
std::map<int, VFPProdTable> getVFPProdTables(size_t timeStep) const;
std::map<int, VFPInjTable> getVFPInjTables(size_t timeStep) const;
std::map<int, std::shared_ptr<const VFPProdTable> > getVFPProdTables(size_t timeStep) const;
std::map<int, std::shared_ptr<const VFPInjTable> > getVFPInjTables(size_t timeStep) const;
/*
Will remove all completions which are connected to cell which is not
active. Will scan through all wells and all timesteps.
*/
void filterCompletions(const EclipseGrid& grid);
void filterConnections(const EclipseGrid& grid);
private:
TimeMap m_timeMap;
@@ -132,10 +136,13 @@ namespace Opm
Phases m_phases;
std::map<int, DynamicState<std::shared_ptr<VFPProdTable>>> vfpprod_tables;
std::map<int, DynamicState<std::shared_ptr<VFPInjTable>>> vfpinj_tables;
DynamicState<std::shared_ptr<WellTestConfig>> wtest_config;
WellProducer::ControlModeEnum m_controlModeWHISTCTL;
std::vector< Well* > getWells(const std::string& wellNamePattern);
std::vector< Group* > getGroups(const std::string& groupNamePattern);
void updateWellStatus( Well& well, size_t reportStep , WellCommon::StatusEnum status);
void addWellToGroup( Group& newGroup , Well& well , size_t timeStep);
void iterateScheduleSection(const ParseContext& parseContext , const SCHEDULESection& , const EclipseGrid& grid,
@@ -145,36 +152,37 @@ namespace Opm
void addWell(const std::string& wellName, const DeckRecord& record, size_t timeStep, WellCompletion::CompletionOrderEnum wellCompletionOrder);
void handleCOMPORD(const ParseContext& parseContext, const DeckKeyword& compordKeyword, size_t currentStep);
void handleWELSPECS( const SCHEDULESection&, size_t, size_t );
void handleWCONProducer( const DeckKeyword& keyword, size_t currentStep, bool isPredictionMode);
void handleWCONHIST( const DeckKeyword& keyword, size_t currentStep);
void handleWCONPROD( const DeckKeyword& keyword, size_t currentStep);
void handleWCONProducer( const DeckKeyword& keyword, size_t currentStep, bool isPredictionMode, const ParseContext& parseContext);
void handleWCONHIST( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWGRUPCON( const DeckKeyword& keyword, size_t currentStep);
void handleCOMPDAT( const DeckKeyword& keyword, size_t currentStep, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties);
void handleCOMPDAT( const DeckKeyword& keyword, size_t currentStep, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties, const ParseContext& parseContext);
void handleCOMPLUMP( const DeckKeyword& keyword, size_t currentStep );
void handleWELSEGS( const DeckKeyword& keyword, size_t currentStep);
void handleCOMPSEGS( const DeckKeyword& keyword, size_t currentStep);
void handleWCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
void handleWPOLYMER( const DeckKeyword& keyword, size_t currentStep);
void handleWSOLVENT( const DeckKeyword& keyword, size_t currentStep);
void handleWTEMP( const DeckKeyword& keyword, size_t currentStep);
void handleWINJTEMP( const DeckKeyword& keyword, size_t currentStep);
void handleWCONINJH( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
void handleWELOPEN( const DeckKeyword& keyword, size_t currentStep );
void handleWELTARG( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
void handleGCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
void handleGCONPROD( const DeckKeyword& keyword, size_t currentStep);
void handleGEFAC( const DeckKeyword& keyword, size_t currentStep);
void handleWEFAC( const DeckKeyword& keyword, size_t currentStep);
void handleWCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWPOLYMER( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWSOLVENT( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWINJTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWCONINJH( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWELOPEN( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext );
void handleWELTARG( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleGCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleGCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleGEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleTUNING( const DeckKeyword& keyword, size_t currentStep);
void handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep);
void handleGRUPNET( const DeckKeyword& keyword, size_t currentStep);
void handleWRFT( const DeckKeyword& keyword, size_t currentStep);
void handleWTEST( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWRFTPLT( const DeckKeyword& keyword, size_t currentStep);
void handleWPIMULT( const DeckKeyword& keyword, size_t currentStep);
void handleDRSDT( const DeckKeyword& keyword, size_t currentStep);
void handleDRVDT( const DeckKeyword& keyword, size_t currentStep);
void handleVAPPARS( const DeckKeyword& keyword, size_t currentStep);
void handleWECON( const DeckKeyword& keyword, size_t currentStep);
void handleWECON( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWHISTCTL(const ParseContext& parseContext, const DeckKeyword& keyword);
void handleMESSAGES(const DeckKeyword& keyword, size_t currentStep);
void handleVFPPROD(const DeckKeyword& vfpprodKeyword, const UnitSystem& unit_system, size_t currentStep);

View File

@@ -27,23 +27,23 @@
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellEconProductionLimits.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellInjectionProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
namespace Opm {
template< typename > class DynamicState;
class Completion;
class CompletionSet;
class COnnection;
class WellConnections;
class Segment;
class SegmentSet;
class WellSegments;
class TimeMap;
class EclipseGrid;
@@ -94,10 +94,29 @@ namespace Opm {
bool isInjector(size_t timeStep) const;
void addWELSPECS(const DeckRecord& deckRecord);
void addCompletions(size_t time_step, const std::vector< Completion >& );
void addCompletionSet(size_t time_step, CompletionSet );
const CompletionSet& getCompletions(size_t timeStep) const;
const CompletionSet& getCompletions() const;
/*
The getCompletions() function will return a map:
{
1 : [Connection, Connection],
2 : [Connection, Connection, Connecton],
-3 : [Connection]
-7 : [Connection]
}
The integer ID's correspond to the COMPLETION id given by the COMPLUMP
keyword. All positive id values come from COMPLUMP, whereas the
negative values are arbitrary negative id values for connections which
have not been lumped together in a completion. In the case of negative
id values the list of connections always has exactly one element.
*/
std::map<int, std::vector<Connection>> getCompletions(size_t time_step) const;
const WellConnections& getConnections(size_t timeStep) const;
const WellConnections& getConnections() const;
WellConnections getActiveConnections(size_t timeStep, const EclipseGrid& grid) const;
WellConnections * newWellConnections(size_t time_step);
void updateWellConnections(size_t time_step, WellConnections * new_set );
/* The rate of a given phase under the following assumptions:
* * Returns zero if production is requested for an injector (and vice
@@ -147,7 +166,7 @@ namespace Opm {
static bool wellNameInWellNamePattern(const std::string& wellName, const std::string& wellNamePattern);
WellCompletion::CompletionOrderEnum getWellCompletionOrdering() const;
WellCompletion::CompletionOrderEnum getWellConnectionOrdering() const;
bool getAllowCrossFlow() const;
bool getAutomaticShutIn() const;
@@ -156,19 +175,26 @@ namespace Opm {
// for multi-segment wells
bool isMultiSegment(size_t time_step) const;
const SegmentSet& getSegmentSet(size_t time_step) const;
const WellSegments& getWellSegments(size_t time_step) const;
void addSegmentSet(size_t time_step, SegmentSet new_segmentset);
void addWellSegments(size_t time_step, WellSegments new_segmentset);
const Events& getEvents() const;
void addEvent(ScheduleEvents::Events event, size_t reportStep);
bool hasEvent(uint64_t eventMask, size_t reportStep) const;
void handleCOMPLUMP(const DeckRecord& record, size_t time_step);
void handleCOMPDAT(size_t time_step, const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties);
void handleCOMPSEGS(const DeckKeyword& keyword, size_t time_step);
void handleWELOPEN(const DeckRecord& record, size_t time_step, WellCompletion::StateEnum status);
void handleWPIMULT(const DeckRecord& record, size_t time_step);
void handleWELSEGS(const DeckKeyword& keyword, size_t time_step);
/*
Will remove all completions which are attached to inactive cells. Will
scan through all timesteps.
*/
void filterCompletions(const EclipseGrid& grid);
void filterConnections(const EclipseGrid& grid);
private:
size_t m_creationTimeStep;
std::string m_name;
@@ -182,7 +208,7 @@ namespace Opm {
DynamicState< double > m_efficiencyFactors;
DynamicState< int > m_isProducer;
DynamicState< CompletionSet > m_completions;
DynamicState< std::shared_ptr<WellConnections> > m_completions;
DynamicState< WellProductionProperties > m_productionProperties;
DynamicState< WellInjectionProperties > m_injectionProperties;
DynamicState< WellPolymerProperties > m_polymerProperties;
@@ -202,7 +228,7 @@ namespace Opm {
bool m_automaticShutIn;
// WELSEGS DATA - for mutli-segment wells
// flag indicating if the well is a multi-segment well
DynamicState< SegmentSet > m_segmentset;
DynamicState< WellSegments > m_segmentset;
size_t timesteps;
Events events;
};

View File

@@ -0,0 +1,95 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONNECTIONSET_HPP_
#define CONNECTIONSET_HPP_
#include <opm/parser/eclipse/EclipseState/Schedule/Connection.hpp>
namespace Opm {
class EclipseGrid;
class Eclipse3DProperties;
class WellConnections {
public:
WellConnections() = default;
WellConnections(int headI, int headJ);
// cppcheck-suppress noExplicitConstructor
WellConnections(const WellConnections& src, const EclipseGrid& grid);
void addConnection(int i, int j , int k ,
double depth,
WellCompletion::StateEnum state ,
const Value<double>& connectionTransmissibilityFactor,
const Value<double>& diameter,
const Value<double>& skinFactor,
const Value<double>& Kh,
const int satTableId,
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z);
void loadCOMPDAT(const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties);
using const_iterator = std::vector< Connection >::const_iterator;
void add( Connection );
size_t size() const;
const Connection& get(size_t index) const;
const Connection& getFromIJK(const int i, const int j, const int k) const;
Connection& getFromIJK(const int i, const int j, const int k);
const_iterator begin() const { return this->m_connections.begin(); }
const_iterator end() const { return this->m_connections.end(); }
void filter(const EclipseGrid& grid);
bool allConnectionsShut() const;
/// Order connections irrespective of input order.
/// The algorithm used is the following:
/// 1. The connection nearest to the given (well_i, well_j)
/// coordinates in terms of the connection's (i, j) is chosen
/// to be the first connection. If non-unique, choose one with
/// lowest z-depth (shallowest).
/// 2. Choose next connection to be nearest to current in (i, j) sense.
/// If non-unique choose closest in z-depth (not logical cartesian k).
///
/// \param[in] well_i logical cartesian i-coordinate of well head
/// \param[in] well_j logical cartesian j-coordinate of well head
/// \param[in] grid EclipseGrid object, used for cell depths
void orderConnections(size_t well_i, size_t well_j);
bool operator==( const WellConnections& ) const;
bool operator!=( const WellConnections& ) const;
private:
void addConnection(int i, int j , int k ,
int complnum,
double depth,
WellCompletion::StateEnum state ,
const Value<double>& connectionTransmissibilityFactor,
const Value<double>& diameter,
const Value<double>& skinFactor,
const Value<double>& Kh,
const int satTableId,
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z);
std::vector< Connection > m_connections;
size_t findClosestConnection(int oi, int oj, double oz, size_t start_pos);
int headI, headJ;
};
}
#endif

View File

@@ -55,7 +55,10 @@ namespace Opm {
bool operator!=(const WellProductionProperties& other) const;
WellProductionProperties();
static WellProductionProperties history(double BHPLimit, const DeckRecord& record);
static WellProductionProperties history(const WellProductionProperties& prevProperties,
const DeckRecord& record,
const WellProducer::ControlModeEnum controlModeWHISTCL);
static WellProductionProperties prediction( const DeckRecord& record, bool addGroupProductionControl );
bool hasProductionControl(WellProducer::ControlModeEnum controlModeArg) const {
@@ -72,6 +75,9 @@ namespace Opm {
m_productionControls += controlModeArg;
}
// this is used to check whether the specified control mode is an effective history matching production mode
static bool effectiveHistoryProductionControl(const WellProducer::ControlModeEnum cmode);
private:
int m_productionControls = 0;

View File

@@ -0,0 +1,64 @@
/*
Copyright 2018 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WELLTEST_CONFIG_H
#define WELLTEST_CONFIG_H
#include <cstddef>
#include <string>
#include <vector>
namespace Opm {
class WellTestConfig {
public:
enum Reason {
PHYSICAL = 1,
ECONOMIC = 2,
GROUP = 4,
THP_DESIGN=8,
COMPLETION=16,
};
struct WTESTWell {
std::string name;
Reason shut_reason;
double test_interval;
int num_test;
double startup_time;
};
WellTestConfig();
void add_well(const std::string& well, Reason reason, double test_interval, int num_test, double startup_time);
void add_well(const std::string& well, const std::string& reasons, double test_interval, int num_test, double startup_time);
void drop_well(const std::string& well);
bool has(const std::string& well) const;
bool has(const std::string& well, Reason reason) const;
const WTESTWell& get(const std::string& well, Reason reason) const;
size_t size() const;
private:
std::vector<WTESTWell> wells;
};
}
#endif

View File

@@ -0,0 +1,117 @@
/*
Copyright 2018 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WELLTEST_STATE_H
#define WELLTEST_STATE_H
#include <cstddef>
#include <string>
#include <vector>
#include <opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp>
namespace Opm {
class WellTestState {
public:
/*
This class implements a small mutable state object which keeps track of
which wells have been automatically closed by the simulator, and by
checking with the WTEST configuration object the class can return a list
(well_name,reason) pairs for wells which should be checked as candiates
for opening.
*/
struct ClosedWell {
std::string name;
WellTestConfig::Reason reason;
double last_test;
int num_attempt;
};
struct ClosedCompletion {
std::string wellName;
int complnum;
double last_test;
int num_attempt;
};
/*
The simulator has decided to close a particular well; we then add it here
as a closed well with a particualar reason.
*/
void addClosedWell(const std::string& well_name, WellTestConfig::Reason reason, double sim_time);
/*
The simulator has decided to close a particular completion in a well; we then add it here
as a closed completions
*/
void addClosedCompletion(const std::string& well_name, int complnum, double sim_time);
/*
The update will consult the WellTestConfig object and return a list of
wells which should be checked for possible reopening; observe that the
update method will update the internal state of the object by counting up
the openiing attempts, and also set the time for the last attempt to open.
*/
std::vector<std::pair<std::string, WellTestConfig::Reason>> updateWell(const WellTestConfig& config, double sim_time);
/*
The update will consult the WellTestConfig object and return a list of
completions which should be checked for possible reopening; observe that the
update method will update the internal state of the object by counting up
the openiing attempts, and also set the time for the last attempt to open.
*/
std::vector<std::pair<std::string, int>> updateCompletion(const WellTestConfig& config, double sim_time);
/*
If the simulator decides that a constraint is no longer met the dropWell()
method should be called to indicate that this reason for keeping the well
closed is no longer active.
*/
void dropWell(const std::string& well_name, WellTestConfig::Reason reason);
/*
If the simulator decides that a constraint is no longer met the dropCompletion()
method should be called to indicate that this reason for keeping the well
closed is no longer active.
*/
void dropCompletion(const std::string& well_name, int complnum);
bool hasWell(const std::string& well_name, WellTestConfig::Reason reason) const;
void openWell(const std::string& well_name);
bool hasCompletion(const std::string& well_name, const int complnum) const;
size_t sizeWells() const;
size_t sizeCompletions() const;
private:
std::vector<ClosedWell> wells;
std::vector<ClosedCompletion> completions;
};
}
#endif

View File

@@ -31,11 +31,12 @@ namespace Opm {
public:
SimulationConfig(const Deck& deck,
SimulationConfig(bool restart,
const Deck& deck,
const Eclipse3DProperties& gridProperties);
const ThresholdPressure& getThresholdPressure() const;
bool hasThresholdPressure() const;
bool useThresholdPressure() const;
bool useCPR() const;
bool hasDISGAS() const;
bool hasVAPOIL() const;

View File

@@ -32,8 +32,8 @@ namespace Opm {
class ThresholdPressure {
public:
ThresholdPressure(const Deck& deck,
ThresholdPressure(bool restart,
const Deck& deck,
const Eclipse3DProperties& eclipseProperties);
@@ -63,8 +63,11 @@ namespace Opm {
*/
double getThresholdPressure(int r1 , int r2) const;
size_t size() const;
bool active() const;
bool restart() const;
private:
bool m_active;
bool m_restart;
static std::pair<int,int> makeIndex(int r1 , int r2);
void addPair(int r1 , int r2 , const std::pair<bool , double>& valuePair);
void addBarrier(int r1 , int r2);

View File

@@ -39,7 +39,6 @@ public:
double owSurfaceTension() const;
const Flag& flag() const;
const Direction& direction() const;
operator bool() const { return m_exists; }
private:
Flag m_flag; // JFUNC flag: WATER, GAS, or BOTH. Default BOTH
@@ -48,7 +47,6 @@ private:
double m_alphaFactor; // alternative porosity term. Default 0.5
double m_betaFactor; // alternative permeability term. Default 0.5
Direction m_direction; // XY, X, Y, Z. Default XY
const bool m_exists; // will be true if JFunc is specified in the deck
};
} // Opm::

View File

@@ -50,10 +50,10 @@ namespace Opm {
class Eqldims;
class Regdims;
class TableManager {
public:
explicit TableManager( const Deck& deck );
TableManager() = default;
const TableContainer& getTables( const std::string& tableName ) const;
const TableContainer& operator[](const std::string& tableName) const;
@@ -293,12 +293,10 @@ namespace Opm {
std::shared_ptr<Eqldims> m_eqldims;
Aqudims m_aqudims;
const bool hasImptvd;// if deck has keyword IMPTVD
const bool hasEnptvd;// if deck has keyword ENPTVD
const bool hasEqlnum;// if deck has keyword EQLNUM
const JFunc m_jfunc;
const bool hasImptvd = false;// if deck has keyword IMPTVD
const bool hasEnptvd = false;// if deck has keyword ENPTVD
const bool hasEqlnum = false;// if deck has keyword EQLNUM
std::shared_ptr<JFunc> jfunc;
double m_rtemp;
};

View File

@@ -243,6 +243,13 @@ namespace Opm {
const static std::string SUMMARY_UNKNOWN_WELL;
const static std::string SUMMARY_UNKNOWN_GROUP;
/*
A well must be specified (e.g. WELSPECS) and have completions
(e.g. COMPDAT) to be able to set control mode (e.g. WCONPROD).
A well missing specification and/or completion(s) will throw.
*/
const static std::string SCHEDULE_INVALID_NAME;
private:
void initDefault();
void initEnv();

View File

@@ -58,7 +58,9 @@ namespace Opm {
gas_surface_rate,
rate,
transmissibility,
effective_Kh,
mass,
mass_rate,
gas_oil_ratio,
oil_gas_ratio,
water_cut,

View File

@@ -82,7 +82,7 @@ class ECLFilesComparator {
//! \param[in] value2 Value for second file, the data type can be bool, int, double or std::string.
//! \details Templatefunction for printing values when exceptions are thrown. The function is defined for bool, int, double and std::string.
template <typename T>
void printValuesForCell(const std::string& keyword, int occurrence1, int occurrence2, size_t cell, const T& value1, const T& value2) const;
void printValuesForCell(const std::string& keyword, int occurrence1, int occurrence2, size_t kw_size, size_t cell, const T& value1, const T& value2) const;
public:
//! \brief Open ECLIPSE files and set tolerances and keywords.
@@ -159,7 +159,7 @@ class RegressionTest: public ECLFilesComparator {
// are larger than absTolerance and relTolerance, respectively. In addition,
// if allowNegativeValues is passed as false, an exception will be thrown when the absolute value
// of a negative value exceeds absTolerance. If no exceptions are thrown, the absolute and relative deviations are added to absDeviation and relDeviation.
void deviationsForCell(double val1, double val2, const std::string& keyword, int occurrence1, int occurrence2, size_t cell, bool allowNegativeValues = true);
void deviationsForCell(double val1, double val2, const std::string& keyword, int occurrence1, int occurrence2, size_t kw_size, size_t cell, bool allowNegativeValues = true);
public:
//! \brief Sets up the regression test.
//! \param[in] file_type Specifies which filetype to be compared, possible inputs are UNRSTFILE, INITFILE and RFTFILE.
@@ -175,8 +175,8 @@ class RegressionTest: public ECLFilesComparator {
void setOnlyLastOccurrence(bool onlyLastOccurrenceArg) {this->onlyLastOccurrence = onlyLastOccurrenceArg;}
//! \brief Compares grid properties of the two cases.
// gridCompare() checks if both the number of active and global cells in the two cases are the same. If they are, all cells are looped over to calculate the cell volume deviation for the two cases. If the both the relative and absolute deviation exceeds the tolerances, an exception is thrown.
void gridCompare() const;
// gridCompare() checks if both the number of active and global cells in the two cases are the same. If they are, and volumecheck is true, all cells are looped over to calculate the cell volume deviation for the two cases. If the both the relative and absolute deviation exceeds the tolerances, an exception is thrown.
void gridCompare(const bool volumecheck) const;
//! \brief Calculates deviations for all keywords.
// This function checks if the number of keywords of the two cases are equal, and if it is, resultsForKeyword() is called for every keyword. If not, an exception is thrown.
void results();

View File

@@ -12,7 +12,7 @@ License: GPL-3.0
Group: Development/Libraries/C and C++
Url: http://www.opm-project.org/
Source0: https://github.com/OPM/%{name}/archive/release/%{version}/%{tag}.tar.gz#/%{name}-%{version}.tar.gz
BuildRequires: git doxygen bc devtoolset-6-toolchain ecl-devel
BuildRequires: git doxygen bc devtoolset-6-toolchain ecl-devel openmpi-devel mpich-devel zlib-devel
%{?el6:BuildRequires: cmake3 boost148-devel}
%{!?el6:BuildRequires: cmake boost-devel}
BuildRoot: %{_tmppath}/%{name}-%{version}-build
@@ -27,6 +27,20 @@ Group: System/Libraries
%description -n libopm-common1
This package contains library for opm-common
%package -n libopm-common1-openmpi
Summary: OPM-common - library
Group: System/Libraries
%description -n libopm-common1-openmpi
This package contains library for opm-common
%package -n libopm-common1-mpich
Summary: OPM-common - library
Group: System/Libraries
%description -n libopm-common1-mpich
This package contains library for opm-common
%package devel
Summary: Development and header files for opm-common
Group: Development/Libraries/C and C++
@@ -35,6 +49,48 @@ Requires: %{name} = %{version}
%description devel
This package contains the development and header files for opm-common
%package openmpi-devel
Summary: Development and header files for opm-common
Group: Development/Libraries/C and C++
Requires: %{name} = %{version}
Requires: libopm-common1-openmpi = %{version}
%description openmpi-devel
This package contains the development and header files for opm-common
%package mpich-devel
Summary: Development and header files for opm-common
Group: Development/Libraries/C and C++
Requires: %{name} = %{version}
Requires: libopm-common1-mpich = %{version}
%description mpich-devel
This package contains the development and header files for opm-common
%package bin
Summary: Applications for opm-common
Group: System/Binaries
Requires: %{name} = %{version}
%description bin
This package the applications for opm-common
%package openmpi-bin
Summary: Applications for opm-common
Group: System/Binaries
Requires: libopm-common1-openmpi = %{version}
%description openmpi-bin
This package the applications for opm-common
%package mpich-bin
Summary: Applications for opm-common
Group: System/Binaries
Requires: libopm-common1-mpich = %{version}
%description mpich-bin
This package the applications for opm-common
%package doc
Summary: Documentation files for opm-common
Group: Documentation
@@ -49,11 +105,45 @@ This package contains the documentation files for opm-common
# consider using -DUSE_VERSIONED_DIR=ON if backporting
%build
scl enable devtoolset-6 bash
%{?el6:cmake28} %{?!el6:cmake} -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSTRIP_DEBUGGING_SYMBOLS=ON -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gfortran %{?el6:-DBOOST_LIBRARYDIR=%{_libdir}/boost148 -DBOOST_INCLUDEDIR=%{_includedir}/boost148}
make
mkdir serial
cd serial
%{?el6:cmake3} %{?!el6:cmake} -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSTRIP_DEBUGGING_SYMBOLS=ON -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gfortran %{?el6:-DBOOST_LIBRARYDIR=%{_libdir}/boost148 -DBOOST_INCLUDEDIR=%{_includedir}/boost148} ..
make %{?_smp_mflags}
make test
cd ..
mkdir openmpi
cd openmpi
%{?el6:module load openmpi-x86_64}
%{?!el6:module load mpi/openmpi-x86_64}
%{?el6:cmake3} %{?!el6:cmake} -DUSE_MPI=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSTRIP_DEBUGGING_SYMBOLS=ON -DCMAKE_INSTALL_PREFIX=%{_prefix}/lib64/openmpi -DCMAKE_INSTALL_LIBDIR=lib -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gfortran %{?el6:-DBOOST_LIBRARYDIR=%{_libdir}/boost148 -DBOOST_INCLUDEDIR=%{_includedir}/boost148} ..
make %{?_smp_mflags}
make test
cd ..
mkdir mpich
cd mpich
%{?el6:module rm openmpi-x86_64}
%{?el6:module load mpich-x86_64}
%{?!el6:module rm mpi/openmpi-x86_64}
%{?!el6:module load mpi/mpich-x86_64}
%{?el6:cmake3} %{?!el6:cmake} -DUSE_MPI=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSTRIP_DEBUGGING_SYMBOLS=ON -DCMAKE_INSTALL_PREFIX=%{_prefix}/lib64/mpich -DCMAKE_INSTALL_LIBDIR=lib -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gfortran %{?el6:-DBOOST_LIBRARYDIR=%{_libdir}/boost148 -DBOOST_INCLUDEDIR=%{_includedir}/boost148} ..
make %{?_smp_mflags}
make test
%install
cd serial
make install DESTDIR=${RPM_BUILD_ROOT}
make install-html DESTDIR=${RPM_BUILD_ROOT}
cd ..
cd openmpi
make install DESTDIR=${RPM_BUILD_ROOT}
mv ${RPM_BUILD_ROOT}/usr/lib64/openmpi/include/* ${RPM_BUILD_ROOT}/usr/include/openmpi-x86_64/
cd ..
cd mpich
make install DESTDIR=${RPM_BUILD_ROOT}
mv ${RPM_BUILD_ROOT}/usr/lib64/mpich/include/* ${RPM_BUILD_ROOT}/usr/include/mpich-x86_64/
%clean
rm -rf %{buildroot}
@@ -64,15 +154,50 @@ rm -rf %{buildroot}
%files doc
%{_docdir}/*
%files bin
%{_bindir}/*
%files openmpi-bin
%{_libdir}/openmpi/bin/*
%files mpich-bin
%{_libdir}/mpich/bin/*
%files -n libopm-common1
%defattr(-,root,root,-)
%{_libdir}/*.so.*
%files -n libopm-common1-openmpi
%defattr(-,root,root,-)
%{_libdir}/openmpi/lib/*.so.*
%files -n libopm-common1-mpich
%defattr(-,root,root,-)
%{_libdir}/mpich/lib/*.so.*
%files devel
%defattr(-,root,root,-)
%{_libdir}/dunecontrol/*
/usr/lib/dunecontrol/*
%{_libdir}/pkgconfig/*
%{_includedir}/*
%{_datadir}/cmake/*
%{_datadir}/opm/*
%{_libdir}/*.so
%files openmpi-devel
%defattr(-,root,root,-)
%{_libdir}/openmpi/lib/dunecontrol/*
%{_libdir}/openmpi/lib/pkgconfig/*
%{_includedir}/openmpi-x86_64/*
%{_libdir}/openmpi/share/cmake/*
%{_libdir}/openmpi/share/opm/*
%{_libdir}/openmpi/lib/*.so
%files mpich-devel
%defattr(-,root,root,-)
%{_libdir}/mpich/lib/dunecontrol/*
%{_libdir}/mpich/lib/pkgconfig/*
%{_includedir}/mpich-x86_64/*
%{_libdir}/mpich/share/cmake/*
%{_libdir}/mpich/share/opm/*
%{_libdir}/mpich/lib/*.so

View File

@@ -23,7 +23,20 @@
#include <iostream>
#include <errno.h> // For errno
#include <stdio.h> // For fileno() and stdout
#if defined(_MSC_VER)
// MS put some POSIX-like functions in io.h, but prefix them with underscore
// since they are considered "vendor" and not standard functions.
#define _CRT_NONSTDC_NO_DEPRECATE
#include <io.h>
#define isatty _isatty
#elif defined(__MINGW32__)
// MinGW also has the isatty function in io.h instead of unistd.h, but without
// the underscore.
#include <io.h>
#else
#include <unistd.h> // For isatty()
#endif
namespace Opm {

View File

@@ -17,6 +17,7 @@
#include <algorithm>
#include <cassert>
#include <cmath>
#include <opm/common/utility/numeric/calculateCellVol.hpp>
@@ -126,6 +127,12 @@ double calculateCellVol(const std::vector<double>& X, const std::vector<double>&
vect[j] = Y.data();
} else if (permutation[j] == 3){
vect[j] = Z.data();
} else {
// this condition can never happen, since all values in 'permutation'
// is covered, but compiler analysis may not be deep enough to not give
// warnings about 'vect' being uninitialized further down.
assert(false);
vect[j] = 0;
}
}

View File

@@ -0,0 +1,811 @@
/*
Copyright 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/output/eclipse/AggregateWellData.hpp>
#include <opm/output/eclipse/VectorItems/intehead.hpp>
#include <opm/output/eclipse/VectorItems/well.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/Units/Units.hpp>
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <iterator>
#include <string>
namespace VI = Opm::RestartIO::Helpers::VectorItems;
// #####################################################################
// Class Opm::RestartIO::Helpers::AggregateWellData
// ---------------------------------------------------------------------
namespace {
std::size_t numWells(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NWELLS];
}
int maxNumGroups(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NWGMAX];
}
std::string trim(const std::string& s)
{
const auto b = s.find_first_not_of(" \t");
if (b == std::string::npos) {
// All blanks. Return empty.
return "";
}
const auto e = s.find_last_not_of(" \t");
assert ((e != std::string::npos) && "Logic Error");
// Remove leading/trailing blanks.
return s.substr(b, e - b + 1);
}
std::vector<std::string>
groupNames(const std::vector<const Opm::Group*>& groups)
{
auto gnms = std::vector<std::string>{};
gnms.reserve(groups.size());
for (const auto* group : groups) {
gnms.push_back(trim(group->name()));
}
return gnms;
}
template <typename WellOp>
void wellLoop(const std::vector<const Opm::Well*>& wells,
WellOp&& wellOp)
{
for (auto nWell = wells.size(), wellID = 0*nWell;
wellID < nWell; ++wellID)
{
const auto* well = wells[wellID];
if (well == nullptr) { continue; }
wellOp(*well, wellID);
}
}
namespace IWell {
std::size_t entriesPerWell(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NIWELZ];
}
Opm::RestartIO::Helpers::WindowedArray<int>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<int>;
return WV {
WV::NumWindows{ numWells(inteHead) },
WV::WindowSize{ entriesPerWell(inteHead) }
};
}
int groupIndex(const std::string& grpName,
const std::vector<std::string>& groupNames,
const int maxGroups)
{
if (grpName == "FIELD") {
// Not really supposed to happen since wells are
// not supposed to be parented dirctly to FIELD.
return maxGroups + 1;
}
auto b = std::begin(groupNames);
auto e = std::end (groupNames);
auto i = std::find(b, e, grpName);
if (i == e) {
// Not really supposed to happen since wells are
// not supposed to be parented dirctly to FIELD.
return maxGroups + 1;
}
// One-based indexing.
return std::distance(b, i) + 1;
}
int wellType(const Opm::Well& well,
const std::size_t sim_step)
{
using WTypeVal = ::Opm::RestartIO::Helpers::
VectorItems::IWell::Value::WellType;
if (well.isProducer(sim_step)) {
return WTypeVal::Producer;
}
using IType = ::Opm::WellInjector::TypeEnum;
const auto itype = well
.getInjectionProperties(sim_step).injectorType;
switch (itype) {
case IType::OIL: return WTypeVal::OilInj;
case IType::WATER: return WTypeVal::WatInj;
case IType::GAS: return WTypeVal::GasInj;
default: return WTypeVal::WTUnk;
}
}
int wellVFPTab(const Opm::Well& well,
const std::size_t sim_step)
{
if (well.isInjector(sim_step)) {
return well.getInjectionProperties(sim_step).VFPTableNumber;
}
return well.getProductionProperties(sim_step).VFPTableNumber;
}
int ctrlMode(const Opm::Well& well,
const std::size_t sim_step)
{
using WMCtrlVal = ::Opm::RestartIO::Helpers::
VectorItems::IWell::Value::WellCtrlMode;
{
const auto stat = well.getStatus(sim_step);
using WStat = ::Opm::WellCommon::StatusEnum;
if ((stat == WStat::SHUT) || (stat == WStat::STOP)) {
return WMCtrlVal::Shut;
}
}
if (well.isInjector(sim_step)) {
const auto& prop = well
.getInjectionProperties(sim_step);
const auto wmctl = prop.controlMode;
const auto wtype = prop.injectorType;
using CMode = ::Opm::WellInjector::ControlModeEnum;
using WType = ::Opm::WellInjector::TypeEnum;
switch (wmctl) {
case CMode::RATE: {
switch (wtype) {
case WType::OIL: return WMCtrlVal::OilRate;
case WType::WATER: return WMCtrlVal::WatRate;
case WType::GAS: return WMCtrlVal::GasRate;
case WType::MULTI: return WMCtrlVal::WMCtlUnk;
}
}
break;
case CMode::RESV: return WMCtrlVal::ResVRate;
case CMode::THP: return WMCtrlVal::THP;
case CMode::BHP: return WMCtrlVal::BHP;
case CMode::GRUP: return WMCtrlVal::Group;
default:
return WMCtrlVal::WMCtlUnk;
}
}
else if (well.isProducer(sim_step)) {
const auto& prop = well
.getProductionProperties(sim_step);
using CMode = ::Opm::WellProducer::ControlModeEnum;
switch (prop.controlMode) {
case CMode::ORAT: return WMCtrlVal::OilRate;
case CMode::WRAT: return WMCtrlVal::WatRate;
case CMode::GRAT: return WMCtrlVal::GasRate;
case CMode::LRAT: return WMCtrlVal::LiqRate;
case CMode::RESV: return WMCtrlVal::ResVRate;
case CMode::THP: return WMCtrlVal::THP;
case CMode::BHP: return WMCtrlVal::BHP;
case CMode::CRAT: return WMCtrlVal::CombRate;
case CMode::GRUP: return WMCtrlVal::Group;
default: return WMCtrlVal::WMCtlUnk;
}
}
return WMCtrlVal::WMCtlUnk;
}
int compOrder(const Opm::Well& well)
{
using WCO = ::Opm::WellCompletion::CompletionOrderEnum;
using COVal = ::Opm::RestartIO::Helpers::
VectorItems::IWell::Value::CompOrder;
switch (well.getWellConnectionOrdering()) {
case WCO::TRACK: return COVal::Track;
case WCO::DEPTH: return COVal::Depth;
case WCO::INPUT: return COVal::Input;
}
return 0;
}
template <class IWellArray>
void staticContrib(const Opm::Well& well,
const std::size_t msWellID,
const std::vector<std::string>& groupNames,
const int maxGroups,
const std::size_t sim_step,
IWellArray& iWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::IWell::index;
iWell[Ix::IHead] = well.getHeadI(sim_step) + 1;
iWell[Ix::JHead] = well.getHeadJ(sim_step) + 1;
// Connections
{
const auto& conn = well.getConnections(sim_step);
iWell[Ix::NConn] = static_cast<int>(conn.size());
iWell[Ix::FirstK] = (iWell[Ix::NConn] == 0)
? 0 : conn.get(0).getK() + 1;
iWell[Ix::LastK] = (iWell[Ix::NConn] == 0)
? 0 : conn.get(conn.size() - 1).getK() + 1;
}
iWell[Ix::Group] =
groupIndex(trim(well.getGroupName(sim_step)),
groupNames, maxGroups);
iWell[Ix::WType] = wellType (well, sim_step);
iWell[Ix::WCtrl] = ctrlMode (well, sim_step);
iWell[Ix::VFPTab] = wellVFPTab(well, sim_step);
// The following items aren't fully characterised yet, but
// needed for restart of M2. Will need further refinement.
iWell[Ix::item18] = -100;
iWell[Ix::item25] = - 1;
iWell[Ix::item32] = 7;
iWell[Ix::item48] = - 1;
iWell[Ix::item50] = iWell[Ix::WCtrl];
// Multi-segmented well information
iWell[Ix::MsWID] = 0; // MS Well ID (0 or 1..#MS wells)
iWell[Ix::NWseg] = 0; // Number of well segments
if (well.isMultiSegment(sim_step)) {
iWell[Ix::MsWID] = static_cast<int>(msWellID);
iWell[Ix::NWseg] =
well.getWellSegments(sim_step).size();
}
iWell[Ix::CompOrd] = compOrder(well);
}
template <class IWellArray>
void dynamicContribShut(IWellArray& iWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::IWell::index;
iWell[Ix::item9 ] = -1000;
iWell[Ix::item11] = -1000;
}
template <class IWellArray>
void dynamicContribOpen(const Opm::data::Well& xw,
IWellArray& iWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::IWell::index;
const auto any_flowing_conn =
std::any_of(std::begin(xw.connections),
std::end (xw.connections),
[](const Opm::data::Connection& c)
{
return c.rates.any();
});
iWell[Ix::item9] = any_flowing_conn
? iWell[Ix::WCtrl] : -1;
iWell[Ix::item11] = 1;
}
} // IWell
namespace SWell {
std::size_t entriesPerWell(const std::vector<int>& inteHead)
{
assert ((inteHead[VI::intehead::NSWELZ] > 121) &&
"SWEL must allocate at least 122 elements per well");
return inteHead[VI::intehead::NSWELZ];
}
float datumDepth(const Opm::Well& well,
const std::size_t sim_step)
{
if (well.isMultiSegment(sim_step)) {
// Datum depth for multi-segment wells is
// depth of top-most segment.
return well.getWellSegments(sim_step)
.depthTopSegment();
}
// Not a multi-segment well--i.e., this is a regular
// well. Use well's reference depth.
return well.getRefDepth(sim_step);
}
Opm::RestartIO::Helpers::WindowedArray<float>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<float>;
return WV {
WV::NumWindows{ numWells(inteHead) },
WV::WindowSize{ entriesPerWell(inteHead) }
};
}
std::vector<float> defaultSWell()
{
const auto dflt = -1.0e+20f;
const auto infty = 1.0e+20f;
const auto zero = 0.0f;
const auto one = 1.0f;
const auto half = 0.5f;
// Initial data by Statoil ASA.
return { // 122 Items (0..121)
// 0 1 2 3 4 5
infty, infty, infty, infty, infty, infty, // 0.. 5 ( 0)
one , zero , zero , zero , zero , 1.0e-05f, // 6.. 11 ( 1)
zero , zero , infty, infty, zero , dflt , // 12.. 17 ( 2)
infty, infty, infty, infty, infty, zero , // 18.. 23 ( 3)
one , zero , zero , zero , zero , zero , // 24.. 29 ( 4)
zero , one , zero , infty, zero , zero , // 30.. 35 ( 5)
zero , zero , zero , zero , zero , zero , // 36.. 41 ( 6)
zero , zero , zero , zero , zero , zero , // 42.. 47 ( 7)
zero , zero , zero , zero , zero , zero , // 48.. 53 ( 8)
infty, zero , zero , zero , zero , zero , // 54.. 59 ( 9)
zero , zero , zero , zero , zero , zero , // 60.. 65 (10)
zero , zero , zero , zero , zero , zero , // 66.. 71 (11)
zero , zero , zero , zero , zero , zero , // 72.. 77 (12)
zero , infty, infty, zero , zero , one , // 78.. 83 (13)
one , one , zero , infty, zero , infty, // 84.. 89 (14)
one , dflt , one , zero , zero , zero , // 90.. 95 (15)
zero , zero , zero , zero , zero , zero , // 96..101 (16)
zero , zero , zero , zero , zero , zero , // 102..107 (17)
zero , zero , half , one , zero , zero , // 108..113 (18)
zero , zero , zero , zero , zero , infty, // 114..119 (19)
zero , one , // 120..121 (20)
};
}
template <class SWellArray>
void assignDefaultSWell(SWellArray& sWell)
{
const auto& init = defaultSWell();
const auto sz = static_cast<
decltype(init.size())>(sWell.size());
auto b = std::begin(init);
auto e = b + std::min(init.size(), sz);
std::copy(b, e, std::begin(sWell));
}
template <class SWellArray>
void staticContrib(const Opm::Well& well,
const Opm::UnitSystem& units,
const std::size_t sim_step,
SWellArray& sWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SWell::index;
using M = ::Opm::UnitSystem::measure;
auto swprop = [&units](const M u, const double x) -> float
{
return static_cast<float>(units.from_si(u, x));
};
assignDefaultSWell(sWell);
if (well.isProducer(sim_step)) {
const auto& pp = well.getProductionProperties(sim_step);
using PP = ::Opm::WellProducer::ControlModeEnum;
if (pp.hasProductionControl(PP::ORAT)) {
sWell[Ix::OilRateTarget] =
swprop(M::liquid_surface_rate, pp.OilRate);
}
if (pp.hasProductionControl(PP::WRAT)) {
sWell[Ix::WatRateTarget] =
swprop(M::liquid_surface_rate, pp.WaterRate);
}
if (pp.hasProductionControl(PP::GRAT)) {
sWell[Ix::GasRateTarget] =
swprop(M::gas_surface_rate, pp.GasRate);
}
if (pp.hasProductionControl(PP::LRAT)) {
sWell[Ix::LiqRateTarget] =
swprop(M::liquid_surface_rate, pp.LiquidRate);
}
else if (pp.hasProductionControl(PP::ORAT) &&
pp.hasProductionControl(PP::WRAT))
{
sWell[Ix::LiqRateTarget] =
swprop(M::liquid_surface_rate, pp.OilRate + pp.WaterRate);
}
if (pp.hasProductionControl(PP::RESV)) {
sWell[Ix::ResVRateTarget] =
swprop(M::rate, pp.ResVRate);
}
if (pp.hasProductionControl(PP::THP)) {
sWell[Ix::THPTarget] =
swprop(M::pressure, pp.THPLimit);
}
sWell[Ix::BHPTarget] = pp.hasProductionControl(PP::BHP)
? swprop(M::pressure, pp.BHPLimit)
: swprop(M::pressure, 100.0e3*::Opm::unit::psia);
}
else if (well.isInjector(sim_step)) {
const auto& ip = well.getInjectionProperties(sim_step);
using IP = ::Opm::WellInjector::ControlModeEnum;
if (ip.hasInjectionControl(IP::THP)) {
sWell[Ix::THPTarget] = swprop(M::pressure, ip.THPLimit);
}
sWell[Ix::BHPTarget] = ip.hasInjectionControl(IP::BHP)
? swprop(M::pressure, ip.BHPLimit)
: swprop(M::pressure, 1.0*::Opm::unit::atm);
}
sWell[Ix::DatumDepth] =
swprop(M::length, datumDepth(well, sim_step));
}
} // SWell
namespace XWell {
std::size_t entriesPerWell(const std::vector<int>& inteHead)
{
assert ((inteHead[VI::intehead::NXWELZ] > 123) &&
"XWEL must allocate at least 124 elements per well");
return inteHead[VI::intehead::NXWELZ];
}
Opm::RestartIO::Helpers::WindowedArray<double>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<double>;
return WV {
WV::NumWindows{ numWells(inteHead) },
WV::WindowSize{ entriesPerWell(inteHead) }
};
}
template <class XWellArray>
void staticContrib(const ::Opm::Well& well,
const Opm::UnitSystem& units,
const std::size_t sim_step,
XWellArray& xWell)
{
using M = ::Opm::UnitSystem::measure;
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
const auto bhpTarget = well.isInjector(sim_step)
? well.getInjectionProperties (sim_step).BHPLimit
: well.getProductionProperties(sim_step).BHPLimit;
xWell[Ix::BHPTarget] = units.from_si(M::pressure, bhpTarget);
}
template <class XWellArray>
void assignProducer(const std::string& well,
const ::Opm::SummaryState& smry,
XWellArray& xWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
auto get = [&smry, &well](const std::string& vector)
{
return smry.get(vector + ':' + well);
};
xWell[Ix::OilPrRate] = get("WOPR");
xWell[Ix::WatPrRate] = get("WWPR");
xWell[Ix::GasPrRate] = get("WGPR");
xWell[Ix::LiqPrRate] = xWell[Ix::OilPrRate]
+ xWell[Ix::WatPrRate];
xWell[Ix::VoidPrRate] = get("WVPR");
xWell[Ix::FlowBHP] = get("WBHP");
xWell[Ix::WatCut] = get("WWCT");
xWell[Ix::GORatio] = get("WGOR");
xWell[Ix::OilPrTotal] = get("WOPT");
xWell[Ix::WatPrTotal] = get("WWPT");
xWell[Ix::GasPrTotal] = get("WGPT");
xWell[Ix::VoidPrTotal] = get("WVPT");
// Not fully characterised.
xWell[Ix::item37] = xWell[Ix::WatPrRate];
xWell[Ix::item38] = xWell[Ix::GasPrRate];
}
template <class XWellArray>
void assignWaterInjector(const std::string& well,
const ::Opm::SummaryState& smry,
XWellArray& xWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
auto get = [&smry, &well](const std::string& vector)
{
return smry.get(vector + ':' + well);
};
// Injection rates reported as negative, cumulative
// totals as positive.
xWell[Ix::WatPrRate] = -get("WWIR");
xWell[Ix::LiqPrRate] = xWell[Ix::WatPrRate];
xWell[Ix::FlowBHP] = get("WBHP");
xWell[Ix::WatInjTotal] = get("WWIT");
xWell[Ix::item37] = xWell[Ix::WatPrRate];
xWell[Ix::item82] = xWell[Ix::WatInjTotal];
xWell[Ix::WatVoidPrRate] = -get("WWVIR");
}
template <class XWellArray>
void assignGasInjector(const std::string& well,
const ::Opm::SummaryState& smry,
XWellArray& xWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
auto get = [&smry, &well](const std::string& vector)
{
return smry.get(vector + ':' + well);
};
// Injection rates reported as negative production rates,
// cumulative injection totals as positive.
xWell[Ix::GasPrRate] = -get("WGIR");
xWell[Ix::VoidPrRate] = -get("WGVIR");
xWell[Ix::FlowBHP] = get("WBHP");
xWell[Ix::GasInjTotal] = get("WGIT");
xWell[Ix::GasFVF] = xWell[Ix::VoidPrRate]
/ xWell[Ix::GasPrRate];
// Not fully characterised.
xWell[Ix::item38] = xWell[Ix::GasPrRate];
xWell[Ix::item83] = xWell[Ix::GasInjTotal];
xWell[Ix::GasVoidPrRate] = xWell[Ix::VoidPrRate];
}
template <class XWellArray>
void dynamicContrib(const ::Opm::Well& well,
const ::Opm::SummaryState& smry,
const std::size_t sim_step,
XWellArray& xWell)
{
if (well.isProducer(sim_step)) {
assignProducer(well.name(), smry, xWell);
}
else if (well.isInjector(sim_step)) {
using IType = ::Opm::WellInjector::TypeEnum;
const auto itype = well
.getInjectionProperties(sim_step).injectorType;
switch (itype) {
case IType::OIL:
// Do nothing.
break;
case IType::WATER:
assignWaterInjector(well.name(), smry, xWell);
break;
case IType::GAS:
assignGasInjector(well.name(), smry, xWell);
break;
case IType::MULTI:
assignWaterInjector(well.name(), smry, xWell);
assignGasInjector (well.name(), smry, xWell);
break;
}
}
}
} // XWell
namespace ZWell {
std::size_t entriesPerWell(const std::vector<int>& inteHead)
{
assert ((inteHead[VI::intehead::NZWELZ] > 1) &&
"ZWEL must allocate at least 1 element per well");
return inteHead[VI::intehead::NZWELZ];
}
Opm::RestartIO::Helpers::WindowedArray<
Opm::RestartIO::Helpers::CharArrayNullTerm<8>
>
allocate(const std::vector<int>& inteHead)
{
using WV = Opm::RestartIO::Helpers::WindowedArray<
Opm::RestartIO::Helpers::CharArrayNullTerm<8>
>;
return WV {
WV::NumWindows{ numWells(inteHead) },
WV::WindowSize{ entriesPerWell(inteHead) }
};
}
template <class ZWellArray>
void staticContrib(const Opm::Well& well, ZWellArray& zWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::ZWell::index;
zWell[Ix::WellName] = well.name();
}
} // ZWell
} // Anonymous
// =====================================================================
Opm::RestartIO::Helpers::AggregateWellData::
AggregateWellData(const std::vector<int>& inteHead)
: iWell_ (IWell::allocate(inteHead))
, sWell_ (SWell::allocate(inteHead))
, xWell_ (XWell::allocate(inteHead))
, zWell_ (ZWell::allocate(inteHead))
, nWGMax_(maxNumGroups(inteHead))
{}
// ---------------------------------------------------------------------
void
Opm::RestartIO::Helpers::AggregateWellData::
captureDeclaredWellData(const Schedule& sched,
const UnitSystem& units,
const std::size_t sim_step)
{
const auto& wells = sched.getWells(sim_step);
// Static contributions to IWEL array.
{
const auto grpNames = groupNames(sched.getGroups());
auto msWellID = std::size_t{0};
wellLoop(wells, [&grpNames, &msWellID, sim_step, this]
(const Well& well, const std::size_t wellID) -> void
{
msWellID += well.isMultiSegment(sim_step); // 1-based index.
auto iw = this->iWell_[wellID];
IWell::staticContrib(well, msWellID, grpNames,
this->nWGMax_, sim_step, iw);
});
}
// Static contributions to SWEL array.
wellLoop(wells, [&units, sim_step, this]
(const Well& well, const std::size_t wellID) -> void
{
auto sw = this->sWell_[wellID];
SWell::staticContrib(well, units, sim_step, sw);
});
// Static contributions to XWEL array.
wellLoop(wells, [&units, sim_step, this]
(const Well& well, const std::size_t wellID) -> void
{
auto xw = this->xWell_[wellID];
XWell::staticContrib(well, units, sim_step, xw);
});
// Static contributions to ZWEL array.
wellLoop(wells,
[this](const Well& well, const std::size_t wellID) -> void
{
auto zw = this->zWell_[wellID];
ZWell::staticContrib(well, zw);
});
}
// ---------------------------------------------------------------------
void
Opm::RestartIO::Helpers::AggregateWellData::
captureDynamicWellData(const Schedule& sched,
const std::size_t sim_step,
const Opm::data::WellRates& xw,
const ::Opm::SummaryState& smry)
{
const auto& wells = sched.getWells(sim_step);
// Dynamic contributions to IWEL array.
wellLoop(wells, [this, &xw]
(const Well& well, const std::size_t wellID) -> void
{
auto iWell = this->iWell_[wellID];
auto i = xw.find(well.name());
if ((i == std::end(xw)) || !i->second.flowing()) {
IWell::dynamicContribShut(iWell);
}
else {
IWell::dynamicContribOpen(i->second, iWell);
}
});
// Dynamic contributions to XWEL array.
wellLoop(wells, [this, sim_step, &smry]
(const Well& well, const std::size_t wellID) -> void
{
auto xw = this->xWell_[wellID];
XWell::dynamicContrib(well, smry, sim_step, xw);
});
}

View File

@@ -0,0 +1,89 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
#include <opm/output/eclipse/DoubHEAD.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/Units/Units.hpp>
#include <chrono>
#include <cstddef>
#include <vector>
namespace {
Opm::RestartIO::DoubHEAD::TimeStamp
computeTimeStamp(const ::Opm::Schedule& sched,
const double elapsed)
{
return {
std::chrono::system_clock::from_time_t(sched.getStartTime()),
std::chrono::duration<
double, std::chrono::seconds::period>{ elapsed },
};
}
double getTimeConv(const ::Opm::UnitSystem& us)
{
switch (us.getType()) {
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC:
return static_cast<double>(Opm::Metric::Time);
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_FIELD:
return static_cast<double>(Opm::Field::Time);
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_LAB:
return static_cast<double>(Opm::Lab::Time);
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_PVT_M:
return static_cast<double>(Opm::PVT_M::Time);
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_INPUT:
throw std::invalid_argument {
"Cannot Run Simulation With Non-Standard Units"
};
}
return static_cast<double>(Opm::Metric::Time);
}
} // Anonymous
// #####################################################################
// Public Interface (createDoubHead()) Below Separator
// ---------------------------------------------------------------------
std::vector<double>
Opm::RestartIO::Helpers::
createDoubHead(const EclipseState& es,
const Schedule& sched,
const std::size_t lookup_step,
const double simTime)
{
const auto dh = DoubHEAD{}
.tuningParameters(sched.getTuning(), lookup_step,
getTimeConv(es.getDeckUnitSystem()))
.timeStamp (computeTimeStamp(sched, simTime))
.drsdt (sched, lookup_step)
;
return dh.data();
}

View File

@@ -0,0 +1,240 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
#include <opm/output/eclipse/InteHEAD.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/Regdims.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <algorithm>
#include <cstddef>
#include <exception>
#include <stdexcept>
#include <vector>
namespace {
Opm::RestartIO::InteHEAD::WellTableDim
getWellTableDims(const ::Opm::Runspec& rspec,
const ::Opm::Schedule& sched,
const std::size_t lookup_step)
{
const auto& wd = rspec.wellDimensions();
const auto numWells = static_cast<int>(sched.numWells(lookup_step));
const auto maxPerf = wd.maxConnPerWell();
const auto maxWellInGroup = wd.maxWellsPerGroup();
const auto maxGroupInField = wd.maxGroupsInField();
return {
numWells,
maxPerf,
maxWellInGroup,
maxGroupInField,
};
}
std::array<int, 4> getNGRPZ(const ::Opm::Runspec& rspec)
{
const auto& wd = rspec.wellDimensions();
const int nigrpz = 97 + std::max(wd.maxWellsPerGroup(),
wd.maxGroupsInField());
const int nsgrpz = 112;
const int nxgrpz = 180;
const int nzgrpz = 5;
return {
nigrpz,
nsgrpz,
nxgrpz,
nzgrpz
};
}
Opm::RestartIO::InteHEAD::UnitSystem
getUnitConvention(const ::Opm::UnitSystem& us)
{
using US = ::Opm::RestartIO::InteHEAD::UnitSystem;
switch (us.getType()) {
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC:
return US::Metric;
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_FIELD:
return US::Field;
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_LAB:
return US::Lab;
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_PVT_M:
return US::PVT_M;
case ::Opm::UnitSystem::UnitType::UNIT_TYPE_INPUT:
throw std::invalid_argument {
"Cannot Run Simulation With Non-Standard Units"
};
}
return US::Metric;
}
Opm::RestartIO::InteHEAD::Phases
getActivePhases(const ::Opm::Runspec& rspec)
{
auto phases = ::Opm::RestartIO::InteHEAD::Phases{};
const auto& phasePred = rspec.phases();
phases.oil = phasePred.active(Opm::Phase::OIL);
phases.water = phasePred.active(Opm::Phase::WATER);
phases.gas = phasePred.active(Opm::Phase::GAS);
return phases;
}
Opm::RestartIO::InteHEAD::TuningPar
getTuningPars(const ::Opm::Tuning& tuning,
const std::size_t lookup_step)
{
const auto& newtmx = tuning.getNEWTMX(lookup_step);
const auto& newtmn = tuning.getNEWTMN(lookup_step);
const auto& litmax = tuning.getLITMAX(lookup_step);
const auto& litmin = tuning.getLITMIN(lookup_step);
const auto& mxwsit = tuning.getMXWSIT(lookup_step);
const auto& mxwpit = tuning.getMXWPIT(lookup_step);
return {
newtmx,
newtmn,
litmax,
litmin,
mxwsit,
mxwpit,
};
}
Opm::RestartIO::InteHEAD::WellSegDims
getWellSegDims(const ::Opm::Runspec& rspec,
const ::Opm::Schedule& sched,
const std::size_t lookup_step)
{
const auto& wsd = rspec.wellSegmentDimensions();
const auto& sched_wells = sched.getWells(lookup_step);
const auto nsegwl =
std::count_if(std::begin(sched_wells), std::end(sched_wells),
[lookup_step](const Opm::Well* wellPtr)
{
return wellPtr->isMultiSegment(lookup_step);
});
const auto nswlmx = wsd.maxSegmentedWells();
const auto nsegmx = wsd.maxSegmentsPerWell();
const auto nlbrmx = wsd.maxLateralBranchesPerWell();
const auto nisegz = 22; // Number of entries per segment in ISEG.
const auto nrsegz = 140; // Number of entries per segment in RSEG array.
const auto nilbrz = 10; // Number of entries per segment in ILBR array.
return {
static_cast<int>(nsegwl),
nswlmx,
nsegmx,
nlbrmx,
nisegz,
nrsegz,
nilbrz
};
}
Opm::RestartIO::InteHEAD::RegDims
getRegDims(const ::Opm::TableManager& tdims,
const ::Opm::Regdims& rdims)
{
const auto ntfip = tdims.numFIPRegions();
const auto nmfipr = rdims.getNMFIPR();
const auto nrfreg = rdims.getNRFREG();
const auto ntfreg = rdims.getNTFREG();
const auto nplmix = rdims.getNPLMIX();
return {
static_cast<int>(ntfip),
static_cast<int>(nmfipr),
static_cast<int>(nrfreg),
static_cast<int>(ntfreg),
static_cast<int>(nplmix),
};
}
} // Anonymous
// #####################################################################
// Public Interface (createInteHead()) Below Separator
// ---------------------------------------------------------------------
std::vector<int>
Opm::RestartIO::Helpers::
createInteHead(const EclipseState& es,
const EclipseGrid& grid,
const Schedule& sched,
const double simTime,
const int num_solver_steps,
const int lookup_step,
const int report_step)
{
const auto& rspec = es.runspec();
const auto& tdim = es.getTableManager();
const auto& rdim = tdim.getRegdims();
const auto ih = InteHEAD{}
.dimensions (grid.getNXYZ())
.numActive (static_cast<int>(grid.getNumActive()))
.unitConventions (getUnitConvention(es.getDeckUnitSystem()))
.wellTableDimensions(getWellTableDims(rspec, sched, lookup_step))
.calendarDate (getSimulationTimePoint(sched.posixStartTime(), simTime))
.activePhases (getActivePhases(rspec))
// The numbers below have been determined experimentally to work
// across a range of reference cases, but are not guaranteed to be
// universally valid.
.params_NWELZ (155, 122, 130, 3) // n{isxz}welz: number of data elements per well in {ISXZ}WELL
.params_NCON (25, 40, 58) // n{isx}conz: number of data elements per completion in ICON
.params_GRPZ (getNGRPZ(rspec))
// ncamax: max number of analytical aquifer connections
// n{isx}aaqz: number of data elements per aquifer in {ISX}AAQ
// n{isa}caqz: number of data elements per aquifer connection in {ISA}CAQ
.params_NAAQZ (1, 18, 24, 10, 7, 2, 4)
.stepParam (num_solver_steps, report_step)
.tuningParam (getTuningPars(sched.getTuning(), lookup_step))
.wellSegDimensions (getWellSegDims(rspec, sched, lookup_step))
.regionDimensions (getRegDims(tdim, rdim))
.variousParam (2014, 100) // Output should be compatible with Eclipse 100, 2014 version.
;
return ih.data();
}

View File

@@ -0,0 +1,45 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
#include <opm/output/eclipse/LogiHEAD.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <vector>
// #####################################################################
// Public Interface (createLogiHead()) Below Separator
// ---------------------------------------------------------------------
std::vector<bool>
Opm::RestartIO::Helpers::
createLogiHead(const EclipseState& es)
{
const auto& rspec = es.runspec();
const auto& wsd = rspec.wellSegmentDimensions();
const auto lh = LogiHEAD{}
.variousParam(false, false, wsd.maxSegmentedWells())
;
return lh.data();
}

View File

@@ -0,0 +1,603 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/output/eclipse/DoubHEAD.hpp>
// Note: DynamicState.hpp and <map> are prerequisites of Tuning.hpp
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp>
#include <opm/parser/eclipse/Units/Units.hpp>
#include <opm/output/eclipse/InteHEAD.hpp> // Opm::RestartIO::makeUTCTime()
#include <chrono>
#include <cmath>
#include <ctime>
#include <iterator>
#include <map>
#include <numeric>
#include <ratio>
#include <utility>
#include <vector>
enum Index : std::vector<double>::size_type {
// 0..9
SimTime = 0,
TsInit = 1,
TsMaxz = 2,
TsMinz = 3,
TsMchp = 4,
TsFMax = 5,
TsFMin = 6,
TsFcnv = 7,
TrgTTE = 8,
TrgCNV = 9,
// 10..19
TrgMBE = 10,
TrgLCV = 11,
dh_012 = 12,
dh_013 = 13,
dh_014 = 14,
dh_015 = 15,
XxxTTE = 16,
XxxCNV = 17,
XxxMBE = 18,
XxxLCV = 19,
// 20..29
XxxWFL = 20,
dh_021 = 21,
dh_022 = 22,
dh_023 = 23,
dh_024 = 24,
dRsdt = 25,
dh_026 = 26,
dh_027 = 27,
dh_028 = 28,
dh_029 = 29,
// 30..39
dh_030 = 30,
dh_031 = 31,
dh_032 = 32,
dh_033 = 33,
dh_034 = 34,
dh_035 = 35,
dh_036 = 36,
dh_037 = 37,
dh_038 = 38,
dh_039 = 39,
// 40..49
dh_040 = 40,
dh_041 = 41,
dh_042 = 42,
dh_043 = 43,
dh_044 = 44,
dh_045 = 45,
dh_046 = 46,
dh_047 = 47,
dh_048 = 48,
dh_049 = 49,
// 50..59
dh_050 = 50,
dh_051 = 51,
dh_052 = 52,
dh_053 = 53,
dh_054 = 54,
dh_055 = 55,
dh_056 = 56,
dh_057 = 57,
dh_058 = 58,
dh_059 = 59,
// 60..69
dh_060 = 60,
dh_061 = 61,
dh_062 = 62,
dh_063 = 63,
dh_064 = 64,
dh_065 = 65,
dh_066 = 66,
dh_067 = 67,
dh_068 = 68,
dh_069 = 69,
// 70..79
dh_070 = 70,
dh_071 = 71,
dh_072 = 72,
dh_073 = 73,
dh_074 = 74,
dh_075 = 75,
dh_076 = 76,
dh_077 = 77,
dh_078 = 78,
dh_079 = 79,
// 80..89
dh_080 = 80,
dh_081 = 81,
TrgDPR = 82,
TfDIFF = 83,
DdpLim = 84,
DdsLim = 85,
dh_086 = 86,
dh_087 = 87,
dh_088 = 88,
dh_089 = 89,
// 90..99
dh_090 = 90,
dh_091 = 91,
dh_092 = 92,
dh_093 = 93,
dh_094 = 94,
dh_095 = 95,
dh_096 = 96,
dh_097 = 97,
dh_098 = 98,
ThrUPT = 99,
// 100..109
XxxDPR = 100,
TrgFIP = 101,
TrgSFT = 102,
dh_103 = 103,
dh_104 = 104,
dh_105 = 105,
dh_106 = 106,
dh_107 = 107,
dh_108 = 108,
dh_109 = 109,
// 110..119
dh_110 = 110,
dh_111 = 111,
dh_112 = 112,
dh_113 = 113,
dh_114 = 114,
dh_115 = 115,
dh_116 = 116,
dh_117 = 117,
dh_118 = 118,
dh_119 = 119,
// 120..129
dh_120 = 120,
dh_121 = 121,
dh_122 = 122,
dh_123 = 123,
dh_124 = 124,
dh_125 = 125,
dh_126 = 126,
dh_127 = 127,
dh_128 = 128,
dh_129 = 129,
// 130..139
dh_130 = 130,
dh_131 = 131,
dh_132 = 132,
dh_133 = 133,
dh_134 = 134,
dh_135 = 135,
dh_136 = 136,
dh_137 = 137,
dh_138 = 138,
dh_139 = 139,
// 140..149
dh_140 = 140,
dh_141 = 141,
dh_142 = 142,
dh_143 = 143,
dh_144 = 144,
dh_145 = 145,
dh_146 = 146,
dh_147 = 147,
dh_148 = 148,
dh_149 = 149,
// 150..159
dh_150 = 150,
dh_151 = 151,
dh_152 = 152,
dh_153 = 153,
dh_154 = 154,
dh_155 = 155,
dh_156 = 156,
dh_157 = 157,
dh_158 = 158,
dh_159 = 159,
// 160..169
Start = 160,
Time = 161,
dh_162 = 162,
dh_163 = 163,
dh_164 = 164,
dh_165 = 165,
dh_166 = 166,
dh_167 = 167,
dh_168 = 168,
dh_169 = 169,
// 170..179
dh_170 = 170,
dh_171 = 171,
dh_172 = 172,
dh_173 = 173,
dh_174 = 174,
dh_175 = 175,
dh_176 = 176,
dh_177 = 177,
dh_178 = 178,
dh_179 = 179,
// 180..189
dh_180 = 180,
dh_181 = 181,
dh_182 = 182,
dh_183 = 183,
dh_184 = 184,
dh_185 = 185,
dh_186 = 186,
dh_187 = 187,
dh_188 = 188,
dh_189 = 189,
// 190..199
dh_190 = 190,
dh_191 = 191,
dh_192 = 192,
dh_193 = 193,
dh_194 = 194,
dh_195 = 195,
dh_196 = 196,
dh_197 = 197,
dh_198 = 198,
dh_199 = 199,
// 200..209
dh_200 = 200,
dh_201 = 201,
dh_202 = 202,
dh_203 = 203,
dh_204 = 204,
dh_205 = 205,
dh_206 = 206,
dh_207 = 207,
dh_208 = 208,
dh_209 = 209,
// 210..219
dh_210 = 210,
dh_211 = 211,
dh_212 = 212,
dh_213 = 213,
dh_214 = 214,
dh_215 = 215,
dh_216 = 216,
dh_217 = 217,
dh_218 = 218,
dh_219 = 219,
// 220..227
dh_220 = 220,
dh_221 = 221,
dh_222 = 222,
dh_223 = 223,
dh_224 = 224,
dh_225 = 225,
dh_226 = 226,
dh_227 = 227,
dh_228 = 228,
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
NUMBER_OF_ITEMS // MUST be last element of enum.
};
namespace {
/// Convert std::tm{} to Date-Number.
///
/// ECL Restrictions:
/// - Calendar start: 1st January 0000
/// - Year length: 365.25 days
/// - No special leap year handling
///
/// \param[in] year tm::tm_year of date (years since 1900).
///
/// \param[in] yday tm::tm_yday of date (days since 1st January).
///
/// \return Date-number corresponding to specified day-of-year in
/// specified year, subject to restrictions outlined above.
double toDateNum(const int year, const int yday)
{
return std::floor(365.25 * (year + 1900))
+ (yday + 1); // Day of year [1 .. 365]
}
double toDateNum(const std::chrono::time_point<std::chrono::system_clock> tp)
{
const auto t0 = std::chrono::system_clock::to_time_t(tp);
const auto tm0 = *std::gmtime(&t0);
// Set clock to 01:00:00+0000 on 2001-<month>-<day> to get
// "accurate" day-of-year calculation (no leap year, no DST offset,
// not previous day reported).
auto tm1 = std::tm{};
tm1.tm_year = 101; // 2001
tm1.tm_mon = tm0.tm_mon;
tm1.tm_mday = tm0.tm_mday;
tm1.tm_hour = 1;
tm1.tm_min = 0;
tm1.tm_sec = 0;
tm1.tm_isdst = 0;
const auto t1 = ::Opm::RestartIO::makeUTCTime(tm1);
if (t1 != static_cast<std::time_t>(-1)) {
tm1 = *std::gmtime(&t1); // Get new tm_yday.
return toDateNum(tm0.tm_year, tm1.tm_yday);
}
// Failed to convert tm1 to time_t (unexpected). Use initial value.
return toDateNum(tm0.tm_year, tm0.tm_yday);
}
}
// =====================================================================
// Public Interface (DoubHEAD member functions) Below Separator
// ---------------------------------------------------------------------
Opm::RestartIO::DoubHEAD::DoubHEAD()
: data_(Index::NUMBER_OF_ITEMS, -1.0e20)
{
// Numbers below have unknown usage, values have been determined by
// experiments to be constant across a range of reference cases.
this->data_[Index::dh_024] = 1.0e+20;
this->data_[Index::dh_026] = 0.0;
this->data_[Index::dh_027] = 0.0;
this->data_[Index::dh_028] = 0.0;
this->data_[Index::dh_050] = 0.01;
this->data_[Index::dh_054] = 1.0e+20;
this->data_[Index::dh_055] = 1.0e+20;
this->data_[Index::dh_063] = 1.0e+20;
this->data_[Index::dh_064] = 1.0e+20;
this->data_[Index::dh_065] = 0.0;
this->data_[Index::dh_066] = 0.0;
this->data_[Index::dh_069] = -1.0;
this->data_[Index::dh_080] = 1.0e+20;
this->data_[Index::dh_081] = 1.0e+20;
this->data_[Index::dh_091] = 0.0;
this->data_[Index::dh_092] = 0.0;
this->data_[Index::dh_093] = 0.0;
this->data_[Index::dh_096] = 0.0;
this->data_[Index::dh_105] = 1.0;
this->data_[Index::dh_108] = 0.0;
this->data_[Index::dh_109] = 0.0;
this->data_[Index::dh_110] = 0.0;
this->data_[Index::dh_123] = 365.0;
this->data_[Index::dh_124] = 0.1;
this->data_[Index::dh_125] = 0.15;
this->data_[Index::dh_126] = 3.0;
this->data_[Index::dh_127] = 0.3;
this->data_[Index::dh_128] = 0.1;
this->data_[Index::dh_129] = 0.1;
this->data_[Index::dh_130] = 0.001;
this->data_[Index::dh_131] = 1.0e-7;
this->data_[Index::dh_132] = 1.0e-4;
this->data_[Index::dh_133] = 10.0;
this->data_[Index::dh_134] = 0.01;
this->data_[Index::dh_135] = 1.0e-6;
this->data_[Index::dh_136] = 0.001;
this->data_[Index::dh_137] = 0.001;
this->data_[Index::dh_140] = 1.0e-20; // check this value
this->data_[Index::dh_141] = 1.013;
this->data_[Index::dh_142] = 0.0;
this->data_[Index::dh_143] = 1.0;
this->data_[Index::dh_145] = 0.3;
this->data_[Index::dh_146] = 2.0;
this->data_[Index::dh_147] = 0.0;
this->data_[Index::dh_148] = 0.0;
this->data_[Index::dh_149] = 0.0;
this->data_[Index::dh_150] = 0.0;
this->data_[Index::dh_151] = 0.0;
this->data_[Index::dh_152] = 0.0;
this->data_[Index::dh_153] = 0.0;
this->data_[Index::dh_154] = 0.0;
this->data_[Index::dh_162] = 1.0;
this->data_[Index::dh_163] = 0.2;
this->data_[Index::dh_164] = 0.4;
this->data_[Index::dh_165] = 1.2;
this->data_[Index::dh_166] = 0.3;
this->data_[Index::dh_167] = 1.0;
this->data_[Index::dh_170] = 0.4;
this->data_[Index::dh_171] = 0.7;
this->data_[Index::dh_172] = 2.0;
this->data_[Index::dh_178] = 1.0;
this->data_[Index::dh_179] = 1.0;
this->data_[Index::dh_180] = 1.0;
this->data_[Index::dh_181] = 0.0;
this->data_[Index::dh_182] = 0.0;
this->data_[Index::dh_183] = 1.0;
this->data_[Index::dh_184] = 1.0e-4;
this->data_[Index::dh_185] = 0.0;
this->data_[Index::dh_186] = 0.0;
this->data_[Index::dh_187] = 1.0e+20;
this->data_[Index::dh_188] = 1.0e+20;
this->data_[Index::dh_189] = 1.0e+20;
this->data_[Index::dh_190] = 1.0e+20;
this->data_[Index::dh_191] = 1.0e+20;
this->data_[Index::dh_192] = 1.0e+20;
this->data_[Index::dh_193] = 1.0e+20;
this->data_[Index::dh_194] = 1.0e+20;
this->data_[Index::dh_195] = 1.0e+20;
this->data_[Index::dh_196] = 1.0e+20;
this->data_[Index::dh_197] = 1.0e+20;
this->data_[Index::dh_198] = 1.0e+20;
this->data_[Index::dh_199] = 1.0;
this->data_[Index::dh_200] = 0.0;
this->data_[Index::dh_201] = 0.0;
this->data_[Index::dh_202] = 0.0;
this->data_[Index::dh_203] = 0.0;
this->data_[Index::dh_204] = 0.0;
this->data_[Index::dh_205] = 0.0;
this->data_[Index::dh_206] = 0.0;
this->data_[Index::dh_207] = 0.0;
this->data_[Index::dh_208] = 0.0;
this->data_[Index::dh_209] = 0.0;
this->data_[Index::dh_210] = 0.0;
this->data_[Index::dh_211] = 0.0;
this->data_[Index::dh_214] = 1.0e-4;
this->data_[Index::dh_215] = -2.0e+20;
this->data_[Index::dh_217] = 0.0;
this->data_[Index::dh_218] = 0.0;
this->data_[Index::dh_219] = 0.0;
this->data_[Index::dh_220] = 0.01;
this->data_[Index::dh_221] = 1.0;
this->data_[Index::dh_222] = 0.0;
this->data_[Index::dh_223] = 1.0e+20;
this->data_[Index::dh_225] = 0.0;
this->data_[Index::dh_226] = 0.0;
this->data_[Index::dh_227] = 0.0;
this->data_[Index::TsInit] = 1.0;
this->data_[Index::TsMaxz] = 365.0;
this->data_[Index::TsMinz] = 0.1;
this->data_[Index::TsMchp] = 0.15;
this->data_[Index::TsFMax] = 3.0;
this->data_[Index::TsFMin] = 0.3;
this->data_[Index::TsFcnv] = 0.1;
this->data_[Index::TrgTTE] = 0.1;
this->data_[Index::TrgCNV] = 0.001;
this->data_[Index::TrgMBE] = 1.0E-7;
this->data_[Index::TrgLCV] = 0.0001;
this->data_[Index::XxxTTE] = 10.0;
this->data_[Index::XxxCNV] = 0.01;
this->data_[Index::XxxMBE] = 1.0e-6;
this->data_[Index::XxxLCV] = 0.001;
this->data_[Index::XxxWFL] = 0.001;
this->data_[Index::dRsdt] = 1.0e+20; // "Infinity"
this->data_[Index::TrgDPR] = 1.0e+6;
this->data_[Index::TfDIFF] = 1.25;
this->data_[Index::DdpLim] = 1.0e+6;
this->data_[Index::DdsLim] = 1.0e+6;
this->data_[Index::ThrUPT] = 1.0e+20;
this->data_[Index::XxxDPR] = 1.0e+20;
this->data_[Index::TrgFIP] = 0.025;
this->data_[Index::TrgSFT] = 1.0e+20;
}
Opm::RestartIO::DoubHEAD&
Opm::RestartIO::DoubHEAD::tuningParameters(const Tuning& tuning,
const std::size_t lookup_step,
const double cnvT)
{
// Record 1
this->data_[Index::TsInit] = tuning.getTSINIT(lookup_step) / cnvT;
this->data_[Index::TsMaxz] = tuning.getTSMAXZ(lookup_step) / cnvT;
this->data_[Index::TsMinz] = tuning.getTSMINZ(lookup_step) / cnvT;
this->data_[Index::TsMchp] = tuning.getTSMCHP(lookup_step) / cnvT;
this->data_[Index::TsFMax] = tuning.getTSFMAX(lookup_step);
this->data_[Index::TsFMin] = tuning.getTSFMIN(lookup_step);
this->data_[Index::TsFcnv] = tuning.getTSFCNV(lookup_step);
this->data_[Index::ThrUPT] = tuning.getTHRUPT(lookup_step);
this->data_[Index::TfDIFF] = tuning.getTFDIFF(lookup_step);
// Record 2
this->data_[Index::TrgTTE] = tuning.getTRGTTE(lookup_step);
this->data_[Index::TrgCNV] = tuning.getTRGCNV(lookup_step);
this->data_[Index::TrgMBE] = tuning.getTRGMBE(lookup_step);
this->data_[Index::TrgLCV] = tuning.getTRGLCV(lookup_step);
this->data_[Index::XxxTTE] = tuning.getXXXTTE(lookup_step);
this->data_[Index::XxxCNV] = tuning.getXXXCNV(lookup_step);
this->data_[Index::XxxMBE] = tuning.getXXXMBE(lookup_step);
this->data_[Index::XxxLCV] = tuning.getXXXLCV(lookup_step);
this->data_[Index::XxxWFL] = tuning.getXXXWFL(lookup_step);
this->data_[Index::TrgFIP] = tuning.getTRGFIP(lookup_step);
this->data_[Index::TrgSFT] = tuning.getTRGSFT(lookup_step);
// Record 3
this->data_[Index::TrgDPR] = tuning.getTRGDPR(lookup_step);
this->data_[Index::XxxDPR] = tuning.getXXXDPR(lookup_step);
this->data_[Index::DdpLim] = tuning.getDDPLIM(lookup_step);
this->data_[Index::DdsLim] = tuning.getDDSLIM(lookup_step);
return *this;
}
Opm::RestartIO::DoubHEAD&
Opm::RestartIO::DoubHEAD::timeStamp(const TimeStamp& ts)
{
using day = std::chrono::duration<double,
std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>
>;
// Elapsed time in days
this->data_[Index::SimTime] = day{ ts.elapsed }.count();
// Start time in date-numbers
this->data_[Index::Start] = toDateNum(ts.start);
// Simulation time-stamp in date-numbers
this->data_[Index::Time] = this->data_[Index::Start]
+ this->data_[Index::SimTime];
return *this;
}
Opm::RestartIO::DoubHEAD&
Opm::RestartIO::DoubHEAD::drsdt(const Schedule& sched,
const std::size_t lookup_step)
{
const auto& vappar =
sched.getOilVaporizationProperties(lookup_step);
this->data_[dRsdt] =
(vappar.getType() == Opm::OilVaporizationEnum::DRSDT)
? vappar.getMaxDRSDT()
: 1.0e+20;
return *this;
}

View File

@@ -33,7 +33,7 @@
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/GridProperty.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
@@ -153,30 +153,30 @@ void RFT::writeTimeStep( std::vector< const Well* > wells,
const auto& wellData = wellDatas.at(well->name());
if (wellData.completions.empty())
if (wellData.connections.empty())
continue;
for( const auto& completion : well->getCompletions( report_step ) ) {
for( const auto& connection : well->getConnections( report_step ) ) {
const size_t i = size_t( completion.getI() );
const size_t j = size_t( completion.getJ() );
const size_t k = size_t( completion.getK() );
const size_t i = size_t( connection.getI() );
const size_t j = size_t( connection.getJ() );
const size_t k = size_t( connection.getK() );
if( !grid.cellActive( i, j, k ) ) continue;
const auto index = grid.getGlobalIndex( i, j, k );
const double depth = grid.getCellDepth( i, j, k );
const auto& completionData = std::find_if( wellData.completions.begin(),
wellData.completions.end(),
[=]( const data::Completion& c ) {
const auto& connectionData = std::find_if( wellData.connections.begin(),
wellData.connections.end(),
[=]( const data::Connection& c ) {
return c.index == index;
} );
const double press = units.from_si(UnitSystem::measure::pressure,completionData->cell_pressure);
const double satwat = units.from_si(UnitSystem::measure::identity, completionData->cell_saturation_water);
const double satgas = units.from_si(UnitSystem::measure::identity, completionData->cell_saturation_gas);
const double press = units.from_si(UnitSystem::measure::pressure,connectionData->cell_pressure);
const double satwat = units.from_si(UnitSystem::measure::identity, connectionData->cell_saturation_water);
const double satgas = units.from_si(UnitSystem::measure::identity, connectionData->cell_saturation_gas);
auto* cell = ecl_rft_cell_alloc_RFT(
i, j, k, depth, press, satwat, satgas );
@@ -418,12 +418,10 @@ void EclipseIO::writeInitial( data::Solution simProps, std::map<std::string, std
void EclipseIO::writeTimeStep(int report_step,
bool isSubstep,
double secs_elapsed,
data::Solution cells,
data::Wells wells,
RestartValue value,
const std::map<std::string, double>& single_summary_values,
const std::map<std::string, std::vector<double> >& region_summary_values,
const std::map<std::pair<std::string, int>, double>& block_summary_values,
const std::map<std::string, std::vector<double>>& extra_restart,
bool write_double)
{
@@ -448,7 +446,7 @@ void EclipseIO::writeTimeStep(int report_step,
secs_elapsed,
es,
schedule,
wells ,
value.wells ,
single_summary_values ,
region_summary_values,
block_summary_values);
@@ -469,7 +467,7 @@ void EclipseIO::writeTimeStep(int report_step,
report_step,
ioConfig.getFMTOUT() );
RestartIO::save( filename , report_step, secs_elapsed, cells, wells, es , grid , schedule, extra_restart , write_double);
RestartIO::save( filename , report_step, secs_elapsed, value, es , grid , schedule, write_double);
}
@@ -489,7 +487,7 @@ void EclipseIO::writeTimeStep(int report_step,
secs_elapsed + this->impl->schedule.posixStartTime(),
units.from_si( UnitSystem::measure::time, secs_elapsed ),
units,
wells );
value.wells );
}
}
@@ -497,7 +495,7 @@ void EclipseIO::writeTimeStep(int report_step,
RestartValue EclipseIO::loadRestart(const std::map<std::string, RestartKey>& keys, const std::map<std::string, bool>& extra_keys) const {
RestartValue EclipseIO::loadRestart(const std::vector<RestartKey>& solution_keys, const std::vector<RestartKey>& extra_keys) const {
const auto& es = this->impl->es;
const auto& grid = this->impl->grid;
const auto& schedule = this->impl->schedule;
@@ -508,7 +506,7 @@ RestartValue EclipseIO::loadRestart(const std::map<std::string, RestartKey>& key
report_step,
false );
return RestartIO::load( filename , report_step , keys , es, grid , schedule, extra_keys);
return RestartIO::load( filename , report_step , solution_keys , es, grid , schedule, extra_keys);
}
EclipseIO::EclipseIO( const EclipseState& es,

View File

@@ -0,0 +1,720 @@
#include <opm/output/eclipse/InteHEAD.hpp>
#include <opm/output/eclipse/VectorItems/intehead.hpp>
#include <algorithm>
#include <chrono>
#include <cmath>
#include <ctime>
#include <ratio>
#include <utility>
#include <vector>
// Public INTEHEAD items are recorded in the common header file
//
// opm/output/eclipse/VectorItems/intehead.hpp
//
// Promote items from 'index' to that list to make them public.
// The 'index' list always uses public items where available.
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
enum index : std::vector<int>::size_type {
ISNUM = VI::intehead::ISNUM , // 0 0 An encoded integer corresponding to the time the file was created. For files not originating from ECLIPSE, this value may be set to zero.
VERSION = VI::intehead::VERSION , // 0 0
UNIT = VI::intehead::UNIT , // (1,2,3) 1 units type: 1 - METRIC, 2 - FIELD, 3 - LAB
ih_003 = 3 , // 0 0
ih_004 = 4 , // 0 0
ih_005 = 5 , // 0 0
ih_006 = 6 , // 0 0
ih_007 = 7 , // 0 0
NX = VI::intehead::NX , // NX 137 Grid x-direction dimension, NX
NY = VI::intehead::NY , // NY 236 Grid x-direction dimension, NY
NZ = VI::intehead::NZ , // NZ 58 Grid x-direction dimension, NZ
NACTIV = VI::intehead::NACTIV , // NACTIV? 89022 NACTIV = number of active cells
ih_012 = 12 , // 0 0
ih_013 = 13 , // 0 0
PHASE = VI::intehead::PHASE , // IPHS 7 IPHS = phase indicator: 1 - oil, 2 - water, 3 - oil/water, 4 - gas, 5 oil/gas, 6 - gas/water, 7 - oil/water/gas (ECLIPSE output only)
ih_015 = 15 , // 0 0
NWELLS = VI::intehead::NWELLS , // NWELLS 39 NWELL = number of wells
NCWMAX = VI::intehead::NCWMAX , // NCWMAX 108 Weldims item2 NCWMAX = maximum number of completions per well
ih_018 = 18 , // NGRP? 0 Number of actual groups
NWGMAX = VI::intehead::NWGMAX , // NWGMAX 0 maximum of weldims item3 or item4 NWGMAX = maximum number of wells in any well group
NGMAXZ = VI::intehead::NGMAXZ , // NGMAXZ 0 weldims item3 + 1 NGMAXZ = maximum number of groups in field
ih_021 = 21 , // 0 0
ih_022 = 22 , // 0 0
ih_023 = 23 , // 0 0
NIWELZ = VI::intehead::NIWELZ , // NIWELZ 155 155 NIWELZ = no of data elements per well in IWEL array (default 97 for ECLIPSE, 94 for ECLIPSE 300)
NSWELZ = VI::intehead::NSWELZ , // NSWELZ 122 122 NSWELZ = number of daelements per well in SWEL array
NXWELZ = VI::intehead::NXWELZ , // NXWELZ 130 130 NXWELZ = number of delements per well in XWEL array
NZWELZ = VI::intehead::NZWELZ , // NZWEL 3 3 NZWEL = no of 8-character words per well in ZWEL array (= 3)
ih_028 = 28 , // 0 0
ih_029 = 29 , // 0 0
ih_030 = 30 , // 0 0
ih_031 = 31 , // 0 0
NICONZ = VI::intehead::NICONZ , // 25 15 25 NICON = no of data elements per completion in ICON array (default 19)
NSCONZ = VI::intehead::NSCONZ , // 40 0 NSCONZ = number of data elements per completion in SCON array
NXCONZ = VI::intehead::NXCONZ , // 58 0 58 NXCONZ = number of data elements per completion in XCON array
ih_035 = 35 , // 0 0
NIGRPZ = VI::intehead::NIGRPZ , // 97+intehead_array[19] 0 97 + intehead[19] NIGRPZ = no of data elements per group in IGRP array
NSGRPZ = VI::intehead::NSGRPZ , // 112 0 112 NSGRPZ = number of data elements per group in SGRP array
NXGRPZ = VI::intehead::NXGRPZ , // 180 0 180 NXGRPZ = number of data elements per group in XGRP array
NZGRPZ = VI::intehead::NZGRPZ , // 5 0 NZGRPZ = number of data elements per group in ZGRP array
ih_040 = 40 , // 0 0
NCAMAX = VI::intehead::NCAMAX , // 1 0 NCAMAX = maximum number of analytic aquifer connections
NIAAQZ = VI::intehead::NIAAQZ , // 18 0 NIAAQZ = number of data elements per aquifer in IAAQ array
NSAAQZ = VI::intehead::NSAAQZ , // 24 0 NSAAQZ = number of data elements per aquifer in SAAQ array
NXAAQZ = VI::intehead::NXAAQZ , // 10 0 NXAAQZ = number of data elements per aquifer in XAAQ array
NICAQZ = VI::intehead::NICAQZ , // 7 0 NSCAQZ= number of data elements per aquifer connection in SCAQ array
NSCAQZ = VI::intehead::NSCAQZ , // 2 0
NACAQZ = VI::intehead::NACAQZ , // 4 0
ih_048 = 48 , // 0 0
ih_049 = 49 , // 0 0
ih_050 = 50 , // 0 0
ih_051 = 51 , // 0 0
ih_052 = 52 , // 0 0
ih_053 = 53 , // 0 0
ih_054 = 54 , // 0 0
ih_055 = 55 , // 0 0
ih_056 = 56 , // 0 0
ih_057 = 57 , // 0 0
ih_058 = 58 , // 0 0
ih_059 = 59 , // 0 0
ih_060 = 60 , // 0 0
ih_061 = 61 , // 0 0
ih_062 = 62 , // 0 0
ih_063 = 63 , // 0 0
DAY = 64 , // IDAY 2 IDAY = calendar day at this report time
MONTH = 65 , // IMON 6 IMON = calendar month at this report time
YEAR = 66 , // IYEAR 2016 IYEAR = calendar year at this report time
NUM_SOLVER_STEPS = 67 , // The number of solver steps the simulator has performed so far.
REPORT_STEP = 68 , // The sequence/report number for for this restart file.
ih_069 = 69 , // 0 0
ih_070 = 70 , // 0 0
ih_071 = 71 , // 0 0
ih_072 = 72 , // 0 0
ih_073 = 73 , // 0 0
ih_074 = 74 , // 0 0
ih_075 = 75 , // 0 0
ih_076 = 76 , // 0 0 2
ih_077 = 77 , // 0 0
ih_078 = 78 , // 0 0
ih_079 = 79 , // 0 0
NEWTMX = 80 , // 0 0 Tuning,Record3,Item1
NEWTMN = 81 , // 0 0 Tuning,Record3,Item2
LITMAX = 82 , // 0 0 Tuning,Record3,Item3
LITMIN = 83 , // 0 0 Tuning,Record3,Item4
ih_084 = 84 , // 0 0 Tuning,Record3,Item5
ih_085 = 85 , // 0 0 Tuning,Record3,Item6
MXWSIT = 86 , // 0 0
MXWPIT = 87 , // 0 0
ih_088 = 88 , // 0 0
NTFIP = 89 , // 0 0 REGDIMS item1, or TABDIMS item 5
ih_090 = 90 , // 0 0
ih_091 = 91 , // 0 0
ih_092 = 92 , // 0 0
ih_093 = 93 , // 0 0
IPROG = 94 , // 0 100 IPROG = simulation program identifier: 100 - ECLIPSE 100, 300 - ECLIPSE 300, 500 - ECLIPSE 300 (thermal option), negative - Other simulator
INITSIZE = 95 , // 0 0
ih_096 = 96 , // 0 0
ih_097 = 97 , // 0 0
ih_098 = 98 , // 0 0
NMFIPR = 99 , // 0 0 REGDIMS item2
ih_100 = 100 , // 0 0
ih_101 = 101 , // 0 0 1
ih_102 = 102 , // 0 0
ih_103 = 103 , // 0 0 1
ih_104 = 104 , // 0 0
ih_105 = 105 , // 0 0
ih_106 = 106 , // 0 0
ih_107 = 107 , // 0 0
ih_108 = 108 , // 0 0
ih_109 = 109 , // 0 0
ih_110 = 110 , // 0 0
ih_111 = 111 , // 0 0
ih_112 = 112 , // 0 0
ih_113 = 113 , // 0 0
ih_114 = 114 , // 0 0
ih_115 = 115 , // 0 0
ih_116 = 116 , // 0 0
ih_117 = 117 , // 0 0
ih_118 = 118 , // 0 0
ih_119 = 119 , // 0 0
ih_120 = 120 , // 0 0
ih_121 = 121 , // 0 0
ih_122 = 122 , // 0 0
ih_123 = 123 , // 0 0
ih_124 = 124 , // 0 0
ih_125 = 125 , // 0 0
ih_126 = 126 , // 0 0
ih_127 = 127 , // 0 0
ih_128 = 128 , // 0 0
ih_129 = 129 , // 0 0
ih_130 = 130 , // 0 0
NODMAX = 131 , // 0 0 NODMAX = maximum number of nodes in extended network option
NBRMAX = 132 , // 0 0 NBRMAX = maximum number of branches in extended network option
NIBRAN = 133 , // 0 0 NIBRAN = number of entries per branch in the IBRAN array
NRBRAN = 134 , // 0 0 NRBRAN = number of tries per branch in the RBRAN array
NINODE = 135 , // 0 0 NINODE = number of entries per node in the INODE array
NRNODE = 136 , // 0 0 NRNODE = number of entries per node in the RNODE array
NZNODE = 137 , // 0 0 NZNODE = number of entries per node in the ZNODE array
NINOBR = 138 , // 0 0 NINOBR = size of the INOBR array
ih_139 = 139 , // 0 0
ih_140 = 140 , // 0 0
ih_141 = 141 , // 0 0
ih_142 = 142 , // 0 0
ih_143 = 143 , // 0 0
ih_144 = 144 , // 0 0
ih_145 = 145 , // 0 0
ih_146 = 146 , // 0 0
ih_147 = 147 , // 0 0
ih_148 = 148 , // 0 0
ih_149 = 149 , // 0 0
ih_150 = 150 , // 0 0
ih_151 = 151 , // 0 0
ih_152 = 152 , // 0 0
ih_153 = 153 , // 0 0
ih_154 = 154 , // 0 0
ih_155 = 155 , // 0 0
ih_156 = 156 , // 0 0
ih_157 = 157 , // 0 0
ih_158 = 158 , // 0 0
ih_159 = 159 , // 0 0
ih_160 = 160 , // 0 0
ih_161 = 161 , // 0 0
NGCAUS = 162 , // 0 0 NGCAUS = maximum number of aquifer connections actually used.
ih_163 = 163 , // 0 0
ih_164 = 164 , // 0 0
ih_165 = 165 , // 0 0
ih_166 = 166 , // 0 0
ih_167 = 167 , // 0 0
ih_168 = 168 , // 0 0
ih_169 = 169 , // 0 0
ih_170 = 170 , // 0 0
ih_171 = 171 , // 0 0
ih_172 = 172 , // 0 0
ih_173 = 173 , // 0 0
NSEGWL = VI::intehead::NSEGWL , // 0 0 number of mswm wells defined with WELSEG
NSWLMX = VI::intehead::NSWLMX , // NSWLMX 0 Item 1 in WSEGDIMS keyword (runspec section) NSWLMX = maximum number of segmented wells
NSEGMX = VI::intehead::NSEGMX , // NSEGMX 0 Item 2 in WSEGDIMS keyword (runspec section) NSEGMX = maximum number of segments per well
NLBRMX = VI::intehead::NLBRMX , // NLBRMX 0 Item 3 in WSEGDIMS keyword (runspec section) NLBRMX = maximum number of lateral branches per well
NISEGZ = VI::intehead::NISEGZ , // 22 0 22 NISEGZ = number of entries per segment in ISEG array
NRSEGZ = VI::intehead::NRSEGZ , // 140 0 140 NRSEGZ = number of entries per segment in RSEG array
NILBRZ = VI::intehead::NILBRZ , // 10 10 NILBRZ = number of entries per segment in ILBR array
RSTSIZE = 181 , // 0
ih_182 = 182 , // 0
ih_183 = 183 , // 0
ih_184 = 184 , // 0
ih_185 = 185 , // 0
ih_186 = 186 , // 0
ih_187 = 187 , // 0
ih_188 = 188 , // 0
ih_189 = 189 , // 0
ih_190 = 190 , // 0
ih_191 = 191 , // 0
ih_192 = 192 , // 0
ih_193 = 193 , // 0
ih_194 = 194 , // 0
ih_195 = 195 , // 0
ih_196 = 196 , // 0
ih_197 = 197 , // 0
ih_198 = 198 , // 0
ih_199 = 199 , // 0
ih_200 = 200 , // 0
ih_201 = 201 , // 0
ih_202 = 202 , // 0
ih_203 = 203 , // 0
ih_204 = 204 , // 0
ih_205 = 205 , // 0
IHOURZ = 206 , // IHOURZ IHOURZ = current simulation time HH:MM:SS number of hours (HH) (0-23).
IMINTS = 207 , // IMINTS IMINTS = current simulation time HH:MM:SS - number of minutes (MM) (0-59).
ih_208 = 208 , // 0
ih_209 = 209 , // 0
ih_210 = 210 , // 0
ih_211 = 211 , // 0
ih_212 = 212 , // 0
ih_213 = 213 , // 0
ih_214 = 214 , // 0
ih_215 = 215 , // 0
ih_216 = 216 , // 0
ih_217 = 217 , // 0
ih_218 = 218 , // 0
ih_219 = 219 , // 0
ih_220 = 220 , // 0
ih_221 = 221 , // 0
ih_222 = 222 , // 0
NIIAQN = 223 , // 0 NIIAQN = number of lines of integer AQUNUM data.
NIRAQN = 224 , // 0 NIRAQN = number of lines of real AQUNUM data.
ih_225 = 225 , // 0
NUMAQN = 226 , // 0 NUMAQN = number of lines of AQUNUM data entered.
ih_227 = 227 , // 0
ih_228 = 228 , // 0
ih_229 = 229 , // 0
ih_230 = 230 , // 0
ih_231 = 231 , // 0
ih_232 = 232 , // 0
ih_233 = 233 , // 0
NICOTZ = 234 , // 0 NICOTZ = number of entries in the ICOT array
NXCOTZ = 235 , // 0 NXCOTZ = number of entries in the XCOT array
NIWETZ = 236 , // 0 NIWETZ = number of entries in the IWET array
NXWETZ = 237 , // 0 NXWETZ = number of entries in the XWET array
NIGRTZ = 238 , // 0 NIGRTZ = number of entries in the IGRT array
NXGRTZ = 239 , // 0 NXGRTZ = number of entries in the XGRT array
NSTRA2 = 240 , // 0 NSTRA2 = number of tracers + 2
ih_241 = 241 , // 0
ih_242 = 242 , // 0
ih_243 = 243 , // 0
ih_244 = 244 , // 0
ih_245 = 245 , // 0
ih_246 = 246 , // 0
ih_247 = 247 , // 0
ih_248 = 248 , // 0
ih_249 = 249 , // 0
ih_250 = 250 , // 0
ih_251 = 251 , // 0
MAAQID = 252 , // 0 MAAQID = maximum number of analytic aquifers
ih_253 = 253 , // 0
ih_254 = 254 , // 0
ih_255 = 255 , // 0
ih_256 = 256 , // 0
ih_257 = 257 , // 0
ih_258 = 258 , // 0
ih_259 = 259 , // 0
ih_260 = 260 , // 0
ih_261 = 261 , // 0
ih_262 = 262 , // 0
ih_263 = 263 , // 0
ih_264 = 264 , // 0
ih_265 = 265 , // 0
ih_266 = 266 , // 0
ih_267 = 267 , // 0
ih_268 = 268 , // 0
ih_269 = 269 , // 0
ih_270 = 270 , // 0
NCRDMX = 271 , // 0 NCRDMX = maximum number of chord segment links per well
ih_272 = 272 , // 0
ih_273 = 273 , // 0
ih_274 = 274 , // 0
ih_275 = 275 , // 0
ih_276 = 276 , // 0
ih_277 = 277 , // 0
ih_278 = 278 , // 0
ih_279 = 279 , // 0
ih_280 = 280 , // 0
ih_281 = 281 , // 0
ih_282 = 282 , // 0
ih_283 = 283 , // 0
ih_284 = 284 , // 0
ih_285 = 285 , // 0
ih_286 = 286 , // 0
ih_287 = 287 , // 0
ih_288 = 288 , // 0
ih_289 = 289 , // 0
ih_290 = 290 , // 0
ih_291 = 291 , // 0
ih_292 = 292 , // 0
ih_293 = 293 , // 0
ih_294 = 294 , // 0
ih_295 = 295 , // 0
ih_296 = 296 , // 0
ih_297 = 297 , // 0
ih_298 = 298 , // 0
ih_299 = 299 , // 0
ih_300 = 300 , // 0
ih_301 = 301 , // 0
ih_302 = 302 , // 0
ih_303 = 303 , // 0
ih_304 = 304 , // 0
ih_305 = 305 , // 0
ih_306 = 306 , // 0
ih_307 = 307 , // 0
ih_308 = 308 , // 0
ih_309 = 309 , // 0
ih_310 = 310 , // 0
ih_311 = 311 , // 0
ih_312 = 312 , // 0
ih_313 = 313 , // 0
ih_314 = 314 , // 0
ih_315 = 315 , // 0
ih_316 = 316 , // 0
ih_317 = 317 , // 0
ih_318 = 318 , // 0
ih_319 = 319 , // 0
ih_320 = 320 , // 0
ih_321 = 321 , // 0
ih_322 = 322 , // 0
ih_323 = 323 , // 0
ih_324 = 324 , // 0
ih_325 = 325 , // 0
ih_326 = 326 , // 0
ih_327 = 327 , // 0
ih_328 = 328 , // 0
ih_329 = 329 , // 0
ih_330 = 330 , // 0
ih_331 = 331 , // 0
ih_332 = 332 , // 0
ih_333 = 333 , // 0
ih_334 = 334 , // 0
ih_335 = 335 , // 0
ih_336 = 336 , // 0
ih_337 = 337 , // 0
ih_338 = 338 , // 0
ih_339 = 339 , // 0
ih_340 = 340 , // 0
ih_341 = 341 , // 0
ih_342 = 342 , // 0
ih_343 = 343 , // 0
ih_344 = 344 , // 0
ih_345 = 345 , // 0
ih_346 = 346 , // 0
ih_347 = 347 , // 0
ih_348 = 348 , // 0
ih_349 = 349 , // 0
ih_350 = 350 , // 0
ih_351 = 351 , // 0
ih_352 = 352 , // 0
ih_353 = 353 , // 0
ih_354 = 354 , // 0
ih_355 = 355 , // 0
ih_356 = 356 , // 0
ih_357 = 357 , // 0
ih_358 = 358 , // 0
ih_359 = 359 , // 0
ih_360 = 360 , // 0
ih_361 = 361 , // 0
ih_362 = 362 , // 0
ih_363 = 363 , // 0
ih_364 = 364 , // 0
ih_365 = 365 , // 0
ih_366 = 366 , // 0
ih_367 = 367 , // 0
ih_368 = 368 , // 0
ih_369 = 369 , // 0
ih_370 = 370 , // 0
ih_371 = 371 , // 0
ih_372 = 372 , // 0
ih_373 = 373 , // 0
ih_374 = 374 , // 0
ih_375 = 375 , // 0
ih_376 = 376 , // 0
ih_377 = 377 , // 0
ih_378 = 378 , // 0
ih_379 = 379 , // 0
ih_380 = 380 , // 0
ih_381 = 381 , // 0
ih_382 = 382 , // 0
ih_383 = 383 , // 0
ih_384 = 384 , // 0
ih_385 = 385 , // 0
ih_386 = 386 , // 0
ih_387 = 387 , // 0
ih_388 = 388 , // 0
ih_389 = 389 , // 0
ih_390 = 390 , // 0
ih_391 = 391 , // 0
ih_392 = 392 , // 0
ih_393 = 393 , // 0
ih_394 = 394 , // 0
ih_395 = 395 , // 0
ih_396 = 396 , // 0
ih_397 = 397 , // 0
ih_398 = 398 , // 0
ih_399 = 399 , // 0
ih_400 = 400 , // 0
ih_401 = 401 , // 0
ih_402 = 402 , // 0
ih_403 = 403 , // 0
ih_404 = 404 , // 0
ih_405 = 405 , // 0
ih_406 = 406 , // 0
ih_407 = 407 , // 0
ih_408 = 408 , // 0
ih_409 = 409 , // 0
ISECND = 410 , // 0 ISECND = current simulation time HH:MM:SS - number of seconds (SS), reported in microseconds (0-59,999,999)
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
INTEHEAD_NUMBER_OF_ITEMS // MUST be last element of enum.
};
// =====================================================================
// Public Interface Below Separator
// =====================================================================
Opm::RestartIO::InteHEAD::InteHEAD()
: data_(INTEHEAD_NUMBER_OF_ITEMS, 0)
{}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::
dimensions(const int nx, const int ny, const int nz)
{
this -> data_[NX] = nx;
this -> data_[NY] = ny;
this -> data_[NZ] = nz;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::
dimensions(const std::array<int,3>& cartDims)
{
return this->dimensions(cartDims[0], cartDims[1], cartDims[2]);
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::numActive(const int nactive)
{
this->data_[NACTIV] = nactive;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::unitConventions(const UnitSystem& usys)
{
const auto unit = [&usys]()
{
switch (usys) {
case UnitSystem::Metric: return 1;
case UnitSystem::Field: return 2;
case UnitSystem::Lab: return 3;
case UnitSystem::PVT_M: return 4;
}
return 1;
}();
this->data_[UNIT] = unit;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::wellTableDimensions(const WellTableDim& wtdim)
{
this->data_[NWELLS] = wtdim.numWells;
this->data_[NCWMAX] = wtdim.maxPerf;
this->data_[NWGMAX] = std::max(wtdim.maxWellInGroup,
wtdim.maxGroupInField);
this->data_[NGMAXZ] = wtdim.maxGroupInField + 1;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::calendarDate(const TimePoint& timePoint)
{
this->data_[DAY] = timePoint.day;
this->data_[MONTH] = timePoint.month;
this->data_[YEAR] = timePoint.year;
this->data_[IHOURZ] = timePoint.hour;
this->data_[IMINTS] = timePoint.minute;
// Microseonds...
this->data_[ISECND] =
((timePoint.second * 1000) * 1000) + timePoint.microseconds;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::activePhases(const Phases& phases)
{
const auto iphs =
(static_cast<unsigned int> (phases.oil) << 0u)
| (static_cast<unsigned int>(phases.water) << 1u)
| (static_cast<unsigned int>(phases.gas) << 2u);
this->data_[PHASE] = static_cast<int>(iphs);
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::
params_NWELZ(const int niwelz, const int nswelz, const int nxwelz, const int nzwelz)
{
this -> data_[NIWELZ] = niwelz;
this -> data_[NSWELZ] = nswelz;
this -> data_[NXWELZ] = nxwelz;
this -> data_[NZWELZ] = nzwelz;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::
params_NCON(const int niconz, const int nsconz, const int nxconz)
{
this -> data_[NICONZ] = niconz;
this -> data_[NSCONZ] = nsconz;
this -> data_[NXCONZ] = nxconz;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::
params_GRPZ(const std::array<int, 4>& grpz)
{
this -> data_[NIGRPZ] = grpz[0];
this -> data_[NSGRPZ] = grpz[1];
this -> data_[NXGRPZ] = grpz[2];
this -> data_[NZGRPZ] = grpz[3];
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::
params_NAAQZ(const int ncamax,
const int niaaqz,
const int nsaaqz,
const int nxaaqz,
const int nicaqz,
const int nscaqz,
const int nacaqz)
{
this -> data_[NCAMAX] = ncamax;
this -> data_[NIAAQZ] = niaaqz;
this -> data_[NSAAQZ] = nsaaqz;
this -> data_[NXAAQZ] = nxaaqz;
this -> data_[NICAQZ] = nicaqz;
this -> data_[NSCAQZ] = nscaqz;
this -> data_[NACAQZ] = nacaqz;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::
stepParam(const int num_solver_steps, const int report_step)
{
this -> data_[NUM_SOLVER_STEPS] = num_solver_steps;
this -> data_[REPORT_STEP] = report_step;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::tuningParam(const TuningPar& tunpar)
{
this->data_[NEWTMX] = tunpar.newtmx;
this->data_[NEWTMN] = tunpar.newtmn;
this->data_[LITMAX] = tunpar.litmax;
this->data_[LITMIN] = tunpar.litmin;
this->data_[MXWSIT] = tunpar.mxwsit;
this->data_[MXWPIT] = tunpar.mxwpit;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::variousParam(const int version,
const int iprog)
{
this->data_[VERSION] = version;
this->data_[IPROG] = iprog;
// ih_076: Usage unknown, experiments fails (zero determinant in well message) with too low numbers. 5 is highest observed across reference cases.
this->data_[ih_076] = 5;
// ih_101: Usage unknown, value fixed across reference cases.
this->data_[ih_101] = 1;
// ih_103: Usage unknown, value not fixed across reference cases, experiments generate warning with 0 but not with 1.
this->data_[ih_103] = 1;
// ih_200: Usage unknown, value fixed across reference cases.
this->data_[ih_200] = 1;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::wellSegDimensions(const WellSegDims& wsdim)
{
this->data_[NSEGWL] = wsdim.nsegwl;
this->data_[NSWLMX] = wsdim.nswlmx;
this->data_[NSEGMX] = wsdim.nsegmx;
this->data_[NLBRMX] = wsdim.nlbrmx;
this->data_[NISEGZ] = wsdim.nisegz;
this->data_[NRSEGZ] = wsdim.nrsegz;
this->data_[NILBRZ] = wsdim.nilbrz;
return *this;
}
Opm::RestartIO::InteHEAD&
Opm::RestartIO::InteHEAD::regionDimensions(const RegDims& rdim)
{
this->data_[NTFIP] = rdim.ntfip;
this->data_[NMFIPR] = rdim.nmfipr;
return *this;
}
// =====================================================================
// Free functions (calendar/time utilities)
// =====================================================================
namespace {
std::time_t advance(const std::time_t tp, const double sec)
{
using namespace std::chrono;
using TP = time_point<system_clock>;
using DoubSec = duration<double, seconds::period>;
const auto t = system_clock::from_time_t(tp) +
duration_cast<TP::duration>(DoubSec(sec));
return system_clock::to_time_t(t);
}
}
std::time_t
Opm::RestartIO::makeUTCTime(const std::tm& timePoint)
{
auto tp = timePoint; // Mutable copy.
const auto ltime = std::mktime(&tp);
auto tmval = *std::gmtime(&ltime); // Mutable.
// offset = ltime - tmval
// == #seconds by which 'ltime' is AHEAD of tmval.
const auto offset =
std::difftime(ltime, std::mktime(&tmval));
// Advance 'ltime' by 'offset' so that std::gmtime(return value) will
// have the same broken-down elements as 'tp'.
return advance(ltime, offset);
}
Opm::RestartIO::InteHEAD::TimePoint
Opm::RestartIO::getSimulationTimePoint(const std::time_t start,
const double elapsed)
{
const auto now = advance(start, elapsed);
const auto tp = *std::gmtime(&now);
auto sec = 0.0; // Not really used here.
auto usec = std::floor(1.0e6 * std::modf(elapsed, &sec));
return {
// Y-m-d
tp.tm_year + 1900,
tp.tm_mon + 1,
tp.tm_mday ,
// H:M:S
tp.tm_hour ,
tp.tm_min ,
std::min(tp.tm_sec, 59), // Ignore leap seconds
// Fractional seconds in microsecond resolution.
static_cast<int>(usec),
};
}

View File

@@ -0,0 +1,165 @@
#include <opm/output/eclipse/LogiHEAD.hpp>
#include <utility>
#include <vector>
enum index : std::vector<int>::size_type {
lh_000 = 0 , // TRUE
lh_001 = 1 , // TRUE
lh_002 = 2 , // FALSE
lh_003 = 3 , // FALSE Flag set to FALSE for a non-radial model, TRUE for a radial model (ECLIPSE 300 and other simulators)
lh_004 = 4 , // FALSE Flag set to FALSE for a non-radial model, TRUE for a radial model (ECLIPSE 100)
lh_005 = 5 , // FALSE
lh_006 = 6 , // FALSE
lh_007 = 7 , // FALSE
lh_008 = 8 , // FALSE
lh_009 = 9 , // FALSE
lh_010 = 10 , // FALSE
lh_011 = 11 , // FALSE
lh_012 = 12 , // FALSE
lh_013 = 13 , // FALSE
lh_014 = 14 , // FALSE Flag for dual porosity model
lh_015 = 15 , // FALSE
lh_016 = 16 , // TRUE
lh_017 = 17 , // FALSE
lh_018 = 18 , // TRUE
lh_019 = 19 , //
lh_020 = 20 , // FALSE
lh_021 = 21 , // FALSE
lh_022 = 22 , // FALSE
lh_023 = 23 , // FALSE
lh_024 = 24 , // FALSE
lh_025 = 25 , // FALSE
lh_026 = 26 , // FALSE
lh_027 = 27 , // FALSE
lh_028 = 28 , // FALSE
lh_029 = 29 , // FALSE
lh_030 = 30 , // FALSE Flag for coalbed methane (ECLIPSE 100)
lh_031 = 31 , // TRUE
lh_032 = 32 , // FALSE
lh_033 = 33 , // FALSE
lh_034 = 34 , // FALSE
lh_035 = 35 , // FALSE
lh_036 = 36 , // FALSE
lh_037 = 37 , //
lh_038 = 38 , // FALSE
lh_039 = 39 , // FALSE
lh_040 = 40 , // FALSE
lh_041 = 41 , // FALSE
lh_042 = 42 , // FALSE
lh_043 = 43 , //
lh_044 = 44 , // TRUE
lh_045 = 45 , // FALSE
lh_046 = 46 , // FALSE
lh_047 = 47 , // FALSE
lh_048 = 48 , //
lh_049 = 49 , // FALSE
lh_050 = 50 , // FALSE
lh_051 = 51 , // FALSE
lh_052 = 52 , // FALSE
lh_053 = 53 , // FALSE
lh_054 = 54 , // FALSE
lh_055 = 55 , // FALSE
lh_056 = 56 , // FALSE
lh_057 = 57 , // FALSE
lh_058 = 58 , // FALSE
lh_059 = 59 , // FALSE
lh_060 = 60 , // FALSE
lh_061 = 61 , // FALSE
lh_062 = 62 , // FALSE
lh_063 = 63 , // FALSE
lh_064 = 64 , // FALSE
lh_065 = 65 , // FALSE
lh_066 = 66 , // FALSE
lh_067 = 67 , // FALSE
lh_068 = 68 , // FALSE
lh_069 = 69 , // FALSE
lh_070 = 70 , // FALSE
lh_071 = 71 , // FALSE
lh_072 = 72 , // FALSE
lh_073 = 73 , // FALSE
lh_074 = 74 , // FALSE
lh_075 = 75 , // TRUE If segmented well model is used
lh_076 = 76 , // TRUE
lh_077 = 77 , // FALSE
lh_078 = 78 , // FALSE
lh_079 = 79 , // FALSE
lh_080 = 80 , // FALSE
lh_081 = 81 , // FALSE
lh_082 = 82 , // FALSE
lh_083 = 83 , // FALSE
lh_084 = 84 , // FALSE
lh_085 = 85 , // FALSE
lh_086 = 86 , //
lh_087 = 87 , // TRUE
lh_088 = 88 , // FALSE
lh_089 = 89 , // FALSE
lh_090 = 90 , // FALSE
lh_091 = 91 , // FALSE
lh_092 = 92 , // FALSE
lh_093 = 93 , //
lh_094 = 94 , // FALSE
lh_095 = 95 , // FALSE
lh_096 = 96 , //
lh_097 = 97 , // FALSE
lh_098 = 98 , // FALSE
lh_099 = 99 , // TRUE
lh_100 = 100 , // FALSE
lh_101 = 101 , // FALSE
lh_102 = 102 , // FALSE
lh_103 = 103 , // FALSE
lh_104 = 104 , // FALSE
lh_105 = 105 , // FALSE
lh_106 = 106 , // FALSE
lh_107 = 107 , // FALSE
lh_108 = 108 , // FALSE
lh_109 = 109 , // FALSE
lh_110 = 110 , // FALSE
lh_111 = 111 , // FALSE
lh_112 = 112 , // FALSE
lh_113 = 113 , // TRUE
lh_114 = 114 , // TRUE
lh_115 = 115 , // TRUE
lh_116 = 116 , // FALSE
lh_117 = 117 , // TRUE
lh_118 = 118 , // FALSE
lh_119 = 119 , // FALSE
lh_120 = 120 , // FALSE
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
LOGIHEAD_NUMBER_OF_ITEMS // MUST be last element of enum.
};
// =====================================================================
// Public Interface Below Separator
// =====================================================================
Opm::RestartIO::LogiHEAD::LogiHEAD()
: data_(LOGIHEAD_NUMBER_OF_ITEMS, false)
{}
Opm::RestartIO::LogiHEAD&
Opm::RestartIO::LogiHEAD::
variousParam(const bool e300_radial, const bool e100_radial, const int nswlmx)
{
this -> data_[lh_000] = true;
this -> data_[lh_001] = true;
this -> data_[lh_003] = e300_radial;
this -> data_[lh_004] = e100_radial;
this -> data_[lh_016] = true;
this -> data_[lh_018] = true;
this -> data_[lh_031] = true;
this -> data_[lh_044] = true;
this -> data_[lh_075] = nswlmx >= 1; // True if MS Wells exist.
this -> data_[lh_076] = true;
this -> data_[lh_087] = true;
this -> data_[lh_099] = true;
this -> data_[lh_113] = true;
this -> data_[lh_114] = true;
this -> data_[lh_115] = true;
this -> data_[lh_117] = true;
return *this;
}

View File

@@ -18,8 +18,8 @@
*/
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Completion.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Connection.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/GridProperty.hpp>
@@ -35,13 +35,13 @@ RegionCache::RegionCache(const Eclipse3DProperties& properties, const EclipseGri
const auto& wells = schedule.getWells();
for (const auto& well : wells) {
const auto& completions = well->getCompletions( );
for (const auto& c : completions) {
const auto& connections = well->getConnections( );
for (const auto& c : connections) {
size_t global_index = grid.getGlobalIndex( c.getI() , c.getJ() , c.getK());
if (grid.cellActive( global_index )) {
size_t active_index = grid.activeIndex( global_index );
int region_id =fipnum.iget( global_index );
auto& well_index_list = this->completion_map[ region_id ];
auto& well_index_list = this->connection_map[ region_id ];
well_index_list.push_back( { well->name() , active_index } );
}
}
@@ -49,10 +49,10 @@ RegionCache::RegionCache(const Eclipse3DProperties& properties, const EclipseGri
}
const std::vector<std::pair<std::string,size_t>>& RegionCache::completions( int region_id ) const {
const auto iter = this->completion_map.find( region_id );
if (iter == this->completion_map.end())
return this->completions_empty;
const std::vector<std::pair<std::string,size_t>>& RegionCache::connections( int region_id ) const {
const auto iter = this->connection_map.find( region_id );
if (iter == this->connection_map.end())
return this->connections_empty;
else
return iter->second;
}

View File

@@ -26,6 +26,7 @@
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/Eqldims.hpp>
#include <opm/output/eclipse/RestartIO.hpp>
@@ -56,13 +57,13 @@ namespace {
static const int NIWELZ = 11; //Number of data elements per well in IWEL array in restart file
static const int NZWELZ = 3; //Number of 8-character words per well in ZWEL array restart file
static const int NICONZ = 15; //Number of data elements per completion in ICON array restart file
static const int NICONZ = 15; //Number of data elements per connection in ICON array restart file
/**
* The constants NIWELZ and NZWELZ referes to the number of
* elements per well that we write to the IWEL and ZWEL eclipse
* restart file data arrays. The constant NICONZ refers to the
* number of elements per completion in the eclipse restart file
* number of elements per connection in the eclipse restart file
* ICON data array.These numbers are written to the INTEHEAD
* header.
*
@@ -103,15 +104,14 @@ namespace {
inline data::Solution restoreSOLUTION( ecl_file_view_type* file_view,
const std::map<std::string, RestartKey>& keys,
const UnitSystem& units,
const std::vector<RestartKey>& solution_keys,
int numcells) {
data::Solution sol;
for (const auto& pair : keys) {
const std::string& key = pair.first;
UnitSystem::measure dim = pair.second.dim;
bool required = pair.second.required;
data::Solution sol( false );
for (const auto& value : solution_keys) {
const std::string& key = value.key;
UnitSystem::measure dim = value.dim;
bool required = value.required;
if( !ecl_file_view_has_kw( file_view, key.c_str() ) ) {
if (required)
@@ -130,8 +130,6 @@ namespace {
+ ", mismatched number of cells" );
std::vector<double> data = double_vector( ecl_kw );
units.to_si( dim , data );
sol.insert( key, dim, data , data::TargetType::RESTART_SOLUTION );
}
@@ -142,12 +140,12 @@ namespace {
using rt = data::Rates::opt;
data::Wells restore_wells( const ecl_kw_type * opm_xwel,
const ecl_kw_type * opm_iwel,
int restart_step,
int sim_step,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule) {
const auto& sched_wells = schedule.getWells( restart_step );
const auto& sched_wells = schedule.getWells( sim_step );
std::vector< rt > phases;
{
const auto& phase = es.runspec().phases();
@@ -159,8 +157,8 @@ data::Wells restore_wells( const ecl_kw_type * opm_xwel,
const auto well_size = [&]( size_t acc, const Well* w ) {
return acc
+ 2 + phases.size()
+ ( w->getCompletions( restart_step ).size()
* (phases.size() + data::Completion::restart_size) );
+ ( w->getConnections( sim_step ).size()
* (phases.size() + data::Connection::restart_size) );
};
const auto expected_xwel_size = std::accumulate( sched_wells.begin(),
@@ -194,22 +192,22 @@ data::Wells restore_wells( const ecl_kw_type * opm_xwel,
for( auto phase : phases )
well.rates.set( phase, *opm_xwel_data++ );
for( const auto& sc : sched_well->getCompletions( restart_step ) ) {
for( const auto& sc : sched_well->getConnections( sim_step ) ) {
const auto i = sc.getI(), j = sc.getJ(), k = sc.getK();
if( !grid.cellActive( i, j, k ) || sc.getState() == WellCompletion::SHUT ) {
opm_xwel_data += data::Completion::restart_size + phases.size();
if( !grid.cellActive( i, j, k ) || sc.state == WellCompletion::SHUT ) {
opm_xwel_data += data::Connection::restart_size + phases.size();
continue;
}
const auto active_index = grid.activeIndex( i, j, k );
well.completions.emplace_back();
auto& completion = well.completions.back();
completion.index = active_index;
completion.pressure = *opm_xwel_data++;
completion.reservoir_rate = *opm_xwel_data++;
well.connections.emplace_back();
auto& connection = well.connections.back();
connection.index = active_index;
connection.pressure = *opm_xwel_data++;
connection.reservoir_rate = *opm_xwel_data++;
for( auto phase : phases )
completion.rates.set( phase, *opm_xwel_data++ );
connection.rates.set( phase, *opm_xwel_data++ );
}
}
@@ -220,12 +218,13 @@ data::Wells restore_wells( const ecl_kw_type * opm_xwel,
/* should take grid as argument because it may be modified from the simulator */
RestartValue load( const std::string& filename,
int report_step,
const std::map<std::string, RestartKey>& keys,
const std::vector<RestartKey>& solution_keys,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const std::map<std::string, bool>& extra_keys) {
const std::vector<RestartKey>& extra_keys) {
int sim_step = std::max(report_step - 1, 0);
const bool unified = ( ERT::EclFiletype( filename ) == ECL_UNIFIED_RESTART_FILE );
ERT::ert_unique_ptr< ecl_file_type, ecl_file_close > file(ecl_file_open( filename.c_str(), 0 ));
ecl_file_view_type * file_view;
@@ -247,23 +246,32 @@ RestartValue load( const std::string& filename,
const ecl_kw_type * opm_iwel = ecl_file_view_iget_named_kw( file_view, "OPM_IWEL", 0 );
UnitSystem units( static_cast<ert_ecl_unit_enum>(ecl_kw_iget_int( intehead , INTEHEAD_UNIT_INDEX )));
RestartValue rst_value( restoreSOLUTION( file_view, keys, units , grid.getNumActive( )),
restore_wells( opm_xwel, opm_iwel, report_step , es, grid, schedule));
RestartValue rst_value( restoreSOLUTION( file_view, solution_keys, grid.getNumActive( )),
restore_wells( opm_xwel, opm_iwel, sim_step , es, grid, schedule));
for (const auto& pair : extra_keys) {
const std::string& key = pair.first;
bool required = pair.second;
for (const auto& extra : extra_keys) {
const std::string& key = extra.key;
bool required = extra.required;
if (ecl_file_view_has_kw( file_view , key.c_str())) {
const ecl_kw_type * ecl_kw = ecl_file_view_iget_named_kw( file_view , key.c_str() , 0 );
const double * data_ptr = ecl_kw_get_double_ptr( ecl_kw );
const double * end_ptr = data_ptr + ecl_kw_get_size( ecl_kw );
rst_value.extra[ key ] = { data_ptr, end_ptr };
rst_value.addExtra(key, extra.dim, {data_ptr, end_ptr});
} else if (required)
throw std::runtime_error("No such key in file: " + key);
}
// Convert solution fields and extra data from user units to SI
rst_value.solution.convertToSI(units);
for (auto & extra_value : rst_value.extra) {
const auto& restart_key = extra_value.first;
auto & data = extra_value.second;
units.to_si(restart_key.dim, data);
}
return rst_value;
}
@@ -273,31 +281,32 @@ RestartValue load( const std::string& filename,
namespace {
std::vector<int> serialize_ICON( int report_step,
std::vector<int> serialize_ICON( int sim_step,
int ncwmax,
const std::vector<const Well*>& sched_wells) {
const std::vector<const Well*>& sched_wells,
const EclipseGrid& /*grid*/) {
size_t well_offset = 0;
std::vector<int> data( sched_wells.size() * ncwmax * NICONZ , 0 );
for (const Well* well : sched_wells) {
const auto& completions = well->getCompletions( report_step );
size_t completion_offset = 0;
for( const auto& completion : completions) {
size_t offset = well_offset + completion_offset;
const auto& connections = well->getConnections( sim_step );
size_t connection_offset = 0;
for( const auto& connection : connections) {
size_t offset = well_offset + connection_offset;
data[ offset + ICON_IC_INDEX ] = 1;
data[ offset + ICON_I_INDEX ] = completion.getI() + 1;
data[ offset + ICON_J_INDEX ] = completion.getJ() + 1;
data[ offset + ICON_K_INDEX ] = completion.getK() + 1;
data[ offset + ICON_DIRECTION_INDEX ] = completion.getDirection();
data[ offset + ICON_I_INDEX ] = connection.getI() + 1;
data[ offset + ICON_J_INDEX ] = connection.getJ() + 1;
data[ offset + ICON_K_INDEX ] = connection.getK() + 1;
data[ offset + ICON_DIRECTION_INDEX ] = connection.dir;
{
const auto open = WellCompletion::StateEnum::OPEN;
data[ offset + ICON_STATUS_INDEX ] = completion.getState() == open
data[ offset + ICON_STATUS_INDEX ] = connection.state == open
? 1
: 0;
}
completion_offset += NICONZ;
connection_offset += NICONZ;
}
well_offset += ncwmax * NICONZ;
}
@@ -305,16 +314,17 @@ std::vector<int> serialize_ICON( int report_step,
}
std::vector<int> serialize_IWEL( size_t step,
const std::vector<const Well *>& wells) {
const std::vector<const Well *>& wells,
const EclipseGrid& grid) {
std::vector<int> data( wells.size() * NIWELZ , 0 );
size_t offset = 0;
for (const auto well : wells) {
const auto& completions = well->getCompletions( step );
const auto& connections = well->getActiveConnections( step, grid );
data[ offset + IWEL_HEADI_INDEX ] = well->getHeadI( step ) + 1;
data[ offset + IWEL_HEADJ_INDEX ] = well->getHeadJ( step ) + 1;
data[ offset + IWEL_CONNECTIONS_INDEX ] = completions.size();
data[ offset + IWEL_CONNECTIONS_INDEX ] = connections.size();
data[ offset + IWEL_GROUP_INDEX ] = 1;
data[ offset + IWEL_TYPE_INDEX ] = to_ert_welltype( *well, step );
@@ -349,7 +359,7 @@ std::vector< int > serialize_OPM_IWEL( const data::Wells& wells,
}
std::vector< double > serialize_OPM_XWEL( const data::Wells& wells,
int report_step,
int sim_step,
const std::vector< const Well* >& sched_wells,
const Phases& phase_spec,
const EclipseGrid& grid ) {
@@ -364,9 +374,9 @@ std::vector< double > serialize_OPM_XWEL( const data::Wells& wells,
std::vector< double > xwel;
for( const auto* sched_well : sched_wells ) {
if( wells.count( sched_well->name() ) == 0 || sched_well->getStatus(report_step) == Opm::WellCommon::SHUT) {
const auto elems = (sched_well->getCompletions( report_step ).size()
* (phases.size() + data::Completion::restart_size))
if( wells.count( sched_well->name() ) == 0 || sched_well->getStatus(sim_step) == Opm::WellCommon::SHUT) {
const auto elems = (sched_well->getConnections( sim_step ).size()
* (phases.size() + data::Connection::restart_size))
+ 2 /* bhp, temperature */
+ phases.size();
@@ -382,32 +392,32 @@ std::vector< double > serialize_OPM_XWEL( const data::Wells& wells,
for( auto phase : phases )
xwel.push_back( well.rates.get( phase ) );
for( const auto& sc : sched_well->getCompletions( report_step ) ) {
for( const auto& sc : sched_well->getConnections( sim_step ) ) {
const auto i = sc.getI(), j = sc.getJ(), k = sc.getK();
const auto rs_size = phases.size() + data::Completion::restart_size;
if( !grid.cellActive( i, j, k ) || sc.getState() == WellCompletion::SHUT ) {
const auto rs_size = phases.size() + data::Connection::restart_size;
if( !grid.cellActive( i, j, k ) || sc.state == WellCompletion::SHUT ) {
xwel.insert( xwel.end(), rs_size, 0.0 );
continue;
}
const auto active_index = grid.activeIndex( i, j, k );
const auto at_index = [=]( const data::Completion& c ) {
const auto at_index = [=]( const data::Connection& c ) {
return c.index == active_index;
};
const auto& completion = std::find_if( well.completions.begin(),
well.completions.end(),
const auto& connection = std::find_if( well.connections.begin(),
well.connections.end(),
at_index );
if( completion == well.completions.end() ) {
if( connection == well.connections.end() ) {
xwel.insert( xwel.end(), rs_size, 0.0 );
continue;
}
xwel.push_back( completion->pressure );
xwel.push_back( completion->reservoir_rate );
xwel.push_back( connection->pressure );
xwel.push_back( connection->reservoir_rate );
for( auto phase : phases )
xwel.push_back( completion->rates.get( phase ) );
xwel.push_back( connection->rates.get( phase ) );
}
}
@@ -436,6 +446,7 @@ void write_kw(ecl_rst_file_type * rst_file , ERT::EclKW< T >&& kw) {
}
void writeHeader(ecl_rst_file_type * rst_file,
int sim_step,
int report_step,
time_t posix_time,
double sim_days,
@@ -451,11 +462,11 @@ void writeHeader(ecl_rst_file_type * rst_file,
rsthead_data.nx = grid.getNX();
rsthead_data.ny = grid.getNY();
rsthead_data.nz = grid.getNZ();
rsthead_data.nwells = schedule.numWells(report_step);
rsthead_data.nwells = schedule.numWells(sim_step);
rsthead_data.niwelz = NIWELZ;
rsthead_data.nzwelz = NZWELZ;
rsthead_data.niconz = NICONZ;
rsthead_data.ncwmax = schedule.getMaxNumCompletionsForWells(report_step);
rsthead_data.ncwmax = schedule.getMaxNumConnectionsForWells(sim_step);
rsthead_data.phase_sum = ert_phase_mask;
rsthead_data.sim_days = sim_days;
rsthead_data.unit_system = units.getEclType( );
@@ -472,15 +483,15 @@ void writeHeader(ecl_rst_file_type * rst_file,
ERT::ert_unique_ptr< ecl_kw_type, ecl_kw_free > kw_ptr;
if (write_double) {
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw.c_str() , data.size() , ECL_DOUBLE );
ecl_kw_set_memcpy_data( ecl_kw , data.data() );
kw_ptr.reset( ecl_kw );
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw.c_str() , data.size() , ECL_DOUBLE );
ecl_kw_set_memcpy_data( ecl_kw , data.data() );
kw_ptr.reset( ecl_kw );
} else {
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw.c_str() , data.size() , ECL_FLOAT );
float * float_data = ecl_kw_get_float_ptr( ecl_kw );
for (size_t i=0; i < data.size(); i++)
float_data[i] = data[i];
kw_ptr.reset( ecl_kw );
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw.c_str() , data.size() , ECL_FLOAT );
float * float_data = ecl_kw_get_float_ptr( ecl_kw );
for (size_t i=0; i < data.size(); i++)
float_data[i] = data[i];
kw_ptr.reset( ecl_kw );
}
return kw_ptr;
@@ -503,10 +514,10 @@ void writeHeader(ecl_rst_file_type * rst_file,
}
void writeExtraData(ecl_rst_file_type* rst_file, const std::map<std::string,std::vector<double>>& extra_data) {
for (const auto& pair : extra_data) {
const std::string& key = pair.first;
const std::vector<double>& data = pair.second;
void writeExtraData(ecl_rst_file_type* rst_file, const RestartValue::ExtraVector& extra_data) {
for (const auto& extra_value : extra_data) {
const std::string& key = extra_value.first.key;
const std::vector<double>& data = extra_value.second;
{
ecl_kw_type * ecl_kw = ecl_kw_alloc_new_shared( key.c_str() , data.size() , ECL_DOUBLE , const_cast<double *>(data.data()));
ecl_rst_file_add_kw( rst_file , ecl_kw);
@@ -517,15 +528,15 @@ void writeExtraData(ecl_rst_file_type* rst_file, const std::map<std::string,std:
void writeWell(ecl_rst_file_type* rst_file, int report_step, const EclipseState& es , const EclipseGrid& grid, const Schedule& schedule, const data::Wells& wells) {
const auto sched_wells = schedule.getWells(report_step);
void writeWell(ecl_rst_file_type* rst_file, int sim_step, const EclipseState& es , const EclipseGrid& grid, const Schedule& schedule, const data::Wells& wells) {
const auto sched_wells = schedule.getWells(sim_step);
const auto& phases = es.runspec().phases();
const size_t ncwmax = schedule.getMaxNumCompletionsForWells(report_step);
const size_t ncwmax = schedule.getMaxNumConnectionsForWells(sim_step);
const auto opm_xwel = serialize_OPM_XWEL( wells, report_step, sched_wells, phases, grid );
const auto opm_xwel = serialize_OPM_XWEL( wells, sim_step, sched_wells, phases, grid );
const auto opm_iwel = serialize_OPM_IWEL( wells, sched_wells );
const auto iwel_data = serialize_IWEL(report_step, sched_wells);
const auto icon_data = serialize_ICON(report_step , ncwmax, sched_wells);
const auto iwel_data = serialize_IWEL(sim_step, sched_wells, grid);
const auto icon_data = serialize_ICON(sim_step , ncwmax, sched_wells, grid);
const auto zwel_data = serialize_ZWEL( sched_wells );
write_kw( rst_file, ERT::EclKW< int >( IWEL_KW, iwel_data) );
@@ -535,44 +546,45 @@ void writeWell(ecl_rst_file_type* rst_file, int report_step, const EclipseState&
write_kw( rst_file, ERT::EclKW< int >( ICON_KW, icon_data ) );
}
void checkSaveArguments(const data::Solution& cells,
const EclipseGrid& grid,
const std::map<std::string, std::vector<double>>& extra_data) {
void checkSaveArguments(const EclipseState& es,
const RestartValue& restart_value,
const EclipseGrid& grid) {
const std::set<std::string> reserved_keys = {"LOGIHEAD", "INTEHEAD" ,"DOUBHEAD", "IWEL", "XWEL","ICON", "XCON" , "OPM_IWEL" , "OPM_XWEL", "ZWEL"};
for (const auto& elm: restart_value.solution)
if (elm.second.data.size() != grid.getNumActive())
throw std::runtime_error("Wrong size on solution vector: " + elm.first);
for (const auto& pair : extra_data) {
const std::string& key = pair.first;
if (key.size() > 8)
throw std::runtime_error("The keys in extra data must have maximum eight characaters");
if (cells.has( key ))
throw std::runtime_error("The keys used must unique across Solution and extra_data");
if (es.getSimulationConfig().getThresholdPressure().size() > 0) {
// If the the THPRES option is active the restart_value should have a
// THPRES field. This is not enforced here because not all the opm
// simulators have been updated to include the THPRES values.
if (!restart_value.hasExtra("THPRES")) {
OpmLog::warning("This model has THPRES active - should have THPRES as part of restart data.");
return;
}
if (reserved_keys.find( key ) != reserved_keys.end())
throw std::runtime_error("The extra_data uses a reserved key");
}
for (const auto& elm: cells)
if (elm.second.data.size() != grid.getNumActive())
throw std::runtime_error("Wrong size on solution vector: " + elm.first);
}
size_t num_regions = es.getTableManager().getEqldims().getNumEquilRegions();
const auto& thpres = restart_value.getExtra("THPRES");
if (thpres.size() != num_regions * num_regions)
throw std::runtime_error("THPRES vector has invalid size - should have num_region * num_regions.");
}
}
} // Anonymous namespace
void save(const std::string& filename,
int report_step,
double seconds_elapsed,
data::Solution cells,
data::Wells wells,
RestartValue value,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
std::map<std::string, std::vector<double>> extra_data,
bool write_double)
bool write_double)
{
checkSaveArguments( cells, grid, extra_data );
checkSaveArguments(es, value, grid);
{
int sim_step = std::max(report_step - 1, 0);
int ert_phase_mask = es.runspec().eclPhaseMask( );
const auto& units = es.getUnits();
time_t posix_time = schedule.posixStartTime() + seconds_elapsed;
@@ -584,14 +596,20 @@ void save(const std::string& filename,
else
rst_file.reset( ecl_rst_file_open_write( filename.c_str() ) );
// Convert solution fields and extra values from SI to user units.
value.solution.convertFromSI(units);
for (auto & extra_value : value.extra) {
const auto& restart_key = extra_value.first;
auto & data = extra_value.second;
cells.convertFromSI( units );
writeHeader( rst_file.get() , report_step, posix_time , sim_time, ert_phase_mask, units, schedule , grid );
writeWell( rst_file.get() , report_step, es , grid, schedule, wells);
writeSolution( rst_file.get() , cells , write_double );
writeExtraData( rst_file.get() , extra_data );
units.from_si(restart_key.dim, data);
}
writeHeader( rst_file.get(), sim_step, report_step, posix_time , sim_time, ert_phase_mask, units, schedule , grid );
writeWell( rst_file.get(), sim_step, es , grid, schedule, value.wells);
writeSolution( rst_file.get(), value.solution, write_double );
writeExtraData( rst_file.get(), value.extra );
}
}
}
}

View File

@@ -0,0 +1,85 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <set>
#include <iostream>
#include <opm/output/eclipse/RestartValue.hpp>
namespace Opm {
namespace {
const std::set<std::string> reserved_keys = {"LOGIHEAD", "INTEHEAD" ,"DOUBHEAD", "IWEL", "XWEL","ICON", "XCON" , "OPM_IWEL" , "OPM_XWEL", "ZWEL"};
}
RestartValue::RestartValue(data::Solution sol, data::Wells wells_arg) :
solution(std::move(sol)),
wells(std::move(wells_arg))
{
}
const std::vector<double>& RestartValue::getExtra(const std::string& key) const {
const auto iter = std::find_if(this->extra.begin(),
this->extra.end(),
[&](const std::pair<RestartKey, std::vector<double>>& pair)
{
return (pair.first.key == key);
});
if (iter == this->extra.end())
throw std::invalid_argument("No such extra key " + key);
return iter->second;
}
bool RestartValue::hasExtra(const std::string& key) const {
const auto iter = std::find_if(this->extra.begin(),
this->extra.end(),
[&](const std::pair<RestartKey, std::vector<double>>& pair)
{
return (pair.first.key == key);
});
return (iter != this->extra.end());
}
void RestartValue::addExtra(const std::string& key, UnitSystem::measure dimension, std::vector<double> data) {
if (key.size() > 8)
throw std::runtime_error("The keys used for Eclipse output must be maximum 8 characters long.");
if (this->hasExtra(key))
throw std::runtime_error("The keys in the extra vector must be unique.");
if (this->solution.has(key))
throw std::runtime_error("The key " + key + " is already present in the solution section.");
if (reserved_keys.find(key) != reserved_keys.end())
throw std::runtime_error("Can not use reserved key:" + key);
this->extra.push_back( std::make_pair(RestartKey(key, dimension), std::move(data)));
}
void RestartValue::addExtra(const std::string& key, std::vector<double> data) {
this->addExtra(key, UnitSystem::measure::identity, std::move(data));
}
}

View File

@@ -17,7 +17,12 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exception>
#include <initializer_list>
#include <iterator>
#include <numeric>
#include <stdexcept>
#include <string>
#include <opm/common/OpmLog/OpmLog.hpp>
@@ -32,12 +37,87 @@
#include <opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/output/eclipse/Summary.hpp>
#include <opm/output/eclipse/RegionCache.hpp>
#include <ert/ecl/ecl_smspec.h>
#include <ert/ecl/ecl_kw_magic.h>
namespace {
std::vector<std::string> requiredRestartVectors()
{
return {
"OPR", "WPR", "GPR", "VPR",
"OPT", "WPT", "GPT", "VPT",
"WIR", "GIR",
"WIT", "GIT",
"WCT", "GOR",
};
}
std::vector<std::pair<std::string, std::string>>
requiredRestartVectors(const ::Opm::Schedule& sched)
{
auto entities = std::vector<std::pair<std::string, std::string>>{};
const auto& vectors = requiredRestartVectors();
auto makeEntities = [&vectors, &entities]
(const char cat, const std::string& name)
{
for (const auto& vector : vectors) {
entities.emplace_back(cat + vector, name);
}
};
for (const auto* well : sched.getWells()) {
const auto& well_name = well->name();
makeEntities('W', well_name);
entities.emplace_back("WBHP" , well_name);
entities.emplace_back("WGVIR", well_name);
entities.emplace_back("WWVIR", well_name);
}
for (const auto* grp : sched.getGroups()) {
const auto& grp_name = grp->name();
if (grp_name != "FIELD") {
makeEntities('G', grp_name);
}
}
makeEntities('F', "FIELD");
return entities;
}
std::string genKey(const std::string& vector,
const std::string& entity)
{
return (entity == "FIELD")
? vector
: vector + ':' + entity;
}
ERT::ert_unique_ptr<smspec_node_type, smspec_node_free>
makeRestartVectorSMSPEC(const std::string& vector,
const std::string& entity)
{
const auto var_type =
ecl_smspec_identify_var_type(vector.c_str());
const int dims[] = { 1, 1, 1 };
return ERT::ert_unique_ptr<smspec_node_type, smspec_node_free> {
smspec_node_alloc(var_type, entity.c_str(), vector.c_str(),
"UNIT", ":", dims, 0, 0, 0.0f)
};
}
} // namespace Anonymous
/*
* This class takes simulator state and parser-provided information and
* orchestrates ert to write simulation results as requested by the SUMMARY
@@ -54,6 +134,7 @@ using rt = data::Rates::opt;
using measure = UnitSystem::measure;
constexpr const bool injector = true;
constexpr const bool producer = false;
constexpr const bool polymer = true;
/* Some numerical value with its unit tag embedded to enable caller to apply
* unit conversion. This removes a lot of boilerplate. ad-hoc solution to poor
@@ -80,6 +161,10 @@ measure div_unit( measure denom, measure div ) {
div == measure::time )
return measure::gas_surface_volume;
if( denom == measure::mass_rate &&
div == measure::time )
return measure::mass;
return measure::identity;
}
@@ -98,6 +183,9 @@ measure mul_unit( measure lhs, measure rhs ) {
( rhs == measure::rate && lhs == measure::time ) )
return measure::volume;
if( lhs == measure::mass_rate && rhs == measure::time)
return measure::mass;
return lhs;
}
@@ -195,7 +283,7 @@ double efac( const std::vector<std::pair<std::string,double>>& eff_factors, cons
return (it != eff_factors.end()) ? it->second : 1;
}
template< rt phase, bool injection = true >
template< rt phase, bool injection = true, bool polymer = false >
inline quantity rate( const fn_args& args ) {
double sum = 0.0;
@@ -205,13 +293,19 @@ inline quantity rate( const fn_args& args ) {
double eff_fac = efac( args.eff_factors, name );
const auto v = args.wells.at(name).rates.get(phase, 0.0) * eff_fac;
double concentration = polymer
? sched_well->getPolymerProperties( args.sim_step ).m_polymerConcentration
: 1;
const auto v = args.wells.at(name).rates.get(phase, 0.0) * eff_fac * concentration;
if( ( v > 0 ) == injection )
sum += v;
}
if( !injection ) sum *= -1;
if( polymer ) return { sum, measure::mass_rate };
return { sum, rate_unit< phase >() };
}
@@ -232,7 +326,7 @@ inline quantity flowing( const fn_args& args ) {
measure::identity };
}
template< rt phase, bool injection = true >
template< rt phase, bool injection = true, bool polymer = false >
inline quantity crate( const fn_args& args ) {
const quantity zero = { 0, rate_unit< phase >() };
// The args.num value is the literal value which will go to the
@@ -242,24 +336,29 @@ inline quantity crate( const fn_args& args ) {
const size_t global_index = args.num - 1;
if( args.schedule_wells.empty() ) return zero;
const auto& name = args.schedule_wells.front()->name();
const auto& well = args.schedule_wells.front();
const auto& name = well->name();
if( args.wells.count( name ) == 0 ) return zero;
const auto& well = args.wells.at( name );
const auto& completion = std::find_if( well.completions.begin(),
well.completions.end(),
[=]( const data::Completion& c ) {
const auto& well_data = args.wells.at( name );
const auto& completion = std::find_if( well_data.connections.begin(),
well_data.connections.end(),
[=]( const data::Connection& c ) {
return c.index == global_index;
} );
if( completion == well.completions.end() ) return zero;
if( completion == well_data.connections.end() ) return zero;
double eff_fac = efac( args.eff_factors, name );
double concentration = polymer
? well->getPolymerProperties( args.sim_step ).m_polymerConcentration
: 1;
const auto v = completion->rates.get( phase, 0.0 ) * eff_fac;
auto v = completion->rates.get( phase, 0.0 ) * eff_fac * concentration;
if( ( v > 0 ) != injection ) return zero;
if( !injection ) v *= -1;
if( !injection ) return { -v, rate_unit< phase >() };
if( polymer ) return { v, measure::mass_rate };
return { v, rate_unit< phase >() };
}
@@ -317,15 +416,7 @@ inline quantity production_history( const fn_args& args ) {
* For well data, looking up historical rates (both for production and
* injection) before simulation actually starts is impossible and
* nonsensical. We therefore default to writing zero (which is what eclipse
* seems to do as well). Additionally, when an input deck is parsed,
* timesteps and rates are structured as such:
*
* The rates observed in timestep N is denoted at timestep N-1, i.e. at the
* **end** of the previous timestep. Which means that what observed at
* timestep 1 is denoted at timestep 0, and what happens "on" timestep 0
* doesn't exist and would in code give an arithmetic error. We therefore
* special-case timestep N == 0, and for all other timesteps look up the
* value *reported* at N-1 which applies to timestep N.
* seems to do as well).
*/
double sum = 0.0;
@@ -388,9 +479,9 @@ inline quantity duration( const fn_args& args ) {
template<rt phase , bool injection>
quantity region_rate( const fn_args& args ) {
double sum = 0;
const auto& well_completions = args.regionCache.completions( args.num );
const auto& well_connections = args.regionCache.connections( args.num );
for (const auto& pair : well_completions) {
for (const auto& pair : well_connections) {
double eff_fac = efac( args.eff_factors, pair.first );
@@ -433,11 +524,13 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "WOIR", rate< rt::oil, injector > },
{ "WGIR", rate< rt::gas, injector > },
{ "WNIR", rate< rt::solvent, injector > },
{ "WCIR", rate< rt::wat, injector, polymer > },
{ "WWIT", mul( rate< rt::wat, injector >, duration ) },
{ "WOIT", mul( rate< rt::oil, injector >, duration ) },
{ "WGIT", mul( rate< rt::gas, injector >, duration ) },
{ "WNIT", mul( rate< rt::solvent, injector >, duration ) },
{ "WCIT", mul( rate< rt::wat, injector, polymer >, duration ) },
{ "WVIT", mul( sum( sum( rate< rt::reservoir_water, injector >, rate< rt::reservoir_oil, injector > ),
rate< rt::reservoir_gas, injector > ), duration ) },
@@ -490,12 +583,14 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "GOIR", rate< rt::oil, injector > },
{ "GGIR", rate< rt::gas, injector > },
{ "GNIR", rate< rt::solvent, injector > },
{ "GCIR", rate< rt::wat, injector, polymer > },
{ "GVIR", sum( sum( rate< rt::reservoir_water, injector >, rate< rt::reservoir_oil, injector > ),
rate< rt::reservoir_gas, injector > ) },
{ "GWIT", mul( rate< rt::wat, injector >, duration ) },
{ "GOIT", mul( rate< rt::oil, injector >, duration ) },
{ "GGIT", mul( rate< rt::gas, injector >, duration ) },
{ "GNIT", mul( rate< rt::solvent, injector >, duration ) },
{ "GCIT", mul( rate< rt::wat, injector, polymer >, duration ) },
{ "GVIT", mul( sum( sum( rate< rt::reservoir_water, injector >, rate< rt::reservoir_oil, injector > ),
rate< rt::reservoir_gas, injector > ), duration ) },
@@ -599,6 +694,7 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "CWIR", crate< rt::wat, injector > },
{ "CGIR", crate< rt::gas, injector > },
{ "CCIR", crate< rt::wat, injector, polymer > },
{ "CWIT", mul( crate< rt::wat, injector >, duration ) },
{ "CGIT", mul( crate< rt::gas, injector >, duration ) },
{ "CNIT", mul( crate< rt::solvent, injector >, duration ) },
@@ -612,6 +708,7 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "COPT", mul( crate< rt::oil, producer >, duration ) },
{ "CGPT", mul( crate< rt::gas, producer >, duration ) },
{ "CNPT", mul( crate< rt::solvent, producer >, duration ) },
{ "CCIT", mul( crate< rt::wat, injector, polymer >, duration ) },
{ "FWPR", rate< rt::wat, producer > },
{ "FOPR", rate< rt::oil, producer > },
@@ -628,7 +725,7 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "FWPT", mul( rate< rt::wat, producer >, duration ) },
{ "FOPT", mul( rate< rt::oil, producer >, duration ) },
{ "FGPT", mul( rate< rt::gas, producer >, duration ) },
{ "FNPT", mul( rate< rt::solvent >, duration ) },
{ "FNPT", mul( rate< rt::solvent, producer >, duration ) },
{ "FLPT", mul( sum( rate< rt::wat, producer >, rate< rt::oil, producer > ),
duration ) },
{ "FVPT", mul(sum (sum( rate< rt::reservoir_water, producer>, rate< rt::reservoir_oil, producer >),
@@ -644,6 +741,7 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "FOIR", rate< rt::oil, injector > },
{ "FGIR", rate< rt::gas, injector > },
{ "FNIR", rate< rt::solvent, injector > },
{ "FCIR", rate< rt::wat, injector, polymer > },
{ "FVIR", sum( sum( rate< rt::reservoir_water, injector>, rate< rt::reservoir_oil, injector >),
rate< rt::reservoir_gas, injector>)},
@@ -652,6 +750,7 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "FOIT", mul( rate< rt::oil, injector >, duration ) },
{ "FGIT", mul( rate< rt::gas, injector >, duration ) },
{ "FNIT", mul( rate< rt::solvent, injector >, duration ) },
{ "FCIT", mul( rate< rt::wat, injector, polymer >, duration ) },
{ "FLIT", mul( sum( rate< rt::wat, injector >, rate< rt::oil, injector > ),
duration ) },
{ "FVIT", mul( sum( sum( rate< rt::reservoir_water, injector>, rate< rt::reservoir_oil, injector >),
@@ -783,8 +882,8 @@ inline std::vector< const Well* > find_wells( const Schedule& schedule,
const auto region = smspec_node_get_num( node );
for ( const auto& completion : regionCache.completions( region ) ){
const auto& w_name = completion.first;
for ( const auto& connection : regionCache.connections( region ) ){
const auto& w_name = connection.first;
const auto& well = schedule.getWell( w_name );
const auto& it = std::find_if( wells.begin(), wells.end(),
@@ -812,7 +911,10 @@ class Summary::keyword_handlers {
std::map< std::pair <std::string, int>, smspec_node_type* > region_nodes;
std::map< std::pair <std::string, int>, smspec_node_type* > block_nodes;
// Memory management for restart-related summary vectors
// that are not requested in SUMMARY section.
std::vector<ERT::ert_unique_ptr<smspec_node_type,
smspec_node_free>> rstvec_backing_store;
};
Summary::Summary( const EclipseState& st,
@@ -944,7 +1046,8 @@ Summary::Summary( const EclipseState& st,
node.num(), // NUMS value for the summary output.
{}, // Well results - data::Wells
{}, // Region <-> cell mappings.
this->grid};
this->grid,
{}};
const auto val = handle( no_args );
@@ -963,6 +1066,42 @@ Summary::Summary( const EclipseState& st,
for ( const auto& keyword : unsupported_keywords ) {
Opm::OpmLog::info("Keyword " + std::string(keyword) + " is unhandled");
}
// Guarantee existence of certain summary vectors (mostly rates and
// cumulative totals for wells, groups, and field) that are required
// for simulation restart.
{
auto& rvec = this->handlers->rstvec_backing_store;
auto& hndlrs = this->handlers->handlers;
for (const auto& vector : requiredRestartVectors(schedule)) {
const auto& kw = vector.first;
const auto& entity = vector.second;
const auto key = genKey(kw, entity);
if (ecl_sum_has_key(this->ecl_sum.get(), key.c_str())) {
// Vector already requested in SUMMARY section.
// Don't add a second evaluation of this.
continue;
}
auto func = funs.find(kw);
if (func == std::end(funs)) {
throw std::logic_error {
"Unable to find handler for '" + kw + "'"
};
}
rvec.push_back(makeRestartVectorSMSPEC(kw, entity));
hndlrs.emplace_back(rvec.back().get(), func->second);
}
}
for (const auto& pair : this->handlers->handlers) {
const auto * nodeptr = pair.first;
if (smspec_node_is_total(nodeptr))
this->prev_state.add(smspec_node_get_gen_key1(nodeptr), 0);
}
}
/*
@@ -1036,6 +1175,7 @@ void Summary::add_timestep( int report_step,
auto* tstep = ecl_sum_add_tstep( this->ecl_sum.get(), report_step, secs_elapsed );
const double duration = secs_elapsed - this->prev_time_elapsed;
SummaryState st;
/* report_step is the number of the file we are about to write - i.e. for instance CASE.S$report_step
* for the data in a non-unified summary file.
@@ -1059,12 +1199,11 @@ void Summary::add_timestep( int report_step,
this->grid,
eff_factors});
const auto unit_applied_val = es.getUnits().from_si( val.unit, val.value );
const auto res = smspec_node_is_total( f.first ) && prev_tstep
? ecl_sum_tstep_get_from_key( prev_tstep, genkey ) + unit_applied_val
: unit_applied_val;
double unit_applied_val = es.getUnits().from_si( val.unit, val.value );
if (smspec_node_is_total(f.first))
unit_applied_val += this->prev_state.get(genkey);
ecl_sum_tstep_set_from_node( tstep, f.first, res );
st.add(genkey, unit_applied_val);
}
for( const auto& value_pair : single_values ) {
@@ -1072,10 +1211,11 @@ void Summary::add_timestep( int report_step,
const auto node_pair = this->handlers->single_value_nodes.find( key );
if (node_pair != this->handlers->single_value_nodes.end()) {
const auto * nodeptr = node_pair->second;
const auto * genkey = smspec_node_get_gen_key1( nodeptr );
const auto unit = single_values_units.at( key );
double si_value = value_pair.second;
double output_value = es.getUnits().from_si(unit , si_value );
ecl_sum_tstep_set_from_node( tstep, nodeptr , output_value );
st.add(genkey, output_value);
}
}
@@ -1085,11 +1225,13 @@ void Summary::add_timestep( int report_step,
const auto node_pair = this->handlers->region_nodes.find( std::make_pair(key, reg+1) );
if (node_pair != this->handlers->region_nodes.end()) {
const auto * nodeptr = node_pair->second;
const auto* genkey = smspec_node_get_gen_key1( nodeptr );
const auto unit = region_units.at( key );
assert (smspec_node_get_num( nodeptr ) - 1 == static_cast<int>(reg));
double si_value = value_pair.second[reg];
double output_value = es.getUnits().from_si(unit , si_value );
ecl_sum_tstep_set_from_node( tstep, nodeptr , output_value );
st.add(genkey, output_value);
}
}
}
@@ -1099,14 +1241,23 @@ void Summary::add_timestep( int report_step,
const auto node_pair = this->handlers->block_nodes.find( key );
if (node_pair != this->handlers->block_nodes.end()) {
const auto * nodeptr = node_pair->second;
const auto * genkey = smspec_node_get_gen_key1( nodeptr );
const auto unit = block_units.at( key.first );
double si_value = value_pair.second;
double output_value = es.getUnits().from_si(unit , si_value );
ecl_sum_tstep_set_from_node( tstep, nodeptr , output_value );
st.add(genkey, output_value);
}
}
this->prev_tstep = tstep;
for (const auto& pair: st) {
const auto* key = pair.first.c_str();
if (ecl_sum_has_key(this->ecl_sum.get(), key)) {
ecl_sum_tstep_set_from_key(tstep, key, pair.second);
}
}
this->prev_state = st;
this->prev_time_elapsed = secs_elapsed;
}
@@ -1116,5 +1267,9 @@ void Summary::write() {
Summary::~Summary() {}
const SummaryState& Summary::get_restart_vectors() const
{
return this->prev_state;
}
}
}} // namespace Opm::out

View File

@@ -0,0 +1,52 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/output/eclipse/SummaryState.hpp>
namespace Opm{
void SummaryState::add(const std::string& key, double value) {
this->values[key] = value;
}
bool SummaryState::has(const std::string& key) const {
return (this->values.find(key) != this->values.end());
}
double SummaryState::get(const std::string& key) const {
const auto iter = this->values.find(key);
if (iter == this->values.end())
throw std::invalid_argument("XX No such key: " + key);
return iter->second;
}
SummaryState::const_iterator SummaryState::begin() const {
return this->values.begin();
}
SummaryState::const_iterator SummaryState::end() const {
return this->values.end();
}
}

View File

@@ -0,0 +1,115 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
#include <ert/ecl_well/well_const.h> // containts ICON_XXX_INDEX
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <vector>
// ----------------------------------------------------------------------------
std::vector<double>
Opm::RestartIO::Helpers::
serialize_SCON(int lookup_step,
int ncwmax,
int nsconz,
const std::vector<const Well*>& sched_wells,
const UnitSystem& units)
// ----------------------------------------------------------------------------
{
const size_t well_field_size = ncwmax * nsconz;
std::vector<double> data(sched_wells.size() * well_field_size, 0);
size_t well_offset = 0;
for (const Opm::Well* well : sched_wells) {
const auto& connections = well->getConnections( lookup_step );
size_t connection_offset = 0;
bool explicit_ctf_not_found = false;
for (const auto& connection : connections) {
const size_t offset = well_offset + connection_offset;
const auto& ctf = connection.getConnectionTransmissibilityFactorAsValueObject();
if (ctf.hasValue()) {
// CTF explicitly set in deck, overrides calculation
// from Peaceman model. We should also give the Kh
// factor, we output an explicitly invalid value
// instead. This is acceptable since it will not be
// used (the explicit CTF factor is used instead).
const double ctf_SI = ctf.getValue();
const double ctf_output = units.from_si(UnitSystem::measure::transmissibility, ctf_SI);
data[ offset + SCON_CF_INDEX ] = ctf_output;
data[ offset + SCON_KH_INDEX ] = UNIMPLEMENTED_VALUE;
} else {
// CTF not set in deck, Peaceman formula used to
// compute it. Here we should store the data for the
// connection required to recalculate the CTF (the Kh
// factor), as well as the actual CTF used by the
// simulator, but that requires access to more data
// from the simulator. As an interim measure we write
// invalid values and give a warning.
data[ offset + SCON_CF_INDEX ] = UNIMPLEMENTED_VALUE;
data[ offset + SCON_KH_INDEX ] = UNIMPLEMENTED_VALUE;
explicit_ctf_not_found = true;
}
connection_offset += nsconz;
}
if (explicit_ctf_not_found) {
OpmLog::warning("restart output connection data missing",
"Explicit connection transmissibility factors for well " + well->name() + " missing, writing dummy values to restart file.");
}
well_offset += well_field_size;
}
return data;
}
// ----------------------------------------------------------------------------
std::vector<int>
Opm::RestartIO::Helpers::
serialize_ICON(int lookup_step,
int ncwmax,
int niconz,
const std::vector<const Opm::Well*>& sched_wells)
// ----------------------------------------------------------------------------
{
const size_t well_field_size = ncwmax * niconz;
std::vector<int> data(sched_wells.size() * well_field_size, 0);
size_t well_offset = 0;
for (const Opm::Well* well : sched_wells) {
const auto& connections = well->getConnections( lookup_step );
size_t connection_offset = 0;
for (const auto& connection : connections) {
const size_t offset = well_offset + connection_offset;
data[ offset + ICON_IC_INDEX ] = connection.complnum;
data[ offset + ICON_I_INDEX ] = connection.getI() + 1;
data[ offset + ICON_J_INDEX ] = connection.getJ() + 1;
data[ offset + ICON_K_INDEX ] = connection.getK() + 1;
data[ offset + ICON_DIRECTION_INDEX ] = connection.dir;
data[ offset + ICON_STATUS_INDEX ] =
(connection.state == WellCompletion::StateEnum::OPEN) ?
1 : -1000;
data[ offset + ICON_SEGMENT_INDEX ] =
connection.attachedToSegment() ?
connection.segment_number : 0;
connection_offset += niconz;
}
well_offset += well_field_size;
}
return data;
}

View File

@@ -31,17 +31,18 @@ namespace Opm {
for (auto& aquctRecord : aquctKeyword){
AquiferCT::AQUCT_data data;
data.c1 = 1.0;
data.c2 = 6.283; // Value of C2 used by E100 (for METRIC, PVT-M and LAB unit systems)
data.aquiferID = aquctRecord.getItem("AQUIFER_ID").template get<int>(0);
data.h = aquctRecord.getItem("THICKNESS_AQ").getSIDouble(0);
data.p0 = aquctRecord.getItem("P_INI").getSIDouble(0);
data.phi_aq = aquctRecord.getItem("PORO_AQ").getSIDouble(0);
data.d0 = aquctRecord.getItem("DAT_DEPTH").getSIDouble(0);
data.C_t = aquctRecord.getItem("C_T").getSIDouble(0);
data.r_o = aquctRecord.getItem("RAD").getSIDouble(0);
data.k_a = aquctRecord.getItem("PERM_AQ").getSIDouble(0);
data.theta = aquctRecord.getItem("INFLUENCE_ANGLE").getSIDouble(0);
data.c1 = 0.008527; // We are using SI
data.c2 = 6.283;
data.theta = aquctRecord.getItem("INFLUENCE_ANGLE").getSIDouble(0)/360.0;
data.inftableID = aquctRecord.getItem("TABLE_NUM_INFLUENCE_FN").template get<int>(0);
data.pvttableID = aquctRecord.getItem("TABLE_NUM_WATER_PRESS").template get<int>(0);

View File

@@ -443,6 +443,20 @@ namespace Opm {
return supportedDoubleKeywords;
}
Eclipse3DProperties::Eclipse3DProperties( UnitSystem unit_system,
const TableManager& tableManager,
const EclipseGrid& eclipseGrid):
m_defaultRegion("FLUXNUM"),
m_deckUnitSystem(unit_system),
// Note that the variants of grid keywords for radial grids are not
// supported. (and hopefully never will be)
// register the grid properties
m_intGridProperties(eclipseGrid, makeSupportedIntKeywords()),
m_doubleGridProperties(eclipseGrid, &unit_system,
makeSupportedDoubleKeywords(&tableManager, &eclipseGrid, &m_intGridProperties))
{
}
Eclipse3DProperties::Eclipse3DProperties( const Deck& deck,
const TableManager& tableManager,
const EclipseGrid& eclipseGrid)

View File

@@ -58,7 +58,7 @@ namespace Opm {
m_inputNnc( deck ),
m_inputGrid( deck, nullptr ),
m_eclipseProperties( deck, m_tables, m_inputGrid ),
m_simulationConfig( deck, m_eclipseProperties ),
m_simulationConfig( m_eclipseConfig.getInitConfig().restartRequested(), deck, m_eclipseProperties ),
m_transMult( GridDims(deck), deck, m_eclipseProperties )
{
m_inputGrid.resetACTNUM(m_eclipseProperties.getIntGridProperty("ACTNUM").getData().data());

View File

@@ -25,6 +25,7 @@
#include <functional>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/common/utility/numeric/calculateCellVol.hpp>
#include <opm/parser/eclipse/Deck/Section.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
@@ -47,7 +48,7 @@
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <ert/ecl/ecl_grid.h>
#include <ert/ecl/ecl_grid.hpp>
namespace Opm {
@@ -57,11 +58,13 @@ namespace Opm {
const std::vector<double>& zcorn ,
const int * actnum,
const double * mapaxes)
: m_minpvValue(0),
: GridDims(dims),
m_minpvValue(0),
m_minpvMode(MinpvMode::ModeEnum::Inactive),
m_pinch("PINCH"),
m_pinchoutMode(PinchMode::ModeEnum::TOPBOT),
m_multzMode(PinchMode::ModeEnum::TOP)
m_multzMode(PinchMode::ModeEnum::TOP),
volume_cache(dims[0] * dims[1] * dims[2], -1.0)
{
initCornerPointGrid( dims, coord , zcorn , actnum , mapaxes );
}
@@ -89,6 +92,8 @@ namespace Opm {
m_nx = ecl_grid_get_nx( c_ptr() );
m_ny = ecl_grid_get_ny( c_ptr() );
m_nz = ecl_grid_get_nz( c_ptr() );
volume_cache.resize(m_nx * m_ny * m_nz, -1.0);
}
@@ -100,6 +105,7 @@ namespace Opm {
m_pinch("PINCH"),
m_pinchoutMode(PinchMode::ModeEnum::TOPBOT),
m_multzMode(PinchMode::ModeEnum::TOP),
volume_cache(nx * ny * nz, -1.0),
m_grid( ecl_grid_alloc_rectangular(nx, ny, nz, dx, dy, dz, NULL) )
{
}
@@ -110,7 +116,8 @@ namespace Opm {
m_minpvMode( src.m_minpvMode ),
m_pinch( src.m_pinch ),
m_pinchoutMode( src.m_pinchoutMode ),
m_multzMode( src.m_multzMode )
m_multzMode( src.m_multzMode ),
volume_cache(src.volume_cache.size(), -1.0)
{
const int * actnum_data = (actnum.empty()) ? nullptr : actnum.data();
m_grid.reset( ecl_grid_alloc_processed_copy( src.c_ptr(), zcorn , actnum_data ));
@@ -163,7 +170,8 @@ namespace Opm {
m_minpvMode(MinpvMode::ModeEnum::Inactive),
m_pinch("PINCH"),
m_pinchoutMode(PinchMode::ModeEnum::TOPBOT),
m_multzMode(PinchMode::ModeEnum::TOP)
m_multzMode(PinchMode::ModeEnum::TOP),
volume_cache(m_nx * m_ny * m_nz, -1.0)
{
const std::array<int, 3> dims = getNXYZ();
@@ -445,8 +453,6 @@ namespace Opm {
const int * actnum,
const double * mapaxes)
{
const std::vector<float> zcorn_float( zcorn.begin() , zcorn.end() );
const std::vector<float> coord_float( coord.begin() , coord.end() );
float * mapaxes_float = nullptr;
if (mapaxes) {
mapaxes_float = new float[6];
@@ -454,14 +460,14 @@ namespace Opm {
mapaxes_float[i] = mapaxes[i];
}
m_grid.reset( ecl_grid_alloc_GRDECL_data(dims[0] ,
dims[1] ,
dims[2] ,
zcorn_float.data() ,
coord_float.data() ,
actnum ,
false, // We do not apply the MAPAXES transformations
mapaxes_float) );
m_grid.reset( ecl::ecl_grid_alloc_GRDECL_data(dims[0] ,
dims[1] ,
dims[2] ,
zcorn.data() ,
coord.data() ,
actnum ,
false, // We do not apply the MAPAXES transformations
mapaxes_float) );
if (mapaxes)
delete[] mapaxes_float;
@@ -730,13 +736,23 @@ namespace Opm {
double EclipseGrid::getCellVolume(size_t globalIndex) const {
assertGlobalIndex( globalIndex );
return ecl_grid_get_cell_volume1( c_ptr() , static_cast<int>(globalIndex));
if (volume_cache[globalIndex] < 0.0) {
// Calculate cell volume and put it in the cache.
std::vector<double> x(8,0);
std::vector<double> y(8,0);
std::vector<double> z(8,0);
for (int i=0; i < 8; i++) {
ecl_grid_get_cell_corner_xyz1(c_ptr(), static_cast<int>(globalIndex), i, &x[i], &y[i], &z[i]);
}
volume_cache[globalIndex] = calculateCellVol(x,y,z);
}
return volume_cache[globalIndex];
}
double EclipseGrid::getCellVolume(size_t i , size_t j , size_t k) const {
assertIJK(i,j,k);
return ecl_grid_get_cell_volume3( c_ptr() , static_cast<int>(i),static_cast<int>(j),static_cast<int>(k));
return getCellVolume(getGlobalIndex(i, j, k));
}
double EclipseGrid::getCellThicknes(size_t i , size_t j , size_t k) const {

View File

@@ -235,19 +235,18 @@ namespace Opm {
for (auto iter = m_searchMap.begin(); iter != m_searchMap.end(); iter++) {
const Opm::GridProperty<int>& region = m_e3DProps.getIntGridProperty( (*iter).first );
MULTREGTSearchMap map = (*iter).second;
const MULTREGTSearchMap& map = (*iter).second;
int regionId1 = region.iget(globalIndex1);
int regionId2 = region.iget(globalIndex2);
std::pair<int,int> pair{regionId1 , regionId2};
std::pair<int,int> pair{ regionId1, regionId2 };
if (map.count(pair) != 1 || !(map.at(pair)->m_directions & faceDir)) {
pair = std::pair<int,int>{regionId2 , regionId1};
if (map.count(pair) != 1 || !(map.at(pair)->m_directions & faceDir))
continue;
}
const MULTREGTRecord * record = map[pair];
const MULTREGTRecord* record = map.at(pair);
bool applyMultiplier = true;
int i1 = globalIndex1 % region.getNX();

View File

@@ -1,338 +0,0 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <cassert>
#include <vector>
#include <iostream>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Completion.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Util/Value.hpp>
namespace Opm {
Completion::Completion(int i, int j , int k ,
int compnum,
double depth,
WellCompletion::StateEnum state ,
const Value<double>& connectionTransmissibilityFactor,
const Value<double>& diameter,
const Value<double>& skinFactor,
const int satTableId,
const WellCompletion::DirectionEnum direction)
: m_i(i), m_j(j), m_k(k),
m_complnum( compnum ),
m_diameter(diameter),
m_connectionTransmissibilityFactor(connectionTransmissibilityFactor),
m_wellPi(1.0),
m_skinFactor(skinFactor),
m_satTableId(satTableId),
m_state(state),
m_direction(direction),
m_center_depth( depth )
{}
Completion::Completion(const Completion& oldCompletion, WellCompletion::StateEnum newStatus ) :
Completion( oldCompletion )
{
this->m_state = newStatus;
}
Completion::Completion(const Completion& oldCompletion, double wellPi) :
Completion( oldCompletion )
{
if( this->m_wellPi != 0 ) {
this->m_wellPi *= wellPi;
} else {
this->m_wellPi = wellPi;
}
}
Completion::Completion( const Completion& c, int num ) :
Completion( c )
{
this->m_complnum = num;
}
Completion::Completion(const Completion& completion_initial, int segment_number, double center_depth)
: Completion(completion_initial)
{
assert(segment_number > 0);
this->m_segment_number = segment_number;
this->m_center_depth = center_depth;
}
bool Completion::sameCoordinate(const Completion& other) const {
if ((m_i == other.m_i) &&
(m_j == other.m_j) &&
(m_k == other.m_k))
return true;
else
return false;
}
bool Completion::sameCoordinate(const int i, const int j, const int k) const {
if ((m_i == i) && (m_j == j) && (m_k == k)) {
return true;
} else {
return false;
}
}
/**
This will break up one record and return a pair: <name ,
[Completion1, Completion2, ... , CompletionN]>. The reason it
will return a list is that the 'K1 K2' structure is
disentangled, and each completion is returned separately.
*/
inline std::vector< Completion >
fromCOMPDAT( const EclipseGrid& grid,
const Eclipse3DProperties& eclipseProperties,
const DeckRecord& compdatRecord,
const Well& well,
int prev_complnum ) {
std::vector< Completion > completions;
// We change from eclipse's 1 - n, to a 0 - n-1 solution
// I and J can be defaulted with 0 or *, in which case they are fetched
// from the well head
const auto& itemI = compdatRecord.getItem( "I" );
const auto defaulted_I = itemI.defaultApplied( 0 ) || itemI.get< int >( 0 ) == 0;
const int I = !defaulted_I ? itemI.get< int >( 0 ) - 1 : well.getHeadI();
const auto& itemJ = compdatRecord.getItem( "J" );
const auto defaulted_J = itemJ.defaultApplied( 0 ) || itemJ.get< int >( 0 ) == 0;
const int J = !defaulted_J ? itemJ.get< int >( 0 ) - 1 : well.getHeadJ();
int K1 = compdatRecord.getItem("K1").get< int >(0) - 1;
int K2 = compdatRecord.getItem("K2").get< int >(0) - 1;
WellCompletion::StateEnum state = WellCompletion::StateEnumFromString( compdatRecord.getItem("STATE").getTrimmedString(0) );
Value<double> connectionTransmissibilityFactor("ConnectionTransmissibilityFactor");
Value<double> diameter("Diameter");
Value<double> skinFactor("SkinFactor");
int satTableId;
const auto& satnum = eclipseProperties.getIntGridProperty("SATNUM");
bool defaultSatTable = true;
{
const auto& connectionTransmissibilityFactorItem = compdatRecord.getItem("CONNECTION_TRANSMISSIBILITY_FACTOR");
const auto& diameterItem = compdatRecord.getItem("DIAMETER");
const auto& skinFactorItem = compdatRecord.getItem("SKIN");
const auto& satTableIdItem = compdatRecord.getItem("SAT_TABLE");
if (connectionTransmissibilityFactorItem.hasValue(0) && connectionTransmissibilityFactorItem.getSIDouble(0) > 0)
connectionTransmissibilityFactor.setValue(connectionTransmissibilityFactorItem.getSIDouble(0));
if (diameterItem.hasValue(0))
diameter.setValue( diameterItem.getSIDouble(0));
if (skinFactorItem.hasValue(0))
skinFactor.setValue( skinFactorItem.get< double >(0));
if (satTableIdItem.hasValue(0) && satTableIdItem.get < int > (0) > 0)
{
satTableId = satTableIdItem.get< int >(0);
defaultSatTable = false;
}
}
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnumFromString(compdatRecord.getItem("DIR").getTrimmedString(0));
for (int k = K1; k <= K2; k++) {
if (defaultSatTable)
satTableId = satnum.iget(grid.getGlobalIndex(I,J,k));
completions.emplace_back( I, J, k,
int( completions.size() + prev_complnum ) + 1,
grid.getCellDepth( I,J,k ),
state,
connectionTransmissibilityFactor,
diameter,
skinFactor,
satTableId,
direction );
}
return completions;
}
/*
Will return a map:
{
"WELL1" : [ Completion1 , Completion2 , ... , CompletionN ],
"WELL2" : [ Completion1 , Completion2 , ... , CompletionN ],
...
}
*/
std::map< std::string, std::vector< Completion > >
Completion::fromCOMPDAT( const EclipseGrid& grid ,
const Eclipse3DProperties& eclipseProperties,
const DeckKeyword& compdatKeyword,
const std::vector< const Well* >& wells ) {
std::map< std::string, std::vector< Completion > > res;
std::vector< int > prev_compls( wells.size(), 0 );
for( const auto& record : compdatKeyword ) {
const auto wellname = record.getItem( "WELL" ).getTrimmedString( 0 );
const auto name_eq = [&]( const Well* w ) {
return w->name() == wellname;
};
auto well = std::find_if( wells.begin(), wells.end(), name_eq );
if( well == wells.end() ) continue;
const auto index = std::distance( wells.begin(), well );
if( prev_compls[ index ] == 0 ) (*well)->getCompletions().size();
auto completions = Opm::fromCOMPDAT( grid,
eclipseProperties,
record,
**well,
prev_compls[ index ] );
prev_compls[ index ] += completions.size();
res[ wellname ].insert( res[ wellname ].end(),
std::make_move_iterator( completions.begin() ),
std::make_move_iterator( completions.end() ) );
}
return res;
}
void Completion::fixDefaultIJ(int wellHeadI , int wellHeadJ) {
if (m_i < 0)
m_i = wellHeadI;
if (m_j < 0)
m_j = wellHeadJ;
}
void Completion::shift_complnum( int shift ) {
this->m_complnum += shift;
}
int Completion::getI() const {
return m_i;
}
int Completion::getJ() const {
return m_j;
}
int Completion::getK() const {
return m_k;
}
int Completion::complnum() const {
return this->m_complnum;
}
WellCompletion::StateEnum Completion::getState() const {
return m_state;
}
double Completion::getConnectionTransmissibilityFactor() const {
return m_connectionTransmissibilityFactor.getValue();
}
double Completion::getDiameter() const {
return m_diameter.getValue();
}
double Completion::getSkinFactor() const {
return m_skinFactor.getValue();
}
int Completion::getSatTableId() const {
return m_satTableId;
}
const Value<double>& Completion::getConnectionTransmissibilityFactorAsValueObject() const {
return m_connectionTransmissibilityFactor;
}
Value<double> Completion::getDiameterAsValueObject() const {
return m_diameter;
}
Value<double> Completion::getSkinFactorAsValueObject() const {
return m_skinFactor;
}
WellCompletion::DirectionEnum Completion::getDirection() const {
return m_direction;
}
double Completion::getWellPi() const {
return m_wellPi;
}
int Completion::getSegmentNumber() const {
if (!attachedToSegment()) {
throw std::runtime_error(" the completion is not attached to a segment!\n ");
}
return m_segment_number;
}
double Completion::getCenterDepth() const {
return m_center_depth;
}
bool Completion::attachedToSegment() const {
return (m_segment_number > 0);
}
bool Completion::operator==( const Completion& rhs ) const {
return this->m_i == rhs.m_i
&& this->m_j == rhs.m_j
&& this->m_k == rhs.m_k
&& this->m_complnum == rhs.m_complnum
&& this->m_diameter == rhs.m_diameter
&& this->m_connectionTransmissibilityFactor
== rhs.m_connectionTransmissibilityFactor
&& this->m_wellPi == rhs.m_wellPi
&& this->m_skinFactor == rhs.m_skinFactor
&& this->m_satTableId == rhs.m_satTableId
&& this->m_state == rhs.m_state
&& this->m_direction == rhs.m_direction
&& this->m_segment_number == rhs.m_segment_number
&& this->m_center_depth == rhs.m_center_depth;
}
bool Completion::operator!=( const Completion& rhs ) const {
return !( *this == rhs );
}
}

View File

@@ -1,157 +0,0 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cassert>
#include <cmath>
#include <limits>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Completion.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
namespace Opm {
CompletionSet::CompletionSet( std::initializer_list< Completion > cs ) {
for( auto&& c : cs ) this->add( c );
}
size_t CompletionSet::size() const {
return m_completions.size();
}
const Completion& CompletionSet::get(size_t index) const {
return this->m_completions.at( index );
}
const Completion& CompletionSet::getFromIJK(const int i, const int j, const int k) const {
for (size_t ic = 0; ic < size(); ++ic) {
if (get(ic).sameCoordinate(i, j, k)) {
return get(ic);
}
}
throw std::runtime_error(" the completion is not found! \n ");
}
void CompletionSet::add( Completion completion ) {
auto same = [&]( const Completion& c ) {
return c.sameCoordinate( completion );
};
auto prev = std::find_if( this->m_completions.begin(),
this->m_completions.end(),
same );
if( prev != this->m_completions.end() ) {
// update the completion, but preserve it's number
*prev = Completion( completion, prev->complnum() );
return;
}
m_completions.emplace_back( completion );
}
bool CompletionSet::allCompletionsShut( ) const {
auto shut = []( const Completion& c ) {
return c.getState() == WellCompletion::StateEnum::SHUT;
};
return std::all_of( this->m_completions.begin(),
this->m_completions.end(),
shut );
}
void CompletionSet::orderCompletions(size_t well_i, size_t well_j)
{
if (m_completions.empty()) {
return;
}
// Find the first completion and swap it into the 0-position.
const double surface_z = 0.0;
size_t first_index = findClosestCompletion(well_i, well_j, surface_z, 0);
std::swap(m_completions[first_index], m_completions[0]);
// Repeat for remaining completions.
//
// Note that since findClosestCompletion() is O(n), this is an
// O(n^2) algorithm. However, it should be acceptable since
// the expected number of completions is fairly low (< 100).
if( this->m_completions.empty() ) return;
for (size_t pos = 1; pos < m_completions.size() - 1; ++pos) {
const auto& prev = m_completions[pos - 1];
const double prevz = prev.getCenterDepth();
size_t next_index = findClosestCompletion(prev.getI(), prev.getJ(), prevz, pos);
std::swap(m_completions[next_index], m_completions[pos]);
}
}
size_t CompletionSet::findClosestCompletion(int oi, int oj, double oz, size_t start_pos)
{
size_t closest = std::numeric_limits<size_t>::max();
int min_ijdist2 = std::numeric_limits<int>::max();
double min_zdiff = std::numeric_limits<double>::max();
for (size_t pos = start_pos; pos < m_completions.size(); ++pos) {
const auto& completion = m_completions[ pos ];
const double depth = completion.getCenterDepth();
const int ci = completion.getI();
const int cj = completion.getJ();
// Using square of distance to avoid non-integer arithmetics.
const int ijdist2 = (ci - oi) * (ci - oi) + (cj - oj) * (cj - oj);
if (ijdist2 < min_ijdist2) {
min_ijdist2 = ijdist2;
min_zdiff = std::abs(depth - oz);
closest = pos;
} else if (ijdist2 == min_ijdist2) {
const double zdiff = std::abs(depth - oz);
if (zdiff < min_zdiff) {
min_zdiff = zdiff;
closest = pos;
}
}
}
assert(closest != std::numeric_limits<size_t>::max());
return closest;
}
bool CompletionSet::operator==( const CompletionSet& rhs ) const {
return this->size() == rhs.size()
&& std::equal( this->begin(), this->end(), rhs.begin() );
}
bool CompletionSet::operator!=( const CompletionSet& rhs ) const {
return !( *this == rhs );
}
void CompletionSet::filter(const EclipseGrid& grid) {
auto new_end = std::remove_if(m_completions.begin(),
m_completions.end(),
[&grid](const Completion& c) { return !grid.cellActive(c.getI(), c.getJ(), c.getK()); });
m_completions.erase(new_end, m_completions.end());
}
}

View File

@@ -0,0 +1,128 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <cassert>
#include <vector>
#include <iostream>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Connection.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Util/Value.hpp>
namespace Opm {
Connection::Connection(int i, int j , int k ,
int compnum,
double depth,
WellCompletion::StateEnum stateArg ,
const Value<double>& connectionTransmissibilityFactor,
const Value<double>& diameter,
const Value<double>& skinFactor,
const Value<double>& Kh,
const int satTableId,
const WellCompletion::DirectionEnum direction)
: dir(direction),
center_depth(depth),
state(stateArg),
sat_tableId(satTableId),
complnum( compnum ),
ijk({i,j,k}),
m_diameter(diameter),
m_connectionTransmissibilityFactor(connectionTransmissibilityFactor),
m_skinFactor(skinFactor),
m_Kh(Kh)
{}
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;
} else {
return false;
}
}
int Connection::getI() const {
return ijk[0];
}
int Connection::getJ() const {
return ijk[1];
}
int Connection::getK() const {
return ijk[2];
}
double Connection::getConnectionTransmissibilityFactor() const {
return m_connectionTransmissibilityFactor.getValue();
}
double Connection::getDiameter() const {
return m_diameter.getValue();
}
double Connection::getSkinFactor() const {
return m_skinFactor.getValue();
}
const Value<double>& Connection::getConnectionTransmissibilityFactorAsValueObject() const {
return m_connectionTransmissibilityFactor;
}
const Value<double>& Connection::getEffectiveKhAsValueObject() const {
return m_Kh;
}
bool Connection::attachedToSegment() const {
return (segment_number > 0);
}
bool Connection::operator==( const Connection& rhs ) const {
return this->ijk == rhs.ijk
&& this->complnum == rhs.complnum
&& this->m_diameter == rhs.m_diameter
&& this->m_connectionTransmissibilityFactor == rhs.m_connectionTransmissibilityFactor
&& this->wellPi == rhs.wellPi
&& this->m_skinFactor == rhs.m_skinFactor
&& this->sat_tableId == rhs.sat_tableId
&& this->state == rhs.state
&& this->dir == rhs.dir
&& this->segment_number == rhs.segment_number
&& this->center_depth == rhs.center_depth;
}
bool Connection::operator!=( const Connection& rhs ) const {
return !( *this == rhs );
}
}

View File

@@ -267,6 +267,11 @@ namespace Opm {
return m_groupNetVFPTable.get(time_step);
}
bool Group::groupNameInGroupNamePattern(const std::string& groupName, const std::string& groupNamePattern) {
if (util_fnmatch( groupNamePattern.c_str() , groupName.c_str()) == 0)
return true;
return false;
}
/*****************************************************************/
bool Group::hasWell(const std::string& wellName , size_t time_step) const {

View File

@@ -22,12 +22,13 @@
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
#include "Compsegs.hpp"
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/C.hpp>
#include "Compsegs.hpp"
namespace Opm {
@@ -40,8 +41,8 @@ namespace Opm {
m_distance_start(distance_start_in),
m_distance_end(distance_end_in),
m_dir(dir_in),
m_center_depth(center_depth_in),
m_segment_number(segment_number_in)
center_depth(center_depth_in),
segment_number(segment_number_in)
{
}
@@ -53,7 +54,7 @@ namespace Opm {
for (size_t recordIndex = 1; recordIndex < compsegsKeyword.size(); ++recordIndex) {
const auto& record = compsegsKeyword.getRecord(recordIndex);
// following the coordinate rule for completions
// following the coordinate rule for connections
const int I = record.getItem<ParserKeywords::COMPSEGS::I>().get< int >(0) - 1;
const int J = record.getItem<ParserKeywords::COMPSEGS::J>().get< int >(0) - 1;
const int K = record.getItem<ParserKeywords::COMPSEGS::K>().get< int >(0) - 1;
@@ -68,7 +69,7 @@ namespace Opm {
} else {
// TODO: the end of the previous connection or range
// 'previous' should be in term of the input order
// since basically no specific order for the completions
// since basically no specific order for the connections
throw std::runtime_error("this way to obtain DISTANCE_START not implemented yet!");
}
if (record.getItem<ParserKeywords::COMPSEGS::DISTANCE_END>().hasValue(0)) {
@@ -89,7 +90,7 @@ namespace Opm {
}
/*
* Defaulted well completion. Must be non-defaulted if DISTANCE_END
* Defaulted well connection. Must be non-defaulted if DISTANCE_END
* is set or a range is specified. If not this is effectively ignored.
*/
WellCompletion::DirectionEnum direction = WellCompletion::X;
@@ -134,20 +135,20 @@ namespace Opm {
return compsegs;
}
void Compsegs::processCOMPSEGS(std::vector< Compsegs >& compsegs, const SegmentSet& segment_set) {
void Compsegs::processCOMPSEGS(std::vector< Compsegs >& compsegs, const WellSegments& segment_set) {
// for the current cases we have at the moment, the distance information is specified explicitly,
// while the depth information is defaulted though, which need to be obtained from the related segment
for( auto& compseg : compsegs ) {
// need to determine the related segment number first
if (compseg.m_segment_number != 0) continue;
if (compseg.segment_number != 0) continue;
const double center_distance = (compseg.m_distance_start + compseg.m_distance_end) / 2.0;
const int branch_number = compseg.m_branch_number;
int segment_number = 0;
double min_distance_difference = 1.e100; // begin with a big value
for (int i_segment = 0; i_segment < segment_set.numberSegment(); ++i_segment) {
for (int i_segment = 0; i_segment < segment_set.size(); ++i_segment) {
const Segment& current_segment = segment_set[i_segment];
if( branch_number != current_segment.branchNumber() ) continue;
@@ -163,30 +164,30 @@ namespace Opm {
throw std::runtime_error("The perforation failed in finding a related segment \n");
}
if (compseg.m_center_depth < 0.) {
if (compseg.center_depth < 0.) {
throw std::runtime_error("Obtaining perforation depth from COMPDAT data is not supported yet");
}
compseg.m_segment_number = segment_number;
compseg.segment_number = segment_number;
// when depth is default or zero, we obtain the depth of the completion based on the information
// when depth is default or zero, we obtain the depth of the connection based on the information
// of the related segments
if (compseg.m_center_depth == 0.) {
if (compseg.center_depth == 0.) {
compseg.calculateCenterDepthWithSegments(segment_set);
}
}
}
void Compsegs::calculateCenterDepthWithSegments(const SegmentSet& segment_set) {
void Compsegs::calculateCenterDepthWithSegments(const WellSegments& segment_set) {
// the depth and distance of the segment to the well head
const Segment& segment = segment_set.getFromSegmentNumber(m_segment_number);
const Segment& segment = segment_set.getFromSegmentNumber(segment_number);
const double segment_depth = segment.depth();
const double segment_distance = segment.totalLength();
// for top segment, no interpolation is needed
if (m_segment_number == 1) {
m_center_depth = segment_depth;
if (segment_number == 1) {
center_depth = segment_depth;
return;
}
@@ -210,7 +211,7 @@ namespace Opm {
if (interpolation_segment_number == 0) {
throw std::runtime_error("Failed in finding a segment to do the interpolation with segment "
+ std::to_string(m_segment_number));
+ std::to_string(segment_number));
}
// performing the interpolation
@@ -223,27 +224,28 @@ namespace Opm {
if (segment_length == 0.) {
throw std::runtime_error("Zero segment length is botained when doing interpolation between segment "
+ std::to_string(m_segment_number) + " and segment " + std::to_string(interpolation_segment_number) );
+ std::to_string(segment_number) + " and segment " + std::to_string(interpolation_segment_number) );
}
m_center_depth = segment_depth + (center_distance - segment_distance) / segment_length * depth_change_segment;
center_depth = segment_depth + (center_distance - segment_distance) / segment_length * depth_change_segment;
}
void Compsegs::updateCompletionsWithSegment(const std::vector< Compsegs >& compsegs,
CompletionSet& completion_set) {
void Compsegs::updateConnectionsWithSegment(const std::vector< Compsegs >& compsegs,
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;
const Completion& completion = completion_set.getFromIJK( i, j, k );
completion_set.add(Completion(completion, compseg.m_segment_number, compseg.m_center_depth) );
Connection& connection = connection_set.getFromIJK( i, j, k );
connection.segment_number = compseg.segment_number;
connection.center_depth = compseg.center_depth;
}
for (size_t ic = 0; ic < completion_set.size(); ++ic) {
if ( !(completion_set.get(ic).attachedToSegment()) ) {
throw std::runtime_error("Not all the completions are attached with a segment. "
for (size_t ic = 0; ic < connection_set.size(); ++ic) {
if ( !(connection_set.get(ic).attachedToSegment()) ) {
throw std::runtime_error("Not all the connections are attached with a segment. "
"The information from COMPSEGS is not complete");
}
}

View File

@@ -28,9 +28,9 @@
namespace Opm {
class CompletionSet;
class WellConnections;
class DeckKeyword;
class SegmentSet;
class WellSegments;
struct Compsegs {
int m_i;
@@ -44,24 +44,24 @@ namespace Opm {
double m_distance_end;
WellCompletion::DirectionEnum m_dir;
double m_center_depth;
double center_depth;
// we do not handle thermal length for the moment
// double m_thermal_length;
int m_segment_number;
int segment_number;
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);
void calculateCenterDepthWithSegments(const SegmentSet& segment_set);
void calculateCenterDepthWithSegments(const WellSegments& segment_set);
static std::vector< Compsegs > compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword );
// get the segment number information and depth information based on the information from SegmentSet
static void processCOMPSEGS(std::vector< Compsegs >& compsegs, const SegmentSet& segment_set );
// 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 Completions
static void updateCompletionsWithSegment(const std::vector< Compsegs >& compsegs,
CompletionSet& completion_set);
// update the segment related information for Connections
static void updateConnectionsWithSegment(const std::vector< Compsegs >& compsegs,
WellConnections& connection_set);
};
}

View File

@@ -113,8 +113,8 @@ namespace Opm {
return m_inlet_segments;
}
void Segment::addInletSegment(const int segment_number) {
m_inlet_segments.push_back(segment_number);
void Segment::addInletSegment(const int segment_number_in) {
m_inlet_segments.push_back(segment_number_in);
}
double Segment::invalidValue() {
@@ -135,15 +135,6 @@ namespace Opm {
}
bool Segment::operator!=( const Segment& rhs ) const {
return this->m_segment_number == rhs.m_segment_number
&& this->m_branch == rhs.m_branch
&& this->m_outlet_segment == rhs.m_outlet_segment
&& this->m_total_length == rhs.m_total_length
&& this->m_depth == rhs.m_depth
&& this->m_internal_diameter == rhs.m_internal_diameter
&& this->m_roughness == rhs.m_roughness
&& this->m_cross_area == rhs.m_cross_area
&& this->m_volume == rhs.m_volume
&& this->m_data_ready == rhs.m_data_ready;
return !this->operator==(rhs);
}
}

View File

@@ -30,75 +30,75 @@
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
namespace Opm {
std::string SegmentSet::wellName() const {
std::string WellSegments::wellName() const {
return m_well_name;
}
int SegmentSet::numberBranch() const {
int WellSegments::numberBranch() const {
return m_number_branch;
}
int SegmentSet::numberSegment() const {
int WellSegments::size() const {
return m_segments.size();
}
double SegmentSet::depthTopSegment() const {
double WellSegments::depthTopSegment() const {
return m_depth_top;
}
double SegmentSet::lengthTopSegment() const {
double WellSegments::lengthTopSegment() const {
return m_length_top;
}
double SegmentSet::volumeTopSegment() const {
double WellSegments::volumeTopSegment() const {
return m_volume_top;
}
WellSegment::LengthDepthEnum SegmentSet::lengthDepthType() const {
WellSegment::LengthDepthEnum WellSegments::lengthDepthType() const {
return m_length_depth_type;
}
WellSegment::CompPressureDropEnum SegmentSet::compPressureDrop() const {
WellSegment::CompPressureDropEnum WellSegments::compPressureDrop() const {
return m_comp_pressure_drop;
}
WellSegment::MultiPhaseModelEnum SegmentSet::multiPhaseModel() const {
WellSegment::MultiPhaseModelEnum WellSegments::multiPhaseModel() const {
return m_multiphase_model;
}
const Segment& SegmentSet::operator[](size_t idx) const {
const Segment& WellSegments::operator[](size_t idx) const {
return m_segments[idx];
}
int SegmentSet::segmentNumberToIndex(const int segment_number) const {
const auto it = m_segment_number_to_index.find(segment_number);
if (it != m_segment_number_to_index.end()) {
int WellSegments::segmentNumberToIndex(const int segment_number) const {
const auto it = segment_number_to_index.find(segment_number);
if (it != segment_number_to_index.end()) {
return it->second;
} else {
return -1;
}
}
void SegmentSet::addSegment( Segment new_segment ) {
void WellSegments::addSegment( Segment new_segment ) {
// decide whether to push_back or insert
const int segment_number = new_segment.segmentNumber();
const int segment_index = segmentNumberToIndex(segment_number);
if (segment_index < 0) { // it is a new segment
m_segment_number_to_index[segment_number] = numberSegment();
segment_number_to_index[segment_number] = size();
m_segments.push_back(new_segment);
} else { // the segment already exists
m_segments[segment_index] = new_segment;
}
}
void SegmentSet::segmentsFromWELSEGSKeyword( const DeckKeyword& welsegsKeyword ) {
void WellSegments::loadWELSEGS( const DeckKeyword& welsegsKeyword ) {
// for the first record, which provides the information for the top segment
// and information for the whole segment set
@@ -203,7 +203,7 @@ namespace Opm {
if (index >= 0) { // found in the existing m_segments already
throw std::logic_error("Segments with same segment number are found!\n");
}
m_segment_number_to_index[segment_number] = i_segment;
segment_number_to_index[segment_number] = i_segment;
}
for (size_t i_segment = 0; i_segment < m_segments.size(); ++i_segment) {
@@ -212,13 +212,13 @@ namespace Opm {
if (outlet_segment <= 0) { // no outlet segment
continue;
}
const int outlet_segment_index = m_segment_number_to_index[outlet_segment];
const int outlet_segment_index = segment_number_to_index[outlet_segment];
m_segments[outlet_segment_index].addInletSegment(segment_number);
}
}
const Segment& SegmentSet::getFromSegmentNumber(const int segment_number) const {
const Segment& WellSegments::getFromSegmentNumber(const int segment_number) const {
// the index of segment in the vector of segments
const int segment_index = segmentNumberToIndex(segment_number);
if (segment_index < 0) {
@@ -228,13 +228,13 @@ namespace Opm {
return m_segments[segment_index];
}
void SegmentSet::processABS() {
void WellSegments::processABS() {
const double invalid_value = Segment::invalidValue(); // meaningless value to indicate unspecified/uncompleted values
orderSegments();
int current_index= 1;
while (current_index< numberSegment()) {
while (current_index< size()) {
if (m_segments[current_index].dataReady()) {
current_index++;
continue;
@@ -247,13 +247,13 @@ namespace Opm {
assert(m_segments[outlet_index].dataReady() == true);
int range_end = range_begin + 1;
for (; range_end < numberSegment(); ++range_end) {
for (; range_end < size(); ++range_end) {
if (m_segments[range_end].dataReady() == true) {
break;
}
}
if (range_end >= numberSegment()) {
if (range_end >= size()) {
throw std::logic_error(" One range records in WELSEGS is wrong. ");
}
@@ -290,7 +290,7 @@ namespace Opm {
// then update the volume for all the segments except the top segment
// this is for the segments specified individually while the volume is not specified.
for (int i = 1; i < numberSegment(); ++i) {
for (int i = 1; i < size(); ++i) {
assert(m_segments[i].dataReady());
if (m_segments[i].volume() == invalid_value) {
Segment new_segment = m_segments[i];
@@ -304,9 +304,9 @@ namespace Opm {
}
}
void SegmentSet::processINC(const bool first_time) {
void WellSegments::processINC(const bool first_time) {
// update the information inside the SegmentSet to be in ABS way
// update the information inside the WellSegments to be in ABS way
if (first_time) {
Segment new_top_segment = (*this)[0];
new_top_segment.setDepthAndLength(depthTopSegment(), lengthTopSegment());
@@ -316,7 +316,7 @@ namespace Opm {
orderSegments();
// begin with the second segment
for (int i_index= 1; i_index< numberSegment(); ++i_index) {
for (int i_index= 1; i_index< size(); ++i_index) {
if( m_segments[i_index].dataReady() ) continue;
// find its outlet segment
@@ -339,7 +339,7 @@ namespace Opm {
}
}
void SegmentSet::orderSegments() {
void WellSegments::orderSegments() {
// re-ordering the segments to make later use easier.
// two principles
// 1. the index of the outlet segment will be stored in the lower index than the segment.
@@ -350,18 +350,18 @@ namespace Opm {
int current_index= 1;
// clear the mapping from segment number to store index
m_segment_number_to_index.clear();
segment_number_to_index.clear();
// for the top segment
m_segment_number_to_index[1] = 0;
segment_number_to_index[1] = 0;
while (current_index< numberSegment()) {
while (current_index< size()) {
// the branch number of the last segment that is done re-ordering
const int last_branch_number = m_segments[current_index-1].branchNumber();
// the one need to be swapped to the current_index.
int target_segment_index= -1;
// looking for target_segment_index
for (int i_index= current_index; i_index< numberSegment(); ++i_index) {
for (int i_index= current_index; i_index< size(); ++i_index) {
const int outlet_segment_number = m_segments[i_index].outletSegment();
const int outlet_segment_index = segmentNumberToIndex(outlet_segment_number);
if (outlet_segment_index < 0) { // not found the outlet_segment in the done re-ordering segments
@@ -390,12 +390,12 @@ namespace Opm {
std::swap(m_segments[current_index], m_segments[target_segment_index]);
}
const int segment_number = m_segments[current_index].segmentNumber();
m_segment_number_to_index[segment_number] = current_index;
segment_number_to_index[segment_number] = current_index;
current_index++;
}
}
bool SegmentSet::operator==( const SegmentSet& rhs ) const {
bool WellSegments::operator==( const WellSegments& rhs ) const {
return this->m_well_name == rhs.m_well_name
&& this->m_number_branch == rhs.m_number_branch
&& this->m_depth_top == rhs.m_depth_top
@@ -405,16 +405,16 @@ namespace Opm {
&& this->m_comp_pressure_drop == rhs.m_comp_pressure_drop
&& this->m_multiphase_model == rhs.m_multiphase_model
&& this->m_segments.size() == rhs.m_segments.size()
&& this->m_segment_number_to_index.size() == rhs.m_segment_number_to_index.size()
&& this->segment_number_to_index.size() == rhs.segment_number_to_index.size()
&& std::equal( this->m_segments.begin(),
this->m_segments.end(),
rhs.m_segments.begin() )
&& std::equal( this->m_segment_number_to_index.begin(),
this->m_segment_number_to_index.end(),
rhs.m_segment_number_to_index.begin() );
&& std::equal( this->segment_number_to_index.begin(),
this->segment_number_to_index.end(),
rhs.segment_number_to_index.begin() );
}
bool SegmentSet::operator!=( const SegmentSet& rhs ) const {
bool WellSegments::operator!=( const WellSegments& rhs ) const {
return !( *this == rhs );
}
}

View File

@@ -17,21 +17,20 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/updatingConnectionsWithSegments.hpp>
#include "Compsegs.hpp"
namespace Opm {
CompletionSet updatingCompletionsWithSegments(const DeckKeyword& compsegs,
const CompletionSet& input_completions,
const SegmentSet& segment_set)
WellConnections * newConnectionsWithSegments(const DeckKeyword& compsegs,
const WellConnections& input_connections,
const WellSegments& segment_set)
{
CompletionSet new_completion_set(input_completions);
WellConnections * new_connection_set = new WellConnections(input_connections);
std::vector<Compsegs> compsegs_vector = Compsegs::compsegsFromCOMPSEGSKeyword( compsegs );
Compsegs::processCOMPSEGS(compsegs_vector, segment_set);
Compsegs::updateCompletionsWithSegment(compsegs_vector, new_completion_set);
return new_completion_set;
Compsegs::updateConnectionsWithSegment(compsegs_vector, *new_connection_set);
return new_connection_set;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@
namespace Opm {
UDQ::UDQ(const UDQConfig& config, const Deck& deck) {
UDQ::UDQ(const UDQConfig& /* config */, const Deck& deck) {
if (deck.hasKeyword("UDQ")) {
const auto& kw = deck.getKeyword("UDQ");
for (const auto& record : kw)

View File

@@ -73,11 +73,11 @@ namespace Opm {
2. For items like '2*(1+WBHP)' the parsing code will expand the 2*
operator to the repeated tokens : (1+WBHP), (1+WBHP)
*/
UDQExpression::UDQExpression(const std::string& action, const std::string& keyword, const std::vector<std::string>& input_data) {
assertKeyword(keyword);
UDQExpression::UDQExpression(const std::string& action_in, const std::string& keyword_in, const std::vector<std::string>& input_data) {
assertKeyword(keyword_in);
this->action = actionString2Enum(action);
this->keyword = keyword;
this->action = actionString2Enum(action_in);
this->keyword = keyword_in;
for (const std::string& item : input_data) {
if (RawConsts::is_quote()(item[0])) {

View File

@@ -22,10 +22,11 @@
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Completion.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Connection.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/updatingConnectionsWithSegments.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
@@ -48,7 +49,7 @@ namespace Opm {
m_guideRateScalingFactor( timeMap, 1.0 ),
m_efficiencyFactors (timeMap, 1.0 ),
m_isProducer( timeMap, true ) ,
m_completions( timeMap, CompletionSet{} ),
m_completions( timeMap, std::make_shared<WellConnections>(headI, headJ) ),
m_productionProperties( timeMap, WellProductionProperties() ),
m_injectionProperties( timeMap, WellInjectionProperties() ),
m_polymerProperties( timeMap, WellPolymerProperties() ),
@@ -64,7 +65,7 @@ namespace Opm {
m_comporder(completionOrdering),
m_allowCrossFlow(allowCrossFlow),
m_automaticShutIn(automaticShutIn),
m_segmentset( timeMap, SegmentSet{} ),
m_segmentset( timeMap, WellSegments{} ),
timesteps( timeMap.numTimesteps() ),
events( timeMap )
{
@@ -231,7 +232,7 @@ namespace Opm {
}
bool Well::setStatus(size_t timeStep, WellCommon::StatusEnum status) {
if ((WellCommon::StatusEnum::OPEN == status) && getCompletions(timeStep).allCompletionsShut()) {
if ((WellCommon::StatusEnum::OPEN == status) && getConnections(timeStep).allConnectionsShut()) {
OpmLog::note("When handling keyword for well " + name() + ": Cannot open a well where all completions are shut" );
return false;
} else {
@@ -329,14 +330,14 @@ namespace Opm {
if( depth >= 0.0 ) return depth;
// ref depth was defaulted and we get the depth of the first completion
const auto& completions = this->getCompletions( timestep );
const auto& completions = this->getConnections( timestep );
if( completions.size() == 0 ) {
throw std::invalid_argument( "No completions defined for well: "
+ name()
+ ". Can not infer reference depth" );
}
return completions.get( 0 ).getCenterDepth();
return completions.get( 0 ).center_depth;
}
void Well::setRefDepth( size_t timestep, double depth ) {
@@ -347,50 +348,34 @@ namespace Opm {
return m_preferredPhase;
}
const CompletionSet& Well::getCompletions(size_t timeStep) const {
return m_completions.get( timeStep );
const WellConnections& Well::getConnections(size_t timeStep) const {
return *m_completions.get( timeStep );
}
const CompletionSet& Well::getCompletions() const {
return m_completions.back();
}
void Well::addCompletions(size_t time_step, const std::vector< Completion >& newCompletions ) {
auto new_set = this->getCompletions( time_step );
int complnum_shift = new_set.size();
std::map<int, std::vector<Connection>> Well::getCompletions(size_t time_step) const {
std::map<int, std::vector<Connection>> completions;
const auto headI = this->m_headI[ time_step ];
const auto headJ = this->m_headJ[ time_step ];
const auto& connections = this->getConnections(time_step);
for (const auto& conn : connections) {
auto pair = completions.find( conn.complnum );
if (pair == completions.end())
completions[conn.complnum] = {};
auto prev_size = new_set.size();
for( auto completion : newCompletions ) {
completion.fixDefaultIJ( headI , headJ );
completion.shift_complnum( complnum_shift );
new_set.add( completion );
const auto new_size = new_set.size();
/* Completions can be "re-added", i.e. same coordinates but with a
* different set of properties. In this case they also inherit the
* completion number (which must otherwise be shifted because
* every COMPDAT keyword thinks it's the only one.
*/
if( new_size == prev_size ) --complnum_shift;
else ++prev_size;
pair = completions.find(conn.complnum);
pair->second.push_back(conn);
}
this->addCompletionSet( time_step, new_set );
return completions;
}
void Well::addCompletionSet(size_t time_step, CompletionSet new_set ){
if( getWellCompletionOrdering() == WellCompletion::TRACK) {
const auto headI = this->m_headI[ time_step ];
const auto headJ = this->m_headJ[ time_step ];
new_set.orderCompletions( headI, headJ );
}
m_completions.update( time_step, std::move( new_set ) );
addEvent( ScheduleEvents::COMPLETION_CHANGE , time_step );
WellConnections Well::getActiveConnections(size_t timeStep, const EclipseGrid& grid) const {
return WellConnections(this->getConnections(timeStep), grid);
}
const WellConnections& Well::getConnections() const {
return *m_completions.back();
}
const std::string Well::getGroupName(size_t time_step) const {
@@ -496,7 +481,7 @@ namespace Opm {
updateRFTActive(time, RFTConnections::RFTEnum::YES);
}
WellCompletion::CompletionOrderEnum Well::getWellCompletionOrdering() const {
WellCompletion::CompletionOrderEnum Well::getWellConnectionOrdering() const {
return m_comporder;
}
@@ -528,15 +513,15 @@ namespace Opm {
}
const SegmentSet& Well::getSegmentSet(size_t time_step) const {
const WellSegments& Well::getWellSegments(size_t time_step) const {
return m_segmentset.get(time_step);
}
bool Well::isMultiSegment(size_t time_step) const {
return (getSegmentSet(time_step).numberSegment() > 0);
return (getWellSegments(time_step).size() > 0);
}
void Well::addSegmentSet(size_t time_step, SegmentSet new_segmentset ) {
void Well::addWellSegments(size_t time_step, WellSegments new_segmentset ) {
// to see if it is the first time entering WELSEGS input to this well.
// if the well is not multi-segment well, it will be the first time
// not sure if a well can switch between mutli-segment well and other
@@ -563,7 +548,20 @@ namespace Opm {
m_segmentset.update(time_step, new_segmentset);
}
WellConnections * Well::newWellConnections(size_t time_step) {
return new WellConnections( this->m_headI[time_step], this->m_headJ[time_step]);
}
void Well::updateWellConnections(size_t time_step, WellConnections * new_set ){
if( getWellConnectionOrdering() == WellCompletion::TRACK) {
const auto headI = this->m_headI[ time_step ];
const auto headJ = this->m_headJ[ time_step ];
new_set->orderConnections( headI, headJ );
}
m_completions.update( time_step, std::shared_ptr<WellConnections>( new_set ));
addEvent( ScheduleEvents::COMPLETION_CHANGE , time_step );
}
void Well::addEvent(ScheduleEvents::Events event, size_t reportStep) {
@@ -576,12 +574,154 @@ namespace Opm {
}
void Well::filterCompletions(const EclipseGrid& grid) {
void Well::filterConnections(const EclipseGrid& grid) {
/*
The m_completions member variable is DynamicState<CompletionSet>
The m_completions member variable is DynamicState<WellConnections>
instance, hence this for loop is over all timesteps.
*/
for (auto& completions : m_completions)
completions.filter(grid);
completions->filter(grid);
}
namespace {
bool defaulted(const DeckRecord& rec, const std::string& s) {
const auto& item = rec.getItem( s );
if (item.defaultApplied(0))
return true;
if (item.get<int>(0) == 0)
return true;
return false;
}
int limit(const DeckRecord& rec, const std::string&s , int shift) {
const auto& item = rec.getItem( s );
return shift + item.get<int>(0);
}
bool match_le(int value, const DeckRecord& rec, const std::string& s, int shift = 0) {
if (defaulted(rec,s))
return true;
return (value <= limit(rec,s,shift));
}
bool match_ge(int value, const DeckRecord& rec, const std::string& s, int shift = 0) {
if (defaulted(rec,s))
return true;
return (value >= limit(rec,s,shift));
}
bool match_eq(int value, const DeckRecord& rec, const std::string& s, int shift = 0) {
if (defaulted(rec,s))
return true;
return (limit(rec,s,shift) == value);
}}
void Well::handleCOMPLUMP(const DeckRecord& record, size_t time_step) {
auto match = [=]( const Connection& c ) -> bool {
if (!match_eq(c.getI(), record, "I" , -1)) return false;
if (!match_eq(c.getJ(), record, "J" , -1)) return false;
if (!match_ge(c.getK(), record, "K1", -1)) return false;
if (!match_le(c.getK(), record, "K2", -1)) return false;
return true;
};
WellConnections * new_connections = this->newWellConnections(time_step);
const int complnum = record.getItem("N").get<int>(0);
if (complnum <= 0)
throw std::invalid_argument("Completion number must be >= 1. COMPLNUM=" + std::to_string(complnum) + "is invalid");
for (auto c : this->getConnections(time_step)) {
if (match(c))
c.complnum = complnum;
new_connections->add(c);
}
this->updateWellConnections(time_step, new_connections);
}
void Well::handleWELOPEN(const DeckRecord& record, size_t time_step, WellCompletion::StateEnum status) {
auto match = [=]( const Connection &c) -> bool {
if (!match_eq(c.getI(), record, "I" , -1)) return false;
if (!match_eq(c.getJ(), record, "J" , -1)) return false;
if (!match_eq(c.getK(), record, "K", -1)) return false;
if (!match_ge(c.complnum, record, "C1")) return false;
if (!match_le(c.complnum, record, "C2")) return false;
return true;
};
WellConnections * new_connections = this->newWellConnections(time_step);
for (auto c : this->getConnections(time_step)) {
if (match(c))
c.state = status;
new_connections->add(c);
}
this->updateWellConnections(time_step, new_connections);
}
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);
this->updateWellConnections(time_step, connections);
}
void Well::handleCOMPSEGS(const DeckKeyword& keyword, 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);
this->updateWellConnections(time_step, new_connection_set);
}
void Well::handleWPIMULT(const DeckRecord& record, size_t time_step) {
auto match = [=]( const Connection &c) -> bool {
if (!match_ge(c.complnum, record, "FIRST")) return false;
if (!match_le(c.complnum, record, "LAST")) return false;
if (!match_eq(c.getI() , record, "I", -1)) return false;
if (!match_eq(c.getJ() , record, "J", -1)) return false;
if (!match_eq(c.getK() , record, "K", -1)) return false;
return true;
};
WellConnections * new_connections = this->newWellConnections(time_step);
double wellPi = record.getItem("WELLPI").get< double >(0);
for (auto c : this->getConnections(time_step)) {
if (match(c))
c.wellPi *= wellPi;
new_connections->add(c);
}
this->updateWellConnections(time_step, new_connections);
}
void Well::handleWELSEGS(const DeckKeyword& keyword, size_t time_step) {
WellSegments newSegmentset;
newSegmentset.loadWELSEGS(keyword);
// update multi-segment related information for the well
this->addWellSegments(time_step, newSegmentset);
}
}

View File

@@ -0,0 +1,299 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cassert>
#include <cmath>
#include <limits>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Connection.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
namespace Opm {
WellConnections::WellConnections(int headIArg, int headJArg) :
headI(headIArg),
headJ(headJArg)
{
}
WellConnections::WellConnections(const WellConnections& src, const EclipseGrid& grid) {
for (const auto& c : src) {
if (grid.cellActive(c.getI(), c.getJ(), c.getK()))
this->add(c);
}
}
void WellConnections::addConnection(int i, int j , int k ,
int complnum,
double depth,
WellCompletion::StateEnum state ,
const Value<double>& connectionTransmissibilityFactor,
const Value<double>& diameter,
const Value<double>& skinFactor,
const Value<double>& Kh,
const int satTableId,
const WellCompletion::DirectionEnum direction)
{
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, connectionTransmissibilityFactor, diameter, skinFactor, Kh, satTableId, direction);
this->add(conn);
}
void WellConnections::addConnection(int i, int j , int k ,
double depth,
WellCompletion::StateEnum state ,
const Value<double>& connectionTransmissibilityFactor,
const Value<double>& diameter,
const Value<double>& skinFactor,
const Value<double>& Kh,
const int satTableId,
const WellCompletion::DirectionEnum direction)
{
int complnum = -(this->m_connections.size() + 1);
this->addConnection(i,
j,
k,
complnum,
depth,
state,
connectionTransmissibilityFactor,
diameter,
skinFactor,
Kh,
satTableId,
direction);
}
void WellConnections::loadCOMPDAT(const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties) {
const auto& itemI = record.getItem( "I" );
const auto defaulted_I = itemI.defaultApplied( 0 ) || itemI.get< int >( 0 ) == 0;
const int I = !defaulted_I ? itemI.get< int >( 0 ) - 1 : this->headI;
const auto& itemJ = record.getItem( "J" );
const auto defaulted_J = itemJ.defaultApplied( 0 ) || itemJ.get< int >( 0 ) == 0;
const int J = !defaulted_J ? itemJ.get< int >( 0 ) - 1 : this->headJ;
int K1 = record.getItem("K1").get< int >(0) - 1;
int K2 = record.getItem("K2").get< int >(0) - 1;
WellCompletion::StateEnum state = WellCompletion::StateEnumFromString( record.getItem("STATE").getTrimmedString(0) );
Value<double> connectionTransmissibilityFactor("CompletionTransmissibilityFactor");
Value<double> diameter("Diameter");
Value<double> skinFactor("SkinFactor");
Value<double> Kh("Kh");
const auto& satnum = eclipseProperties.getIntGridProperty("SATNUM");
int satTableId = -1;
bool defaultSatTable = true;
{
const auto& connectionTransmissibilityFactorItem = record.getItem("CONNECTION_TRANSMISSIBILITY_FACTOR");
const auto& diameterItem = record.getItem("DIAMETER");
const auto& skinFactorItem = record.getItem("SKIN");
const auto& KhItem = record.getItem("Kh");
const auto& satTableIdItem = record.getItem("SAT_TABLE");
if (connectionTransmissibilityFactorItem.hasValue(0) && connectionTransmissibilityFactorItem.getSIDouble(0) > 0)
connectionTransmissibilityFactor.setValue(connectionTransmissibilityFactorItem.getSIDouble(0));
if (diameterItem.hasValue(0))
diameter.setValue( diameterItem.getSIDouble(0));
if (skinFactorItem.hasValue(0))
skinFactor.setValue( skinFactorItem.get< double >(0));
if (KhItem.hasValue(0) && (KhItem.get< double >(0) > 0.0))
Kh.setValue( KhItem.getSIDouble(0));
if (satTableIdItem.hasValue(0) && satTableIdItem.get < int > (0) > 0)
{
satTableId = satTableIdItem.get< int >(0);
defaultSatTable = false;
}
}
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnumFromString(record.getItem("DIR").getTrimmedString(0));
for (int k = K1; k <= K2; k++) {
if (defaultSatTable)
satTableId = satnum.iget(grid.getGlobalIndex(I,J,k));
auto same_ijk = [&]( const Connection& c ) {
return c.sameCoordinate( I,J,k );
};
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,
grid.getCellDepth( I,J,k ),
state,
connectionTransmissibilityFactor,
diameter,
skinFactor,
Kh,
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,
complnum,
grid.getCellDepth(I,J,k),
state,
connectionTransmissibilityFactor,
diameter,
skinFactor,
Kh,
satTableId,
direction );
}
}
}
size_t WellConnections::size() const {
return m_connections.size();
}
const Connection& WellConnections::get(size_t index) const {
return this->m_connections.at( index );
}
const Connection& WellConnections::getFromIJK(const int i, const int j, const int k) const {
for (size_t ic = 0; ic < size(); ++ic) {
if (get(ic).sameCoordinate(i, j, k)) {
return get(ic);
}
}
throw std::runtime_error(" the connection is not found! \n ");
}
Connection& WellConnections::getFromIJK(const int i, const int j, const int k) {
for (size_t ic = 0; ic < size(); ++ic) {
if (get(ic).sameCoordinate(i, j, k)) {
return this->m_connections[ic];
}
}
throw std::runtime_error(" the connection is not found! \n ");
}
void WellConnections::add( Connection connection ) {
m_connections.emplace_back( connection );
}
bool WellConnections::allConnectionsShut( ) const {
auto shut = []( const Connection& c ) {
return c.state == WellCompletion::StateEnum::SHUT;
};
return std::all_of( this->m_connections.begin(),
this->m_connections.end(),
shut );
}
void WellConnections::orderConnections(size_t well_i, size_t well_j)
{
if (m_connections.empty()) {
return;
}
// Find the first connection and swap it into the 0-position.
const double surface_z = 0.0;
size_t first_index = findClosestConnection(well_i, well_j, surface_z, 0);
std::swap(m_connections[first_index], m_connections[0]);
// Repeat for remaining connections.
//
// Note that since findClosestConnection() is O(n), this is an
// O(n^2) algorithm. However, it should be acceptable since
// the expected number of connections is fairly low (< 100).
if( this->m_connections.empty() ) return;
for (size_t pos = 1; pos < m_connections.size() - 1; ++pos) {
const auto& prev = m_connections[pos - 1];
const double prevz = prev.center_depth;
size_t next_index = findClosestConnection(prev.getI(), prev.getJ(), prevz, pos);
std::swap(m_connections[next_index], m_connections[pos]);
}
}
size_t WellConnections::findClosestConnection(int oi, int oj, double oz, size_t start_pos)
{
size_t closest = std::numeric_limits<size_t>::max();
int min_ijdist2 = std::numeric_limits<int>::max();
double min_zdiff = std::numeric_limits<double>::max();
for (size_t pos = start_pos; pos < m_connections.size(); ++pos) {
const auto& connection = m_connections[ pos ];
const double depth = connection.center_depth;
const int ci = connection.getI();
const int cj = connection.getJ();
// Using square of distance to avoid non-integer arithmetics.
const int ijdist2 = (ci - oi) * (ci - oi) + (cj - oj) * (cj - oj);
if (ijdist2 < min_ijdist2) {
min_ijdist2 = ijdist2;
min_zdiff = std::abs(depth - oz);
closest = pos;
} else if (ijdist2 == min_ijdist2) {
const double zdiff = std::abs(depth - oz);
if (zdiff < min_zdiff) {
min_zdiff = zdiff;
closest = pos;
}
}
}
assert(closest != std::numeric_limits<size_t>::max());
return closest;
}
bool WellConnections::operator==( const WellConnections& rhs ) const {
return this->size() == rhs.size()
&& std::equal( this->begin(), this->end(), rhs.begin() );
}
bool WellConnections::operator!=( const WellConnections& rhs ) const {
return !( *this == rhs );
}
void WellConnections::filter(const EclipseGrid& grid) {
auto new_end = std::remove_if(m_connections.begin(),
m_connections.end(),
[&grid](const Connection& c) { return !grid.cellActive(c.getI(), c.getJ(), c.getK()); });
m_connections.erase(new_end, m_connections.end());
}
}

View File

@@ -41,7 +41,9 @@ namespace Opm {
{}
WellProductionProperties WellProductionProperties::history(const double BHPLimit, const DeckRecord& record)
WellProductionProperties WellProductionProperties::history(const WellProductionProperties& prev_properties,
const DeckRecord& record,
const WellProducer::ControlModeEnum controlModeWHISTCL)
{
WellProductionProperties p(record);
p.predictionMode = false;
@@ -50,9 +52,14 @@ namespace Opm {
const auto& cmodeItem = record.getItem("CMODE");
if ( !cmodeItem.defaultApplied(0) ) {
namespace wp = WellProducer;
const auto cmode = wp::ControlModeFromString( cmodeItem.getTrimmedString( 0 ) );
if (cmode == wp::LRAT || cmode == wp::RESV || cmode == wp::ORAT ||
cmode == wp::WRAT || cmode == wp::GRAT || cmode == wp::BHP) {
auto cmode = wp::ControlModeFromString( cmodeItem.getTrimmedString( 0 ) );
// when there is an effective control mode specified by WHISTCL, we always use this control mode
if (effectiveHistoryProductionControl(controlModeWHISTCL) ) {
cmode = controlModeWHISTCL;
}
if (effectiveHistoryProductionControl(cmode) ) {
p.addProductionControl( cmode );
p.controlMode = cmode;
} else {
@@ -70,7 +77,7 @@ namespace Opm {
if (cmode == wp::BHP)
p.BHPLimit = record.getItem( "BHP" ).getSIDouble( 0 );
else
p.BHPLimit = BHPLimit;
p.BHPLimit = prev_properties.BHPLimit;
}
if ( record.getItem( "BHP" ).hasValue(0) )
@@ -78,6 +85,16 @@ namespace Opm {
if ( record.getItem( "THP" ).hasValue(0) )
p.THPH = record.getItem("THP").getSIDouble(0);
p.VFPTableNumber = record.getItem("VFPTable").get< int >(0);
if (p.VFPTableNumber == 0)
p.VFPTableNumber = prev_properties.VFPTableNumber;
p.ALQValue = record.getItem("Lift").get< double >(0); //NOTE: Unit of ALQ is never touched
if (p.ALQValue == 0.)
p.ALQValue = prev_properties.ALQValue;
return p;
}
@@ -96,15 +113,21 @@ namespace Opm {
p.VFPTableNumber = record.getItem("VFP_TABLE").get< int >(0);
namespace wp = WellProducer;
using mode = std::pair< const char*, wp::ControlModeEnum >;
using mode = std::pair< const std::string, wp::ControlModeEnum >;
static const mode modes[] = {
{ "ORAT", wp::ORAT }, { "WRAT", wp::WRAT }, { "GRAT", wp::GRAT },
{ "LRAT", wp::LRAT }, { "RESV", wp::RESV }, { "THP", wp::THP }
};
for( const auto& cmode : modes ) {
if( !record.getItem( cmode.first ).defaultApplied( 0 ) )
p.addProductionControl( cmode.second );
if( !record.getItem( cmode.first ).defaultApplied( 0 ) ) {
// a zero value THP limit will not be handled as a THP limit
if (cmode.first == "THP" && p.THPLimit == 0.)
continue;
p.addProductionControl( cmode.second );
}
}
// There is always a BHP constraint, when not specified, will use the default value
@@ -169,4 +192,11 @@ namespace Opm {
<< "prediction: " << wp.predictionMode << " }";
}
bool WellProductionProperties::effectiveHistoryProductionControl(const WellProducer::ControlModeEnum cmode) {
// Note, not handling CRAT for now
namespace wp = WellProducer;
return ( (cmode == wp::LRAT || cmode == wp::RESV || cmode == wp::ORAT ||
cmode == wp::WRAT || cmode == wp::GRAT || cmode == wp::BHP) );
}
} // namespace Opm

View File

@@ -0,0 +1,113 @@
/*
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 <stdexcept>
#include <algorithm>
#include <opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp>
namespace Opm {
WellTestConfig::WellTestConfig() {
}
void WellTestConfig::add_well(const std::string& well, Reason shut_reason, double test_interval, int num_retries, double startup_time) {
wells.push_back({well, shut_reason, test_interval, num_retries, startup_time});
}
void WellTestConfig::add_well(const std::string& well, const std::string& reasons, double test_interval, int num_retries, double startup_time) {
if (reasons.size() == 0)
throw std::invalid_argument("Can not pass empty string to stop testing to add_well() method.");
for (auto c : reasons) {
switch(c) {
case 'P' :
add_well(well, Reason::PHYSICAL, test_interval, num_retries, startup_time);
break;
case 'E' :
add_well(well, Reason::ECONOMIC, test_interval, num_retries, startup_time);
break;
case 'G':
add_well(well, Reason::GROUP, test_interval, num_retries, startup_time);
break;
case 'D':
add_well(well, Reason::THP_DESIGN, test_interval, num_retries, startup_time);
break;
case 'C':
add_well(well, Reason::COMPLETION, test_interval, num_retries, startup_time);
break;
default:
throw std::invalid_argument("Invalid character in WTEST configuration");
}
}
}
void WellTestConfig::drop_well(const std::string& well) {
wells.erase(std::remove_if(wells.begin(),
wells.end(),
[&well](const WTESTWell& wtest_well) { return (wtest_well.name == well); }),
wells.end());
}
bool WellTestConfig::has(const std::string& well) const {
const auto well_iter = std::find_if(wells.begin(),
wells.end(),
[&well](const WTESTWell& wtest_well) { return (wtest_well.name == well); });
return (well_iter != wells.end());
}
bool WellTestConfig::has(const std::string& well, Reason reason) const {
const auto well_iter = std::find_if(wells.begin(),
wells.end(),
[&well, &reason](const WTESTWell& wtest_well)
{
return (reason == wtest_well.shut_reason && wtest_well.name == well);
});
return (well_iter != wells.end());
}
const WellTestConfig::WTESTWell& WellTestConfig::get(const std::string& well, Reason reason) const {
const auto well_iter = std::find_if(wells.begin(),
wells.end(),
[&well, &reason](const WTESTWell& wtest_well)
{
return (reason == wtest_well.shut_reason && wtest_well.name == well);
});
if (well_iter == wells.end())
throw std::invalid_argument("No such WTEST object");
return *well_iter;
}
size_t WellTestConfig::size() const {
return wells.size();
}
}

View File

@@ -0,0 +1,138 @@
/*
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 <stdexcept>
#include <algorithm>
#include <opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellTestState.hpp>
namespace Opm {
void WellTestState::addClosedWell(const std::string& well_name, WellTestConfig::Reason reason, double sim_time) {
if (this->hasWell(well_name, reason))
return;
this->wells.push_back({well_name, reason, sim_time, 0});
}
void WellTestState::openWell(const std::string& well_name) {
wells.erase(std::remove_if(wells.begin(),
wells.end(),
[&well_name](const ClosedWell& well) { return (well.name == well_name); }),
wells.end());
}
void WellTestState::dropWell(const std::string& well_name, WellTestConfig::Reason reason) {
wells.erase(std::remove_if(wells.begin(),
wells.end(),
[&well_name, reason](const ClosedWell& well) { return (well.name == well_name && well.reason == reason); }),
wells.end());
}
bool WellTestState::hasWell(const std::string& well_name, WellTestConfig::Reason reason) const {
const auto well_iter = std::find_if(wells.begin(),
wells.end(),
[&well_name, &reason](const ClosedWell& well)
{
return (reason == well.reason && well.name == well_name);
});
return (well_iter != wells.end());
}
size_t WellTestState::sizeWells() const {
return this->wells.size();
}
std::vector<std::pair<std::string, WellTestConfig::Reason>> WellTestState::updateWell(const WellTestConfig& config, double sim_time) {
std::vector<std::pair<std::string, WellTestConfig::Reason>> output;
for (auto& closed_well : this->wells) {
if (config.has(closed_well.name, closed_well.reason)) {
const auto& well_config = config.get(closed_well.name, closed_well.reason);
double elapsed = sim_time - closed_well.last_test;
if (elapsed >= well_config.test_interval)
if (well_config.num_test == 0 || (closed_well.num_attempt < well_config.num_test)) {
closed_well.last_test = sim_time;
closed_well.num_attempt += 1;
output.push_back(std::make_pair(closed_well.name, closed_well.reason));
}
}
}
return output;
}
void WellTestState::addClosedCompletion(const std::string& well_name, int complnum, double sim_time) {
if (this->hasCompletion(well_name, complnum))
return;
this->completions.push_back( {well_name, complnum, sim_time, 0} );
}
void WellTestState::dropCompletion(const std::string& well_name, int complnum) {
completions.erase(std::remove_if(completions.begin(),
completions.end(),
[&well_name, complnum](const ClosedCompletion& completion) { return (completion.wellName == well_name && completion.complnum == complnum); }),
completions.end());
}
bool WellTestState::hasCompletion(const std::string& well_name, const int complnum) const {
const auto completion_iter = std::find_if(completions.begin(),
completions.end(),
[&well_name, &complnum](const ClosedCompletion& completion)
{
return (complnum == completion.complnum && completion.wellName == well_name);
});
return (completion_iter != completions.end());
}
size_t WellTestState::sizeCompletions() const {
return this->completions.size();
}
std::vector<std::pair<std::string, int>> WellTestState::updateCompletion(const WellTestConfig& config, double sim_time) {
std::vector<std::pair<std::string, int>> output;
for (auto& closed_completion : this->completions) {
if (config.has(closed_completion.wellName, WellTestConfig::Reason::COMPLETION)) {
const auto& well_config = config.get(closed_completion.wellName, WellTestConfig::Reason::COMPLETION);
double elapsed = sim_time - closed_completion.last_test;
if (elapsed >= well_config.test_interval)
if (well_config.num_test == 0 || (closed_completion.num_attempt < well_config.num_test)) {
closed_completion.last_test = sim_time;
closed_completion.num_attempt += 1;
output.push_back(std::make_pair(closed_completion.wellName, closed_completion.complnum));
}
}
}
return output;
}
}

View File

@@ -46,9 +46,10 @@
namespace Opm {
SimulationConfig::SimulationConfig(const Deck& deck,
SimulationConfig::SimulationConfig(bool restart,
const Deck& deck,
const Eclipse3DProperties& eclipseProperties) :
m_ThresholdPressure( deck, eclipseProperties ),
m_ThresholdPressure( restart, deck, eclipseProperties ),
m_useCPR(false),
m_DISGAS(false),
m_VAPOIL(false)
@@ -75,8 +76,8 @@ namespace Opm {
return m_ThresholdPressure;
}
bool SimulationConfig::hasThresholdPressure() const {
return m_ThresholdPressure.size() > 0;
bool SimulationConfig::useThresholdPressure() const {
return m_ThresholdPressure.active();
}
bool SimulationConfig::useCPR() const {

View File

@@ -28,8 +28,11 @@
namespace Opm {
ThresholdPressure::ThresholdPressure(const Deck& deck,
const Eclipse3DProperties& eclipseProperties)
ThresholdPressure::ThresholdPressure(bool restart,
const Deck& deck,
const Eclipse3DProperties& eclipseProperties) :
m_active(false),
m_restart(restart)
{
if( !Section::hasRUNSPEC( deck ) || !Section::hasSOLUTION( deck ) )
@@ -38,7 +41,6 @@ namespace Opm {
RUNSPECSection runspecSection( deck );
SOLUTIONSection solutionSection( deck );
bool thpresOption = false;
const bool thpresKeyword = solutionSection.hasKeyword<ParserKeywords::THPRES>();
const bool hasEqlnumKeyword = eclipseProperties.hasDeckIntGridProperty( "EQLNUM" );
int maxEqlnum = 0;
@@ -55,19 +57,35 @@ namespace Opm {
throw std::runtime_error("Cannot use IRREVERS version of THPRES option, not implemented");
if( opt == "THPRES" )
thpresOption = true;
m_active = true;
}
}
if( thpresOption && !thpresKeyword ) {
throw std::runtime_error("Invalid solution section; "
"the EQLOPTS THPRES option is set in RUNSPEC, "
"but no THPRES keyword is found in SOLUTION." );
/*
When performing a restart in Eclipse the solution section must be
updated, and in particuar the THPRES keyword should be removed. The
THPRES values should be read from the restart file instead. To ensure
that reservoir engineers can follow the same file-manipulation
workflow they are used to when running Eclipse we accept a deck
without THPRES and just assume it will come from the restart file at a
later stage.
If this is a restart AND the deck still contains the THPRES values
they will be loaded from the deck, but quite probably - the simulator
will ignore the deck initialized values and just use the values from
the restart file.
*/
if( m_active && !thpresKeyword ) {
if (!m_restart)
throw std::runtime_error("Invalid solution section; "
"the EQLOPTS THPRES option is set in RUNSPEC, "
"but no THPRES keyword is found in SOLUTION." );
}
//Option is set and keyword is found
if( thpresOption && thpresKeyword ) {
if( m_active && thpresKeyword ) {
if( !hasEqlnumKeyword )
throw std::runtime_error("Error when internalizing THPRES: EQLNUM keyword not found in deck");
@@ -164,6 +182,13 @@ namespace Opm {
return m_pressureTable.size();
}
bool ThresholdPressure::active() const {
return m_active;
}
bool ThresholdPressure::restart() const {
return m_restart;
}
bool ThresholdPressure::hasThresholdPressure(int r1 , int r2) const {
std::pair<int,int> indexPair = makeIndex(r1,r2);

View File

@@ -28,8 +28,8 @@
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/GridDims.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Completion.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Connection.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
@@ -211,7 +211,7 @@ inline std::array< int, 3 > getijk( const DeckRecord& record,
}};
}
inline std::array< int, 3 > getijk( const Completion& completion ) {
inline std::array< int, 3 > getijk( const Connection& completion ) {
return {{ completion.getI(), completion.getJ(), completion.getK() }};
}
@@ -292,9 +292,9 @@ inline void keywordC( std::vector< ERT::smspec_node >& list,
* over a well's completions regardless of the desired block is
* defaulted or not
*/
for( const auto& completion : well->getCompletions( last_timestep ) ) {
for( const auto& connection : well->getConnections( last_timestep ) ) {
/* block coordinates defaulted */
auto cijk = getijk( completion );
auto cijk = getijk( connection );
if( record.getItem( 1 ).defaultApplied( 0 ) ) {
list.emplace_back( keywordstring, name, dims.getNXYZ().data(), cijk.data() );

View File

@@ -23,11 +23,8 @@
namespace Opm {
JFunc::JFunc(const Deck& deck) :
m_exists(deck.hasKeyword("JFUNC"))
JFunc::JFunc(const Deck& deck)
{
if (!m_exists)
return;
const auto& kw = *deck.getKeywordList<ParserKeywords::JFUNC>()[0];
const auto& rec = kw.getRecord(0);
const auto& kw_flag = rec.getItem("FLAG").get<std::string>(0);

View File

@@ -18,6 +18,8 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <memory>
#include <opm/common/OpmLog/LogUtil.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/E.hpp>
@@ -86,15 +88,19 @@
namespace Opm {
TableManager::TableManager( const Deck& deck )
:
m_tabdims( Tabdims(deck)),
m_aqudims( Aqudims(deck)),
hasImptvd (deck.hasKeyword("IMPTVD")),
hasEnptvd (deck.hasKeyword("ENPTVD")),
hasEqlnum (deck.hasKeyword("EQLNUM")),
m_jfunc( deck )
hasEqlnum (deck.hasKeyword("EQLNUM"))
{
if (deck.hasKeyword("JFUNC"))
jfunc.reset( new JFunc(deck) );
// determine the default resevoir temperature in Kelvin
m_rtemp = ParserKeywords::RTEMP::TEMP::defaultValue;
m_rtemp += Metric::TemperatureOffset; // <- default values always use METRIC as the unit system!
@@ -656,10 +662,10 @@ namespace Opm {
const TableContainer& TableManager::getPlyshlogTables() const {
return getTables("PLYSHLOG");
}
const TableContainer& TableManager::getAqutabTables() const {
return getTables("AQUTAB");
}
}
const std::vector<PvtgTable>& TableManager::getPvtgTables() const {
return m_pvtgTables;
@@ -713,9 +719,9 @@ namespace Opm {
}
const JFunc& TableManager::getJFunc() const {
if (!useJFunc())
if (!jfunc)
throw std::invalid_argument("Cannot get JFUNC table when JFUNC not in deck");
return m_jfunc;
return *jfunc;
}
bool TableManager::useImptvd() const {
@@ -731,7 +737,10 @@ namespace Opm {
}
bool TableManager::useJFunc() const {
return m_jfunc;
if (jfunc)
return true;
else
return false;
}

View File

@@ -85,6 +85,7 @@ namespace Opm {
addKey(SUMMARY_UNKNOWN_WELL, InputError::THROW_EXCEPTION);
addKey(SUMMARY_UNKNOWN_GROUP, InputError::THROW_EXCEPTION);
addKey(SCHEDULE_INVALID_NAME, InputError::THROW_EXCEPTION);
}
void ParseContext::initEnv() {
@@ -257,6 +258,8 @@ namespace Opm {
const std::string ParseContext::SUMMARY_UNKNOWN_WELL = "SUMMARY_UNKNOWN_WELL";
const std::string ParseContext::SUMMARY_UNKNOWN_GROUP = "SUMMARY_UNKNOWN_GROUP";
const std::string ParseContext::SCHEDULE_INVALID_NAME = "SCHEDULE_INVALID_NAME";
}

View File

@@ -38,6 +38,10 @@ namespace {
* metric and field arrays. C++ does not support designated initializers, so
* this cannot be done in a declaration-order independent matter.
*/
// =================================================================
// METRIC Unit Conventions
static const double from_metric_offset[] = {
0.0,
0.0,
@@ -65,6 +69,8 @@ namespace {
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
};
@@ -85,7 +91,9 @@ namespace {
1 / ( Metric::GasSurfaceVolume / Metric::Time ),
1 / ( Metric::ReservoirVolume / Metric::Time ),
1 / Metric::Transmissibility,
1 / (Metric::Permeability * Metric::Length),
1 / Metric::Mass,
1 / ( Metric::Mass / Metric::Time ),
1, /* gas-oil ratio */
1, /* oil-gas ratio */
1, /* water cut */
@@ -115,7 +123,9 @@ namespace {
Metric::GasSurfaceVolume / Metric::Time,
Metric::ReservoirVolume / Metric::Time,
Metric::Transmissibility,
Metric::Permeability * Metric::Length,
Metric::Mass,
Metric::Mass / Metric::Time,
1, /* gas-oil ratio */
1, /* oil-gas ratio */
1, /* water cut */
@@ -145,7 +155,9 @@ namespace {
"SM3/DAY",
"RM3/DAY",
"CPR3/DAY/BARS",
"MDM",
"KG",
"KG/DAY",
"SM3/SM3",
"SM3/SM3",
"SM3/SM3",
@@ -158,6 +170,9 @@ namespace {
"KJ", /* energy */
};
// =================================================================
// FIELD Unit Conventions
static const double from_field_offset[] = {
0.0,
0.0,
@@ -185,6 +200,8 @@ namespace {
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
};
@@ -205,7 +222,9 @@ namespace {
1 / ( Field::GasSurfaceVolume / Field::Time ),
1 / ( Field::ReservoirVolume / Field::Time ),
1 / Field::Transmissibility,
1 / (Field::Permeability * Field::Length),
1 / Field::Mass,
1 / ( Field::Mass / Field::Time ),
1 / ( Field::GasSurfaceVolume / Field::LiquidSurfaceVolume ), /* gas-oil ratio */
1 / ( Field::LiquidSurfaceVolume / Field::GasSurfaceVolume ), /* oil-gas ratio */
1, /* water cut */
@@ -235,7 +254,9 @@ namespace {
Field::GasSurfaceVolume / Field::Time,
Field::ReservoirVolume / Field::Time,
Field::Transmissibility,
Field::Permeability * Field::Length,
Field::Mass,
Field::Mass / Field::Time,
Field::GasSurfaceVolume / Field::LiquidSurfaceVolume, /* gas-oil ratio */
Field::LiquidSurfaceVolume / Field::GasSurfaceVolume, /* oil-gas ratio */
1, /* water cut */
@@ -265,7 +286,9 @@ namespace {
"MSCF/DAY",
"RB/DAY",
"CPRB/DAY/PSI",
"MDFT",
"LB",
"LB/DAY"
"MSCF/STB",
"STB/MSCF",
"STB/STB",
@@ -278,6 +301,9 @@ namespace {
"BTU", /* energy */
};
// =================================================================
// LAB Unit Conventions
static const double from_lab_offset[] = {
0.0,
0.0,
@@ -305,6 +331,8 @@ namespace {
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
};
@@ -325,7 +353,9 @@ namespace {
1 / ( Lab::GasSurfaceVolume / Lab::Time ),
1 / ( Lab::ReservoirVolume / Lab::Time ),
1 / Lab::Transmissibility,
1 / (Lab::Permeability * Lab::Length),
1 / Lab::Mass,
1 / ( Lab::Mass / Lab::Time ),
1 / Lab::GasDissolutionFactor, /* gas-oil ratio */
1 / Lab::OilDissolutionFactor, /* oil-gas ratio */
1, /* water cut */
@@ -355,7 +385,9 @@ namespace {
Lab::GasSurfaceVolume / Lab::Time,
Lab::ReservoirVolume / Lab::Time,
Lab::Transmissibility,
Lab::Permeability * Lab::Length,
Lab::Mass,
Lab::Mass / Lab::Time,
Lab::GasDissolutionFactor, /* gas-oil ratio */
Lab::OilDissolutionFactor, /* oil-gas ratio */
1, /* water cut */
@@ -385,7 +417,9 @@ namespace {
"SCC/HR",
"RCC/HR",
"CPRCC/HR/ATM",
"MDCC",
"G",
"G/HR",
"SCC/SCC",
"SCC/SCC",
"SCC/SCC",
@@ -398,6 +432,9 @@ namespace {
"J", /* energy */
};
// =================================================================
// PVT-M Unit Conventions
static const double from_pvt_m_offset[] = {
0.0,
0.0,
@@ -425,6 +462,8 @@ namespace {
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
};
@@ -445,7 +484,9 @@ namespace {
1 / ( PVT_M::GasSurfaceVolume / PVT_M::Time ),
1 / ( PVT_M::ReservoirVolume / PVT_M::Time ),
1 / PVT_M::Transmissibility,
1 / (PVT_M::Permeability * PVT_M::Length),
1 / PVT_M::Mass,
1 / ( PVT_M::Mass / PVT_M::Time ),
1 / (PVT_M::GasSurfaceVolume / PVT_M::LiquidSurfaceVolume), // Rs
1 / (PVT_M::LiquidSurfaceVolume / PVT_M::GasSurfaceVolume), // Rv
1, /* water cut */
@@ -475,7 +516,9 @@ namespace {
PVT_M::GasSurfaceVolume / PVT_M::Time,
PVT_M::ReservoirVolume / PVT_M::Time,
PVT_M::Transmissibility,
PVT_M::Permeability * PVT_M::Length,
PVT_M::Mass,
PVT_M::Mass / PVT_M::Time,
PVT_M::GasSurfaceVolume / PVT_M::LiquidSurfaceVolume, // Rs
PVT_M::LiquidSurfaceVolume / PVT_M::GasSurfaceVolume, // Rv
1, /* water cut */
@@ -505,7 +548,9 @@ namespace {
"SM3/DAY",
"RM3/DAY",
"CPR3/DAY/ATM",
"MDM",
"KG",
"KG/DAY",
"SM3/SM3",
"SM3/SM3",
"SM3/SM3",
@@ -518,6 +563,8 @@ namespace {
"KJ" /* energy */
};
// =================================================================
// INPUT Unit Conventions
static const double from_input_offset[] = {
0.0,
@@ -546,6 +593,8 @@ namespace {
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
};
@@ -576,6 +625,8 @@ namespace {
1,
1,
1,
1,
1,
1
};
@@ -606,6 +657,8 @@ namespace {
1,
1,
1,
1,
1,
1
};
@@ -626,7 +679,9 @@ namespace {
"SM3/DAY",
"RM3/DAY",
"CPR3/DAY/BARS",
"MDM",
"KG",
"KG/DAY",
"SM3/SM3",
"SM3/SM3",
"SM3/SM3",
@@ -639,8 +694,7 @@ namespace {
"KJ", /* energy */
};
}
} // namespace Anonymous
UnitSystem::UnitSystem(const UnitType unit) :
m_unittype( unit )
@@ -674,8 +728,15 @@ namespace {
this->measure_table_to_si_offset = from_pvt_m_offset;
this->unit_name_table = pvt_m_names;
break;
case(UnitType::UNIT_TYPE_INPUT):
m_name = "Input";
this->measure_table_from_si = to_input;
this->measure_table_to_si = from_input;
this->measure_table_to_si_offset = from_input_offset;
this->unit_name_table = input_names;
break;
default:
//do nothing
throw std::runtime_error("Tried to construct UnitSystem with unknown unit family.");
break;
};
}
@@ -742,6 +803,7 @@ namespace {
case UnitType::UNIT_TYPE_FIELD: return ECL_FIELD_UNITS;
case UnitType::UNIT_TYPE_LAB: return ECL_LAB_UNITS;
case UnitType::UNIT_TYPE_PVT_M: return ECL_PVT_M_UNITS;
case UnitType::UNIT_TYPE_INPUT: throw std::runtime_error("UNIT_TYPE_INPUT has no counterpart in the ert_ecl_unit_enum type.");
default:
throw std::runtime_error("What has happened here?");
}

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