Compare commits

..

390 Commits

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

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

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

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

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

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

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

Added new implementation of serialize_ICON

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

Handle wildcard in group keywords

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

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

Add key string to RestartKey

Pass dimension information for extra fields in restart

Verify that the extra container has THPRES
2018-09-19 16:01:54 +02:00
Jostein Alvestad
a284acc3ed Further additions and changes to implement preparation and writing of group data to the restart file 2018-09-19 16:01:54 +02:00
Jostein Alvestad
19bb0e0077 Additional changes to create restart group data in general and igrp data in particular 2018-09-19 16:01:53 +02:00
Jostein Alvestad
89b11dfd26 Further changes to write group data to restart file 2018-09-19 16:01:53 +02:00
Jostein Alvestad
2552750bed Initial changes to implement group data into writing of restart file 2018-09-19 16:01:52 +02:00
Jostein Alvestad
7b2c36bde5 Added changes to include no of groups in InteHEAD 2018-09-19 16:01:52 +02:00
Jostein Alvestad
b9bb0ae60a Initial changes to add group data to restart output plus adding changes to include no of groups in inteHEAD 2018-09-19 16:01:51 +02:00
Arne Morten Kvarving
4c6d4ee201 Merge pull request #498 from joakim-hove/komodo
Komodo: cmake config changes
2018-09-19 09:08:53 +02:00
Joakim Hove
906ff3f4b5 Add ability to CMAKE variable DIST_PREFIX before find_package(opm--) 2018-09-19 09:07:05 +02:00
Joakim Hove
238d3ddb58 Move CMAKE_MODULE_PATH manipulations before @OPM_PROJECT_EXTRA_CODE@ 2018-09-17 09:12:29 +02:00
Joakim Hove
42745e0bfc Merge pull request #493 from joakim-hove/default-ecl-compatible
Make ecl compatible restart files default
2018-09-15 11:09:44 +02:00
Bård Skaflestad
4e593da140 Merge pull request #497 from totto82/start2
Write restart when SAVE keyword is in the schedule file
2018-09-14 19:54:25 +02:00
Joakim Hove
662d673c44 Merge pull request #496 from joakim-hove/summary-start-at1
Summary start at1
2018-09-14 17:13:45 +02:00
Tor Harald Sandve
fdc4b0142e Write restart when SAVE keyword is in the schedule file 2018-09-14 13:36:22 +02:00
Arne Morten Kvarving
142994dde6 Merge pull request #491 from akva2/improve_lto
improve lto support
2018-09-14 12:30:16 +02:00
Arne Morten Kvarving
d58001f608 improve lto support
need to use the wrappers for ar and ranlib, or static
libraries are problematic.
2018-09-14 10:29:59 +02:00
Joakim Hove
7dccd13c50 Merge pull request #492 from totto82/minpvfil
fix unit of minpvfil
2018-09-13 19:08:45 +02:00
Joakim Hove
fb5e1229ef Merge pull request #495 from joakim-hove/remove-include
Remove include + use plain C api for test_area
2018-09-13 19:07:37 +02:00
Joakim Hove
d30fc975e3 Merge pull request #444 from lars-petter-hauge/support_ctfac
Support CTFAC
2018-09-13 18:21:24 +02:00
Joakim Hove
36af2aadb5 Will not write summary data for report step == 0 2018-09-13 18:08:57 +02:00
Joakim Hove
cf754c499d White space change 2018-09-13 18:07:37 +02:00
Joakim Hove
9d7ec59e9e Use plain C api for test area 2018-09-13 17:25:33 +02:00
Joakim Hove
eded8bacfc Remove unused include 2018-09-13 17:11:49 +02:00
Lars Petter Øren Hauge
87e3beb601 Support CTFAC in output 2018-09-13 10:23:47 +02:00
Joakim Hove
079d946723 Make ecl compatible restart files default 2018-09-12 18:02:47 +02:00
Joakim Hove
492a240f09 Merge pull request #488 from joakim-hove/opm-formatted-rst
Add opm_formatted property to the IOConfig
2018-09-12 12:57:26 +02:00
Tor Harald Sandve
e6c0ccb5bf fix unit of minpvfil 2018-09-12 11:44:33 +02:00
Joakim Hove
71d92c3dc8 Add opm_formatted property to the IOConfig 2018-09-12 11:34:57 +02:00
Bård Skaflestad
2ea1b7860f Merge pull request #490 from bska/fix-index-oob
Ensure Correctly Sized ACTNUM Vector
2018-09-12 10:09:24 +02:00
Bård Skaflestad
9fd5ce396b Ensure Correctly Sized ACTNUM Vector
Size must be equal to number of global (Cartesian) cells.
2018-09-12 09:46:53 +02:00
Arne Morten Kvarving
bff3c0bff1 Merge pull request #489 from joakim-hove/ignore-extra-kwII
Add option to ignore extra keywords in the regresstion testing
2018-09-11 16:09:53 +02:00
Joakim Hove
7cd29ea7d7 Add option to ignore extra keywords in the regresstion testing 2018-09-11 13:34:51 +02:00
Arne Morten Kvarving
a3c9943a5e Merge pull request #487 from joakim-hove/fix-shared-build
Fix build of tests when using shared library
2018-09-11 13:27:06 +02:00
Joakim Hove
552c390465 Merge pull request #464 from joakim-hove/peaceman-formula
Peaceman formula
2018-09-11 13:18:40 +02:00
Joakim Hove
9f9041dcae Fix build of tests when using shared library 2018-09-10 18:33:47 +02:00
Joakim Hove
c870172a30 Merge pull request #484 from joakim-hove/use-c-smspec
Using plain C api for smspec_nodes
2018-09-10 17:51:23 +02:00
Arne Morten Kvarving
80918f030b Merge pull request #486 from akva2/combine_compare_apps
Combine comparison applications into one
2018-09-10 11:06:31 +02:00
Joakim Hove
1d55e923f9 Merge pull request #483 from joakim-hove/use-c-testare
Use c testare
2018-09-10 10:15:23 +02:00
Arne Morten Kvarving
cb525c5c75 changed: fold compareSummary into compareECL application 2018-09-10 08:42:26 +02:00
Joakim Hove
4a5b71d8c1 Include Peaceman calculation in Connection class
- The calculation of well connection transmissibility CF and effective
   permeability is calculated.

 - The Connection objects are immutable; should never be updated.

 - The properties of the Connection class are just plain properties, have
   removed getter methods and the use of Value<double>.
2018-09-09 11:16:42 +02:00
Joakim Hove
ff939b44f2 Add testdecks SPE1 and SPE9 2018-09-09 11:16:42 +02:00
Joakim Hove
9e8110e67b Add Peaceman utility functions from opm-simulators 2018-09-09 11:16:42 +02:00
Arne Morten Kvarving
b877c8b340 changed: put Deviation struct in a separate header
ODR
2018-09-07 15:33:50 +02:00
Arne Morten Kvarving
7a034ffd01 changed: split ECL(Integration|Regression)Test classes to separate files
to unify code with the summary comparison classes
2018-09-07 15:33:46 +02:00
Arne Morten Kvarving
6e0c31bed4 changed: make getCellVolume a static member of ECLFilesComparator
needed in upcoming splitting commit
2018-09-07 14:38:03 +02:00
Arne Morten Kvarving
ef63206925 changed: rename (Integration|Regression)Test ECL(Integration|RegressionTest)
for clarity
2018-09-07 14:38:03 +02:00
Arne Morten Kvarving
0b6d36658d changed: pass basenames as std::string
to unify code with the other comparison classes
2018-09-07 14:38:03 +02:00
Arne Morten Kvarving
44f3b86547 changed: rename the summary regression/integrationtest classes
it restores c++ ODR which is nice, but the main reason is to
allow usage of summary and generic comparison classes in the
the same application.
2018-09-07 14:38:03 +02:00
Arne Morten Kvarving
bee4590aaa changed: move the comparison classes out of libopmcommon
these classes are really not made for reusability.
thus they should only be built into the applications.
2018-09-07 14:38:03 +02:00
Joakim Hove
5aa0bfadf0 Use plain C api for smspec_nodes 2018-09-07 13:56:04 +02:00
Joakim Hove
e1948ccf99 Add operator[] to GridDims 2018-09-07 10:20:50 +02:00
Joakim Hove
45e81a02fa Use plain C api for temporary testarea 2018-09-07 05:53:20 +02:00
Joakim Hove
085bbc263b Merge pull request #482 from joakim-hove/thpres-fixup
Fixup: THPRESPR -> THRESPR
2018-09-05 21:10:34 +02:00
Joakim Hove
3e95d3f42b Fixup: THPRESPR -> THRESHPR 2018-09-05 17:53:33 +02:00
Joakim Hove
6b93051616 Merge pull request #480 from joakim-hove/thrpes-solution-section
Thrpes solution section
2018-09-04 14:18:14 +02:00
Joakim Hove
d3249d965f Merge pull request #477 from joakim-hove/multregt-default
Multregt default
2018-09-04 14:17:50 +02:00
Joakim Hove
4a10023c0d Make sure the THPRESPR field is written in solution section 2018-09-04 08:38:15 +02:00
Joakim Hove
065b9c9c9f Merge pull request #479 from joakim-hove/thpres-move-it
Rename THPRES string to THPRESPR
2018-09-04 08:25:55 +02:00
Joakim Hove
ae3c4e0d8c Rename THPRES string to THPRESPR 2018-09-03 17:15:01 +02:00
Joakim Hove
4d5ef337ec Accept default values when parsing MULTREGT keyword 2018-08-31 15:47:28 +02:00
Joakim Hove
a2394c06f5 Refacored MULTREGT scanner 2018-08-31 14:32:10 +02:00
Atgeirr Flø Rasmussen
43e4f0ca87 Merge pull request #473 from alfbr/master
Make compiling with OpenMP default.
2018-08-27 13:28:38 +02:00
Joakim Hove
cdf876fa15 Merge pull request #475 from dhan16opm/dhan16_fixes
fix missing "include <string>" in InitConfig.hpp
2018-08-25 09:24:34 +02:00
CDN MacbookPro13
12402916a7 See #https://github.com/OPM/opm-common/issues/474. header files should be self-sufficient 2018-08-25 12:50:58 +05:30
Alf Birger Rustad
0183fa884a Make compiling with OpenMP default. 2018-08-17 13:39:44 +02:00
Arne Morten Kvarving
e407e65b54 Merge pull request #472 from akva2/add_analysis
added: error analysis support in compareSummary / compareECL
2018-08-15 08:08:47 +02:00
Arne Morten Kvarving
e072365234 added: error analysis support in compareSummary / compareECL
useful for debugging purposes. replaces scripts in opm-simulators
2018-08-14 11:02:56 +02:00
Joakim Hove
070acf4bef Merge pull request #460 from joakim-hove/ACTIONX
Actionx
2018-08-10 20:26:03 +02:00
Joakim Hove
451d52c18a Refactor iteration over Schedule section to for ACTIONX 2018-08-10 11:30:07 +02:00
Joakim Hove
bbb5e27e90 Add basic ACTIONX keyword 2018-08-10 11:29:46 +02:00
Joakim Hove
37ddd82545 Fix typo in keyword defintion 2018-08-10 11:28:52 +02:00
Joakim Hove
3c90adeea9 Remove unused functionality for directory loading of keywords 2018-08-10 11:28:52 +02:00
Joakim Hove
903118736a Remove unused include 2018-08-10 11:28:52 +02:00
Joakim Hove
18a22d8f68 Merge pull request #463 from joakim-hove/restart-cwd
Restart cwd
2018-08-10 11:26:33 +02:00
Atgeirr Flø Rasmussen
46be17cf58 Merge pull request #470 from joakim-hove/set-opm-pack
Add cmake variable $OPM_PACK_COMMAND
2018-08-08 13:26:47 +02:00
Joakim Hove
ce5c617f41 Add cmake variable $OPM_PACK_COMMAND 2018-08-07 22:50:56 +02:00
Joakim Hove
ca1833e6ed Merge pull request #471 from joakim-hove/parse-test-spe9
Add precision property to DeckOutput class - default = 10
2018-08-07 18:45:05 +02:00
Joakim Hove
bb2e5e0370 Add precision property to DeckOutput class - default = 10 2018-08-07 18:44:05 +02:00
Atgeirr Flø Rasmussen
f6cc04a4ab Merge pull request #467 from akva2/remove_deck_assignment_operator
changed: delete assignment operator in Deck class
2018-08-03 14:55:35 +02:00
Arne Morten Kvarving
d6c56982cc Merge pull request #469 from akva2/update_data_with_pr
fixed: allow using update_data with a opm-tests PR
2018-08-03 12:58:44 +02:00
Arne Morten Kvarving
ee6fab7395 Merge pull request #468 from akva2/strip_test_prefix
added: strip test_ prefix from tests added with opm_add_test
2018-08-03 12:08:15 +02:00
Arne Morten Kvarving
93b8d26f86 fixed: allow using update_data with a opm-tests PR
the update_data command needs a full opm-tests checkout,
not just a shallow clone of the PR branch. we thus first
copy the shared copy, then we pull the PR branch into that copy.
2018-08-03 10:19:08 +02:00
Arne Morten Kvarving
0627a9f8ef added: strip test_ prefix from tests added with opm_add_test 2018-08-03 09:58:59 +02:00
Arne Morten Kvarving
3c88335852 changed: delete assignment operator in Deck class 2018-08-01 13:37:21 +02:00
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
Joakim Hove
4502333751 Ensure that path to restart file is interpreted relative to DATAFILE 2018-07-20 22:11:12 +02:00
Joakim Hove
64e5d123a2 Deck will internalize path to datafile 2018-07-19 08:20:04 +02:00
Joakim Hove
f80644b616 Remove special case for Travis 2018-07-19 06:44:20 +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
220 changed files with 30863 additions and 4579 deletions

View File

@@ -23,19 +23,25 @@ macro (dir_hook)
endmacro (dir_hook)
# We need to define this variable in the installed cmake config file.
set(OPM_PROJECT_EXTRA_CODE_INSTALLED "set(OPM_MACROS_ROOT ${CMAKE_INSTALL_PREFIX}/share/opm)
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)")
set(OPM_PROJECT_EXTRA_CODE_INSTALLED "#ENABLE_ECL_INPUT is needed by opm-common-prereq.cmake
set(ENABLE_ECL_INPUT ${ENABLE_ECL_INPUT})
set(OPM_MACROS_ROOT ${CMAKE_INSTALL_PREFIX}/share/opm)
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)
include(OpmPackage) #Make macros availabe after find_package(opm-common)")
set(OPM_PROJECT_EXTRA_CODE_INTREE "set(OPM_MACROS_ROOT ${OPM_MACROS_ROOT})
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)")
set(OPM_PROJECT_EXTRA_CODE_INTREE "#ENABLE_ECL_INPUT is needed by opm-common-prereq.cmake
set(ENABLE_ECL_INPUT ${ENABLE_ECL_INPUT})
set(OPM_MACROS_ROOT ${OPM_MACROS_ROOT})
list(APPEND CMAKE_MODULE_PATH \${OPM_MACROS_ROOT}/cmake/Modules)
include(OpmPackage) #Make macros availabe after find_package(opm-common)")
if(ENABLE_ECL_OUTPUT)
set(OPM_PROJECT_EXTRA_CODE_INSTALLED "${OPM_PROJECT_EXTRA_CODE_INSTALLED}
set(COMPARE_SUMMARY_COMMAND ${CMAKE_INSTALL_PREFIX}/bin${${name}_VER_DIR}/compareSummary)
set(COMPARE_ECL_COMMAND ${CMAKE_INSTALL_PREFIX}/bin${${name}_VER_DIR}/compareECL)")
set(COMPARE_ECL_COMMAND ${CMAKE_INSTALL_PREFIX}/bin${${name}_VER_DIR}/compareECL)
set(OPM_PACK_COMMAND ${CMAKE_INSTALL_PREFIX}/bin${${name}_VER_DIR}/opmpack)")
set(OPM_PROJECT_EXTRA_CODE_INTREE "${OPM_PROJECT_EXTRA_CODE_INTREE}
set(COMPARE_SUMMARY_COMMAND ${PROJECT_BINARY_DIR}/bin/compareSummary)
set(COMPARE_ECL_COMMAND ${PROJECT_BINARY_DIR}/bin/compareECL)")
set(COMPARE_ECL_COMMAND ${PROJECT_BINARY_DIR}/bin/compareECL)
set(OPM_PACK_COMMAND ${PROJECT_BINARY_DIR}/bin/opmpack)")
endif()
# project information is in dune.module. Read this file and set variables.
@@ -124,5 +130,37 @@ endmacro (install_hook)
# all setup common to the OPM library modules is done here
include (OpmLibMain)
# Build the compare utilities
if(ENABLE_ECL_INPUT)
add_library(testutil STATIC
examples/test_util/EclFilesComparator.cpp
examples/test_util/EclIntegrationTest.cpp
examples/test_util/EclRegressionTest.cpp
examples/test_util/summaryComparator.cpp
examples/test_util/summaryIntegrationTest.cpp
examples/test_util/summaryRegressionTest.cpp)
target_link_libraries(testutil ecl)
add_executable(compareECL examples/test_util/compareECL.cpp)
target_link_libraries(compareECL testutil opmcommon)
# Add the tests
set(_libs testutil opmcommon
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
opm_add_test(test_compareSummary CONDITION ENABLE_ECL_INPUT
LIBRARIES ${_libs})
opm_add_test(test_EclFilesComparator CONDITION ENABLE_ECL_INPUT
LIBRARIES ${_libs})
if(HAVE_DYNAMIC_BOOST_TEST)
set_target_properties(test_compareSummary PROPERTIES
COMPILE_DEFINITIONS BOOST_TEST_DYN_LINK)
set_target_properties(test_EclFilesComparator PROPERTIES
COMPILE_DEFINITIONS BOOST_TEST_DYN_LINK)
endif()
install(TARGETS compareECL DESTINATION bin)
endif()
# Install build system files
install(DIRECTORY cmake DESTINATION share/opm)
# Install tab completion skeleton
install(FILES etc/opm_bash_completion.sh.in DESTINATION share/opm/etc)

View File

@@ -73,16 +73,17 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp
src/opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.cpp
src/opm/parser/eclipse/EclipseState/Runspec.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Completion.cpp
src/opm/parser/eclipse/EclipseState/Schedule/CompletionSet.cpp
src/opm/parser/eclipse/EclipseState/Schedule/ActionX.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Connection.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellConnections.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Events.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group.cpp
src/opm/parser/eclipse/EclipseState/Schedule/GroupTree.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MessageLimits.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MSW/updatingConnectionsWithSegments.cpp
src/opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp
src/opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.cpp
@@ -93,6 +94,8 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/Schedule/WellInjectionProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.cpp
src/opm/parser/eclipse/EclipseState/Schedule/WellTestState.cpp
src/opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.cpp
src/opm/parser/eclipse/EclipseState/SimulationConfig/ThresholdPressure.cpp
src/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp
@@ -132,17 +135,28 @@ if(ENABLE_ECL_INPUT)
endif()
if(ENABLE_ECL_OUTPUT)
list( APPEND MAIN_SOURCE_FILES
src/opm/test_util/summaryIntegrationTest.cpp
src/opm/test_util/summaryRegressionTest.cpp
src/opm/test_util/summaryComparator.cpp
src/opm/test_util/EclFilesComparator.cpp
src/opm/output/eclipse/AggregateConnectionData.cpp
src/opm/output/eclipse/AggregateGroupData.cpp
src/opm/output/eclipse/AggregateMSWData.cpp
src/opm/output/eclipse/AggregateWellData.cpp
src/opm/output/eclipse/CreateDoubHead.cpp
src/opm/output/eclipse/CreateInteHead.cpp
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/libECLRestart.cpp
src/opm/output/eclipse/LinearisedOutputTable.cpp
src/opm/output/eclipse/LoadRestart.cpp
src/opm/output/eclipse/LogiHEAD.cpp
src/opm/output/eclipse/RestartIO.cpp
src/opm/output/eclipse/Summary.cpp
src/opm/output/eclipse/SummaryState.cpp
src/opm/output/eclipse/Tables.cpp
src/opm/output/eclipse/RegionCache.cpp
src/opm/output/eclipse/RestartValue.cpp
src/opm/output/data/Solution.cpp
)
endif()
@@ -161,13 +175,14 @@ list (APPEND TEST_SOURCE_FILES
)
if(ENABLE_ECL_INPUT)
list(APPEND TEST_SOURCE_FILES
tests/parser/ACTIONX.cpp
tests/parser/ADDREGTests.cpp
tests/parser/AquiferCTTests.cpp
tests/parser/AqudimsTests.cpp
tests/parser/AquanconTests.cpp
tests/parser/BoxTests.cpp
tests/parser/ColumnSchemaTests.cpp
tests/parser/CompletionTests.cpp
tests/parser/ConnectionTests.cpp
tests/parser/COMPSEGUnits.cpp
tests/parser/CopyRegTests.cpp
tests/parser/DeckTests.cpp
@@ -216,22 +231,29 @@ if(ENABLE_ECL_INPUT)
tests/parser/UnitTests.cpp
tests/parser/ValueTests.cpp
tests/parser/WellSolventTests.cpp
tests/parser/WellTests.cpp)
tests/parser/WellTests.cpp
tests/parser/WTEST.cpp)
endif()
if(ENABLE_ECL_OUTPUT)
list (APPEND TEST_SOURCE_FILES
tests/test_compareSummary.cpp
tests/test_EclFilesComparator.cpp
tests/test_AggregateWellData.cpp
tests/test_CharArrayNullTerm.cpp
tests/test_EclipseIO.cpp
tests/test_DoubHEAD.cpp
tests/test_InteHEAD.cpp
tests/test_LinearisedOutputTable.cpp
tests/test_LogiHEAD.cpp
tests/test_regionCache.cpp
tests/test_Restart.cpp
tests/test_RFT.cpp
tests/test_Solution.cpp
tests/test_Summary.cpp
tests/test_Tables.cpp
tests/test_Wells.cpp
tests/test_WindowedArray.cpp
tests/test_writenumwells.cpp
tests/test_Solution.cpp
tests/test_regionCache.cpp
tests/test_serialize_ICON.cpp
tests/test_serialize_SCON.cpp
)
endif()
@@ -241,6 +263,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
@@ -248,6 +271,8 @@ if(ENABLE_ECL_OUTPUT)
tests/table_deck.DATA
tests/summary_deck_non_constant_porosity.DATA
tests/SUMMARY_EFF_FAC.DATA
tests/SPE1CASE1.DATA
tests/SPE9_CP_PACKED.DATA
)
endif()
@@ -256,14 +281,9 @@ list (APPEND EXAMPLE_SOURCE_FILES
if(ENABLE_ECL_INPUT)
list (APPEND EXAMPLE_SOURCE_FILES
examples/opmi.cpp
examples/opmpack.cpp
)
endif()
if(ENABLE_ECL_OUTPUT)
list(APPEND EXAMPLE_SOURCE_FILES
examples/test_util/compareECL.cpp
examples/test_util/compareSummary.cpp
)
endif()
# programs listed here will not only be compiled, but also marked for
# installation
@@ -272,14 +292,9 @@ list (APPEND PROGRAM_SOURCE_FILES
if(ENABLE_ECL_INPUT)
list (APPEND PROGRAM_SOURCE_FILES
examples/opmi.cpp
examples/opmpack.cpp
)
endif()
if(ENABLE_ECL_OUTPUT)
list(APPEND PROGRAM_SOURCE_FILES
examples/test_util/compareECL.cpp
examples/test_util/compareSummary.cpp
)
endif()
list( APPEND PUBLIC_HEADER_FILES
opm/common/ErrorMacros.hpp
@@ -419,6 +434,7 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/EclipseConfig.hpp
opm/parser/eclipse/EclipseState/Aquancon.hpp
opm/parser/eclipse/EclipseState/AquiferCT.hpp
opm/parser/eclipse/EclipseState/Schedule/ActionX.hpp
opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp
opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.hpp
opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.hpp
@@ -435,13 +451,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 +483,33 @@ 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/connection.hpp
opm/output/eclipse/VectorItems/intehead.hpp
opm/output/eclipse/VectorItems/well.hpp
opm/output/eclipse/AggregateGroupData.hpp
opm/output/eclipse/AggregateConnectionData.hpp
opm/output/eclipse/AggregateMSWData.hpp
opm/output/eclipse/AggregateWellData.hpp
opm/output/eclipse/CharArrayNullTerm.hpp
opm/output/eclipse/DoubHEAD.hpp
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/libECLRestart.hpp
opm/output/eclipse/LinearisedOutputTable.hpp
opm/output/eclipse/LogiHEAD.hpp
opm/output/eclipse/RegionCache.hpp
opm/output/eclipse/RestartIO.hpp
opm/output/eclipse/RestartValue.hpp
opm/output/eclipse/Summary.hpp
opm/output/eclipse/SummaryState.hpp
opm/output/eclipse/Tables.hpp
opm/output/eclipse/RegionCache.hpp
opm/output/data/Solution.hpp
opm/test_util/EclFilesComparator.hpp
opm/test_util/summaryRegressionTest.hpp
opm/test_util/summaryComparator.hpp)
opm/output/eclipse/WindowedArray.hpp
opm/output/eclipse/WriteRestartHelpers.hpp
opm/output/OutputWriter.hpp
)
endif()

21
CopyHeaders.cmake Normal file
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

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

View File

@@ -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

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

View File

@@ -47,7 +47,7 @@ macro (opm_defaults opm)
endif(NOT PRECOMPILE_HEADERS)
# Use of OpenMP is considered experimental
set (USE_OPENMP_DEFAULT OFF)
set (USE_OPENMP_DEFAULT ON)
# if we are on a system where CMake 2.6 is the default (Hi RHEL 6!),
# the configuration files for Boost will trip up the library paths

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

@@ -228,6 +228,13 @@ macro(opm_add_test TestName)
set(CURTEST_EXE_NAME ${TestName})
endif()
# Strip test_ prefix from name
if ("${TestName}" MATCHES "^test_([^/]*)$")
string (REGEX REPLACE "^test_([^/]*)$" "\\1" _FANCY "${TestName}")
else()
set(_FANCY ${TestName})
endif()
# try to auto-detect the name of the source file if SOURCES are not
# explicitly specified.
if (NOT CURTEST_SOURCES)
@@ -331,7 +338,7 @@ macro(opm_add_test TestName)
endif()
endif()
add_test(NAME ${TestName}
add_test(NAME ${_FANCY}
WORKING_DIRECTORY "${CURTEST_WORKING_DIRECTORY}"
COMMAND ${CURTEST_COMMAND})
@@ -359,7 +366,7 @@ macro(opm_add_test TestName)
# CDash dashboard. it this is removed, the test is just silently
# ignored.
if (NOT CURTEST_ONLY_COMPILE AND ADD_DISABLED_CTESTS)
add_test(${TestName} skip_test_dummy)
add_test(${_FANCY} skip_test_dummy)
endif()
endif()
endmacro()

View File

@@ -21,10 +21,28 @@ if (CXX_COMPAT_GCC)
# disabled due to widespread bugs in the linker plugin
option (WHOLE_PROG_OPTIM "Whole program optimization (lto)" OFF)
if (WHOLE_PROG_OPTIM)
check_cxx_accepts_flag ("-flto" HAVE_LINK_OPTS)
if (HAVE_LINK_OPTS)
list (APPEND _opt_flags "-flto")
endif (HAVE_LINK_OPTS)
check_cxx_accepts_flag ("-flto" HAVE_LINK_OPTS)
check_cxx_accepts_flag ("-fuse-linker-plugin" HAVE_LINK_PLUGIN)
if (HAVE_LINK_OPTS)
list (APPEND _opt_flags "-flto")
endif (HAVE_LINK_OPTS)
if (HAVE_LINK_PLUGIN)
list (APPEND _opt_flags "-fuse-linker-plugin")
endif (HAVE_LINK_PLUGIN)
if(HAVE_LINK_OPTS AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
string(REPLACE "." ";" VERSION_LIST "${CMAKE_C_COMPILER_VERSION}")
list(GET VERSION_LIST 0 VER_MAJOR)
find_program(LTO_AR_COMMAND NAMES ${CMAKE_C_COMPILER}-ar gcc-ar-${VER_MAJOR} gcc-ar)
find_program(LTO_RANLIB_COMMAND NAMES ${CMAKE_C_COMPILER}-ranlib gcc-ranlib-${VER_MAJOR} gcc-ranlib)
if(LTO_AR_COMMAND)
set(CMAKE_AR ${LTO_AR_COMMAND})
message(STATUS "Using LTO-enabled ar: ${CMAKE_AR}")
endif()
if(LTO_RANLIB_COMMAND)
set(CMAKE_RANLIB ${LTO_RANLIB_COMMAND})
message(STATUS "Using LTO-enabled ranlib: ${CMAKE_RANLIB}")
endif()
endif()
endif (WHOLE_PROG_OPTIM)
# native instruction set tuning

View File

@@ -21,20 +21,42 @@
# 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@")
set (@opm-project_NAME@_LIBRARY_DIRS "@opm-project_LIBRARY_DIRS@" "@CMAKE_LIBRARY_OUTPUT_DIRECTORY@")
set (@opm-project_NAME@_LINKER_FLAGS "@opm-project_LINKER_FLAGS@")
set (@opm-project_NAME@_CONFIG_VARS "@opm-project_CONFIG_VARS@")
set (HAVE_@opm-project_NAME_UC@ 1)
# libraries come from the build tree where this file was generated
set (@opm-project_NAME@_LIBRARY "@opm-project_LIBRARY@")
set (@opm-project_NAME@_LIBRARIES ${@opm-project_NAME@_LIBRARY} "@opm-project_LIBRARIES@")
# The purpose of this string replacement operation is to enable use of the
# generated opm-project-config.cmake file also in the situation where 'make
# install' has been invoked with the DESTDIR option:
#
# opm-common/build> cmake .. -DCMAKE_INSTALL_PREFIX=/real/prefix
# opm-common/budil> make install DESTDIR=/tmp/prefix
#
# downstream/build> cmake .. -DDEST_PREFIX=/tmp/prefix -DCMAKE_PREFIX_PATH=/tmp/prefix
# downstream/build> make install
#
# That way the downstream dependency can still use find_package( opm-common )
# even though the opm-common-config.cmake file is not internally consistent
# with it's own location in the filesystem.
if(DEST_PREFIX)
set(DEST_PREFIX "${DEST_PREFIX}${@opm-project_NAME@_PREFIX}")
string(REPLACE ${@opm-project_NAME@_PREFIX} ${DEST_PREFIX} @opm-project_NAME@_INCLUDE_DIRS "${@opm-project_NAME@_INCLUDE_DIRS}")
string(REPLACE ${@opm-project_NAME@_PREFIX} ${DEST_PREFIX} @opm-project_NAME@_LIBRARY_DIRS "${@opm-project_NAME@_LIBRARY_DIRS}")
string(REPLACE ${@opm-project_NAME@_PREFIX} ${DEST_PREFIX} @opm-project_NAME@_LIBRARY "${@opm-project_NAME@_LIBRARY}")
endif()
set (HAVE_@opm-project_NAME_UC@ 1)
mark_as_advanced (@opm-project_NAME@_LIBRARY)
# not all projects have targets; conditionally add this part
@@ -72,6 +94,17 @@ if(NOT @opm-project_NAME@_FOUND)
# this is the contents of config.h as far as our probes can tell:
# extra code
@OPM_PROJECT_EXTRA_CODE@
# The settings in this block do not mix well with the DEST_PREFIX
# setting.
if (NOT DEST_PREFIX)
# This is required to include OpmPackage
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" @PREREQ_LOCATION@)
# extra code from variable OPM_PROJECT_EXTRA_CODE
@OPM_PROJECT_EXTRA_CODE@
# end extra code
include(@opm-project_NAME@-prereqs)
endif()
endif()

2
debian/changelog vendored
View File

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

View File

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

View File

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

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

@@ -0,0 +1,32 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEVIATION_HPP
#define DEVIATION_HPP
/*! \brief Deviation struct.
\details The member variables are default initialized to -1,
which is an invalid deviation value.
*/
struct Deviation {
double abs = -1; //!< Absolute deviation
double rel = -1; //!< Relative deviation
};
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,11 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/test_util/EclFilesComparator.hpp>
#include "EclIntegrationTest.hpp"
#include "EclRegressionTest.hpp"
#include "summaryIntegrationTest.hpp"
#include "summaryRegressionTest.hpp"
#include <opm/common/ErrorMacros.hpp>
#include <ert/util/util.h>
@@ -29,32 +33,40 @@
#include <getopt.h>
static void printHelp() {
std::cout << "\ncompareECL compares ECLIPSE files (restart (.RST), unified restart (.UNRST), initial (.INIT) or .RFT) and gridsizes (from .EGRID or .GRID file) from two simulations.\n"
std::cout << "\ncompareECL compares ECLIPSE files (restart (.RST), unified restart (.UNRST), initial (.INIT), summary (.SMRY), unified summary (.UNSMRY) or .RFT) and gridsizes (from .EGRID or .GRID file) from two simulations.\n"
<< "The program takes four arguments:\n\n"
<< "1. Case number 1 (full path without extension)\n"
<< "2. Case number 2 (full path without extension)\n"
<< "3. Absolute tolerance\n"
<< "4. Relative tolerance (between 0 and 1)\n\n"
<< "In addition, the program takes these options (which must be given before the arguments):\n\n"
<< "-a Run a full analysis of errors.\n"
<< "-g Will print the vector with the greatest error ratio.\n"
<< "-h Print help and exit.\n"
<< "-i Execute integration test (regression test is default).\n"
<< " The integration test compares SGAS, SWAT and PRESSURE in unified restart files, so this option can not be used in combination with -t.\n"
<< "-I Same as -i, but throws an exception when the number of keywords in the two cases differ. Can not be used in combination with -t.\n"
<< "-k Specify specific keyword to compare (capitalized), for example -k PRESSURE.\n"
<< "-K Will not allow different amount of keywords in the two files. Throws an exception if the amount are different.\n"
<< "-l Only do comparison for the last occurrence. This option is only for the regression test, and can therefore not be used in combination with -i or -I.\n"
<< "-m mainVar. Will calculate the error ratio for one main variable. Valid input is WOPR, WWPR, WGPR or WBHP.\n"
<< "-n Do not throw on errors.\n"
<< "-p Print keywords in both cases and exit. Can not be used in combination with -P.\n"
<< "-P Print common and uncommon keywords in both cases and exit. Can not be used in combination with -p.\n"
<< "-R Will allow comparison between a restarted simulation and a normal simulation for summary regression tests. The files must end at the same time.\n"
<< "-s int Sets the number of spikes that are allowed for each keyword in summary integration tests.\n"
<< "-t Specify ECLIPSE filetype to compare (unified restart is default). Can not be used in combination with -i or -I. Different possible arguments are:\n"
<< " -t UNRST \t Compare two unified restart files (.UNRST). This the default value, so it is the same as not passing option -t.\n"
<< " -t INIT \t Compare two initial files (.INIT).\n"
<< " -t RFT \t Compare two RFT files (.RFT).\n"
<< " -t RST \t Compare two cases consisting of restart files (.Xnnnn).\n"
<< " -t SMRY \t Compare two cases consistent of (unified) summary files.\n"
<< " -t RST1 \t Compare two cases where the first case consists of restart files (.Xnnnn), and the second case consists of a unified restart file (.UNRST).\n"
<< " -t RST2 \t Compare two cases where the first case consists of a unified restart file (.UNRST), and the second case consists of restart files (.Xnnnn).\n"
<< " Note that when dealing with restart files (.Xnnnn), the program concatenates all of them into one unified restart file, which is used for comparison and stored in the same directory as the restart files.\n"
<< " This will overwrite any existing unified restart file in that directory.\n\n"
<< "Example usage of the program: \n\n"
<< "-v For the rate keywords WOPR, WGPR, WWPR and WBHP. Calculates the error volume of the two summary files. This is printed to screen.\n"
<< "\nExample usage of the program: \n\n"
<< "compareECL -k PRESSURE <path to first casefile> <path to second casefile> 1e-3 1e-5\n"
<< "compareECL -t INIT -k PORO <path to first casefile> <path to second casefile> 1e-3 1e-5\n"
<< "compareECL -i <path to first casefile> <path to second casefile> 0.01 1e-6\n\n"
@@ -107,19 +119,37 @@ int main(int argc, char** argv) {
ecl_file_enum file_type = ECL_UNIFIED_RESTART_FILE;
// RegressionTest is default
bool integrationTest = false;
bool allowDifferentAmount = true;
bool checkNumKeywords = false;
bool findGreatestErrorRatio = false;
bool findVolumeError = false;
bool onlyLastOccurrence = false;
bool printKeywords = false;
bool printKeywordsDifference = false;
bool restartFile = false;
bool specificKeyword = false;
bool specificFileType = false;
bool allowSpikes = false;
bool throwOnError = true;
bool throwTooGreatErrorRatio = true;
bool acceptExtraKeywords = false;
bool analysis = false;
bool volumecheck = true;
char* keyword = nullptr;
char* fileTypeCstr = nullptr;
const char* mainVariable = nullptr;
int c = 0;
int spikeLimit = -1;
while ((c = getopt(argc, argv, "hiIk:lnpPt:")) != -1) {
while ((c = getopt(argc, argv, "hiIk:alnpPt:VRgs:m:vKx")) != -1) {
switch (c) {
case 'a':
analysis = true;
break;
case 'g':
findGreatestErrorRatio = true;
throwTooGreatErrorRatio = false;
break;
case 'h':
printHelp();
return 0;
@@ -130,29 +160,51 @@ int main(int argc, char** argv) {
integrationTest = true;
checkNumKeywords = true;
break;
case 'n':
throwOnError = false;
break;
case 'k':
specificKeyword = true;
keyword = optarg;
break;
case 'K':
allowDifferentAmount = false;
break;
case 'l':
onlyLastOccurrence = true;
break;
case 'm':
mainVariable = optarg;
break;
case 'n':
throwOnError = false;
break;
case 'p':
printKeywords = true;
break;
case 'P':
printKeywordsDifference = true;
break;
case 'R':
restartFile = true;
break;
case 's':
allowSpikes = true;
spikeLimit = atof(optarg);
break;
case 't':
specificFileType = true;
fileTypeCstr = optarg;
break;
case 'v':
findVolumeError = true;
break;
case 'V':
volumecheck = false;
break;
case 'x':
acceptExtraKeywords = true;
break;
case '?':
if (optopt == 'k') {
std::cerr << "Option k requires a keyword as argument, see manual (-h) for more information." << std::endl;
if (optopt == 'k' || optopt == 'm' || optopt == 's') {
std::cerr << "Option " << optopt << " requires a keyword as argument, see manual (-h) for more information." << std::endl;
return EXIT_FAILURE;
}
else if (optopt == 't') {
@@ -181,6 +233,7 @@ int main(int argc, char** argv) {
<< "Please run compareECL -h to see manual." << std::endl;
return EXIT_FAILURE;
}
std::string basename1 = argv[argOffset];
std::string basename2 = argv[argOffset + 1];
double absTolerance = strtod(argv[argOffset + 2], nullptr);
@@ -206,15 +259,67 @@ int main(int argc, char** argv) {
else if (fileTypeString == "RFT") {
file_type = ECL_RFT_FILE;
}
else if (fileTypeString == "SMRY")
file_type = ECL_SUMMARY_FILE;
else {
std::cerr << "Unknown ECLIPSE filetype specified with option -t. Please run compareECL -h to see manual." << std::endl;
return EXIT_FAILURE;
}
}
if (restartFile && (file_type != ECL_SUMMARY_FILE || integrationTest)) {
std::cerr << "Error: -R can only be used in for summary regression tests." << std::endl;
return EXIT_FAILURE;
}
std::cout << "Comparing '" << basename1 << "' to '" << basename2 << "'." << std::endl;
try {
if (integrationTest) {
IntegrationTest comparator(basename1, basename2, absTolerance, relTolerance);
if (file_type == ECL_SUMMARY_FILE) {
if(!integrationTest){
SummaryRegressionTest compare(basename1,basename2,absTolerance,relTolerance);
compare.throwOnErrors(throwOnError);
compare.doAnalysis(analysis);
compare.setPrintKeywords(printKeywords);
compare.setIsRestartFile(restartFile);
if(specificKeyword){
compare.getRegressionTest(keyword);
}
else{
compare.setPrintKeywords(printKeywords);
compare.getRegressionTest();
}
} else {
SummaryIntegrationTest compare(basename1,basename2,absTolerance,relTolerance);
compare.throwOnErrors(throwOnError);
compare.setFindVectorWithGreatestErrorRatio(findGreatestErrorRatio);
compare.setAllowSpikes(allowSpikes);
if (mainVariable) {
compare.setOneOfTheMainVariables(true);
std::string str(mainVariable);
std::transform(str.begin(), str.end(),str.begin(), ::toupper);
if(str == "WOPR" ||str=="WWPR" ||str=="WGPR" || str == "WBHP"){
compare.setMainVariable(str);
}else{
throw std::invalid_argument("The input is not a main variable. -m option requires a valid main variable.");
}
}
compare.setFindVolumeError(findVolumeError);
if (spikeLimit != -1) {
compare.setSpikeLimit(spikeLimit);
}
compare.setAllowDifferentAmountOfKeywords(allowDifferentAmount);
compare.setPrintKeywords(printKeywords);
compare.setThrowExceptionForTooGreatErrorRatio(throwTooGreatErrorRatio);
if(specificKeyword){
compare.setPrintSpecificKeyword(specificKeyword);
compare.getIntegrationTest(keyword);
return 0;
}
compare.getIntegrationTest();
}
}
else if (integrationTest) {
ECLIntegrationTest comparator(basename1, basename2, absTolerance, relTolerance);
if (printKeywords) {
comparator.printKeywords();
return 0;
@@ -240,8 +345,10 @@ int main(int argc, char** argv) {
}
}
else {
RegressionTest comparator(file_type, basename1, basename2, absTolerance, relTolerance);
ECLRegressionTest comparator(file_type, basename1, basename2, absTolerance, relTolerance);
comparator.throwOnErrors(throwOnError);
comparator.doAnalysis(analysis);
comparator.setAcceptExtraKeywords(acceptExtraKeywords);
if (printKeywords) {
comparator.printKeywords();
return 0;
@@ -254,11 +361,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

@@ -18,8 +18,8 @@
*/
#include <opm/test_util/summaryRegressionTest.hpp>
#include <opm/test_util/summaryIntegrationTest.hpp>
#include "summaryRegressionTest.hpp"
#include "summaryIntegrationTest.hpp"
#include <string>
#include <algorithm>
#include <stdexcept>
@@ -37,6 +37,7 @@ void printHelp(){
std::cout << "The program is capable of performing both a regression test and an integration test, \nhowever only one type of test at a time. ";
std::cout << "By default the program will run a regression test."<< std::endl;
std::cout << "\nThe program have command line options:" << std::endl;
std::cout << "-a \tRun a full analysis of errors." << std::endl;
std::cout << "-h \t\tPrint help message." << std::endl << std::endl;
std::cout << "For the regression test: " << std::endl;
std::cout << "-r \t\tChoosing regression test (this is default)."<< std::endl;
@@ -80,6 +81,7 @@ int main (int argc, char ** argv){
bool throwExceptionForTooGreatErrorRatio = true;
bool isRestartFile = false;
bool throwOnError = true;
bool analysis = false;
const char* keyword = nullptr;
const char* mainVariable = nullptr;
int c = 0;
@@ -88,8 +90,11 @@ int main (int argc, char ** argv){
//------------------------------------------------
//For setting the options selected
while ((c = getopt(argc, argv, "dghik:Km:npP:rRs:vV:")) != -1) {
while ((c = getopt(argc, argv, "dghik:Km:napP:rRs:vV:")) != -1) {
switch (c) {
case 'a':
analysis = true;
break;
case 'd':
throwExceptionForTooGreatErrorRatio = false;
break;
@@ -175,8 +180,9 @@ int main (int argc, char ** argv){
try {
if(regressionTest){
RegressionTest compare(basename1,basename2, absoluteTolerance, relativeTolerance);
SummaryRegressionTest compare(basename1,basename2, absoluteTolerance, relativeTolerance);
compare.throwOnErrors(throwOnError);
compare.doAnalysis(analysis);
if(printKeywords){compare.setPrintKeywords(true);}
if(isRestartFile){compare.setIsRestartFile(true);}
if(specificKeyword){
@@ -188,7 +194,7 @@ int main (int argc, char ** argv){
}
}
if(integrationTest){
IntegrationTest compare(basename1,basename2, absoluteTolerance, relativeTolerance);
SummaryIntegrationTest compare(basename1,basename2, absoluteTolerance, relativeTolerance);
compare.throwOnErrors(throwOnError);
if(findVectorWithGreatestErrorRatio){compare.setFindVectorWithGreatestErrorRatio(true);}
if(allowSpikes){compare.setAllowSpikes(true);}

View File

@@ -16,7 +16,7 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/test_util/summaryComparator.hpp>
#include "summaryComparator.hpp"
#include <ert/ecl/ecl_sum.h>
#include <ert/util/stringlist.h>
#include <ert/util/int_vector.h>
@@ -25,9 +25,11 @@
#include <cmath>
#include <numeric>
SummaryComparator::SummaryComparator(const char* basename1, const char* basename2, double absoluteTol, double relativeTol){
ecl_sum1 = ecl_sum_fread_alloc_case(basename1, ":");
ecl_sum2 = ecl_sum_fread_alloc_case(basename2, ":");
SummaryComparator::SummaryComparator(const std::string& basename1,
const std::string& basename2,
double absoluteTol, double relativeTol){
ecl_sum1 = ecl_sum_fread_alloc_case(basename1.c_str(), ":");
ecl_sum2 = ecl_sum_fread_alloc_case(basename2.c_str(), ":");
if (ecl_sum1 == nullptr || ecl_sum2 == nullptr) {
OPM_THROW(std::runtime_error, "Not able to open files");
}

View File

@@ -20,8 +20,10 @@
#ifndef SUMMARYCOMPARATOR_HPP
#define SUMMARYCOMPARATOR_HPP
#include "Deviation.hpp"
#include <iostream>
#include <iomanip>
#include <map>
#include <vector>
#include <algorithm>
#include <string>
@@ -46,13 +48,6 @@ struct ecl_sum_struct;
typedef struct ecl_sum_struct ecl_sum_type;
//! \brief Struct for storing the deviation between two values.
struct Deviation {
double abs = 0;//!< The absolute deviation
double rel = 0; //!< The relative deviation
};
class SummaryComparator {
private:
double absoluteTolerance = 0; //!< The maximum absolute deviation that is allowed between two values.
@@ -73,6 +68,8 @@ class SummaryComparator {
bool printKeyword = false; //!< Boolean value for choosing whether to print the keywords or not
bool printSpecificKeyword = false; //!< Boolean value for choosing whether to print the vectors of a keyword or not
bool throwOnError = true; //!< Throw on first error
bool analysis = false; //!< Perform error analysis
std::map<std::string, std::vector<Deviation>> deviations;
//! \brief Calculate deviation between two data values and stores it in a Deviation struct.
//! \param[in] refIndex Index in reference data
@@ -142,7 +139,9 @@ class SummaryComparator {
//! \param[in] absoluteTolerance The absolute tolerance which is to be used in the test.
//! \param[in] relativeTolerance The relative tolerance which is to be used in the test.
//! \details The constructor creates an object of the class, and openes the files, an exception is thrown if the opening of the files fails. \n It creates stringlists, in which keywords are to be stored, and figures out which keylist that contains the more/less keywords. \n Also the private member variables aboluteTolerance and relativeTolerance are set.
SummaryComparator(const char* basename1, const char* basename2, double absoluteTolerance, double relativeTolerance);
SummaryComparator(const std::string& basename1,
const std::string& basename2,
double absoluteTolerance, double relativeTolerance);
//! \brief Destructor
//! \details The destructor takes care of the allocated memory in which data has been stored.
@@ -175,6 +174,9 @@ class SummaryComparator {
//! \brief Set whether to throw on errors or not.
void throwOnErrors(bool dothrow) { throwOnError = dothrow; }
//! \brief Set whether or not to perform error analysis.
void doAnalysis(bool analyse) { analysis = analyse; }
};
#endif

View File

@@ -17,14 +17,14 @@
*/
#include <opm/test_util/summaryIntegrationTest.hpp>
#include "summaryIntegrationTest.hpp"
#include <opm/common/ErrorMacros.hpp>
#include <ert/ecl/ecl_sum.h>
#include <ert/util/stringlist.h>
#include <cmath>
void IntegrationTest::getIntegrationTest(){
void SummaryIntegrationTest::getIntegrationTest(){
std::vector<double> timeVec1, timeVec2;
setTimeVecs(timeVec1, timeVec2); // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
setDataSets(timeVec1, timeVec2);
@@ -89,7 +89,7 @@ void IntegrationTest::getIntegrationTest(){
}
void IntegrationTest::getIntegrationTest(const char* keyword){
void SummaryIntegrationTest::getIntegrationTest(const char* keyword){
if(stringlist_contains(keysShort,keyword) && stringlist_contains(keysLong, keyword)){
std::vector<double> timeVec1, timeVec2;
setTimeVecs(timeVec1, timeVec2); // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
@@ -115,9 +115,9 @@ void IntegrationTest::getIntegrationTest(const char* keyword){
}
void IntegrationTest::checkForKeyword(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const char* keyword){
void SummaryIntegrationTest::checkForKeyword(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const char* keyword){
std::vector<double> dataVec1, dataVec2;
getDataVecs(dataVec1,dataVec2,keyword);
chooseReference(timeVec1, timeVec2,dataVec1,dataVec2);
@@ -130,7 +130,7 @@ void IntegrationTest::checkForKeyword(const std::vector<double>& timeVec1,
}
int IntegrationTest::checkDeviation(const Deviation& deviation){
int SummaryIntegrationTest::checkDeviation(const Deviation& deviation){
double absTol = getAbsTolerance();
double relTol = getRelTolerance();
if (deviation.rel> relTol && deviation.abs > absTol){
@@ -140,10 +140,10 @@ int IntegrationTest::checkDeviation(const Deviation& deviation){
}
void IntegrationTest::findGreatestErrorRatio(const WellProductionVolume& volume,
double &greatestRatio,
const char* currentKeyword,
std::string &greatestErrorRatio){
void SummaryIntegrationTest::findGreatestErrorRatio(const WellProductionVolume& volume,
double &greatestRatio,
const char* currentKeyword,
std::string &greatestErrorRatio){
if (volume.total != 0 && (volume.total - volume.error > getAbsTolerance()) ){
if(volume.error/volume.total > greatestRatio){
greatestRatio = volume.error/volume.total;
@@ -154,7 +154,7 @@ void IntegrationTest::findGreatestErrorRatio(const WellProductionVolume& volume,
}
void IntegrationTest::volumeErrorCheck(const char* keyword){
void SummaryIntegrationTest::volumeErrorCheck(const char* keyword){
const smspec_node_type * node = ecl_sum_get_general_var_node (ecl_sum_fileShort ,keyword);//doesn't matter which ecl_sum_file one uses, the kewyord SHOULD be equal in terms of smspec data.
bool hist = smspec_node_is_historical(node);
/* returns true if the keyword corresponds to a summary vector "history".
@@ -199,7 +199,7 @@ void IntegrationTest::volumeErrorCheck(const char* keyword){
}
void IntegrationTest::updateVolumeError(const char* keyword){
void SummaryIntegrationTest::updateVolumeError(const char* keyword){
std::string keywordString(keyword);
std::string firstFour = keywordString.substr(0,4);
@@ -223,7 +223,7 @@ void IntegrationTest::updateVolumeError(const char* keyword){
}
WellProductionVolume IntegrationTest::getWellProductionVolume(const char * keyword){
WellProductionVolume SummaryIntegrationTest::getWellProductionVolume(const char * keyword){
double total = integrate(*referenceVec, *referenceDataVec);
double error = integrateError(*referenceVec, *referenceDataVec,
*checkVec, *checkDataVec);
@@ -239,7 +239,7 @@ WellProductionVolume IntegrationTest::getWellProductionVolume(const char * keywo
}
void IntegrationTest::evaluateWellProductionVolume(){
void SummaryIntegrationTest::evaluateWellProductionVolume(){
if(mainVariable.empty()){
double ratioWOP, ratioWWP, ratioWGP, ratioWBHP;
ratioWOP = WOP.error/WOP.total;
@@ -266,7 +266,7 @@ void IntegrationTest::evaluateWellProductionVolume(){
}
void IntegrationTest::checkWithSpikes(const char* keyword){
void SummaryIntegrationTest::checkWithSpikes(const char* keyword){
int errorOccurrences = 0;
size_t jvar = 0 ;
bool spikeCurrent = false;
@@ -295,9 +295,9 @@ void IntegrationTest::checkWithSpikes(const char* keyword){
WellProductionVolume
IntegrationTest::getSpecificWellVolume(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const char* keyword){
SummaryIntegrationTest::getSpecificWellVolume(const std::vector<double>& timeVec1,
const std::vector<double>& timeVec2,
const char* keyword){
std::vector<double> dataVec1, dataVec2;
getDataVecs(dataVec1,dataVec2,keyword);
chooseReference(timeVec1, timeVec2,dataVec1,dataVec2);
@@ -305,20 +305,8 @@ IntegrationTest::getSpecificWellVolume(const std::vector<double>& timeVec1,
}
#if 0
bool IntegrationTest::checkUnits(const char * keyword){
const smspec_node_type * node1 = ecl_sum_get_general_var_node (ecl_sum_fileShort ,keyword);
const smspec_node_type * node2 = ecl_sum_get_general_var_node (ecl_sum_fileLong ,keyword);
if(strcmp(smspec_node_get_unit(node1),smspec_node_get_unit(node2)) == 0){
return true;
}
return false;
}
#endif
double IntegrationTest::integrate(const std::vector<double>& timeVec,
const std::vector<double>& dataVec){
double SummaryIntegrationTest::integrate(const std::vector<double>& timeVec,
const std::vector<double>& dataVec){
double totalSum = 0;
if(timeVec.size() != dataVec.size()){
OPM_THROW(std::runtime_error, "The size of the time vector does not match the size of the data vector.");
@@ -332,10 +320,10 @@ double IntegrationTest::integrate(const std::vector<double>& timeVec,
}
double IntegrationTest::integrateError(const std::vector<double>& timeVec1,
const std::vector<double>& dataVec1,
const std::vector<double>& timeVec2,
const std::vector<double>& dataVec2){
double SummaryIntegrationTest::integrateError(const std::vector<double>& timeVec1,
const std::vector<double>& dataVec1,
const std::vector<double>& timeVec2,
const std::vector<double>& dataVec2){
// When the data corresponds to a rate the integration will become a Riemann
// sum. This function calculates the Riemann sum of the error. The reason why
// a Riemann sum is used is because of the way the data is written to file.

View File

@@ -17,7 +17,7 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/test_util/summaryComparator.hpp>
#include "summaryComparator.hpp"
//! \brief Struct for storing the total area under a graph.
//! \details Used when plotting summary vector against time. In most cases this represents a volume.
@@ -35,7 +35,7 @@ struct WellProductionVolume{
};
//! \details The class inherits from the SummaryComparator class, which takes care of all file reading. \n The IntegrationTest class compares values from the two different files and throws exceptions when the deviation is unsatisfying.
class IntegrationTest: public SummaryComparator {
class SummaryIntegrationTest: public SummaryComparator {
private:
bool allowSpikes = false; //!< Boolean value, when true checkForSpikes is included as a sub test in the integration test. By default: false.
bool findVolumeError = false; //!< Boolean value, when true volumeErrorCheck() is included as a sub test in the integration test. By default: false.
@@ -124,8 +124,9 @@ class IntegrationTest: public SummaryComparator {
//! \param[in] atol The absolute tolerance which is to be used in the test.
//! \param[in] rtol The relative tolerance which is to be used in the test.
//! \details The constructor calls the constructor of the super class.
IntegrationTest(const char* basename1, const char* basename2,
double atol, double rtol) :
SummaryIntegrationTest(const std::string& basename1,
const std::string& basename2,
double atol, double rtol) :
SummaryComparator(basename1, basename2, atol, rtol) {}
//! \brief This function sets the private member variable allowSpikes.

View File

@@ -16,13 +16,13 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/test_util/summaryRegressionTest.hpp>
#include "summaryRegressionTest.hpp"
#include <opm/common/ErrorMacros.hpp>
#include <ert/ecl/ecl_sum.h>
#include <ert/util/stringlist.h>
#include <string>
void RegressionTest::getRegressionTest(){
void SummaryRegressionTest::getRegressionTest(){
std::vector<double> timeVec1, timeVec2;
setTimeVecs(timeVec1, timeVec2); // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
setDataSets(timeVec1, timeVec2); //Figures which dataset that contains more/less values pr keyword vector.
@@ -72,15 +72,39 @@ void RegressionTest::getRegressionTest(){
}
ivar++;
}
if (analysis) {
std::cout << deviations.size() << " summary keyword"
<< (deviations.size() > 1 ? "s":"") << " exhibit failures" << std::endl;
size_t len = ecl_sum_get_data_length(ecl_sum1);
for (const auto& iter : deviations) {
std::cout << "\t" << iter.first << std::endl;
std::cout << "\t\tFails for " << iter.second.size() << " / " << len << " steps." << std::endl;
std::cout.precision(7);
double absErr = std::max_element(iter.second.begin(), iter.second.end(),
[](const Deviation& a, const Deviation& b)
{
return a.abs < b.abs;
})->abs;
double relErr = std::max_element(iter.second.begin(), iter.second.end(),
[](const Deviation& a, const Deviation& b)
{
return a.rel < b.rel;
})->rel;
std::cout << "\t\tLargest absolute error: "
<< std::scientific << absErr << std::endl;
std::cout << "\t\tLargest relative error: "
<< std::scientific << relErr << std::endl;
}
}
if (throwAtEnd)
OPM_THROW(std::runtime_error, "Regression test failed.");
else
else if (deviations.empty())
std::cout << "Regression test succeeded." << std::endl;
}
void RegressionTest::getRegressionTest(const char* keyword){
void SummaryRegressionTest::getRegressionTest(const char* keyword){
std::vector<double> timeVec1, timeVec2;
setTimeVecs(timeVec1, timeVec2); // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
setDataSets(timeVec1, timeVec2); //Figures which dataset that contains more/less values pr keyword vector.
@@ -102,18 +126,22 @@ void RegressionTest::getRegressionTest(const char* keyword){
bool RegressionTest::checkDeviation(Deviation deviation, const char* keyword, int refIndex, int checkIndex){
bool SummaryRegressionTest::checkDeviation(Deviation deviation, const char* keyword, int refIndex, int checkIndex){
double absTol = getAbsTolerance();
double relTol = getRelTolerance();
if (deviation.rel > relTol && deviation.abs > absTol){
std::cout << "For keyword " << keyword << std::endl;
std::cout << "(days, reference value) and (days, check value) = (" << (*referenceVec)[refIndex] << ", " << (*referenceDataVec)[refIndex]
<< ") and (" << (*checkVec)[checkIndex-1] << ", " << (*checkDataVec)[checkIndex-1] << ")\n";
// -1 in [checkIndex -1] because checkIndex is updated after leaving getDeviation function
std::cout << "The absolute deviation is " << deviation.abs << ". The tolerance limit is " << absTol << std::endl;
std::cout << "The relative deviation is " << deviation.rel << ". The tolerance limit is " << relTol << std::endl;
HANDLE_ERROR(std::runtime_error, "Deviation exceed the limit.");
if (analysis) {
deviations[keyword].push_back(deviation);
} else {
std::cout << "For keyword " << keyword << std::endl;
std::cout << "(days, reference value) and (days, check value) = (" << (*referenceVec)[refIndex] << ", " << (*referenceDataVec)[refIndex]
<< ") and (" << (*checkVec)[checkIndex-1] << ", " << (*checkDataVec)[checkIndex-1] << ")\n";
// -1 in [checkIndex -1] because checkIndex is updated after leaving getDeviation function
std::cout << "The absolute deviation is " << deviation.abs << ". The tolerance limit is " << absTol << std::endl;
std::cout << "The relative deviation is " << deviation.rel << ". The tolerance limit is " << relTol << std::endl;
HANDLE_ERROR(std::runtime_error, "Deviation exceed the limit.");
}
return false;
}
return true;
@@ -121,7 +149,7 @@ bool RegressionTest::checkDeviation(Deviation deviation, const char* keyword, in
bool RegressionTest::checkForKeyword(std::vector<double>& timeVec1, std::vector<double>& timeVec2, const char* keyword){
bool SummaryRegressionTest::checkForKeyword(std::vector<double>& timeVec1, std::vector<double>& timeVec2, const char* keyword){
std::vector<double> dataVec1, dataVec2;
getDataVecs(dataVec1,dataVec2,keyword);
chooseReference(timeVec1, timeVec2,dataVec1,dataVec2);
@@ -130,7 +158,7 @@ bool RegressionTest::checkForKeyword(std::vector<double>& timeVec1, std::vector<
bool RegressionTest::startTest(const char* keyword){
bool SummaryRegressionTest::startTest(const char* keyword){
size_t jvar = 0;
Deviation deviation;
bool result = true;

View File

@@ -20,10 +20,10 @@
#ifndef SUMMARYREGRESSIONTEST_HPP
#define SUMMARYREGRESSIONTEST_HPP
#include <opm/test_util/summaryComparator.hpp>
#include "summaryComparator.hpp"
//! \details The class inherits from the SummaryComparator class, which takes care of all file reading. \n The RegressionTest class compares the values from the two different files and throws exceptions when the deviation is unsatisfying.
class RegressionTest: public SummaryComparator {
class SummaryRegressionTest: public SummaryComparator {
private:
//! \brief Gathers the correct data for comparison for a specific keyword
//! \param[in] timeVec1 The time steps of file 1.
@@ -55,7 +55,9 @@ class RegressionTest: public SummaryComparator {
//! \param[in] relativeTol The relative tolerance which is to be used in the test.
//! \param[in] absoluteTol The absolute tolerance which is to be used in the test.
//! \details The constructor calls the constructor of the super class.
RegressionTest(const char* basename1, const char* basename2, double relativeTol, double absoluteTol):
SummaryRegressionTest(const std::string& basename1,
const std::string& basename2,
double relativeTol, double absoluteTol) :
SummaryComparator(basename1, basename2, relativeTol, absoluteTol) {}
//! \details The function executes a regression test for all the keywords. If the two files do not match in amount of keywords, an exception is thrown.

View File

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

View File

@@ -16,9 +16,14 @@ then
cp $OPM_TESTS_ROOT_PREDEFINED $WORKSPACE/deps/opm-tests -R
fi
else
# Specified in trigger, download it
source $WORKSPACE/deps/opm-common/jenkins/build-opm-module.sh
clone_module opm-tests $OPM_TESTS_REVISION
# We need a full repo checkout
cp $OPM_TESTS_ROOT_PREDEFINED $WORKSPACE/deps/opm-tests -R
pushd $WORKSPACE/deps/opm-tests
# Then we fetch the PR branch
git remote add PR https://github.com/OPM/opm-tests
git fetch --depth 1 PR $OPM_TESTS_REVISION:branch_to_build
git checkout branch_to_build
popd
fi
else
if ! test -d $WORKSPACE/deps/opm-tests

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,75 @@
/*
Copyright (c) 2018 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_AGGREGATE_CONNECTION_DATA_HPP
#define OPM_AGGREGATE_CONNECTION_DATA_HPP
#include <opm/output/eclipse/WindowedArray.hpp>
#include <cstddef>
#include <string>
#include <vector>
namespace Opm {
class EclipseGrid;
class Schedule;
class UnitSystem;
} // Opm
namespace Opm { namespace data {
class WellRates;
}}
namespace Opm { namespace RestartIO { namespace Helpers {
class AggregateConnectionData
{
public:
explicit AggregateConnectionData(const std::vector<int>& inteHead);
void captureDeclaredConnData(const Opm::Schedule& sched,
const Opm::EclipseGrid& grid,
const Opm::UnitSystem& units,
const Opm::data::WellRates& xw,
const std::size_t sim_step);
const std::vector<int>& getIConn() const
{
return this->iConn_.data();
}
const std::vector<float>& getSConn() const
{
return this->sConn_.data();
}
const std::vector<double>& getXConn() const
{
return this->xConn_.data();
}
private:
WindowedMatrix<int> iConn_;
WindowedMatrix<float> sConn_;
WindowedMatrix<double> xConn_;
};
}}} // Opm::RestartIO::Helpers
#endif // OPM_AGGREGATE_CONNECTION_DATA_HPP

View File

@@ -0,0 +1,159 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_AGGREGATE_GROUP_DATA_HPP
#define OPM_AGGREGATE_GROUP_DATA_HPP
#include <opm/output/eclipse/CharArrayNullTerm.hpp>
#include <opm/output/eclipse/WindowedArray.hpp>
#include <cstddef>
#include <string>
#include <vector>
#include <map>
namespace Opm {
class Schedule;
class SummaryState;
class Group;
} // Opm
namespace Opm { namespace RestartIO { namespace Helpers {
class groupMaps {
public:
const std::map <size_t, const Opm::Group*>& indexGroupMap() const;
const std::map <const std::string, size_t>& groupNameIndexMap() const;
void currentGrpTreeNameSeqIndMap(const Opm::Schedule& sched,
const size_t simStep,
const std::map<const std::string , size_t>& GnIMap,
const std::map<size_t, const Opm::Group*>& IGMap);
private:
std::map <size_t, const Opm::Group*> m_indexGroupMap;
std::map <const std::string, size_t> m_groupNameIndexMap;
};
class AggregateGroupData
{
public:
explicit AggregateGroupData(const std::vector<int>& inteHead);
void captureDeclaredGroupData(const Opm::Schedule& sched,
const std::vector<std::string>& restart_group_keys,
const std::vector<std::string>& restart_field_keys,
const std::map<std::string, size_t>& groupKeyToIndex,
const std::map<std::string, size_t>& fieldKeyToIndex,
const bool ecl_compatible_rst,
const std::size_t simStep,
const Opm::SummaryState& sumState,
const std::vector<int>& inteHead);
const std::vector<int>& getIGroup() const
{
return this->iGroup_.data();
}
const std::vector<float>& getSGroup() const
{
return this->sGroup_.data();
}
const std::vector<double>& getXGroup() const
{
return this->xGroup_.data();
}
const std::vector<CharArrayNullTerm<8>>& getZGroup() const
{
return this->zGroup_.data();
}
const std::vector<std::string> restart_group_keys = {"GOPP", "GWPP", "GOPR", "GWPR", "GGPR",
"GVPR", "GWIR", "GGIR", "GWCT", "GGOR",
"GOPT", "GWPT", "GGPT", "GVPT", "GWIT",
"GGIT"};
const std::vector<std::string> restart_field_keys = {"FOPP", "FWPP", "FOPR", "FWPR", "FGPR",
"FVPR", "FWIR", "FGIR", "FWCT", "FGOR",
"FOPT", "FWPT", "FGPT", "FVPT", "FWIT",
"FGIT"};
const std::map<std::string, size_t> groupKeyToIndex = {
{"GOPR", 0},
{"GWPR", 1},
{"GGPR", 2},
{"GVPR", 3},
{"GWIR", 5},
{"GGIR", 6},
{"GWCT", 8},
{"GGOR", 9},
{"GOPT", 10},
{"GWPT", 11},
{"GGPT", 12},
{"GVPT", 13},
{"GWIT", 15},
{"GGIT", 16},
{"GOPP", 22},
{"GWPP", 23},
};
const std::map<std::string, size_t> fieldKeyToIndex = {
{"FOPR", 0},
{"FWPR", 1},
{"FGPR", 2},
{"FVPR", 3},
{"FWIR", 5},
{"FGIR", 6},
{"FWCT", 8},
{"FGOR", 9},
{"FOPT", 10},
{"FWPT", 11},
{"FGPT", 12},
{"FVPT", 13},
{"FWIT", 15},
{"FGIT", 16},
{"FOPP", 22},
{"FWPP", 23},
};
private:
/// Aggregate 'IWEL' array (Integer) for all wells.
WindowedArray<int> iGroup_;
/// Aggregate 'SWEL' array (Real) for all wells.
WindowedArray<float> sGroup_;
/// Aggregate 'XWEL' array (Double Precision) for all wells.
WindowedArray<double> xGroup_;
/// Aggregate 'ZWEL' array (Character) for all wells.
WindowedArray<CharArrayNullTerm<8>> zGroup_;
/// Maximum number of wells in a group.
int nWGMax_;
/// Maximum number of groups
int nGMaxz_;
};
}}} // Opm::RestartIO::Helpers
#endif // OPM_AGGREGATE_WELL_DATA_HPP

View File

@@ -0,0 +1,105 @@
/*
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_AGGREGATE_MSW_DATA_HPP
#define OPM_AGGREGATE_MSW_DATA_HPP
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/output/eclipse/CharArrayNullTerm.hpp>
#include <opm/output/eclipse/WindowedArray.hpp>
#include <string>
#include <vector>
namespace Opm {
class Phases;
class Schedule;
class EclipseGrid;
class UnitSystem;
class SummaryState;
} // Opm
namespace Opm { namespace RestartIO { namespace Helpers {
struct BranchSegmentPar {
int outletS;
int noSegInBranch;
int firstSeg;
int lastSeg;
int branch;
};
class AggregateMSWData
{
public:
explicit AggregateMSWData(const std::vector<int>& inteHead);
void captureDeclaredMSWData(const Opm::Schedule& sched,
const std::size_t rptStep,
const Opm::UnitSystem& units,
const std::vector<int>& inteHead,
const Opm::EclipseGrid& grid,
const ::Opm::SummaryState& smry
);
/// Retrieve Integer Multisegment well data Array.
const std::vector<int>& getISeg() const
{
return this->iSeg_.data();
}
/// Retrieve Double precision segment data Array.
const std::vector<double>& getRSeg() const
{
return this->rSeg_.data();
}
/// Retrieve Integer multisegment well data Array for lateral branches (ILBS)
const std::vector<int>& getILBs() const
{
return this->iLBS_.data();
}
/// Retrieve Integer multisegment well data Array for lateral branches (ILBR)
const std::vector<int>& getILBr() const
{
return this->iLBR_.data();
}
private:
/// Aggregate 'ISEG' array (Integer) for all multisegment wells
WindowedArray<int> iSeg_;
/// Aggregate 'RSEG' array (Double) for all multisegment wells
WindowedArray<double> rSeg_;
/// Aggregate 'ILBS' array (Integer) for all multisegment wells
WindowedArray<int> iLBS_;
/// Aggregate 'ILBR' array (Integer) for all multisegment wells
WindowedArray<int> iLBR_;
};
}}} // Opm::RestartIO::Helpers
#endif // OPM_AGGREGATE_WELL_DATA_HPP

View File

@@ -0,0 +1,104 @@
/*
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 Schedule& sched,
const UnitSystem& units,
const std::size_t sim_step,
const ::Opm::SummaryState& smry,
const std::vector<int>& inteHead);
void captureDynamicWellData(const Opm::Schedule& sched,
const std::size_t sim_step,
const bool ecl_compatible_rst,
const Opm::data::WellRates& xw,
const Opm::SummaryState& smry);
/// 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

@@ -35,6 +35,7 @@
#include <opm/output/data/Solution.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/RestartValue.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
namespace Opm {
@@ -173,13 +174,11 @@ 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);
const bool write_double = false);
/*
@@ -220,7 +219,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;

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

@@ -0,0 +1,137 @@
/*
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;
};
struct Group {
int ngroups;
};
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);
InteHEAD& ngroups(const Group& gr);
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

@@ -46,6 +46,7 @@ class EclipseGrid;
class EclipseState;
class Phases;
class Schedule;
class SummaryState;
namespace RestartIO {
@@ -72,7 +73,7 @@ namespace RestartIO {
the report step argument '99'.
*/
void save(const std::string& filename,
/*void save(const std::string& filename,
int report_step,
double seconds_elapsed,
data::Solution cells,
@@ -81,16 +82,25 @@ void save(const std::string& filename,
const EclipseGrid& grid,
const Schedule& schedule,
std::map<std::string, std::vector<double>> extra_data = {},
bool write_double = false);
bool write_double = false);
*/
void save(const std::string& filename,
int report_step,
double seconds_elapsed,
RestartValue value,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const SummaryState& sumState,
bool write_double = false);
RestartValue load( const std::string& filename,
int report_step,
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,27 @@ 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;
void convertFromSI(const UnitSystem& units);
void convertToSI(const UnitSystem& units);
};
}

View File

@@ -25,10 +25,10 @@
#include <unordered_map>
#include <ert/ecl/ecl_sum.h>
#include <ert/ecl/Smspec.hpp>
#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 +61,8 @@ class Summary {
~Summary();
const SummaryState& get_restart_vectors() const;
private:
class keyword_handlers;
@@ -68,8 +70,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,74 @@
/*
Copyright (c) 2018 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_OUTPUT_ECLIPSE_VECTOR_CONNECTION_HPP
#define OPM_OUTPUT_ECLIPSE_VECTOR_CONNECTION_HPP
#include <vector>
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
namespace IConn {
enum index : std::vector<int>::size_type {
SeqIndex = 0, // Connection sequence index
CellI = 1, // I-location (1-based cell index) of connection
CellJ = 2, // J-location (1-based cell index) of connection
CellK = 3, // K-location (1-based cell index) of connection
ConnStat = 5, // Connection status.
// > 0 => open, shut otherwise
Drainage = 6, // Saturation function (table ID) for drainage
Imbibition = 9, // Saturation function (table ID) for imbibition
ComplNum = 12, // Completion ID (1-based)
ConnDir = 13, // Penetration direction (1:X, 2:Y, 3:Z)
Segment = 14, // Segment ID of connection
// 0 for regular connections, > 0 for MSW.
};
} // IConn
namespace SConn {
enum index : std::vector<float>::size_type {
ConnTrans = 0, // Connection transmissibility factor
Depth = 1, // Connection centre depth
Diameter = 2, // Connection diameter
EffectiveKH = 3, // Effective Kh product of connection
item12 = 11, // Unknown
SegDistEnd = 20, // Distance to end of connection in segment
SegDistStart = 21, // Distance to start of connection in segment
item30 = 29, // Unknown
item31 = 30, // Unknown
};
} // SConn
namespace XConn {
enum index : std::vector<double>::size_type {
OilRate = 0, // Surface flow rate (oil)
WaterRate = 1, // Surface flow rate (water)
GasRate = 2, // Surface Flow rate (gas)
ResVRate = 49, // Reservoir voidage rate
};
} // XConn
}}}} // Opm::RestartIO::Helpers::VectorItems
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_CONNECTION_HPP

View File

@@ -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.
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

File diff suppressed because it is too large Load Diff

View File

@@ -131,6 +131,9 @@ namespace Opm {
Deck( const Deck& );
//! \brief Deleted assignment operator.
Deck& operator=(const Deck& rhs) = delete;
void addKeyword( DeckKeyword&& keyword );
void addKeyword( const DeckKeyword& keyword );
@@ -141,7 +144,8 @@ namespace Opm {
UnitSystem& getActiveUnitSystem();
UnitSystem& getDefaultUnitSystem();
const std::string getDataFile() const;
const std::string& getInputPath() const;
const std::string& getDataFile() const;
void setDataFile(const std::string& dataFile);
iterator begin();
@@ -156,6 +160,7 @@ namespace Opm {
UnitSystem activeUnits;
std::string m_dataFile;
std::string input_path;
};
}
#endif /* DECK_HPP */

View File

@@ -28,7 +28,8 @@ namespace Opm {
class DeckOutput {
public:
explicit DeckOutput(std::ostream& s);
explicit DeckOutput(std::ostream& s, int precision = 10);
~DeckOutput();
void stash_default( );
void start_record( );
@@ -51,9 +52,11 @@ namespace Opm {
size_t default_count;
size_t row_count;
bool record_on;
int org_precision;
template <typename T> void write_value(const T& value);
void write_sep( );
void set_precision(int precision);
};
}

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

@@ -42,6 +42,7 @@ namespace Opm {
size_t getNY() const;
size_t getNZ() const;
size_t operator[](int dim) const;
const std::array<int, 3> getNXYZ() const;

View File

@@ -52,14 +52,14 @@ namespace Opm {
class MULTREGTRecord {
public:
MULTREGTRecord(const DeckRecord& deckRecord , const std::string& defaultRegion);
MULTREGTRecord(int src, int target, double trans_mult, int directions, MULTREGT::NNCBehaviourEnum nnc_behaviour, const std::string& region_name);
Value<int> m_srcRegion;
Value<int> m_targetRegion;
double m_transMultiplier;
int m_directions;
MULTREGT::NNCBehaviourEnum m_nncBehaviour;
Value<std::string> m_region;
int src_value;
int target_value;
int directions;
double trans_mult;
MULTREGT::NNCBehaviourEnum nnc_behaviour;
std::string region_name;
};
typedef std::map< std::pair<int , int> , const MULTREGTRecord * > MULTREGTSearchMap;
@@ -75,7 +75,7 @@ namespace Opm {
double getRegionMultiplier(size_t globalCellIdx1, size_t globalCellIdx2, FaceDir::DirEnum faceDir) const;
private:
void addKeyword( const DeckKeyword& deckKeyword, const std::string& defaultRegion);
void addKeyword( const Eclipse3DProperties& props, const DeckKeyword& deckKeyword, const std::string& defaultRegion);
void assertKeywordSupported(const DeckKeyword& deckKeyword, const std::string& defaultRegion);
std::vector< MULTREGTRecord > m_records;
std::map<std::string , MULTREGTSearchMap> m_searchMap;

View File

@@ -105,6 +105,41 @@ namespace Opm {
------ Default ------
If no keywords for config of writing restart files have been handled; no restart files are written.
ECL compatible restart
======================
Unfortunately flow & eclipse are not compatible across restarts. The
RestartIO implementation can write restart files for flow -> flow restart
or alternatively for flow -> eclipse restart. This is regulated by the
boolean flag ecl_compatible_restart in the IOConfig class. The difference
between the two are as follows:
ecl_compatible_restart = false:
1. The 'extra' fields in the RestartValue structure are actually
written to disk.
2. You can optionally ask the RestartIO::save() function to save the
solution in double precision.
3. The RestartIO::save() function will save opm specific vector OPM_IWEL
and OPM_XWEL.
ecl_compatible_restart = true:
1. The 'extra' fields in the RestartValue are silently ignored.
2. If request double precision solution data that is silently ignored,
it will be float.
3. The OPM_IWEL and OPM_XWEL vectors will not be written.
Observe that the solution data in the RestartValue is passed
unconditionally to the solution section in the restart file, so if you
pass a field in the solution section which Eclipse does not recognize you
will end up with a restart file which Eclipse can not read, even if you
have set ecl_compatible_restart to true.
*/
@@ -117,7 +152,8 @@ namespace Opm {
explicit IOConfig( const Deck& );
explicit IOConfig( const std::string& input_path );
void setEclCompatibleRST(bool ecl_rst);
bool getEclCompatibleRST() const;
bool getWriteEGRIDFile() const;
bool getWriteINITFile() const;
bool getUNIFOUT() const;
@@ -165,6 +201,7 @@ namespace Opm {
std::string m_output_dir;
std::string m_base_name;
bool m_nosim;
bool ecl_compatible_rst = true;
IOConfig( const GRIDSection&,
const RUNSPECSection&,

View File

@@ -362,6 +362,7 @@ namespace Opm {
DynamicState< RestartSchedule > restart_schedule;
DynamicState< std::map< std::string, int > > restart_keywords;
std::vector< bool > save_keywords;
};
} //namespace Opm

View File

@@ -20,6 +20,8 @@
#ifndef OPM_INIT_CONFIG_HPP
#define OPM_INIT_CONFIG_HPP
#include <string>
#include <opm/parser/eclipse/EclipseState/InitConfig/Equil.hpp>
namespace Opm {

View File

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

View File

@@ -0,0 +1,70 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ActionX_HPP_
#define ActionX_HPP_
#include <string>
namespace Opm {
/*
The ActionX class internalizes the ACTIONX keyword. This keyword represents a
small in-deck programming language for the SCHEDULE section. In the deck the
ACTIONX keyword comes together with a 'ENDACTIO' kewyord and then a list of
regular keywords in the between. The principle is then that ACTIONX represents
a condition, and when that condition is satisfied the keywords are applied. In
the example below the ACTIONX keyword defines a condition whether well OPX has
watercut above 0.75, when the condition is met the WELOPEN keyword is applied
- and the well is shut.
ACTIONX
'NAME' /
WWCT OPX > 0.50 /
/
WELOPEN
'OPX' OPEN /
/
ENDACTION
*/
class DeckKeyword;
class ActionX {
public:
ActionX(const std::string& name, size_t max_run, double max_wait);
explicit ActionX(const DeckKeyword& kw);
void addKeyword(const DeckKeyword& kw);
const std::string& name() const;
private:
std::string m_name;
size_t max_run;
double max_wait;
std::vector<DeckKeyword> keywords;
};
}
#endif /* WELL_HPP_ */

View File

@@ -1,110 +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 COMPLETION_HPP_
#define COMPLETION_HPP_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Util/Value.hpp>
namespace Opm {
class DeckKeyword;
class DeckRecord;
class Well;
class EclipseGrid;
class Eclipse3DProperties;
class Completion {
public:
Completion(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 int satTableId,
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z);
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;
WellCompletion::DirectionEnum getDirection() 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;
private:
int m_i, m_j, m_k;
int m_complnum;
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;
// related segment number
// -1 means the completion is not related to segment
int m_segment_number = -1;
double m_center_depth;
};
}
#endif /* COMPLETION_HPP_ */

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

@@ -0,0 +1,115 @@
/*
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 COMPLETION_HPP_
#define COMPLETION_HPP_
#include <array>
#include <cstddef>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Util/Value.hpp>
namespace Opm {
class DeckKeyword;
class DeckRecord;
class Connection {
public:
Connection(int i, int j , int k ,
int complnum,
double depth,
WellCompletion::StateEnum state,
double CF,
double Kh,
double rw,
const int satTableId,
const WellCompletion::DirectionEnum direction,
const std::size_t seqIndex,
const double segDistStart,
const double segDistEnd,
const bool defaultSatTabId
);
bool attachedToSegment() const;
bool sameCoordinate(const int i, const int j, const int k) const;
int getI() const;
int getJ() const;
int getK() const;
WellCompletion::StateEnum state() const;
WellCompletion::DirectionEnum dir() const;
double depth() const;
int satTableId() const;
int complnum() const;
int segment() const;
double CF() const;
double Kh() const;
double rw() const;
double wellPi() const;
void setState(WellCompletion::StateEnum state);
void setComplnum(int compnum);
void scaleWellPi(double wellPi);
void updateSegment(int segment_number, double center_depth, std::size_t seqIndex);
const std::size_t& getSeqIndex() const;
const bool& getDefaultSatTabId() const;
const std::size_t& getCompSegSeqIndex() const;
void setCompSegSeqIndex(std::size_t index);
void setDefaultSatTabId(bool id);
const double& getSegDistStart() const;
const double& getSegDistEnd() const;
void setSegDistStart(const double& distStart);
void setSegDistEnd(const double& distEnd);
bool operator==( const Connection& ) const;
bool operator!=( const Connection& ) const;
private:
WellCompletion::DirectionEnum direction;
double center_depth;
WellCompletion::StateEnum open_state;
int sat_tableId;
int m_complnum;
double m_CF;
double m_Kh;
double m_rw;
std::array<int,3> ijk;
std::size_t m_seqIndex;
double m_segDistStart;
double m_segDistEnd;
bool m_defaultSatTabId;
std::size_t m_compSeg_seqIndex=0;
// related segment number
// -1 means the completion is not related to segment
int segment_number = -1;
double wPi = 1.0;
};
}
#endif /* COMPLETION_HPP_ */

View File

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

View File

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

View File

@@ -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,18 @@
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>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.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, const EclipseGrid& grid, std::size_t& totNC);
}
#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;
@@ -93,31 +94,39 @@ namespace Opm
is an inefficient way to get all the wells defined at time
't'.
*/
*/
//std::vector< const Group& > getChildGroups(const std::string& group_name, size_t timeStep) const;
std::vector< const Group* > getChildGroups(const std::string& group_name, size_t timeStep) const;
std::vector< const Well* > getWells(const std::string& group, size_t timeStep) const;
std::vector< const Well* > getChildWells(const std::string& group_name, size_t timeStep) const;
std::vector< const Well* > getWellsMatching( const std::string& ) const;
const OilVaporizationProperties& getOilVaporizationProperties(size_t timestep) const;
const WellTestConfig& wtestConfig(size_t timestep) const;
const GroupTree& getGroupTree(size_t t) const;
size_t numGroups() const;
size_t numGroups(size_t timeStep) const;
bool hasGroup(const std::string& groupName) const;
const Group& getGroup(const std::string& groupName) const;
std::vector< const Group* > getGroups() const;
std::vector< const Group* > getGroups(size_t timeStep) const;
const Tuning& getTuning() const;
const MessageLimits& getMessageLimits() const;
void invalidNamePattern (const std::string& namePattern, const ParseContext& parseContext, const DeckKeyword& keyword) const;
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 +141,13 @@ namespace Opm
Phases m_phases;
std::map<int, DynamicState<std::shared_ptr<VFPProdTable>>> vfpprod_tables;
std::map<int, DynamicState<std::shared_ptr<VFPInjTable>>> vfpinj_tables;
DynamicState<std::shared_ptr<WellTestConfig>> wtest_config;
WellProducer::ControlModeEnum m_controlModeWHISTCTL;
std::vector< Well* > getWells(const std::string& wellNamePattern);
std::vector< Group* > getGroups(const std::string& groupNamePattern);
void updateWellStatus( Well& well, size_t reportStep , WellCommon::StatusEnum status);
void addWellToGroup( Group& newGroup , Well& well , size_t timeStep);
void iterateScheduleSection(const ParseContext& parseContext , const SCHEDULESection& , const EclipseGrid& grid,
@@ -145,42 +157,52 @@ namespace Opm
void addWell(const std::string& wellName, const DeckRecord& record, size_t timeStep, WellCompletion::CompletionOrderEnum wellCompletionOrder);
void handleCOMPORD(const ParseContext& parseContext, const DeckKeyword& compordKeyword, size_t currentStep);
void handleWELSPECS( const SCHEDULESection&, size_t, size_t );
void handleWCONProducer( const DeckKeyword& keyword, size_t currentStep, bool isPredictionMode);
void handleWCONHIST( const DeckKeyword& keyword, size_t currentStep);
void handleWCONPROD( const DeckKeyword& keyword, size_t currentStep);
void handleWCONProducer( const DeckKeyword& keyword, size_t currentStep, bool isPredictionMode, const ParseContext& parseContext);
void handleWCONHIST( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWGRUPCON( const DeckKeyword& keyword, size_t currentStep);
void handleCOMPDAT( const DeckKeyword& keyword, size_t currentStep, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties);
void handleCOMPDAT( const DeckKeyword& keyword, size_t currentStep, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties, const ParseContext& parseContext);
void handleCOMPLUMP( const DeckKeyword& keyword, size_t currentStep );
void handleWELSEGS( const DeckKeyword& keyword, size_t currentStep);
void handleCOMPSEGS( const DeckKeyword& keyword, size_t currentStep);
void handleWCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
void handleWPOLYMER( const DeckKeyword& keyword, size_t currentStep);
void handleWSOLVENT( const DeckKeyword& keyword, size_t currentStep);
void handleWTEMP( const DeckKeyword& keyword, size_t currentStep);
void handleWINJTEMP( const DeckKeyword& keyword, size_t currentStep);
void handleWCONINJH( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
void handleWELOPEN( const DeckKeyword& keyword, size_t currentStep );
void handleWELTARG( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
void handleGCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep);
void handleGCONPROD( const DeckKeyword& keyword, size_t currentStep);
void handleGEFAC( const DeckKeyword& keyword, size_t currentStep);
void handleWEFAC( const DeckKeyword& keyword, size_t currentStep);
void handleCOMPSEGS( const DeckKeyword& keyword, size_t currentStep, const EclipseGrid& grid);
void handleWCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWPOLYMER( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWSOLVENT( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWINJTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWCONINJH( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWELOPEN( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext );
void handleWELTARG( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleGCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleGCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleGEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleTUNING( const DeckKeyword& keyword, size_t currentStep);
void handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep);
void handleGRUPNET( const DeckKeyword& keyword, size_t currentStep);
void handleWRFT( const DeckKeyword& keyword, size_t currentStep);
void handleWTEST( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWRFTPLT( const DeckKeyword& keyword, size_t currentStep);
void handleWPIMULT( const DeckKeyword& keyword, size_t currentStep);
void handleDRSDT( const DeckKeyword& keyword, size_t currentStep);
void handleDRVDT( const DeckKeyword& keyword, size_t currentStep);
void handleVAPPARS( const DeckKeyword& keyword, size_t currentStep);
void handleWECON( const DeckKeyword& keyword, size_t currentStep);
void handleWECON( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext);
void handleWHISTCTL(const ParseContext& parseContext, const DeckKeyword& keyword);
void handleMESSAGES(const DeckKeyword& keyword, size_t currentStep);
void handleVFPPROD(const DeckKeyword& vfpprodKeyword, const UnitSystem& unit_system, size_t currentStep);
void handleVFPINJ(const DeckKeyword& vfpprodKeyword, const UnitSystem& unit_system, size_t currentStep);
void checkUnhandledKeywords( const SCHEDULESection& ) const;
void checkIfAllConnectionsIsShut(size_t currentStep);
void handleKeyword(size_t& currentStep,
const SCHEDULESection& section,
size_t keywordIdx,
const DeckKeyword& keyword,
const ParseContext& parseContext,
const EclipseGrid& grid,
const Eclipse3DProperties& eclipseProperties,
const UnitSystem& unit_system,
std::vector<std::pair<const DeckKeyword*, size_t > >& rftProperties);
static double convertInjectionRateToSI(double rawRate, WellInjector::TypeEnum wellType, const Opm::UnitSystem &unitSystem);
static double convertInjectionRateToSI(double rawRate, Phase wellPhase, const Opm::UnitSystem &unitSystem);

View File

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

View File

@@ -27,35 +27,38 @@
#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>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.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;
class Well {
public:
Well(const std::string& name, int headI,
Well(const std::string& name, const size_t& seqIndex, int headI,
int headJ, double refDepth, Phase preferredPhase,
const TimeMap& timeMap, size_t creationTimeStep,
WellCompletion::CompletionOrderEnum completionOrdering = WellCompletion::TRACK,
bool allowCrossFlow = true, bool automaticShutIn = true);
const std::string& name() const;
const size_t& seqIndex() const;
const std::size_t getTotNoConn() const;
void setTotNoConn(std::size_t noConn);
bool hasBeenDefined(size_t timeStep) const;
const std::string getGroupName(size_t timeStep) const;
void setGroupName(size_t timeStep , const std::string& groupName);
@@ -94,10 +97,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 +169,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,23 +178,32 @@ 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, const EclipseGrid& grid, size_t time_step);
void handleWELOPEN(const DeckRecord& record, size_t time_step, WellCompletion::StateEnum status);
void handleWPIMULT(const DeckRecord& record, size_t time_step);
void handleWELSEGS(const DeckKeyword& keyword, size_t time_step);
/*
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;
std::size_t m_seqIndex;
std::size_t m_totNoConn=0;
DynamicState< WellCommon::StatusEnum > m_status;
DynamicState< int > m_isAvailableForGroupControl;
@@ -182,7 +213,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 +233,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,105 @@
/*
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 ,
double CF,
double Kh,
double rw,
const int satTableId,
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z,
const std::size_t seqIndex = 0,
const double segDistStart= 0.0,
const double segDistEnd= 0.0,
const bool defaultSatTabId = true);
void loadCOMPDAT(const DeckRecord& record, const EclipseGrid& grid, const Eclipse3DProperties& eclipseProperties, std::size_t& totNC);
using const_iterator = std::vector< Connection >::const_iterator;
void add( Connection );
size_t size() const;
const Connection& operator[](size_t index) 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(); }
std::size_t totNoConn() const { return this->m_connections.size(); }
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 ,
double CF,
double Kh,
double rw,
const int satTableId,
const WellCompletion::DirectionEnum direction = WellCompletion::DirectionEnum::Z,
const std::size_t seqIndex = 0,
const double segDistStart= 0.0,
const double segDistEnd= 0.0,
const bool defaultSatTabId = true);
std::vector< Connection > m_connections;
size_t findClosestConnection(int oi, int oj, double oz, size_t start_pos);
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

@@ -24,10 +24,59 @@
#include <vector>
#include <set>
#include <ert/ecl/Smspec.hpp>
#include <ert/ecl/smspec_node.h>
namespace Opm {
/*
Very small utility class to get value semantics on the smspec_node
pointers. This should die as soon as the smspec_node class proper gets
value semantics.
*/
class SummaryNode {
public:
SummaryNode(smspec_node_type * c_ptr) :
ptr(c_ptr)
{}
SummaryNode(const SummaryNode& other) :
ptr( smspec_node_alloc_copy(other.get()))
{}
const smspec_node_type * get() const {
return this->ptr;
}
std::string wgname() const {
return smspec_node_get_wgname(this->ptr);
}
std::string keyword() const {
return smspec_node_get_keyword(this->ptr);
}
int num() const {
return smspec_node_get_num(this->ptr);
}
ecl_smspec_var_type type() const {
return smspec_node_get_var_type(this->ptr);
}
SummaryNode& operator=(const SummaryNode &other) {
this->ptr = smspec_node_alloc_copy(other.ptr);
return *this;
}
~SummaryNode() {
smspec_node_free(this->ptr);
}
private:
smspec_node_type * ptr;
};
class Deck;
class TableManager;
class EclipseState;
@@ -38,7 +87,9 @@ namespace Opm {
class SummaryConfig {
public:
typedef std::vector< ERT::smspec_node >::const_iterator const_iterator;
typedef SummaryNode keyword_type;
typedef std::vector< keyword_type > keyword_list;
typedef keyword_list::const_iterator const_iterator;
SummaryConfig( const Deck&, const Schedule&,
const TableManager&, const ParseContext&);
@@ -80,7 +131,7 @@ namespace Opm {
part, e.g. "WWCT", and not the qualification with
well/group name or a numerical value.
*/
std::vector< ERT::smspec_node > keywords;
keyword_list keywords;
std::set<std::string> short_keywords;
std::set<std::string> summary_keywords;
};

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

@@ -40,14 +40,9 @@ namespace Opm {
bool hasKeyword(const std::string& keyword) const;
std::shared_ptr<const ParserKeyword> getKeyword(const std::string& keyword) const;
std::string getJsonFile(const std::string& keyword) const;
size_t loadKeywordDirectory(const std::string& pathname);
size_t loadKeywordDirectory(boost::filesystem::path& path);
void loadKeyword(const std::string& filename);
void loadKeyword(boost::filesystem::path& path);
static std::vector<std::string> sortSubdirectories( const std::string& directory );
size_t loadMultipleKeywordDirectories(const std::string& directory);
std::map<std::string , std::shared_ptr<ParserKeyword> >::const_iterator keyword_begin( ) const;
std::map<std::string , std::shared_ptr<ParserKeyword> >::const_iterator keyword_end( ) const;
private:

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

@@ -1,245 +0,0 @@
/*
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECLFILESCOMPARATOR_HPP
#define ECLFILESCOMPARATOR_HPP
#include <vector>
#include <string>
struct ecl_file_struct; //!< Prototype for eclipse file struct, from ERT library.
typedef struct ecl_file_struct ecl_file_type;
struct ecl_grid_struct; //!< Prototype for eclipse grid struct, from ERT library.
typedef struct ecl_grid_struct ecl_grid_type;
struct ecl_kw_struct; //!< Prototype for eclipse keyword struct, from ERT library.
typedef struct ecl_kw_struct ecl_kw_type;
/*! \brief Deviation struct.
\details The member variables are default initialized to -1,
which is an invalid deviation value.
*/
struct Deviation {
double abs = -1; //!< Absolute deviation
double rel = -1; //!< Relative deviation
};
/*! \brief A class for comparing ECLIPSE files.
\details ECLFilesComparator opens ECLIPSE files
(unified restart, initial and RFT in addition to grid file)
from two simulations. This class has only the functions
printKeywords() and printKeywordsDifference(), in addition to a
couple of get-functions: the comparison logic is implemented in
the subclasses RegressionTest and IntegrationTest. */
class ECLFilesComparator {
private:
int file_type;
double absTolerance = 0;
double relTolerance = 0;
protected:
ecl_file_type* ecl_file1 = nullptr;
ecl_grid_type* ecl_grid1 = nullptr;
ecl_file_type* ecl_file2 = nullptr;
ecl_grid_type* ecl_grid2 = nullptr;
std::vector<std::string> keywords1, keywords2;
bool throwOnError = true; //!< Throw on first error
mutable size_t num_errors = 0;
//! \brief Checks if the keyword exists in both cases.
//! \param[in] keyword Keyword to check.
//! \details If the keyword does not exist in one of the cases, the function throws an exception.
void keywordValidForComparing(const std::string& keyword) const;
//! \brief Stores keyword data for a given occurrence
//! \param[out] ecl_kw1 Pointer to a ecl_kw_type, which stores keyword data for first case given the occurrence.
//! \param[out] ecl_kw2 Pointer to a ecl_kw_type, which stores keyword data for second case given the occurrence.
//! \param[in] keyword Which keyword to consider.
//! \param[in] occurrence Which keyword occurrence to consider.
//! \details This function stores keyword data for the given keyword and occurrence in #ecl_kw1 and #ecl_kw2, and returns the number of cells (for which the keyword has a value at the occurrence). If the number of cells differ for the two cases, an exception is thrown.
unsigned int getEclKeywordData(ecl_kw_type*& ecl_kw1, ecl_kw_type*& ecl_kw2, const std::string& keyword, int occurrence1, int occurrence2) const;
//! \brief Prints values for a given keyword, occurrence and cell
//! \param[in] keyword Which keyword to consider.
//! \param[in] occurrence Which keyword occurrence to consider.
//! \param[in] cell Which cell occurrence to consider (numbered by global index).
//! \param[in] value1 Value for first file, the data type can be bool, int, double or std::string.
//! \param[in] value2 Value for second file, the data type can be bool, int, double or std::string.
//! \details Templatefunction for printing values when exceptions are thrown. The function is defined for bool, int, double and std::string.
template <typename T>
void printValuesForCell(const std::string& keyword, int occurrence1, int occurrence2, size_t cell, const T& value1, const T& value2) const;
public:
//! \brief Open ECLIPSE files and set tolerances and keywords.
//! \param[in] file_type Specifies which filetype to be compared, possible inputs are UNRSTFILE, INITFILE and RFTFILE.
//! \param[in] basename1 Full path without file extension to the first case.
//! \param[in] basename2 Full path without file extension to the second case.
//! \param[in] absTolerance Tolerance for absolute deviation.
//! \param[in] relTolerance Tolerance for relative deviation.
//! \details The content of the ECLIPSE files specified in the input is stored in the ecl_file_type and ecl_grid_type member variables. In addition the keywords and absolute and relative tolerances (member variables) are set. If the constructor is unable to open one of the ECLIPSE files, an exception will be thrown.
ECLFilesComparator(int file_type, const std::string& basename1, const std::string& basename2, double absTolerance, double relTolerance);
//! \brief Closing the ECLIPSE files.
~ECLFilesComparator();
//! \brief Set whether to throw on errors or not.
void throwOnErrors(bool dothrow) { throwOnError = dothrow; }
//! \brief Returns the number of errors encountered in the performed comparisons.
size_t getNoErrors() const { return num_errors; }
//! \brief Returns the ECLIPSE filetype of this
int getFileType() const {return file_type;}
//! \brief Returns the absolute tolerance stored as a private member variable in the class
double getAbsTolerance() const {return absTolerance;}
//! \brief Returns the relative tolerance stored as a private member variable in the class
double getRelTolerance() const {return relTolerance;}
//! \brief Print all keywords and their respective Eclipse type for the two input cases.
void printKeywords() const;
//! \brief Print common and uncommon keywords for the two input cases.
void printKeywordsDifference() const;
//! \brief Calculate deviations for two values.
//! \details Using absolute values of the input arguments: If one of the values are non-zero, the Deviation::abs returned is the difference between the two input values. In addition, if both values are non-zero, the Deviation::rel returned is the absolute deviation divided by the largest value.
static Deviation calculateDeviations(double val1, double val2);
//! \brief Calculate median of a vector.
//! \details Returning the median of the input vector, i.e. the middle value of the sorted vector if the number of elements is odd or the mean of the two middle values if the number of elements are even.
static double median(std::vector<double> vec);
//! \brief Calculate average of a vector.
//! \details Returning the average of the input vector, i.e. the sum of all values divided by the number of elements.
static double average(const std::vector<double>& vec);
};
/*! \brief A class for executing a regression test for two ECLIPSE files.
\details This class inherits from ECLFilesComparator, which opens and
closes the input cases and stores keywordnames.
The three public functions gridCompare(), results() and
resultsForKeyword() can be invoked to compare griddata
or keyworddata for all keywords or a given keyword (resultsForKeyword()).
*/
class RegressionTest: public ECLFilesComparator {
private:
// These vectors store absolute and relative deviations, respecively. Note that they are whiped clean for every new keyword comparison.
std::vector<double> absDeviation, relDeviation;
// Keywords which should not contain negative values, i.e. uses allowNegativeValues = false in deviationsForCell():
const std::vector<std::string> keywordDisallowNegatives = {"SGAS", "SWAT", "PRESSURE"};
// Only compare last occurrence
bool onlyLastOccurrence = false;
// Prints results stored in absDeviation and relDeviation.
void printResultsForKeyword(const std::string& keyword) const;
// Function which compares data at specific occurrences and for a specific keyword type. The functions takes two occurrence inputs to also be able to
// compare keywords which are shifted relative to each other in the two files. This is for instance handy when running flow with restart from different timesteps,
// and comparing the last timestep from the two runs.
void boolComparisonForOccurrence(const std::string& keyword, int occurrence1, int occurrence2) const;
void charComparisonForOccurrence(const std::string& keyword, int occurrence1, int occurrence2) const;
void intComparisonForOccurrence(const std::string& keyword, int occurrence1, int occurrence2) const;
void doubleComparisonForOccurrence(const std::string& keyword, int occurrence1, int occurrence2);
// deviationsForCell throws an exception if both the absolute deviation AND the relative deviation
// are larger than absTolerance and relTolerance, respectively. In addition,
// if allowNegativeValues is passed as false, an exception will be thrown when the absolute value
// of a negative value exceeds absTolerance. If no exceptions are thrown, the absolute and relative deviations are added to absDeviation and relDeviation.
void deviationsForCell(double val1, double val2, const std::string& keyword, int occurrence1, int occurrence2, size_t cell, bool allowNegativeValues = true);
public:
//! \brief Sets up the regression test.
//! \param[in] file_type Specifies which filetype to be compared, possible inputs are UNRSTFILE, INITFILE and RFTFILE.
//! \param[in] basename1 Full path without file extension to the first case.
//! \param[in] basename2 Full path without file extension to the second case.
//! \param[in] absTolerance Tolerance for absolute deviation.
//! \param[in] relTolerance Tolerance for relative deviation.
//! \details This constructor only calls the constructor of the superclass, see the docs for ECLFilesComparator for more information.
RegressionTest(int file_type, const std::string& basename1, const std::string& basename2, double absTolerance, double relTolerance):
ECLFilesComparator(file_type, basename1, basename2, absTolerance, relTolerance) {}
//! \brief Option to only compare last occurrence
void setOnlyLastOccurrence(bool onlyLastOccurrenceArg) {this->onlyLastOccurrence = onlyLastOccurrenceArg;}
//! \brief Compares grid properties of the two cases.
// gridCompare() checks if both the number of active and global cells in the two cases are the same. If they are, all cells are looped over to calculate the cell volume deviation for the two cases. If the both the relative and absolute deviation exceeds the tolerances, an exception is thrown.
void gridCompare() const;
//! \brief Calculates deviations for all keywords.
// This function checks if the number of keywords of the two cases are equal, and if it is, resultsForKeyword() is called for every keyword. If not, an exception is thrown.
void results();
//! \brief Calculates deviations for a specific keyword.
//! \param[in] keyword Keyword which should be compared, if this keyword is absent in one of the cases, an exception will be thrown.
//! \details This function loops through every report step and every cell and compares the values for the given keyword from the two input cases. If the absolute or relative deviation between the two values for each step exceeds both the absolute tolerance and the relative tolerance (stored in ECLFilesComparator), an exception is thrown. In addition, some keywords are marked for "disallow negative values" -- these are SGAS, SWAT and PRESSURE. An exception is thrown if a value of one of these keywords is both negative and has an absolute value larger than the absolute tolerance. If no exceptions are thrown, resultsForKeyword() uses the private member funtion printResultsForKeyword to print the average and median deviations.
void resultsForKeyword(const std::string& keyword);
};
/*! \brief A class for executing a integration test for two ECLIPSE files.
\details This class inherits from ECLFilesComparator, which opens and closes
the input cases and stores keywordnames. The three public functions
equalNumKeywords(), results() and resultsForKeyword() can be invoked
to compare griddata or keyworddata for all keywords or a given
keyword (resultsForKeyword()).
*/
class IntegrationTest: public ECLFilesComparator {
private:
std::vector<double> cellVolumes; //!< Vector of cell volumes in second input case (indexed by global index)
std::vector<double> initialCellValues; //!< Keyword values for all cells at first occurrence (index by global index)
// These are the only keywords which are compared, since SWAT should be "1 - SOIL - SGAS", this keyword is omitted.
const std::vector<std::string> keywordWhitelist = {"SGAS", "SWAT", "PRESSURE"};
void setCellVolumes();
void initialOccurrenceCompare(const std::string& keyword);
void occurrenceCompare(const std::string& keyword, int occurrence) const;
public:
//! \brief Sets up the integration test.
//! \param[in] basename1 Full path without file extension to the first case.
//! \param[in] basename2 Full path without file extension to the second case.
//! \param[in] absTolerance Tolerance for absolute deviation.
//! \param[in] relTolerance Tolerance for relative deviation.
//! \details This constructor calls the constructor of the superclass, with input filetype unified restart. See the docs for ECLFilesComparator for more information.
IntegrationTest(const std::string& basename1, const std::string& basename2, double absTolerance, double relTolerance);
//! \brief Checks if a keyword is supported for comparison.
//! \param[in] keyword Keyword to check.
bool elementInWhitelist(const std::string& keyword) const;
//! \brief Checks if the number of keywords equal in the two input cases.
//! \param[in] keyword Keyword to check.
void equalNumKeywords() const;
//! \brief Finds deviations for all supported keywords.
//! \details results() loops through all supported keywords for integration test (defined in keywordWhitelist -- this is SGAS, SWAT and PRESSURE) and calls resultsForKeyword() for each keyword.
void results();
//! \brief Finds deviations for a specific keyword.
//! \param[in] keyword Keyword to check.
/*! \details First, resultsForKeyword() checks if the keyword exits in both cases, and if the number of keyword occurrences in the two cases differ. If these tests fail, an exception is thrown. Then deviaitons are calculated as described below for each occurrence, and an exception is thrown if the relative error ratio \f$E\f$ is larger than the relative tolerance.
* Calculation:\n
* Let the keyword values for occurrence \f$n\f$ and cell \f$i\f$ be \f$p_{n,i}\f$ and \f$q_{n,i}\f$ for input case 1 and 2, respectively.
* Consider first the initial occurrence (\f$n=0\f$). The function uses the second cases as reference, and calculates the volume weighted sum of \f$q_{0,i}\f$ over all cells \f$i\f$:
* \f[ S_0 = \sum_{i} q_{0,i} v_i \f]
* where \f$v_{i}\f$ is the volume of cell \f$i\f$ in case 2. Then, the deviations between the cases for each cell are calculated:
* \f[ \Delta = \sum_{i} |p_{0,i} - q_{0,i}| v_i.\f]
* The error ratio is then \f$E = \Delta/S_0\f$.\n
* For all other occurrences \f$n\f$, the deviation value \f$\Delta\f$ is calculated the same way, but the total value \f$S\f$ is calculated relative to the initial occurrence total \f$S_0\f$:
* \f[ S = \sum_{i} |q_{n,i} - q_{0,i}| v_i. \f]
* The error ratio is \f$ E = \Delta/S\f$. */
void resultsForKeyword(const std::string& keyword);
};
#endif

View File

@@ -5,14 +5,14 @@
%define tag final
Name: opm-common
Version: 2018.04
Version: 2018.10
Release: 0
Summary: Open Porous Media - common helpers and buildsystem
License: GPL-3.0
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,325 @@
/*
Copyright 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/output/eclipse/AggregateConnectionData.hpp>
#include <opm/output/eclipse/VectorItems/connection.hpp>
#include <opm/output/eclipse/VectorItems/intehead.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <cassert>
#include <cstddef>
#include <iostream>
#include <cmath>
namespace VI = Opm::RestartIO::Helpers::VectorItems;
// #####################################################################
// Class Opm::RestartIO::Helpers::AggregateConnectionData
// ---------------------------------------------------------------------
namespace {
std::size_t numWells(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NWELLS];
}
std::size_t maxNumConn(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NCWMAX];
}
std::map <std::size_t, const Opm::Connection*> mapSeqIndexToConnection(const Opm::WellConnections& conns)
{
// make seqIndex to Connection map
std::map <std::size_t, const Opm::Connection*> seqIndConnMap;
for (const auto & conn : conns) {
std::size_t sI = conn.getSeqIndex();
seqIndConnMap.insert(std::make_pair(sI, &conn));
}
return seqIndConnMap;
}
std::map <std::size_t, const Opm::Connection*> mapCompSegSeqIndexToConnection(const Opm::WellConnections& conns)
{
// make CompSegSeqIndex to Connection map
std::map <std::size_t, const Opm::Connection*> cs_seqIndConnMap;
for (const auto & conn : conns) {
std::size_t sI = conn.getCompSegSeqIndex();
cs_seqIndConnMap.insert(std::make_pair(sI, &conn));
}
return cs_seqIndConnMap;
}
template <class ConnOp>
void connectionLoop(const std::vector<const Opm::Well*>& wells,
const Opm::EclipseGrid& grid,
const std::size_t sim_step,
ConnOp&& connOp)
{
for (auto nWell = wells.size(), wellID = 0*nWell;
wellID < nWell; ++wellID)
{
const auto* well = wells[wellID];
if (well == nullptr) { continue; }
const auto& conns = well->getActiveConnections(sim_step, grid);
const int niSI = static_cast<int>(well->getTotNoConn());
std::map <std::size_t, const Opm::Connection*> sIToConn;
//Branch according to MSW well or not and
//sort active connections according to appropriate seqIndex
if (well->isMultiSegment(sim_step)) {
//sort connections according to input sequence in COMPSEGS
sIToConn = mapCompSegSeqIndexToConnection(conns);
} else
{
//sort connections according to input sequence in COMPDAT
sIToConn = mapSeqIndexToConnection(conns);
}
std::vector<const Opm::Connection*> connSI;
for (int iSI = 0; iSI < niSI; iSI++) {
const auto searchSI = sIToConn.find(static_cast<std::size_t>(iSI));
if (searchSI != sIToConn.end()) {
connSI.push_back(searchSI->second);
}
}
for (auto nConn = connSI.size(), connID = 0*nConn;
connID < nConn; ++connID)
{
connOp(*well, wellID, *(connSI[connID]), connID);
}
}
}
namespace IConn {
std::size_t entriesPerConn(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NICONZ];
}
Opm::RestartIO::Helpers::WindowedMatrix<int>
allocate(const std::vector<int>& inteHead)
{
using WM = Opm::RestartIO::Helpers::WindowedMatrix<int>;
return WM {
WM::NumRows { numWells(inteHead) },
WM::NumCols { maxNumConn(inteHead) },
WM::WindowSize{ entriesPerConn(inteHead) }
};
}
template <class IConnArray>
void staticContrib(const Opm::Connection& conn,
const std::size_t connID,
IConnArray& iConn)
{
using ConnState = ::Opm::WellCompletion::StateEnum;
using Ix = ::Opm::RestartIO::Helpers::VectorItems::IConn::index;
iConn[Ix::SeqIndex] = connID + 1;
iConn[Ix::CellI] = conn.getI() + 1;
iConn[Ix::CellJ] = conn.getJ() + 1;
iConn[Ix::CellK] = conn.getK() + 1;
iConn[Ix::ConnStat] = (conn.state() == ConnState::OPEN)
? 1 : -1000;
iConn[Ix::Drainage] = conn.getDefaultSatTabId()
? 0 : conn.satTableId();
// Don't support differing sat-func tables for
// draining and imbibition curves at connections.
iConn[Ix::Imbibition] = iConn[Ix::Drainage];
iConn[Ix::ComplNum] = std::abs(conn.complnum());
//iConn[Ix::ComplNum] = iConn[Ix::SeqIndex];
iConn[Ix::ConnDir] = conn.dir();
iConn[Ix::Segment] = conn.attachedToSegment()
? conn.segment() : 0;
}
} // IConn
namespace SConn {
std::size_t entriesPerConn(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NSCONZ];
}
Opm::RestartIO::Helpers::WindowedMatrix<float>
allocate(const std::vector<int>& inteHead)
{
using WM = Opm::RestartIO::Helpers::WindowedMatrix<float>;
return WM {
WM::NumRows { numWells(inteHead) },
WM::NumCols { maxNumConn(inteHead) },
WM::WindowSize{ entriesPerConn(inteHead) }
};
}
template <class SConnArray>
void staticContrib(const Opm::Connection& conn,
const Opm::UnitSystem& units,
SConnArray& sConn)
{
using M = ::Opm::UnitSystem::measure;
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SConn::index;
auto scprop = [&units](const M u, const double x) -> float
{
return static_cast<float>(units.from_si(u, x));
};
sConn[Ix::ConnTrans] =
scprop(M::transmissibility, conn.CF());
sConn[Ix::Depth] = scprop(M::length, conn.depth());
sConn[Ix::Diameter] = scprop(M::length, 2*conn.rw());
sConn[Ix::EffectiveKH] =
scprop(M::effective_Kh, conn.Kh());
sConn[Ix::item12] = sConn[Ix::ConnTrans];
sConn[Ix::SegDistEnd] = scprop(M::length, conn.getSegDistEnd());
sConn[Ix::SegDistStart] = scprop(M::length, conn.getSegDistStart());
sConn[Ix::item30] = -1.0e+20f;
sConn[Ix::item31] = -1.0e+20f;
}
} // SConn
namespace XConn {
std::size_t entriesPerConn(const std::vector<int>& inteHead)
{
return inteHead[VI::intehead::NXCONZ];
}
Opm::RestartIO::Helpers::WindowedMatrix<double>
allocate(const std::vector<int>& inteHead)
{
using WM = Opm::RestartIO::Helpers::WindowedMatrix<double>;
return WM {
WM::NumRows { numWells(inteHead) },
WM::NumCols { maxNumConn(inteHead) },
WM::WindowSize{ entriesPerConn(inteHead) }
};
}
template <class XConnArray>
void dynamicContrib(const Opm::data::Connection& x,
const Opm::UnitSystem& units,
XConnArray& xConn)
{
using M = ::Opm::UnitSystem::measure;
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XConn::index;
using R = ::Opm::data::Rates::opt;
// Note flow rate sign. Treat production rates as positive.
const auto& Q = x.rates;
if (Q.has(R::oil)) {
xConn[Ix::OilRate] =
- units.from_si(M::liquid_surface_rate, Q.get(R::oil));
}
if (Q.has(R::wat)) {
xConn[Ix::WaterRate] =
- units.from_si(M::liquid_surface_rate, Q.get(R::wat));
}
if (Q.has(R::gas)) {
xConn[Ix::WaterRate] =
- units.from_si(M::gas_surface_rate, Q.get(R::gas));
}
xConn[Ix::ResVRate] = 0.0;
if (Q.has(R::reservoir_oil)) {
xConn[Ix::ResVRate] -=
units.from_si(M::rate, Q.get(R::reservoir_oil));
}
if (Q.has(R::reservoir_water)) {
xConn[Ix::ResVRate] -=
units.from_si(M::rate, Q.get(R::reservoir_water));
}
if (Q.has(R::reservoir_gas)) {
xConn[Ix::ResVRate] -=
units.from_si(M::rate, Q.get(R::reservoir_gas));
}
}
} // XConn
} // Anonymous
Opm::RestartIO::Helpers::AggregateConnectionData::
AggregateConnectionData(const std::vector<int>& inteHead)
: iConn_(IConn::allocate(inteHead))
, sConn_(SConn::allocate(inteHead))
, xConn_(XConn::allocate(inteHead))
{}
// ---------------------------------------------------------------------
void
Opm::RestartIO::Helpers::AggregateConnectionData::
captureDeclaredConnData(const Schedule& sched,
const EclipseGrid& grid,
const UnitSystem& units,
const data::WellRates& xw,
const std::size_t sim_step)
{
const auto& wells = sched.getWells(sim_step);
connectionLoop(wells, grid, sim_step, [&units, &xw, this]
(const Well& well, const std::size_t wellID,
const Connection& conn, const std::size_t connID) -> void
{
auto ic = this->iConn_(wellID, connID);
auto sc = this->sConn_(wellID, connID);
IConn::staticContrib(conn, connID, ic);
SConn::staticContrib(conn, units, sc);
auto xi = xw.find(well.name());
if ((xi != xw.end()) &&
(connID < xi->second.connections.size()))
{
auto xc = this->xConn_(wellID, connID);
XConn::dynamicContrib(xi->second.connections[connID],
units, xc);
}
});
}

View File

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

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