Compare commits

...

756 Commits

Author SHA1 Message Date
Atgeirr Flø Rasmussen
1a2b0c8cba
Merge pull request #1212 from akva2/mark_deprecated
mark module as deprecated
2018-01-17 21:14:53 +01:00
Arne Morten Kvarving
07151426f1 mark module as deprecated 2018-01-17 17:53:22 +01:00
Atgeirr Flø Rasmussen
4e62c66dcd
Merge pull request #1211 from akva2/remove_grid_utilities
remove some grid related utilities
2018-01-17 12:41:29 +01:00
Joakim Hove
f693b757d3
Merge pull request #1210 from stefoss23/test_RelpermDiagnostics_PARSE_EXTRA_RECORDS_compliant
test_RelpermDiagnostics made to use PARSE_EXTRA_RECORDS.
2018-01-17 12:27:24 +01:00
Steinar Foss
d887618581 test_relpermdiagnostics: ParseContext set to default for all enum fields. 2018-01-17 11:27:16 +01:00
Arne Morten Kvarving
8240cca69e remove some grid related utilities
moved to opm-grid
2018-01-17 10:40:51 +01:00
Steinar Foss
aa125c2620 test_relpermdiagnostics makes no reference to PARSE_EXTRA_RECORDS. 2018-01-17 10:34:01 +01:00
Steinar Foss
68cd8510cd test_RelpermDiagnostics: .DATA file correct, test throws exception for parser errors. 2018-01-17 09:50:21 +01:00
Steinar Foss
cb61da132b test_RelpermDiagnostics made to use PARSE_EXTRA_RECORDS. 2018-01-16 17:59:05 +01:00
Atgeirr Flø Rasmussen
de2c3817bc
Merge pull request #1209 from akva2/remove_more_utilities
remove some generic utility classes
2018-01-16 17:44:44 +01:00
Arne Morten Kvarving
f4111ead14 remove some generic utility classes
moved to opm-common
2018-01-16 13:57:54 +01:00
Atgeirr Flø Rasmussen
5881cfe5da
Merge pull request #1208 from akva2/remove_utilities
changed: remove some generic utility classes
2018-01-12 10:43:00 +01:00
Arne Morten Kvarving
9603fbd57f changed: remove some generic utility classes
moved to opm-common
2018-01-11 16:58:43 +01:00
Arne Morten Kvarving
6c9365ac17
Merge pull request #1207 from atgeirr/utility-fixes
Utility fixes
2018-01-11 16:02:20 +01:00
Atgeirr Flø Rasmussen
2977d8659e Make constructor generic.
This supports std::vector and Opm::TableColumn (from opm-parser) as before,
but without requiring any OPM includes, making the class independent.
2018-01-11 15:00:49 +01:00
Atgeirr Flø Rasmussen
d700402b15 Remove unused boost include. 2018-01-11 15:00:20 +01:00
Atgeirr Flø Rasmussen
666591d79c
Merge pull request #1206 from atgeirr/remove-unused-program
Remove unused program
2018-01-11 13:59:16 +01:00
Atgeirr Flø Rasmussen
900dbc6096 Remove unneeded includes from compute_tof_from_files.cpp 2018-01-11 12:27:24 +01:00
Atgeirr Flø Rasmussen
a5c14af204 Remove unused program compute_tof. 2018-01-11 12:26:55 +01:00
Atgeirr Flø Rasmussen
cf82a41229
Merge pull request #1205 from akva2/remove_transport
remove implicit transport code
2018-01-10 16:07:21 +01:00
Arne Morten Kvarving
529278d2b9 remove implicit transport code
moved to opm-upscaling
2018-01-09 16:09:28 +01:00
Joakim Hove
cc20b89e73
Merge pull request #1196 from GitPaean/fixing_history_tests
fixing history mode tests
2018-01-09 14:37:10 +01:00
Kai Bao
0d96749d4d fixing a test related to history mode. 2018-01-08 09:08:05 +01:00
Arne Morten Kvarving
c2c35b90b8
Merge pull request #1204 from akva2/package_prereq
package prereqs file
2018-01-05 16:13:41 +01:00
Arne Morten Kvarving
3b89515a8c package prereqs file 2018-01-05 10:42:52 +01:00
Atgeirr Flø Rasmussen
8b34a6e795
Merge pull request #1203 from akva2/remove_build_status
remove travis build status from README.md
2018-01-04 12:58:59 +01:00
Arne Morten Kvarving
a77b07ddfd remove travis build status from README.md 2018-01-04 12:09:55 +01:00
Joakim Hove
b190a0531d
Merge pull request #1202 from joakim-hove/rm-travis
Removed travis integration
2018-01-02 20:29:57 +01:00
Joakim Hove
1f4447df98 Removed travis integration 2017-12-26 12:31:05 +01:00
Arne Morten Kvarving
0f70255b86
Merge pull request #1201 from akva2/self_prereqs
changed: put prereqs in module itself
2017-12-20 15:19:23 +01:00
dr-robertk
761788100d
Merge pull request #1200 from andlaus/some_fixes
Some fixes
2017-12-20 13:04:12 +01:00
Arne Morten Kvarving
6264404883 changed: put prereqs in module itself 2017-12-19 12:42:19 +01:00
Andreas Lauser
8d98d76c17 do not conditionally remove the PETSc and UMFPack source files from the list anymore
these files should now compile even if the corresponding libraries
are not available.
2017-12-14 12:17:59 +01:00
Andreas Lauser
a1543115aa remove unused travis files
these have not been used for a while. .travis.yml and the files in opm-common/travis/ are in charge
2017-12-11 11:33:52 +01:00
Andreas Lauser
204ef58bb6 replace #if HAVE_CONFIG_H by #ifdef HAVE_CONFIG_H
it seems like most build systems pass a -DHAVE_CONFIG_H flag to the
compiler which still causes `#if HAVE_CONFIG_H` to be false while it
clearly is supposed to be triggered.

That said, I do not really see a good reason why the inclusion of the
`config.h` file should be guarded in the first place: the file is
guaranteed to always available by proper build systems, and if it was
not included the build either breaks at the linking stage or -- at the
very least -- the runtime behavior of the resulting libraries will be
very awkward.
2017-12-11 11:33:52 +01:00
Andreas Lauser
634a7bef42 make call_umfpack.c compile even if UMFPACK is not available
That said, don't try to call any of its functions or you'll regret it
at runtime!
2017-12-11 11:33:52 +01:00
Andreas Lauser
fbec8c2300 make the PETSc code compile even if PETSc is not available
if PETSc is not available, the .cpp file will compile fine because it
will be reduced to be empty, but trying to include
LinearSolverPetsc.hpp in this case will result in an error.
2017-12-11 11:33:52 +01:00
Andreas Lauser
9796066199 remove bit-rotten SimulatorState.cpp file
the corresponding header file is MIA.
2017-12-11 11:33:52 +01:00
Atgeirr Flø Rasmussen
ec58bfb224
Merge pull request #1192 from andlaus/add_energy_phase
Add energy phase
2017-12-11 11:32:31 +01:00
Andreas Lauser
93a7b2da36 PhaseUsage: handle polymer and solvent the same way as energy 2017-12-11 10:30:14 +01:00
Andreas Lauser
c685e86f91 add an energy "phase"
This is quite a hack: Even though energy is not a "phase" and it is
also not considered in MaxNumPhases and pu.num_phases because this
would break a lot of assumptions in old code, it is nevertheless
assigned an "canonical index" that can be translated "active index"
via PhaseUsage::phase_pos[]. This awkwardness is needed because much
of the legacy OPM code conflates the concepts of "fluid phase" and
"conserved quantity" and fixing that issue would basically mean an
almost complete rewrite of much of the legacy code. That said, the
same statement applies to polymer and solvent, but these are currently
handled as even more second-class citizens because they are not even
given a canonical index and also cannot be translated into an active
one.
2017-12-11 10:30:14 +01:00
Atgeirr Flø Rasmussen
d97a5c5734
Merge pull request #1197 from akva2/remove_tutorials
remove tutorials which have been moved to opm-simulators
2017-12-06 12:33:15 +01:00
Arne Morten Kvarving
febdc04e80 remove tutorials which have been moved to opm-simulators 2017-12-06 12:07:33 +01:00
Bård Skaflestad
efc2915b74
Merge pull request #1195 from akva2/quell_unhandled_warning
fixed: add ENERGY to switch to quell unhandled enum value warning
2017-12-05 19:51:17 +01:00
Arne Morten Kvarving
0c1ed25eb1 fixed: add ENERGY to switch to quell unhandled enum value warning 2017-12-05 17:13:08 +01:00
Atgeirr Flø Rasmussen
c9c4c81661
Merge pull request #1188 from totto82/handleWEFAC
Handle WEFAC
2017-12-05 08:37:44 +01:00
Atgeirr Flø Rasmussen
55348d6441
Merge pull request #1193 from akva2/move_utils_to_simulators
Move utils to simulators
2017-12-05 08:36:54 +01:00
Atgeirr Flø Rasmussen
54b5910921
Merge pull request #1194 from akva2/move_average_to_upscaling
remove Average.hpp (from build system)
2017-12-05 08:36:13 +01:00
Arne Morten Kvarving
0a4cc569aa remove Average.hpp (from build system)
moved to opm-upscaling
2017-12-04 16:48:18 +01:00
Arne Morten Kvarving
860e3d5831 remove some unused files 2017-12-04 16:32:14 +01:00
Arne Morten Kvarving
97098ac190 remove files moved to opm-simulators from build system 2017-12-04 16:25:27 +01:00
Tor Harald Sandve
bcd83025ec Add efficiencyFactor to GuideRate 2017-12-01 11:32:35 +01:00
Tor Harald Sandve
1b13f44e12 Handle WEFAC
Added test combining WEFAC and GEFAC
2017-11-30 13:45:05 +01:00
Atgeirr Flø Rasmussen
1d1347d2b3
Merge pull request #1190 from totto82/BUGFIX_equil
Fix pvtIndex map for cases with non-active eqlnum regions.
2017-11-28 07:31:04 +01:00
Tor Harald Sandve
19796e2ddc Fix pvtIndex map for cases with non-active eqlnum regions. 2017-11-27 13:40:09 +01:00
Atgeirr Flø Rasmussen
2a88805822
Merge pull request #1187 from totto82/removeBlackOilPropsFromInit
Remove black oil props from init
2017-11-27 07:26:45 +01:00
Atgeirr Flø Rasmussen
37421c62da
Merge pull request #1189 from andlaus/remove_configure
remove the configure wrapper script
2017-11-24 13:12:14 +01:00
Tor Harald Sandve
729d6cf30e Adress PR review issues 2 2017-11-24 10:52:57 +01:00
Andreas Lauser
f786d4749e remove the configure wrapper script
this used to provide autotools compatibility, but it has not been working for a while. Thus it is IMO better to remove it in order not to mislead people.
2017-11-24 10:36:46 +01:00
Tor Harald Sandve
d1a654f414 Fix 2p bug 2017-11-22 09:24:52 +01:00
Tor Harald Sandve
bce19d87dc Adress PR review issues 2017-11-22 08:31:57 +01:00
Tor Harald Sandve
833b019413 Remove the usage of partition_unif_idx() from opm-core 2017-11-21 15:01:52 +01:00
Tor Harald Sandve
3486e98ae3 Cleaning the initialization code
-remove whitespaces
-fix documentation
2017-11-21 12:52:07 +01:00
Tor Harald Sandve
e613f2b8c5 Use &ref not shared_pointer to MaterialLawManager 2017-11-21 12:08:10 +01:00
Tor Harald Sandve
12108d57ab Remove blackoilPhases and phaseUsage from the initialization code
Note 1: The initialization code now always consider 3 phases.
For 2-phase cases a trivial (0) state is returned.
Note 2: The initialization code does not compute a BlackoilStats,
but instead pass the initialization object with the initial state.
2017-11-21 12:08:10 +01:00
Tor Harald Sandve
8def11ff93 Remove BlackoilProps from equil initalization code
Use FluidSystem and materialLaw from opm-material
directly not via the BlackoilProps in opm-core
2017-11-21 12:08:10 +01:00
Atgeirr Flø Rasmussen
d049125205
Merge pull request #1186 from akva2/remove_param_group
remove ParameterGroup code
2017-11-18 09:14:11 +01:00
Arne Morten Kvarving
acc631f504 remove ParameterGroup code
moved to opm-common
2017-11-17 13:55:07 +01:00
Atgeirr Flø Rasmussen
d4bbaa1d3e
Merge pull request #1185 from akva2/more_removals
remove more sources which are unused after removals in opm-upscaling
2017-11-17 12:52:28 +01:00
Arne Morten Kvarving
476a64c370 remove more sources which are unused after removals in opm-upscaling 2017-11-17 10:47:15 +01:00
Atgeirr Flø Rasmussen
c3121f0a1a
Merge pull request #1184 from akva2/remove_unused_sources
remove unused code
2017-11-15 14:09:31 +01:00
Arne Morten Kvarving
b208db1b74 remove unused code 2017-11-15 11:56:40 +01:00
Atgeirr Flø Rasmussen
18e230a18b
Merge pull request #1122 from atgeirr/fix-type-bug-in-equil
Fix type bug in equil
2017-11-14 14:40:47 +01:00
Joakim Hove
c2dd80f6c5
Merge pull request #1182 from joakim-hove/use-wells
Updated NNC() constructor arguments.
2017-11-06 17:06:22 +01:00
Atgeirr Flø Rasmussen
c1f16be87b Merge pull request #1183 from akva2/update_rh_packaging
update redhat packaging
2017-10-25 13:06:37 +02:00
Arne Morten Kvarving
132cfc0ff7 update redhat packaging 2017-10-25 09:43:30 +02:00
Joakim Hove
210364ecde Schedule no longer part of EclipseState. 2017-10-24 20:38:15 +02:00
Andreas Lauser
10a07ef9a4 change version to 2018.04-pre 2017-10-19 19:30:31 +02:00
Atgeirr Flø Rasmussen
1e0135c9bd Update swatinit tests to account for bugfix. 2017-10-12 14:27:32 +02:00
Atgeirr Flø Rasmussen
ac9a20da20 Update equil regression reference after bugfix.
Also reduce some very coarse tolerances to more reasonable levels.
2017-10-12 14:27:32 +02:00
Atgeirr Flø Rasmussen
e5a7535a22 Bugfix: type for target capillary pressure. 2017-10-12 14:27:32 +02:00
Atgeirr Flø Rasmussen
e4a8fad29c Merge pull request #1180 from blattms/cleanup-version-ifs
[cleanup] Removes unnecessary if clauses for unsupported DUNE versions.
2017-10-12 13:28:50 +02:00
Atgeirr Flø Rasmussen
c8fc2bd336 Merge pull request #1177 from alfbr/master
Removing redundant checks from Nexus
2017-10-11 21:57:36 +02:00
Markus Blatt
a46e2c7121 [cleanup] Removes unnecessary if clauses for unsupported DUNE versions.
We are targetting DUNE 2.4.* and 2.5.* currently. Therefore this commit removes
the if checks for lower versions to cleanup the code.
2017-10-11 21:25:18 +02:00
Atgeirr Flø Rasmussen
e0fc476fbe Merge pull request #1179 from totto82/fixSwatInitTest
Update the swatinit test base on fix in opm-material#248
2017-10-11 18:53:21 +02:00
Alf B. Rustad
75ff5ea7d5 Cosmetic change 2017-10-11 10:45:18 +02:00
Alf B. Rustad
7e40af760f Cosmetic change 2017-10-11 10:45:18 +02:00
Alf B. Rustad
0a6baab957 Remove remaining Nexus checks 2017-10-11 10:45:17 +02:00
Alf B. Rustad
8f445699e9 Avoid false positives by introducing a tolerance 2017-10-11 10:45:17 +02:00
Alf B. Rustad
8321530c4e Removing redundant checks from Nexus 2017-10-11 10:44:59 +02:00
Tor Harald Sandve
75657ff482 Update the swatinit test base on fix in opm-material#248 2017-10-11 09:39:12 +02:00
Atgeirr Flø Rasmussen
417c5b2d46 Merge pull request #1178 from andlaus/fix_mcu
mark initHydroCarbonState() as inline
2017-10-05 09:06:57 +02:00
Andreas Lauser
2ab9b5de45 mark initHydroCarbonState() as inline
this allows it to be used in multiple compile units without the linker
running amok.
2017-10-04 19:24:20 +02:00
Arne Morten Kvarving
33305c4f1f Merge pull request #1175 from blattms/cmakify-sibling-search
Cmakify sibling search
2017-09-27 09:34:48 +02:00
Joakim Hove
f696042f26 Merge pull request #1176 from joakim-hove/master
Updated NNC() constructor.
2017-09-26 18:43:54 +02:00
Markus Blatt
6ff0433435 Got rid of false warning for empty opm_common_DIR. 2017-09-26 16:38:41 +02:00
Joakim Hove
8a3fe0a3f6 Updated NNC() constructor. 2017-09-26 14:30:50 +02:00
Markus Blatt
660a65aec9 Drop support for OPM_COMMON_ROOT.
Users should either rely in sibling search, use opm-common_DIR, or
set CMAKE_PREFIX_PATH correctly to find opm-common.
2017-09-25 12:58:10 +02:00
Markus Blatt
9a278c32b1 Allow arbitrary clone directories and <prefix><module-name><postfix> build directories 2017-09-25 12:48:08 +02:00
Markus Blatt
b544bfe9cd Warn if OPM_COMMON_ROOT and opm-common_DIR are set and use the latter. 2017-09-25 12:29:54 +02:00
Markus Blatt
babfbd5e28 Changed find_package call to require opm-common.
Previously, QUIET was passed to opm-common which would
not even print a message if there is a problem. Now cmake
will fail if OPM_COMMON_ROOT is not set, and neither guessing
opm_common_DIR did  work nor searching in the default locations.
2017-09-25 12:29:54 +02:00
Markus Blatt
1f8e56311e Added deprecation warning if OPM_COMMON_ROOT is used 2017-09-25 12:29:54 +02:00
Markus Blatt
355d4e7809 Added warning if opm-common_DIR is not an existing directory. 2017-09-25 12:29:49 +02:00
Atgeirr Flø Rasmussen
1a8ae0a95a Merge pull request #1174 from akva2/update_packaging_libecl
update packaging to reflect new libecl
2017-09-25 10:05:40 +02:00
Arne Morten Kvarving
059cfa5a0c update packaging to reflect new libecl 2017-09-25 09:44:52 +02:00
Arne Morten Kvarving
96c4e8f531 Merge pull request #1171 from akva2/req_dune_2.4
require dune >= 2.4
2017-09-22 11:38:44 +02:00
Markus Blatt
b8838d28b3 Added sibling search mechanism using ${PROJECT_BINARY_DIR} for opm-common
If sibling search is activated and opm-common_DIR is not set, then
we try to determine the build directory layout from ${PROJECT_BINARY_DIR}.
The following two possibilities are supported:
 + <modules-build-dir>/<project-name>
 + <project-name>/<build-dir>
where <project-name> is the case sensitive module name (in this case
opm-common).

This results in the following search precedence:
1. User set opm-common_DIR
2. sibling directories search (if the directories exist)
3. Default (system) CMake search path
2017-09-15 15:37:51 +02:00
Markus Blatt
d3b7f24abb Introduced mandatory call to project in top level CMakeLists.txt
Somehow this was never called in the OPM modules. But the CMake documentation
actually says:
"The top-level ``CMakeLists.txt`` file for a project must contain a
literal, direct call to the ``project()`` command; loading one
through the ``include()`` command is not sufficient.  If no such
call exists CMake will implicitly add one to the top that enables the
default languages (``C`` and ``CXX``).
"

Without it some variables (like CMAKE_PROJECT_NAME) are not correctly defined.
2017-09-15 15:37:51 +02:00
Atgeirr Flø Rasmussen
c98683e31e Merge pull request #1173 from totto82/fix_fallout_none_productionSpecification
Fix fallout if no group controll (NONE) is specified for a group
2017-08-18 12:21:03 +02:00
Tor Harald Sandve
9a306def92 Fix fallout if no group controll (NONE) is specified for a group 2017-08-18 08:56:26 +02:00
Atgeirr Flø Rasmussen
4a8d74a910 Merge pull request #1172 from totto82/removeState
Add interface for passing cell pressures directly in wellState.init(...)
2017-08-10 14:21:53 +02:00
Tor Harald Sandve
843e8c9a6f Add interface for passing cell pressures directly in wellState.init(...) 2017-08-03 10:31:10 +02:00
Arne Morten Kvarving
86524b27aa require dune >= 2.4 2017-07-19 14:32:57 +02:00
Atgeirr Flø Rasmussen
41234f1bee Merge pull request #1169 from totto82/impl_polymer
Add polymer to blackoilstate
2017-06-23 13:31:40 +02:00
Tor Harald Sandve
d935458fca Add polymer to phase usage. 2017-06-16 13:40:29 +02:00
Tor Harald Sandve
fc380041f2 Add polymer to blackoilstate 2017-06-12 15:37:57 +02:00
Atgeirr Flø Rasmussen
a8a46ee5ae Merge pull request #1167 from GitPaean/fixing_petsc_compilation
removing the unused parameter:: for LinearSolverPetsc
2017-06-12 11:12:45 +02:00
Atgeirr Flø Rasmussen
4bab353e90 Merge pull request #1168 from dr-robertk/PR/remove-warnings
[cleanup] remove two uninitialized warnings in SaturationProposFromDeck.
2017-06-07 14:08:57 +02:00
Robert Kloefkorn
d058d8e380 [cleanup] remove two uninitialized warnings in SaturationProposFromDeck. 2017-06-07 13:19:21 +02:00
Kai Bao
67fbac5c95 removing the unused parameter:: for LinearSolverPetsc
to fix the compilation when PETsc exists.
2017-06-06 11:00:51 +02:00
Atgeirr Flø Rasmussen
d504715caa Merge pull request #1165 from blattms/fix-warnings
Fix some warnings
2017-06-02 17:03:14 +02:00
Markus Blatt
327d146caa Fix uninitialized warning intpfa calculation 2017-05-24 12:12:52 +02:00
Markus Blatt
1231870e56 Add missing include of config.h
Closes OPM/opm-core#1164
2017-05-24 12:11:49 +02:00
Atgeirr Flø Rasmussen
3f403a8470 Merge pull request #1162 from totto82/add_solvent_to_pu
Implement solvent model in flow_ebos
2017-05-19 10:02:59 +02:00
Joakim Hove
02b1e58a77 Merge pull request #1161 from joakim-hove/use-libecl
Use libecl in jenkins
2017-05-10 13:36:53 +02:00
Tor Harald Sandve
dbe7930ef7 Add SSOL to blackoilState
Stores the solvent saturation in the simulator container.
2017-05-10 11:14:53 +02:00
Tor Harald Sandve
daecfa7e55 Add solvent to phaseUsage 2017-05-08 10:29:51 +02:00
Joakim Hove
419aedfcbf Use libecl in jenkins 2017-05-07 12:54:08 +02:00
Atgeirr Flø Rasmussen
acc0f81260 Merge pull request #1160 from akva2/remove_parameters
changed: remove embedded 'parameters' namespace in ParamGroup
2017-05-02 07:19:14 +02:00
Arne Morten Kvarving
f5999e3fcb changed: remove embedded 'parameters' namespace in ParamGroup
inconsistent and unnecessary.

this is purely a cosmetic change, the only exception was a function with
the generic name 'split', which was renamed to splitParam to avoid confusion.
2017-04-28 15:34:11 +02:00
Atgeirr Flø Rasmussen
eeadc43cad Merge pull request #1159 from akva2/remove_xml_params
changed: remove XML support for ParameterGroup
2017-04-28 14:07:23 +02:00
Arne Morten Kvarving
a59ce6581f changed: remove XML support for ParameterGroup 2017-04-28 11:26:38 +02:00
Atgeirr Flø Rasmussen
d837401d33 Merge pull request #1158 from akva2/no_native_in_packaging
disable native tuning in packaging
2017-04-28 08:36:55 +02:00
Arne Morten Kvarving
9dc2fc4a82 disable native tuning in packaging 2017-04-26 14:55:47 +02:00
Atgeirr Flø Rasmussen
fdd7b39587 Merge pull request #1157 from andlaus/fix-non-MPI-build
fix non-MPI builds
2017-04-20 21:47:08 +02:00
Atgeirr Flø Rasmussen
0cb21a8c04 Merge pull request #1156 from totto82/memfix_wellControl
FIX memory leakage in well_controls
2017-04-20 20:59:09 +02:00
Andreas Lauser
d690549842 fix non-MPI builds
some headers must be included unconditionally.
2017-04-20 15:12:34 +02:00
Tor Harald Sandve
a96c1f9ea0 FIX memory leakage in well_controls
The Alq and vfp is set free in well_controls_destroy to avoid memory
leakage.
2017-04-20 12:58:16 +02:00
Atgeirr Flø Rasmussen
e52b7ef2ad Merge pull request #1155 from akva2/add_deps
Packinging update backport
2017-04-18 23:17:14 +02:00
Arne Morten Kvarving
b6c5247ef9 remove binary package
no binaries left here
2017-04-18 12:17:42 +02:00
Arne Morten Kvarving
aed63397c5 add new dependencies 2017-04-18 12:09:18 +02:00
Andreas Lauser
8ef90deb2a Change the version to 2017.10-pre 2017-04-13 12:58:55 +02:00
Andreas Lauser
2e9b04fc37 Merge pull request #1152 from GitPaean/fixing_updating_well_petentials_2
[WIP] changes needed to compute well potentials each time step.
2017-04-12 10:34:24 +02:00
Kai Bao
e77f726906 adding flag to tell when using well potential for guide rate
for WellNode.
2017-04-11 16:53:19 +02:00
Kai Bao
29372e287c removing well potentails from WellsManager 2017-04-11 16:53:19 +02:00
Kai Bao
44924b9ee9 small corrections in WellsGroup
should not change reults.
2017-04-11 16:53:19 +02:00
Kai Bao
bd9ff2ad94 not negative rate_for_group_control
in WellsGroup::updateWellProductionTargets. The current implementation
of group control is allowed tiny over-producing of the group target
while it cause negative rate_for_group_control . When all the wells are
not under group controls, it can cause oscillation of the control mode
later.

Probably a better way is to do something when we see overproducing
happens.
2017-04-11 16:53:19 +02:00
Kai Bao
b7ea707928 Tracking situation when group overproducing its target
Bascially it means that something wrong with our algorithms. Not sure
how to handle it properly yet.
2017-04-11 16:53:19 +02:00
Kai Bao
a6f4772ca1 not applying the group control in WellsManager
since the guide rates are not completed yet.
2017-04-11 16:53:19 +02:00
Kai Bao
17fb6f9ffe not setting up guide_rates in WellsManager based on well potentials
That part is moved to well_collection, will be handled in the beginning
of time step.
2017-04-11 16:53:19 +02:00
Kai Bao
d50d21d8e0 Wells specified with GRUP will be put under group control
immediately.
2017-04-11 16:53:19 +02:00
Kai Bao
2fcb449196 Always updating the well targets under group control
for each iteration. Even all the wells are under individual controls,
their group targets/constraints should also be updated for correct group
behavoirs.
2017-04-11 16:53:19 +02:00
Kai Bao
7701b68814 handle the situatioin when giving a NaN prod target to injectors
When all production wells are under individual controls, the group can
have zero production guide rates, which can result NaN value targets for
injectors.
2017-04-11 16:53:19 +02:00
Kai Bao
81fb20160c Considering the injection phase when applying VREP group controls
GCONINJE only support single phase injection. When we inject one phase,
the values of distr for other phases should be set to be zero.

It will provide one strategy to figure out which phase we are
injecting. It is important when we inject one phase while the well is
claimed to be another phase in WELSPECS.
2017-04-11 16:53:19 +02:00
Kai Bao
aaaacce49e adding a flag to indicate whether group controls applied
for WellCollection.
2017-04-11 16:53:19 +02:00
Kai Bao
be00224a4b adding a function setGuideRatesWithPotentials() to WellCollection
it only handles the calculation based on wellPotentials though.

Or it should also give each well a value for wells does not specify a
guide rates? which will be some value same for all the wells?
2017-04-11 16:53:19 +02:00
Atgeirr Flø Rasmussen
524233c60a Merge pull request #1154 from andlaus/report-failure
SimulatorReport: make it possible to report failed time steps
2017-04-11 12:29:37 +02:00
Andreas Lauser
b368cb0177 SimulatorReport: make it possible to report failed time steps
the method can still be called as it used to be. in this case no
failures are reported, though.
2017-04-10 23:31:24 +02:00
Atgeirr Flø Rasmussen
3b5e15771b Merge pull request #1153 from babrodtk/hysteresis_output
Added functions in SaturationProps for hysteresis IO
2017-04-07 15:54:26 +02:00
Atgeirr Flø Rasmussen
901dbc248e Merge pull request #1145 from totto82/add_sat_table_id
Add sat table id to well struct
2017-04-07 14:43:33 +02:00
babrodtk
c3dc875005 Added functions in SaturationProps for hysteresis IO 2017-04-07 14:31:22 +02:00
Tor Harald Sandve
a8261b62da Add sat table id to well struct 2017-04-06 13:52:27 +02:00
Atgeirr Flø Rasmussen
e2f8375a1a Merge pull request #1151 from totto82/fix_test_equil
Fix test equil
2017-04-05 09:01:12 +02:00
Tor Harald Sandve
e289c8f35b Enable swatinit equil test 2017-03-22 10:26:03 +01:00
Tor Harald Sandve
77b9311f2c FIX swatinit test in test_equil
The capillarySwatinit.DATA is updated to make it possible to run in Ecl.
Referance solutions is updated accordingly.
2017-03-22 10:20:59 +01:00
Joakim Hove
0b1d5745a6 Merge pull request #1149 from joakim-hove/disable-equil-swatinit
Temporarily disabled EQUIL + SWATINIT test.
2017-03-21 19:50:55 +01:00
Joakim Hove
b55ce6b53e Temporarily disabled EQUIL + SWATINIT test. 2017-03-21 16:49:14 +01:00
Joakim Hove
53eb7e2f1c Merge pull request #1150 from joakim-hove/travis-install-bc
Travis: apt-get install bc
2017-03-21 16:48:28 +01:00
Joakim Hove
1caaa5bd35 Travis: apt-get install bc 2017-03-21 16:21:47 +01:00
Atgeirr Flø Rasmussen
d3d7c64107 Merge pull request #1147 from totto82/fix_initial_rs
Do not extrapolate initial rs and rv values in the depth tables
2017-03-16 13:55:17 +01:00
Tor Harald Sandve
7579f2bdb9 Do not extrapolate initial rs and rv values in the depth tables 2017-03-16 12:57:56 +01:00
Atgeirr Flø Rasmussen
7bf6da1953 Merge pull request #1146 from GitPaean/putting_wells_under_group_control
putting wells under immidatel group control when specified with GRUP
2017-03-10 10:18:39 +01:00
Kai Bao
70b19780b4 putting wells under immidatel group control when specified
with GRUP.
2017-03-07 12:48:30 +01:00
Atgeirr Flø Rasmussen
03e005bb76 Merge pull request #1143 from GitPaean/fixing_thp_initialization
Fixing thp initialization
2017-03-02 15:51:38 +01:00
Atgeirr Flø Rasmussen
aecfa0e448 Merge pull request #1144 from totto82/output_initial_rs
Do not set rs=rsSat and rv=rvSat for the saturated case
2017-02-23 09:13:40 +01:00
Tor Harald Sandve
70b6a6e5ef Do not set rs=rsSat and rv=rvSat for the saturated case 2017-02-22 15:57:53 +01:00
Kai Bao
b97c585519 do not assign non-zero THP value when no THP involved. 2017-02-17 13:45:55 +01:00
Kai Bao
6ca48313ca correcting the confusing indent in WellState init 2017-02-17 13:28:29 +01:00
Atgeirr Flø Rasmussen
6d01c29686 Merge pull request #1142 from GitPaean/output_thp
adding thp to the report for summary output.
2017-02-16 13:16:14 +01:00
Kai Bao
8198c256a9 adding thp to the report for summary output. 2017-02-13 10:15:58 +01:00
Atgeirr Flø Rasmussen
d5a9f27e5e Merge pull request #1141 from akva2/remove_adaptive_time_stepping
remove AdaptiveTimeStepping class
2017-02-10 15:16:56 +01:00
Arne Morten Kvarving
e6cad074c2 Remove adaptive time stepping and simulator timer classes and tests/examples
They have been moved to opm-simulators
2017-02-10 14:53:22 +01:00
Atgeirr Flø Rasmussen
119b5b1a3a Merge pull request #1140 from andlaus/fix_gcc7_warnings
fix a GCC 7 warning
2017-02-10 10:31:13 +01:00
Arne Morten Kvarving
61e8c0b8d3 Merge pull request #1139 from akva2/fipnum_in_adaptive
changed: pass fipnum array into adaptive time stepping loop
2017-02-09 12:06:39 +01:00
Arne Morten Kvarving
1e25b6fcfb changed: pass fipnum array into adaptive time stepping loop
needed as substep summary reports requires FIP data to be available.
add calculation of this data if output is requested and summary
config holds relevant keywords.
2017-02-09 09:33:32 +01:00
Andreas Lauser
8ef2a923ec fix a GCC 7 warning
GCC 7 warns

```
dynamic exception specifications are deprecated in C++11; use ‘noexcept’ instead [-Wdeprecated]
```

here.
2017-02-07 12:55:26 +01:00
Atgeirr Flø Rasmussen
c5a80e97a2 Merge pull request #1138 from andlaus/refactor_well_permeability
do not explicitly pass the permeability to the well model anymore
2017-01-27 13:15:50 +01:00
Andreas Lauser
c5a0ea7524 do not explicitly pass the permeability to the well model anymore
this information is already part of the EclipseState. The reason why
this should IMO be avoided is that this enforces an implementation
(ordering of the permeability matrices) the simulator on the well
model. If this needs to be done for performance reasons, IMO it would
be smarter to pass an array of matrices, instead of passing a raw
array of doubles.  I doubt that this is necessary, though: completing
the full Norne deck takes about 0.25 seconds longer on my machine,
that's substantially less than 0.1% of the total runtime.

in order to avoid code duplication, the permeability extraction
function of the RockFromDeck class is now made a public static
function and used as an implementation detail of the WellsManager.

finally, the permfield_valid_ attribute is removed from the
RockFromDeck class because this data was unused and not accessible via
the class' public API.
2017-01-27 12:51:12 +01:00
Atgeirr Flø Rasmussen
5aa5ac89c5 Merge pull request #1137 from GitPaean/group_ebos_vrep
set the VREP control as current control when applying VREP control
2017-01-27 11:11:42 +01:00
Kai Bao
78bf488a2a set the VREP control as current control when applying VREP control
for the first time

Not sure it is always the better things to do here, while it can help
the consistence of the two current controls in the well_controls and
well_state.
2017-01-25 14:11:37 +01:00
Atgeirr Flø Rasmussen
5e67765229 Merge pull request #1136 from andlaus/update_dune.module
update the dune.module file
2017-01-20 13:58:48 +01:00
Andreas Lauser
24f709f983 update the dune.module file 2017-01-20 13:26:26 +01:00
Atgeirr Flø Rasmussen
674d97c660 Merge pull request #1134 from GitPaean/group_ebos
updating the group control limit for individual control wells
2017-01-18 14:08:33 +01:00
Kai Bao
cb84571540 considering effieciency factor when calculating production rate. 2017-01-16 16:13:44 +01:00
Kai Bao
9fe6d80f99 adding groupTargetConverged() to WellCollection 2017-01-16 15:55:35 +01:00
Kai Bao
3a06a2dd50 adding groupProdTargetConverged() to WellsGroup
When the group is producing its target, we consider it is converged.
When the group is not producing its target, while the group can not
produce more based on its own limits, we also consider it is converged.

When the group is not producing its target, while the group can
potentially produce more, we consider it is not converged.
2017-01-16 14:19:52 +01:00
Kai Bao
8f658a92f2 adding canProdueMore() function to wellsGroup
to indicate whether the group can produce more to match the group target
when they are not producing enough compared with the group target.
2017-01-16 11:25:23 +01:00
Kai Bao
713c833b0a updating the group control limit for individual control wells
to provide a better standard for the wells under individual control to
return to group control. For example, some wells get really big group
control limit and switch to individual control, it is very difficult for
them to return to group control with that kind of unreasonable fixed
group limit.
2017-01-12 15:44:44 +01:00
Atgeirr Flø Rasmussen
7830083e9b Merge pull request #1133 from blattms/parallel-accumulate
Added an accumulate method that allows to switch off non-owner entries.
2017-01-11 15:16:48 +01:00
Markus Blatt
ac6965de2e Added an accumulate method that allows to switch off overlap entries.
It does using a mask vector with entries 0 or 1. If that is not provided
it falls back to std::accumulate.
2017-01-11 12:18:39 +01:00
Atgeirr Flø Rasmussen
8851f072a3 Merge pull request #1132 from atgeirr/throw-on-solvent
Throw if solvent phase injected.
2017-01-10 08:28:16 +01:00
Atgeirr Flø Rasmussen
00dad30432 Throw if solvent phase injected. 2017-01-09 16:33:03 +01:00
Atgeirr Flø Rasmussen
7ef8971be4 Merge pull request #1120 from jokva/density-from-eclipsestate
Use Density from EclipseState
2017-01-09 10:38:30 +01:00
Atgeirr Flø Rasmussen
8daa0f440c Merge pull request #1125 from jokva/reduce-deck-use-relperm-diagnostics
Don't rely on Deck for checkTable and checkPhase
2017-01-09 09:35:25 +01:00
Atgeirr Flø Rasmussen
e2023ed38e Merge pull request #1124 from jokva/read-rock-from-eclipsestate
Read ROCK from EclipseState, not Deck
2017-01-09 09:33:47 +01:00
Atgeirr Flø Rasmussen
898ca1b7e0 Merge pull request #1131 from atgeirr/increase-iters-for-equil
Increase max iterations for capillary curve inversion.
2017-01-09 09:31:14 +01:00
Atgeirr Flø Rasmussen
be26c072e1 Increase max iterations for capillary curve inversion.
Triggered by a new two-phase case.
2017-01-06 15:24:08 +01:00
Atgeirr Flø Rasmussen
3e3a76d37d Merge pull request #1129 from totto82/test_swatinit_fix
Make it optinal to apply SWATINIT
2017-01-06 10:23:39 +01:00
Tor Harald Sandve
d5e2e5d2e5 Add test for swatinit 2017-01-05 09:09:25 +01:00
Tor Harald Sandve
5ac89ad8a7 Make it optinal to apply SWATINIT
The reasoning behind this to make it possible to initialize the case
without SWATINIT in order to compute the same defaulted THPRES values as
Ecl. The initialization needs to be re-computed to account for SWATINIT
in the simulations.
2017-01-02 15:10:09 +01:00
Andreas Lauser
cf9f37169d Merge pull request #1128 from atgeirr/remove-unused-deck-arg
Remove unused Deck function argument.
2017-01-02 11:01:43 +01:00
Atgeirr Flø Rasmussen
fdd81eacaa Remove unused Deck function argument. 2017-01-02 09:47:57 +01:00
Andreas Lauser
d89b48689b Merge pull request #1127 from atgeirr/silence-warning
Fix order of initialization.
2016-12-29 14:05:41 +01:00
Atgeirr Flø Rasmussen
2e49273da7 Fix order of initialization. 2016-12-29 13:55:42 +01:00
Jørgen Kvalsvik
bca5c8e8de Don't rely on Deck for checkTable and checkPhase
Prefer using EclipseState over Deck.
2016-12-20 14:08:58 +01:00
Jørgen Kvalsvik
ad4033b9dc Read ROCK from EclipseState, not Deck 2016-12-20 12:24:27 +01:00
jokva
ec060d513b Merge pull request #1123 from jokva/read-pressure-swat-sgas-from-es
Read RS,RV,PRESSURE,SWAT,SGAS from EclipseState
2016-12-20 10:01:13 +01:00
Jørgen Kvalsvik
8cc624fd0d Read RS,RV,PRESSURE,SWAT,SGAS from EclipseState
Prefer reading these values from EclipseState rather than the Deck type.
2016-12-19 14:26:27 +01:00
Atgeirr Flø Rasmussen
4ea6611ecc Merge pull request #1117 from totto82/storeIfTimeStepFails
Store whether timestep failed or not
2016-12-19 12:21:31 +01:00
Tor Harald Sandve
2a3a825895 Store whether timestep failed or not
Used in flow ebos to tell the simulator to recalculate the cached
quantities for failed timesteps.
2016-12-19 10:52:59 +01:00
Atgeirr Flø Rasmussen
f65739c718 Merge pull request #1121 from andlaus/fix_build
add missing semicolon to fix the build
2016-12-16 11:08:54 +01:00
Andreas Lauser
62c56ff716 add missing semicolon to fix the build
some versions of boost seem to be more picky about this than others...
2016-12-16 10:29:52 +01:00
Jørgen Kvalsvik
59cc0a1635 Use Density from EclipseState 2016-12-15 16:06:46 +01:00
Joakim Hove
e53b0a58fa Merge pull request #1119 from jokva/pvtw-from-eclipsestate
Read PVTW from EclipseState
2016-12-06 22:41:39 +01:00
Jørgen Kvalsvik
f0b4c4f390 Read PVTW from EclipseState
Read the PVTW table entries from EclipseState rather than manually
through the Deck object.
2016-12-06 14:53:41 +01:00
Bård Skaflestad
28a02f6953 Merge pull request #1118 from atgeirr/remove-redundant-tests
Remove redundant tests.
2016-12-05 13:43:05 +01:00
Atgeirr Flø Rasmussen
dec5bdf7c4 Remove redundant tests.
The unit constant test has been added to opm-parser since the
unit support has been moved there. The parser test is simply
redundant.
2016-12-05 12:55:37 +01:00
Andreas Lauser
078de1b039 Merge pull request #1116 from andlaus/SimulatorReport_fix_substep_output
AdaptiveTimeStepping: fix stupid (but harmless) mistake in the sub-step info message
2016-12-03 15:08:05 +01:00
Andreas Lauser
b5b3507cb0 AdaptiveTimeStepping: fix stupid (but harmless) mistake in the sub-step info message
that was a copy-and-pasto: newton iterations = linearizations - 1
2016-12-03 15:04:32 +01:00
Atgeirr Flø Rasmussen
87650a3819 Merge pull request #1115 from atgeirr/remove-more-grid-stuff
Remove more files moved to opm-grid.
2016-12-01 13:52:35 +01:00
Atgeirr Flø Rasmussen
f72f996008 Merge pull request #1112 from andlaus/improve_SimulatorReport
Improve simulator report
2016-11-30 19:33:55 +01:00
Atgeirr Flø Rasmussen
fd552926d8 Remove more files moved to opm-grid. 2016-11-30 14:29:37 +01:00
Andreas Lauser
ce02a4bb92 clean up and extend the SimulationReport class
it now also accounts for assembly, linear solve, update and output
write time and indicates if an operation has converged.
2016-11-30 11:27:49 +01:00
Atgeirr Flø Rasmussen
ebfcea125d Merge pull request #1114 from akva2/update_jenkins_grid
update jenkins dependency graph
2016-11-29 22:50:09 +01:00
Arne Morten Kvarving
868d008353 update jenkins dependency graph
opm-grid is now an upstream
2016-11-29 21:54:08 +01:00
Atgeirr Flø Rasmussen
8d129d7172 Merge pull request #1113 from atgeirr/remove-grid-stuff
Move grid things to opm-grid.
2016-11-29 21:04:14 +01:00
Atgeirr Flø Rasmussen
ec85a922ac Update dune.module to reflect changed dependency graph. 2016-11-29 13:31:48 +01:00
Atgeirr Flø Rasmussen
c7cc24385a Remove files moved to opm-grid. 2016-11-29 13:25:22 +01:00
Atgeirr Flø Rasmussen
602f3252e6 Merge pull request #1103 from GitPaean/fixing_warning
warning fixed related to petsc
2016-11-23 12:37:31 +01:00
Joakim Hove
647e005297 Merge pull request #1109 from jokva/get-ref-depth-timestep
Ask for reference depth at timestep.
2016-11-22 23:12:34 +01:00
Arne Morten Kvarving
1edcdbc055 Merge pull request #1110 from akva2/update_downstreams_ewoms
update downstream list
2016-11-22 16:03:28 +01:00
Arne Morten Kvarving
1dd4500bd2 update downstream list
ewoms moved in the hierarchy
2016-11-22 15:24:56 +01:00
Jørgen Kvalsvik
cadb14c9e8 Ask for reference depth at timestep. 2016-11-22 14:22:09 +01:00
Atgeirr Flø Rasmussen
1e462f4c04 Merge pull request #1107 from GitPaean/fixing_findWellNode
Adding a flag to WellCollection whether group control active
2016-11-17 23:27:06 +01:00
Kai Bao
4427c85d77 a flag to WellCollection whether group control active 2016-11-17 16:26:19 +01:00
Atgeirr Flø Rasmussen
af874ada54 Merge pull request #1106 from atgeirr/remove-moved-tests
Remove tests that were moved to opm-output.
2016-11-17 10:41:06 +01:00
Atgeirr Flø Rasmussen
3c35e767d4 Remove tests that were moved to opm-output. 2016-11-17 09:47:58 +01:00
Bård Skaflestad
1429046029 Merge pull request #1105 from andlaus/fix_valgrind_errors
fix some valgrind errors in the init code
2016-11-16 19:08:48 +01:00
Andreas Lauser
1d98c3b8ca fix some valgrind errors in the EQUIL code
this fixes some valgrind errors while doing the twophase capability
for flow_ebos: In all previously tested cases, these errors were
probably non-fatal because the memory illegally accessed here is
likely to be allocated (but after this function was finished it
contained garbage).

note that I'm not completely sure if this patch is semantically
correct, so I'd appreciate some input who understands it. (what is
"z"?)
2016-11-16 17:20:24 +01:00
Kai Bao
fda1016532 warning fixed related to petsc 2016-11-16 15:35:35 +01:00
Atgeirr Flø Rasmussen
054fa92e61 Merge pull request #1104 from GitPaean/fixing_findWellNode
rewriting the findWellNode function
2016-11-16 15:00:13 +01:00
Kai Bao
6e4f9e708e rewriting the findWellNode function
with assuming we should always find the well in the well collection.
2016-11-16 14:27:15 +01:00
Joakim Hove
df920e4970 Merge pull request #1101 from jokva/changes-in-grouptree
GroupTree interface changed upstream
2016-11-16 13:26:58 +01:00
Atgeirr Flø Rasmussen
c901e2ec7c Merge pull request #1088 from GitPaean/group_control
group control_updating well production targets within a group.
2016-11-16 13:20:04 +01:00
Kai Bao
c3b00dc7fd fixing the comments.
No change in the functions and results.
2016-11-16 11:40:10 +01:00
Kai Bao
708bfd169b addressing a few comments. 2016-11-16 09:51:06 +01:00
Kai Bao
bf2f9b3f06 adding target_updated_ flag to WellNode
to save some repeated efforts when updating Well Targets.
2016-11-16 09:43:28 +01:00
Kai Bao
55eec0b2ed checking whehter need to update before updateWellTargets. 2016-11-15 13:56:49 +01:00
Kai Bao
f9f5bacee4 cleaning up more unused flag from WellsGroup 2016-11-11 11:29:12 +01:00
Joakim Hove
0cf4021698 Merge pull request #1102 from jokva/stack-allocd-items
Use new DeckItem constructor interface.
2016-11-11 11:07:34 +01:00
Kai Bao
91b8c872eb removing a few not-used function with the new strategy. 2016-11-10 17:50:30 +01:00
Kai Bao
95997e208c different strategy is using when updating the well targets
When the group has wells both under individual control and group
control, since the well rates under individual control changes each
iteration, the well targets for this kind of group need to be updated
each iteration.

When we change to use implicit well potentials later, which is supposed
to be more accurate, we probably should always (unless we decided not to)
update the well targets each iteration.
2016-11-10 17:22:25 +01:00
Kai Bao
085785bf26 adding function findWellNode() to WellCollection
to return the WellNode* instead of WellGroupInterface*
2016-11-10 16:28:40 +01:00
Kai Bao
b319e1a75d cleaning up and adding more comments for better understanding.
No functional change.
2016-11-10 16:28:40 +01:00
Kai Bao
3e8b1bdb82 applying the efficiency factor to VREP control. 2016-11-10 16:28:40 +01:00
Kai Bao
76a2108ea9 adding VREP injection support.
not handling multiple injection wells for moment.
2016-11-10 16:28:40 +01:00
Kai Bao
88181f4948 using variable only_group instead of hard-coded false.
when applying group production control.
2016-11-10 16:28:40 +01:00
Kai Bao
06d380df51 correcting the typo in efficiency
It was efficicency, which causes inconvenience when searching variables
or functions.
2016-11-10 16:28:40 +01:00
Kai Bao
2b289f8964 adding basic support for group injection control.
more testing will be required later.
2016-11-10 16:28:40 +01:00
Kai Bao
63e5755fa9 applying efficiency factor to the group control. 2016-11-10 16:28:40 +01:00
Kai Bao
a0e1fcf89d function for accumulative efficiency factor for WellNode
This is the final efficiency factor that goes to the source/sink terms
in the material balance equations.
2016-11-10 16:28:40 +01:00
Kai Bao
013c907e66 adding efficiency factor to the WellsGroupInterface.
The one for the WellNode should be specified with WEFAC, which we are
not handling for the moment, so we just set it to be 1.0 for the moment.
2016-11-10 16:28:40 +01:00
Kai Bao
2e135388a6 refactoring function updateWellProductionTargets()
To handle different types of control mode.
2016-11-10 16:28:40 +01:00
Kai Bao
b8ac674f9b When NONE is specified, no group control enforcement.
NONE is specified in GCONPROD or GCONINJE.
2016-11-10 16:28:40 +01:00
Kai Bao
65d61d1c4f output cleanining up 2016-11-10 16:28:40 +01:00
Kai Bao
352c185edf removing the use of cast between base class and derived class
between WellsGroupInterface and WellsGroup, WellNode.
2016-11-10 16:28:40 +01:00
Kai Bao
32e9b26ce8 revising updateWellTargets to remove the dependency of WellState
avoiding template using here. It is possible we will need WellState
eventually, while only using the well_rates for the moment.
2016-11-10 16:28:40 +01:00
Kai Bao
fec53a1af5 fixing the comilation problem from rebasing. 2016-11-10 16:28:40 +01:00
Kai Bao
e183ab6ccd revising injectionGuideRate and productionGuideRate
for WellNode. It gives a better logic.
2016-11-10 16:28:40 +01:00
Kai Bao
7295f26f54 adding updateWellInjectionTargets updateWellProductionTargets
For WellsGroup. At least for the current moment, the updation of the
well targets for injectors and producers should be handled in a
seprate way.
2016-11-10 16:28:40 +01:00
Kai Bao
46a9a62741 functions for indicating injection and production upating.
it is for WellCollection, which is logically wrong. It should be done in
the group level, while things will be different for multi-level groups.

The current implementation basically works for current needs, that we
only have one group.
2016-11-10 16:28:40 +01:00
Kai Bao
6942a986da adding isProducer() and isProjector() to wellNode class.
Did not see type() function there, while it should still be a okay idea.
2016-11-10 16:28:40 +01:00
Kai Bao
e28715b601 parameter forced to only_group from applyInjGroup applyProdGroup
forced and only_group basically mean two opposite things. Having both of
them in the same context will be really confusing and error-prone.

And also, we do not do anything forcedly. We do things base on what
setup tells us to do.

Only_group may not be the final name, while deinitely a better one than
forced.
2016-11-10 16:28:40 +01:00
Kai Bao
a438680fb0 putting more things in the prototyping test. 2016-11-10 16:28:40 +01:00
Kai Bao
0d5a86cc71 keeping adding group control related in. 2016-11-10 16:28:40 +01:00
Kai Bao
f628064884 keeping putting group controlling in. 2016-11-10 16:28:40 +01:00
Kai Bao
4214cfec83 adding a non-const wellCollection() in WellsManager.
For the WellModel from the simulator to use. Not decided totally,
    well_collection might need to be updated during the simualtion due
    to the update the target of wells.
2016-11-10 16:28:40 +01:00
Kai Bao
36bedfcf67 not returning zero from double WellNode::productionGuideRate
Current understanding. Two ways might prevent to return the guide_rate here
1. preventing the well from group control with keyword WGRUPCON
2. the well violating some limits and working under limits. We do not have strategy
to handle this situation yet.
2016-11-10 16:28:40 +01:00
Kai Bao
3bdf0eae11 Not return from the WellNode:applyInjGroupControl
unless we prevent the well from group control with keyword WGRUPCON.
2016-11-10 16:28:40 +01:00
Kai Bao
c5958da6c9 To make the injection well be able to receive the target.
Very hacky way here. The logic of the code is that only
a well is specified under GRUP control, it is under group
control. Which is not the case observed from the result.
From the result, if we specify group control with GCONPROD
and WCONPROD for a well, it looks like the well will be
under group control. TODO: make the logic correct here
instead of using `false` here.
2016-11-10 16:28:40 +01:00
Kai Bao
a0d3ceff62 group can be both injection group and production group.
Change if else to two ifs.
2016-11-10 16:28:40 +01:00
Kai Bao
f79fe1f7ad adding support for the FLD for the control type of group control.
And also adding support for the liquid rate type of guide rate type.
2016-11-10 16:28:40 +01:00
Jørgen Kvalsvik
48cbbdee19 GroupTree interface changed upstream
Updates to the slightly modified GroupTree interface from opm-parser.
2016-11-09 13:04:33 +01:00
Jørgen Kvalsvik
24acbd1c23 Use new DeckItem constructor interface. 2016-11-07 15:07:04 +01:00
Atgeirr Flø Rasmussen
59ef5f2b11 Merge pull request #1100 from akva2/fix_well_serialization
fixed: use correct indices for perforation pressure
2016-11-07 14:53:09 +01:00
Arne Morten Kvarving
630d5477d8 fixed: use correct indices for well state completion data 2016-11-04 16:40:09 +01:00
Atgeirr Flø Rasmussen
76bdc081c0 Merge pull request #1099 from atgeirr/bump-version
dune.module: change version to 2017.04-pre
2016-11-04 12:30:17 +01:00
Atgeirr Flø Rasmussen
be462f6c3a dune.module: change version to 2017.04-pre 2016-11-04 12:26:59 +01:00
Joakim Hove
e348baa6c7 Merge pull request #1098 from jokva/phase-in-runspec
Read phase information from EclipseState.runspec
2016-11-02 11:52:24 +01:00
Andreas Lauser
5376fb618d Merge pull request #1096 from andlaus/Evaluation_accessors
use accessor methods to access the value and derivatives of Evaluation objects
2016-11-01 13:16:05 +01:00
Jørgen Kvalsvik
23ef9dce5c Read phase information from EclipseState.runspec 2016-11-01 11:37:27 +01:00
Atgeirr Flø Rasmussen
5d33f0d900 Merge pull request #1095 from atgeirr/fix-diag-twophase
Fix saturation family diagnostics for two-phase case.
2016-10-28 10:41:17 +02:00
Atgeirr Flø Rasmussen
e0dc670604 Merge pull request #1097 from totto82/initialTimestep
Make it possible to set initial timestep
2016-10-28 10:26:31 +02:00
Tor Harald Sandve
d96b7193ee Make it possible to set initial timestep
Default is kept at -1.0. I.e. this PR does not change the current
behaviour.
2016-10-28 09:03:29 +02:00
Andreas Lauser
1387c5f834 use accessor methods to access the value and derivatives of Evaluation objects 2016-10-27 16:53:52 +02:00
Atgeirr Flø Rasmussen
1ce4c47b09 Fix saturation family diagnostics for two-phase case. 2016-10-27 11:58:50 +02:00
Atgeirr Flø Rasmussen
5963dd0027 Merge pull request #1094 from atgeirr/completion-data-changes
Adapt to changed data::Wells API.
2016-10-25 13:58:37 +02:00
Atgeirr Flø Rasmussen
9dfd16cffb Adapt to changed data::Wells API. 2016-10-25 10:41:16 +02:00
Atgeirr Flø Rasmussen
125d1696d6 Merge pull request #1093 from dr-robertk/PR/fix-wellmanager-constructor
Make WellsManager compile with c++-11.
2016-10-23 07:36:08 +02:00
Atgeirr Flø Rasmussen
ad5d98664c Merge pull request #1075 from jokva/output-data-wells-sans-vectors
WIP: Restore from data::Wells without vector dumps
2016-10-21 14:58:10 +02:00
Robert Kloefkorn
d082d977fd Merge remote-tracking branch 'upstream/master' into PR/fix-wellmanager-constructor 2016-10-21 13:55:21 +02:00
Atgeirr Flø Rasmussen
cc72693348 Merge pull request #1090 from atgeirr/convergence-failure-problem-not-error
Convergence failure is "problem" not "error"
2016-10-21 12:49:10 +02:00
Robert Kloefkorn
044d47b9fb [bugfix] Make WellsManager compile with c++-11. 2016-10-21 10:43:32 +02:00
Andreas Lauser
c884b5c1d5 Merge pull request #1087 from andlaus/implement_JFUNC
RelpermDiagnostics: fix the build
2016-10-21 10:05:54 +02:00
Atgeirr Flø Rasmussen
069b65a635 Add option to enable logging (default true).
This makes it possible to avoid logging from this class in a parallel setting.
2016-10-20 22:39:08 +02:00
Atgeirr Flø Rasmussen
e38b9ffcb7 Classify convergence failure as a "problem" not "error". 2016-10-20 22:36:20 +02:00
Atgeirr Flø Rasmussen
8e8b624d4c Ensure logging only on first rank. 2016-10-20 22:36:20 +02:00
Andreas Lauser
7d9097490b RelpermDiagnostics: fix the build
this broke because EclEpsScalingPointsInfo::extractScaled() now
requires the deck and the EclipseState as additional parameters.
2016-10-20 20:01:03 +02:00
jokva
f4586f5380 Merge pull request #1089 from jokva/remove-shared-ptr
The great shared_ptr purge
2016-10-20 19:18:41 +02:00
Jørgen Kvalsvik
e98d6204ad Restore from data::Wells without vector dumps
opm-output's data::Wells interface changed to no longer just accept a
dump of opm-core's WellState object. Update WellState to restore itself
from this new interface rather than reading the dumped vectors as-is.
2016-10-20 16:36:47 +02:00
Jørgen Kvalsvik
1057e6d3d0 Update to shared_ptr-less parser interface. 2016-10-20 10:14:41 +02:00
Atgeirr Flø Rasmussen
518c9849ff Merge pull request #1092 from andlaus/fix_make_install
fix `make install`
2016-10-20 09:44:16 +02:00
Andreas Lauser
4ae5f16cb3 fix make install
some CMakeLists_files.txt needed some adaptation after the recent unit
changes. this is analogous to OPM/opm-parser#943
2016-10-19 15:22:41 +02:00
Atgeirr Flø Rasmussen
1fe0ee77c6 Merge pull request #1091 from atgeirr/fix-compile
Undo premature API change adaption.
2016-10-18 15:37:40 +02:00
Atgeirr Flø Rasmussen
33872cfb4a Undo premature API change adaption. 2016-10-18 15:34:53 +02:00
Atgeirr Flø Rasmussen
f72832dbd6 Merge pull request #1085 from andlaus/opm-parser_units
consolidate the units code to opm-parser
2016-10-18 15:25:20 +02:00
Joakim Hove
99d8ab73f4 Merge pull request #1081 from joakim-hove/celldata-container
Header file moved in opm-output.
2016-10-17 11:46:33 +02:00
Arne Morten Kvarving
35ffd9b647 Merge pull request #1086 from akva2/update_packaging_devtoolset
update redhat6 packaging
2016-10-12 15:53:47 +02:00
Arne Morten Kvarving
d25cefa011 update redhat6 packaging
build using devtoolset-3
2016-10-12 14:15:15 +02:00
Arne Morten Kvarving
7a295747de Merge pull request #1084 from akva2/update_packaging_dep_tree
update packaging to reflect new dependency tree
2016-10-12 14:14:48 +02:00
Andreas Lauser
07707ecc30 consolidate the unit system to opm-parser
since the unit code within opm-parser is now a drop-in replacement,
this simplifies things and make them less error-prone.

unfortunately, this requires quite a few PRs. (most are pretty
trivial, though.)
2016-10-10 17:50:26 +02:00
Arne Morten Kvarving
f91cb76086 update packaging to reflect new dependency tree 2016-10-10 09:39:24 +02:00
Joakim Hove
5fdb868526 Header file moved in opm-output. 2016-10-06 14:23:47 +02:00
Pål Grønås Drange
edb57704f9 Merge pull request #1082 from jokva/remove-shared-ptrs-from-schedule
Schedule::getGroup returns reference, not pointer
2016-10-06 13:01:19 +02:00
Jørgen Kvalsvik
29ba3465b4 Schedule::getGroup returns reference, not pointer 2016-10-05 15:24:14 +02:00
Atgeirr Flø Rasmussen
df24d28671 Merge pull request #1077 from blattms/quiet-opm-throw
Log the message of exceptions in the catch clause of adaptive time stepper
2016-10-04 12:34:26 +02:00
Markus Blatt
a44500623a Log the message of exceptions in the catch clause of adaptive time stepper. 2016-10-04 10:33:56 +02:00
Atgeirr Flø Rasmussen
22f7d1ec32 Merge pull request #1078 from andlaus/fix_initial_rs_and_rv
set the Rv and Rs factors to the saturated values for cells which have no gas and no oil
2016-09-30 14:40:06 +02:00
Atgeirr Flø Rasmussen
dda280fcf9 Merge pull request #1080 from akva2/units_constexpr
changed: generate unit type conversion constants on compile-time
2016-09-30 13:42:37 +02:00
Atgeirr Flø Rasmussen
227b5851b8 Merge pull request #1076 from totto82/start_using_TUNING2
Add contructor for adaptiveTimeStepper that uses values from TUNING
2016-09-30 13:02:50 +02:00
Arne Morten Kvarving
04fe79aa23 changed: generate unit type conversion constants on compile-time
as a bonus it avoids unused variable warnings in compile
units only using parts of the conversion units.
2016-09-30 11:35:28 +02:00
Tor Harald Sandve
f202f2948c Add initalizer for adaptiveTimeStepper that uses values from TUNING
Some of the tuning values from the TUNING keywords is used to tune the
timestepping.
2016-09-30 10:36:30 +02:00
Atgeirr Flø Rasmussen
a6995fdf3e Merge pull request #1073 from blattms/only-write-substeps-in-adaptive-time-stepper
Only call writeTimeStep for real sub steps.
2016-09-29 17:48:12 +02:00
Atgeirr Flø Rasmussen
fe19c589c4 Merge pull request #1071 from totto82/moveBlackoilstate
Remove Compat.hpp
2016-09-29 17:32:57 +02:00
Atgeirr Flø Rasmussen
98402c2e8d Merge pull request #1079 from akva2/update_petsc
update petsc code
2016-09-29 16:49:03 +02:00
Arne Morten Kvarving
e8c3389b80 update petsc code
- api changes in newer versions
- do not manually destroy the preconditioner. this is, and has always
  been, owned by the ksp object and dies with its destruction.
2016-09-29 14:19:48 +02:00
Andreas Lauser
3647834b96 set the Rv and Rs factors to the saturated values for cells which have no gas and no oil
the purpose of this is to get a more defined behaviour when doing the
gravity correction/upstream cell determination in the flux term.

I consider this to be just a kludge, so if anyone has a better idea of
what the composition for the non-existing gas and oil phases is,
please tell me. (note that generic compositional models do not exhibit
this issue because the composition of all fluids is always fully
defined because each component is assumed to dissolve in every phase.)
2016-09-28 16:38:40 +02:00
Tor Harald Sandve
60da3d9213 Remove Compat.hpp
Compat.hpp is moved to opm-simulators
2016-09-27 08:39:26 +02:00
Markus Blatt
ac37eef547 Only call writeTimeStep for real sub steps.
Previously, we also called it when the full time step was done.
As the simulator writes that information anyway and we cannot call
it a sub step, we omit the final write in the adaptive time stepper.
2016-09-26 11:51:17 +02:00
Atgeirr Flø Rasmussen
08b90e8acd Merge pull request #1064 from totto82/hardcodedTimestepping
Timestepper based on user input
2016-09-26 08:53:36 +02:00
Joakim Hove
7f1026551a Merge pull request #1072 from atgeirr/fix-warnings
Fix a few warnings
2016-09-25 21:06:33 +02:00
Atgeirr Flø Rasmussen
74e9925769 Avoid shadowing warning by using explicit scope. 2016-09-23 15:15:17 +02:00
Atgeirr Flø Rasmussen
cd75174650 Forward declare structs as same to avoid warning. 2016-09-23 15:14:36 +02:00
Atgeirr Flø Rasmussen
040e3f9872 Merge pull request #1067 from blattms/zero-initialize-wells-with-no-perforations
Zero initialize wells with no perforations.
2016-09-22 10:08:55 +02:00
Tor Harald Sandve
ff81d48551 Guard against non-existing file 2016-09-21 13:46:31 +02:00
Markus Blatt
f426a03801 Zero initialize wells with no perforations.
For these wells access its well_cells might read of the bounds
an array if they are the last wells in the struct. Therefore
we cannnot initialiue first_cell and the well control is uninitialized,
to.

With this commit theses wells are now detected and theor bhp, thp, and well_rates
are initialized to zero.
2016-09-21 12:23:34 +02:00
Tor Harald Sandve
f1bdd67438 Small fixes hardcodedTimestepControl
-- avoid using eof()
-- add comments
-- no longer assumes two lines of comments.
-- revert change to default value for timestep.initial_step_length
-- make contructer explicit
-- pass reference
2016-09-21 09:39:36 +02:00
Tor Harald Sandve
6e9bb4cf0b Timestepper based on userInput
A new timestepper that reads timesteps from a file generated using
ecl_summary "DECK" TIME
and applies it to the simulator

Also a parameter timestep.initial_step_length (default 1 day) is added
to controll the frist timestep.
2016-09-21 09:39:36 +02:00
Atgeirr Flø Rasmussen
ce78dc5560 Merge pull request #1065 from ANerd/output_present_phases
Pass PhaseUsage to WellState::report
2016-09-20 11:03:35 +02:00
Anders Matheson
18a5c0b748 Remove unused parameter warning 2016-09-20 10:00:50 +02:00
Anders Matheson
4186a37563 Pass PhaseUsage to WellState::report 2016-09-20 09:41:20 +02:00
Atgeirr Flø Rasmussen
cf16b0affe Merge pull request #1062 from blattms/refactor-parallel-wellsmanager
Use provided set of deactivated wells in parallel.
2016-09-19 13:42:37 +02:00
Atgeirr Flø Rasmussen
ff7be8eced Merge pull request #1063 from totto82/fix_miscNum_diagnostics
Bugfix: Let NTMISC determine number of MISC tables
2016-09-16 13:15:50 +02:00
Tor Harald Sandve
a1058d45ea use table.size() instead of read from deck. 2016-09-16 10:31:41 +02:00
Tor Harald Sandve
da29e292b5 Bugfix: Let NTMISC determine number of MISC tables
Number of misc tables is given by NTMISC (MISCNUM) and not NTSFUN
(SATNUM)
2016-09-16 10:31:41 +02:00
Markus Blatt
82822160af Use an unordered_set of string to identify defunct wells.
We do not rely on the order of the set and hope that the lookup
might be faster as it prevents string comparisons.
2016-09-13 10:55:15 +02:00
Markus Blatt
21de431eb1 Do exclude SHUT wells from lookup of deactivated wells.
This should be prevent some unnecessary find calls in the set.
2016-09-13 10:55:15 +02:00
Markus Blatt
c4f0539534 Revert "Use index according to eclipse schedule to identify deactivated wells."
This reverts commit 09205dfa074af24b381595d02c15e799523ddb2b.

We cannot use the index as it might change for a well between different
report steps. Unfortunately the only persistent way to identify wells
over all report steps in the schedule seems to be the well name.
2016-09-13 10:55:15 +02:00
Markus Blatt
05add1884f Use index according to eclipse schedule to identify deactivated wells. 2016-09-13 10:55:15 +02:00
Markus Blatt
17f93ce3bd Use provided set of deactivated wells in parallel.
Before this commit we tried to compute whether a well is represented on
the processor using the grid information. Due to the overlap region and
possible completion on deactivated cells of the global grid this is not
even possible. E.g. we cannot distinguish whether a completion is just
not represented on the domain of a process or the corresponding cell is
not active in the simulation.

With this commit we refactor to passing the well manager an explicit
list of name of wells that should be completely neglected. This information
can easily by computed after the loadbalancer has computed partitions.
2016-09-13 10:55:15 +02:00
Atgeirr Flø Rasmussen
474128fe2d Merge pull request #1060 from babrodtk/output_writer_celldata
Output writer cell data
2016-09-08 09:55:14 +02:00
Joakim Hove
19f6d540fc Merge pull request #1059 from joakim-hove/create-eclipsegrid
Create eclipsegrid
2016-09-07 11:11:10 +02:00
Joakim Hove
8666c8b687 UgGridHelpers::createEclipseGrid( )
- A new function createEclipsegrid has been added to the UgGridHelpers
  namespace.

- The UnstructuredGrid C structure has been augmented with a new member:
  double * zcorn which can be used to hold a copy of the zcorn
  value *after* minpv induced modifications.
2016-09-07 10:56:29 +02:00
Atgeirr Flø Rasmussen
8efc75367b Merge pull request #1061 from babrodtk/warning_fixes
Warning fixes
2016-09-07 10:46:15 +02:00
babrodtk
466e721e0b Fixed warnings 2016-09-06 07:50:02 +02:00
Joakim Hove
b7bb01b77e shared_ptr<EclipseGrid> -> const EclipseGrid& 2016-09-03 17:49:46 +02:00
babrodtk
d71aceff0b Initial version for outputting cell data 2016-09-01 14:37:41 +02:00
Joakim Hove
9615f0e9d7 Using { .. } initialization. 2016-08-31 09:55:28 +02:00
babrodtk
aef10cc292 Merge branch 'master' of github.com:OPM/opm-core 2016-08-30 14:53:11 +02:00
Arne Morten Kvarving
8329dc7474 Merge pull request #1058 from akva2/add_multiconfiguration
add multiconfiguration support to jenkins build script
2016-08-24 16:02:08 +02:00
Arne Morten Kvarving
14cd4b0472 add multiconfiguration support to jenkins build script
also unifies build.sh and build-pr.sh and gets rid of
build-opm-core.sh
2016-08-23 14:09:18 +02:00
Joakim Hove
89a22c30b0 Merge pull request #1057 from akva2/simplify_after_ert_reorg
simplify jenkins build scripts after ert reorganization
2016-08-22 17:29:28 +02:00
Arne Morten Kvarving
8ea0b62b33 simplify jenkins build scripts after ert reorganization 2016-08-22 13:23:30 +02:00
Joakim Hove
a6a95eeac1 Merge pull request #1056 from pgdr/downstream-transmult-and-shared_ptrs
TransMult and InitConfig are references
2016-08-09 09:33:06 +02:00
Pål Grønås Drange
77a93abcac Minor tweaks and updates in test blackoilstate 2016-08-08 15:58:17 +02:00
Pål Grønås Drange
2a773b735e transmult and initconfig are ref's, use ref for EclipseState constructor 2016-08-08 10:02:53 +02:00
Atgeirr Flø Rasmussen
6f264781b0 Merge pull request #1053 from andlaus/print_linearizations
also keep track of the number of linearizations needed for the simulation
2016-08-02 15:01:19 +02:00
Andreas Lauser
d3ff659437 also keep track of the number of linearizations needed for the simulation 2016-08-02 14:05:14 +02:00
Atgeirr Flø Rasmussen
a6f08d13d5 Merge pull request #1052 from andlaus/pass_timer_instead_of_dt
pass the timer object instead of the time step size to the simulators
2016-08-02 11:05:33 +02:00
Bård Skaflestad
bc0977ec3d Merge pull request #1054 from qilicun/fix-output-well-iterations
Drop useage of std::numeric_limits
2016-07-22 00:47:23 +02:00
Bård Skaflestad
bb387e16f9 Merge pull request #1055 from andlaus/fix_rock_compressibility
fix incorrect derivative  of rock compressibility w.r.t. pressure
2016-07-20 11:32:19 +02:00
Andreas Lauser
25c4a8c156 fix incorrect derivative of rock compressibility w.r.t. pressure
since

f(x) = 1 + 0.5*g(x)*g(x)

the derivative is

f'(x) = 0 + 2*0.5*g(x) * g'(x) = g(x)*g'(x)

note that the previous incorrect values do not affect the quality of
the obtained results (if the tolerance of the non-linear solver is
chosen to be small enough), but it may have deteriorated convergence
rates.
2016-07-19 18:19:30 +02:00
Liu Ming
65c7a2c197 fix indentation. 2016-07-14 10:30:20 +08:00
Liu Ming
a792c29f00 drop useage of std::numeric_limits 2016-07-14 10:27:13 +08:00
Atgeirr Flø Rasmussen
dae94b5041 Merge pull request #1051 from GitPaean/support_WECON
Support of the keyword WECON
2016-07-05 21:56:48 +02:00
Andreas Lauser
ff899f3c53 pass the timer object instead of the time step size to the simulators 2016-07-05 12:23:55 +02:00
Kai Bao
6f8acf49f8 adding default constructor for DynamicListEconLimited 2016-07-04 16:21:55 +02:00
Kai Bao
1fc189065c adding a initialStep() function to SimulatorTimer
to indicate if the current step is the inital step.
2016-07-04 11:12:53 +02:00
Kai Bao
c58a0fce43 addressing comments.
no functional change.
2016-06-30 16:20:38 +02:00
Kai Bao
30bc54ba4a removing some commented lines. 2016-06-30 15:17:13 +02:00
Kai Bao
4b4492e877 adding stopped wells list to DynamicListEconLimited
when well is closed due to rate economic limits, based on the auto
shut-in configuration, the well can be STOP or SHUT.

When well is closed due to all the connections are closed, it should be
SHUT.
2016-06-30 14:41:14 +02:00
Kai Bao
a07f628469 handling connection closing in DynamicListEconLimited
due to econ limits.
2016-06-30 14:41:14 +02:00
Kai Bao
c7c38374ec adding list_econ_limited to setupWellControls 2016-06-30 14:41:14 +02:00
Kai Bao
bc1fb8e477 WIP in adding class DynamicListEconLimited
to handle the closed wells and connection dynamically based on the
economic limits provied by keyword WECON
2016-06-30 14:41:14 +02:00
Atgeirr Flø Rasmussen
9c6eeae068 Merge pull request #1045 from qilicun/time-messages-to-PRT-file
Change adaptive time stepping message type to OpmLog::note
2016-06-30 09:19:49 +02:00
Liu Ming
50573d1168 output well iterations if it is a valid number. 2016-06-30 09:03:30 +08:00
Liu Ming
2c25bb8262 Add space. 2016-06-28 15:26:06 +08:00
Liu Ming
745666468f output well iterations and non-linear iterations. 2016-06-28 13:40:32 +08:00
Bård Skaflestad
c1b4ed8bc8 Merge pull request #1050 from blattms/make-wells_equal-work-for-null-wells
Make wells_equal work for null wells.
2016-06-27 15:18:09 +02:00
Markus Blatt
cd32e65632 Use NULL instead of 0 in null comparison. 2016-06-27 14:38:30 +02:00
Markus Blatt
7d97ef7e4a Make wells_equal work for only one null pointer. 2016-06-27 13:29:44 +02:00
Markus Blatt
f66f699fca Make wells_equal work for null wells.
This is needed to run test cases without wells with debugging on.
Without this commit we get segmentation fault in an assert statement.
2016-06-27 12:21:45 +02:00
Atgeirr Flø Rasmussen
2177aa745e Merge pull request #1027 from totto82/fix_2p_equil_init
Fix two phase equil initialization
2016-06-24 14:42:48 +02:00
Tor Harald Sandve
fd049a6962 Fixing some nitpicks 2016-06-24 13:36:05 +02:00
Atgeirr Flø Rasmussen
3d5689dc72 Merge pull request #1046 from pgdr/add-dimens-to-norne-deck-test
Added DX/DY/DZ to norne_pvt.data
2016-06-21 22:45:36 +02:00
Pål Grønås Drange
f1024bb210 Added DX/DY/DZ to norne_pvt.data 2016-06-21 16:10:32 +02:00
Liu Ming
afc9e4453a get current date time. 2016-06-21 11:25:05 +08:00
Liu Ming
49d5d4c79a mark time stepping messages type as OpmLog::note 2016-06-21 08:44:32 +08:00
Atgeirr Flø Rasmussen
bdebcf48a3 Merge pull request #1043 from pgdr/remove-return-type-warn
Remove warnings (by throwing), added copyright header
2016-06-20 22:34:40 +02:00
Pål Grønås Drange
06cd6c85f3 Using OPM_THROW to log messages, fixed Copyright headers 2016-06-20 17:20:33 +02:00
Atgeirr Flø Rasmussen
7ddf390bf8 Merge pull request #1044 from akva2/fix_jenkins_again
fixed: broken array loop in jenkins script
2016-06-20 15:00:25 +02:00
Joakim Hove
c686ec69d7 Merge pull request #1041 from jokva/removal-shared_ptr-well
WellPtr and GroupPtr deprecated
2016-06-20 14:57:10 +02:00
Arne Morten Kvarving
08e8297b47 fixed: broken array loop in jenkins script
python, bash, c++, fortran. sometimes you get lost in the syntax jungle.
2016-06-20 14:44:37 +02:00
Pål Grønås Drange
4323b2f4fa Remove [-Wreturn-type] warnings (added throw), added copyright header 2016-06-20 14:13:29 +02:00
Tor Harald Sandve
db03e88090 Fix bug for OIL-GAS case
- Differentiate between active and canonical phase index
2016-06-20 11:14:36 +02:00
Tor Harald Sandve
bd9c514457 Fix reference pressure for oil-water problem
In opm-material the wetting phase is the reference phase for two-phase
problems i.e water for oil-water system, but for flow it is always oil.
Add oil capillary pressure value to shift the reference phase to oil
2016-06-20 10:36:24 +02:00
Tor Harald Sandve
4db70d1902 Fix two phase EQUIL initialization 2016-06-20 10:36:24 +02:00
Atgeirr Flø Rasmussen
d9c33cbcb6 Merge pull request #1039 from atgeirr/fix-compile-maxabs-unsigned
Avoid ambiguous calls to abs with unsigned integers.
2016-06-17 08:02:20 +02:00
Atgeirr Flø Rasmussen
9b2acf96bf Merge pull request #1042 from andlaus/update_dune.module
add opm-output as a dependency to dune.module
2016-06-16 15:21:21 +02:00
Andreas Lauser
aee0020a98 add opm-output as a dependency to dune.module
without it, building with dunecontrol fails...
2016-06-16 14:09:02 +02:00
Atgeirr Flø Rasmussen
f3f6170881 Merge pull request #1038 from qilicun/equil-check
Rise up a warning if equil region has no active cells.
2016-06-16 10:02:49 +02:00
Jørgen Kvalsvik
6e2099d293 WellPtr and GroupPtr deprecated
shared_ptr aliases are considered deprecated and has largely been
removed upstream (and replaced by raw pointers).
2016-06-16 09:33:43 +02:00
Atgeirr Flø Rasmussen
89cb2680a1 Make specialization for all unsigned integer types. 2016-06-16 08:47:21 +02:00
Bård Skaflestad
8f4d65a0c2 Merge pull request #1037 from atgeirr/add-phasepresence-ops
Add operator== and operator!= to PhasePresence.
2016-06-15 19:56:11 +02:00
Bård Skaflestad
6fdfcefaa0 Merge pull request #1040 from atgeirr/fix-linsolverfactory-default-solver
Set default solver depending on configuration.
2016-06-15 17:34:41 +02:00
Atgeirr Flø Rasmussen
15e12c89bf Merge pull request #1034 from qilicun/minor-format-change
Minor format changes
2016-06-15 15:10:57 +02:00
Atgeirr Flø Rasmussen
8f2e2c91b1 Merge pull request #1029 from blattms/make-ownermask-accessible
Make ParallelIstlInformation::ownerMask_ accessible.
2016-06-15 15:08:58 +02:00
Atgeirr Flø Rasmussen
8b2ebc690b Address review comments. 2016-06-15 15:01:45 +02:00
Atgeirr Flø Rasmussen
e6da69575a Set default solver depending on configuration. 2016-06-15 14:32:00 +02:00
Atgeirr Flø Rasmussen
291b13c2d4 Avoid ambiguous calls to abs with unsigned integers. 2016-06-15 10:55:42 +02:00
Liu Ming
34805c1bf7 it should be the same number in EQLNUM. 2016-06-15 16:53:51 +08:00
Liu Ming
a824ef9c22 use correct region number. 2016-06-15 16:52:32 +08:00
Liu Ming
cb82608779 Rise up a warning if equil region has no active cells. 2016-06-15 15:40:38 +08:00
Atgeirr Flø Rasmussen
b5dc48af0e Make new ops const. 2016-06-15 09:20:19 +02:00
Atgeirr Flø Rasmussen
fcb99e425d Add operator== and operator!= to PhasePresence.
This makes it simpler to write code debugging or inspecting changed phase configurations.
2016-06-15 08:57:20 +02:00
Liu Ming
d87afa29ab fix indentation issue. 2016-06-15 11:26:06 +08:00
Liu Ming
881ed8fc49 unify output. 2016-06-15 11:24:20 +08:00
Atgeirr Flø Rasmussen
1b6048016b Merge pull request #1031 from akva2/opm_output_upstream
update jenkins build scripts
2016-06-13 13:37:00 +02:00
Bård Skaflestad
bbd6a5f03d Merge pull request #1035 from akva2/revert_umfpack
Revert "Check for HAVE_UMFPACK in LinearSolverFactory"
2016-06-13 12:37:58 +02:00
Arne Morten Kvarving
ba255d89d3 Revert "Check for HAVE_UMFPACK in LinearSolverFactory"
This reverts commit f54c74db06.
2016-06-13 10:43:21 +02:00
Atgeirr Flø Rasmussen
192bb54e70 Merge pull request #1017 from jokva/umfpack-correct-preprocessor-directive
Check for HAVE_UMFPACK in LinearSolverFactory
2016-06-13 08:43:30 +02:00
Liu Ming
413e3fe381 add "\n" at the end of the message. 2016-06-13 13:55:01 +08:00
Liu Ming
6ae9c3104f minor format changes 2016-06-13 13:49:58 +08:00
Jørgen Kvalsvik
f54c74db06 Check for HAVE_UMFPACK in LinearSolverFactory
Check for the right preprocessor define to enable umfpack support.
Matches the directive set in config.h
2016-06-10 17:00:34 +02:00
jokva
4e40b784af Merge pull request #1032 from joakim-hove/travis-reorg
Using build-all travis script.
2016-06-10 16:38:09 +02:00
Joakim Hove
98707b87a8 Using build-all travis script. 2016-06-10 13:38:13 +02:00
Arne Morten Kvarving
6a8ddb76b2 update jenkins build scripts
output is now an upstream and not a downstream
2016-06-10 13:20:26 +02:00
Joakim Hove
d3aa0926c8 Merge pull request #1016 from jokva/refactor-output-restart
Breaking opm-core dependency in opm-output; new summary implementation
2016-06-10 13:15:34 +02:00
Markus Blatt
c94cdb0de8 Make ParallelIstlInformation::ownerMask_ accessible.
This is needed in opm-simulator to calculate the parallel euclidian
product of the saturations.
2016-06-08 11:02:13 +02:00
Atgeirr Flø Rasmussen
bb2a582aa8 Merge pull request #1028 from qilicun/format-message
Format message
2016-06-08 10:57:31 +02:00
Liu Ming
1db1b3d178 Output file name and line number. 2016-06-08 09:45:32 +02:00
Liu Ming
f948d9ea44 add a blank line. 2016-06-08 09:45:04 +02:00
Atgeirr Flø Rasmussen
7f355929ac Merge pull request #1026 from blattms/add-parallel-linfinity-norm
Added utilities to compute a real L-infinity norm in parallel.
2016-06-07 20:26:23 +02:00
Markus Blatt
324e60171c Added utilities to compute a real L-infinity norm in parallel. 2016-06-07 15:00:57 +02:00
Atgeirr Flø Rasmussen
681846686a Merge pull request #1024 from andlaus/lad_to_dad
rename some variables from "Lad" to "Eval" (was: to "Dad")
2016-06-07 11:43:42 +02:00
Atgeirr Flø Rasmussen
f5cf2d47e1 Merge pull request #1025 from totto82/fix_hydrocarbonstate
Fix to handle cases without DISGAS and VAPOIL
2016-06-07 11:38:16 +02:00
Andreas Lauser
20662fffb9 rename some variables from "*Lad" to "*Eval"
this was an involuntary omission in the "local AD" to "dense AD"
rename...
2016-06-07 11:14:11 +02:00
Tor Harald Sandve
ae9a10942e Fix to handle cases without DISGAS and VAPOIL
- adds boolean has_disgas and has_vapoil to initHydroCarbonState()
2016-06-07 08:18:09 +02:00
Andreas Lauser
42e5e41fa2 Merge pull request #1022 from andlaus/localad_to_densead
rename "local AD" to "dense AD"
2016-06-06 14:02:45 +02:00
Jørgen Kvalsvik
2ad419bd1a Make struct wells unique member of WellState 2016-06-06 12:42:54 +02:00
Jørgen Kvalsvik
392dc8557d 2 -> To 2016-06-06 12:41:48 +02:00
Jørgen Kvalsvik
c0b0b0d40a Newlines 2016-06-06 12:41:04 +02:00
Jørgen Kvalsvik
c6fc7f5e30 Braces. 2016-06-06 12:40:44 +02:00
Jørgen Kvalsvik
1bf201f294 Travis: build opm-output 2016-06-06 12:40:44 +02:00
Jørgen Kvalsvik
be0187d512 WellState::report() to make opm-output Well data 2016-06-06 12:40:44 +02:00
Atgeirr Flø Rasmussen
39924206ca Merge pull request #1023 from qilicun/refine-messagetype
paramemters output should go in Debug mode.
2016-06-06 12:35:37 +02:00
Liu Ming
408ea0845d paramemters output should go in Debug mode. 2016-06-06 11:57:05 +02:00
Andreas Lauser
2d2f86f089 rename "local AD" to "dense AD" 2016-06-03 21:57:48 +02:00
Jørgen Kvalsvik
8f3829bb76 utility/Compat
Introduces some helper functions to quickly enable support for the new
opm-output implementation. Conversion from simulator oriented cell- and
well representation to opm-output defined representation.
2016-05-30 14:24:25 +02:00
Atgeirr Flø Rasmussen
7de314bb7e Merge pull request #1021 from blattms/add-missing-fstream-include
Fix incomplete type error for std::ofstream in examples
2016-05-27 11:15:33 +02:00
Markus Blatt
dbf425411f Fix incomplete type error for std::ofstream in examples
On my system I got
```c++
error: variable ‘std::ofstream file’ has initializer but incomplete type
         std::ofstream file(fname.str().c_str());
```
This is fixed with this commit by including fstream. Previously,
this include might have happened implicitely.
2016-05-27 08:59:00 +00:00
Atgeirr Flø Rasmussen
ef2125f39e Merge pull request #1019 from qilicun/log-more-messages
Write more messages into OpmLog.
2016-05-26 11:20:49 +02:00
Liu Ming
94ee69505a make toString() method as static. 2016-05-24 09:07:28 +08:00
Liu Ming
7eba8b01f5 fix strange indentation. 2016-05-23 10:55:36 +08:00
Liu Ming
eab67baa3b simplify the implementation. 2016-05-23 10:48:51 +08:00
Liu Ming
97eeee516d fix indentation and messages. 2016-05-23 10:47:26 +08:00
Liu Ming
341472456a write well related information into OpmLog. 2016-05-20 16:14:16 +08:00
Liu Ming
b7f7352b6d Add enum to string functions. 2016-05-20 16:13:37 +08:00
Atgeirr Flø Rasmussen
537c4dd730 Merge pull request #1010 from qilicun/log_timer_messages
Log timer messages
2016-05-20 08:39:14 +02:00
Atgeirr Flø Rasmussen
f582de6023 Merge pull request #1018 from qilicun/cleanup-prefix
Cleanup the prefix.
2016-05-20 08:37:39 +02:00
Liu Ming
d06b515c47 write the parameters information into OpmLog. 2016-05-20 14:30:43 +08:00
Liu Ming
f55d216561 log the warning messages to OpmLog. 2016-05-20 14:27:38 +08:00
Liu Ming
a44ab90759 Cleanup the prefix. 2016-05-20 08:54:12 +08:00
Atgeirr Flø Rasmussen
2a43e9631f Merge pull request #1011 from qilicun/format-output-relperm-diagnostics
Unify output messages format.
2016-05-19 15:06:52 +02:00
Liu Ming
b3db61bf7e remove the prefix from raw string, using OpmLog format. 2016-05-19 10:07:36 +08:00
Liu Ming
b5e78ab1ec use StreamLog to output messages. 2016-05-19 09:48:12 +08:00
Liu Ming
3028e819c6 remove internal counter. 2016-05-19 09:47:57 +08:00
Liu Ming
b25a964597 remove internal messages container. 2016-05-19 09:28:34 +08:00
Liu Ming
98a413bf5c use tag for terminal output control. 2016-05-19 09:22:03 +08:00
Atgeirr Flø Rasmussen
747ec8fa8c Merge pull request #1015 from totto82/hydrocarbonState
Add member hydroCarbonState to the BlackoilState
2016-05-18 14:16:53 +02:00
Liu Ming
d660dea73b add missing braces. 2016-05-16 09:04:54 +08:00
Tor Harald Sandve
79f04b6c9e Fixing PR comments
- Use std::vector<HydroCarbonState> instead of std::vector<int>
- Use the initializer list to initialize members in constructors
- Fix indent
- Return OilOnly for cases without gas to avoid potential trouble
further down the line
2016-05-13 12:49:45 +02:00
Tor Harald Sandve
cb4b698b51 Add method for calculating the initial hydroCarbonState
The following hydroCarbonState are used
    enum HydroCarbonState {
        GasOnly = 0,
        GasAndOil = 1,
        OilOnly = 2
    };
Cells almost filled with water are treated as a GasAndOil state
2016-05-13 09:10:13 +02:00
Tor Harald Sandve
31133af803 Add member hydroCarbonState to the BlackoilState
The hydroCarbonState is used to store the hydroCarbonState
  State 1: Gas only
  State 2: Gas and Oil
  State 3: Oil only
An empty vector is return at initialization as
no default values are provided by the blackoilstate.
2016-05-12 10:32:39 +02:00
Liu Ming
dd510244f8 unify the format. 2016-05-10 14:52:13 +08:00
Liu Ming
da70ab4e84 use OpmLog only for error messages. 2016-05-10 14:13:33 +08:00
Atgeirr Flø Rasmussen
8b43643e25 Merge pull request #1009 from blattms/prevent-dereferencing-past-the-end
Prevent dereferencing the end iterator.
2016-05-09 09:40:53 +02:00
Liu Ming
9f90e6cc3f output timer messages for terminal and log file. 2016-05-09 13:31:04 +08:00
Liu Ming
684614fe77 use ostream not std::cout directly. 2016-05-09 13:30:28 +08:00
Markus Blatt
e7a0b60b1c Prevent dereferencing the end iterator.
This happened for empty regions and surfaced when compiling
with "-D_GLIBCXX_DEBUG  -DDEBUG -DGLIBCXX_FORCE_NEW".
2016-05-06 21:40:33 +02:00
Atgeirr Flø Rasmussen
a5d858f396 Merge pull request #1005 from akva2/add_downstream_trigger_support
added: downstream build support in the jenkins trigger
2016-05-03 15:27:09 +02:00
Atgeirr Flø Rasmussen
022e594850 Merge pull request #1006 from atgeirr/bump-version
dune.module: change version to 2016.10-pre
2016-05-03 14:35:28 +02:00
Atgeirr Flø Rasmussen
b248655314 dune.module: change version to 2016.10-pre 2016-05-03 14:31:32 +02:00
Arne Morten Kvarving
94266d37fc added: downstream build support in the jenkins trigger
use 'jenkins build this with downstreams please'.

this will build all downstreams against the PR, and
execute their tests. PR's for upstream and downstream modules
can be specified.

the aggregated test results are attached to the job result on jenkins.
2016-04-29 22:52:09 +02:00
Atgeirr Flø Rasmussen
1fbc689f6c Merge pull request #1003 from babrodtk/two_phase_bugfixes
Two phase bugfixes
2016-04-28 15:42:59 +02:00
babrodtk
131e900cf3 Code cleanup 2016-04-26 07:48:58 +02:00
babrodtk
c8d5174113 Runs first iterations of two-phase test case plausibly 2016-04-26 07:48:58 +02:00
babrodtk
404929fe34 Checkpoint 2016-04-26 07:48:58 +02:00
Arne Morten Kvarving
6db874cbd7 fixed: debian packaging
superlu package was renamed in xenial
2016-04-22 15:28:21 +02:00
Joakim Hove
f9b7a5fe66 Merge pull request #1002 from pgdr/eclipsegrid-is-input
Using getInputGrid API from Parser
2016-04-20 15:50:13 +02:00
babrodtk
3fd6a47e1c Fixed bug where phase_pos was used instead of phase_used 2016-04-20 09:48:15 +02:00
Pål Grønås Drange
973438128c Using getInputGrid API from Parser, changed GridManager to no longer accept Deck in constructor 2016-04-20 08:51:10 +02:00
Pål Grønås Drange
668cd14755 Fixed major indentation issue---whole file indented arbitrarily 2016-04-19 15:20:34 +02:00
Atgeirr Flø Rasmussen
b07f4dd494 Merge pull request #1000 from akva2/updates_for_16.04_packaging
Updates for 16.04 packaging
2016-04-18 11:13:13 +02:00
Arne Morten Kvarving
34ee734737 update debian packaging
- README file was renamed
- build with MPI enabled and add related dependencies
2016-04-18 11:02:56 +02:00
Arne Morten Kvarving
6d9ae3f050 update redhat packaging
- README file was renamed
- use boost 1.48 only on rhel6. rhel7 supplies a newer boost by default.
2016-04-18 11:02:29 +02:00
Andreas Lauser
30956131ec Merge pull request #999 from andlaus/nested_ad
Fix build
2016-04-18 11:01:27 +02:00
Andreas Lauser
145d61d751 adapt code w.r.t. the removal of the tags for Opm::Evaluation 2016-04-15 18:48:47 +02:00
Atgeirr Flø Rasmussen
b6e381d627 Merge pull request #998 from totto82/bugfix_wellgroup
BUGFIX. Comparison with null pointer
2016-04-15 13:16:23 +02:00
Tor Harald Sandve
e76b9dd7f1 BUGFIX. Comparison with null pointer 2016-04-15 12:56:04 +02:00
Atgeirr Flø Rasmussen
165b17564d Merge pull request #997 from totto82/Fix_guiderates
Bugfix in setup guiderates
2016-04-15 08:46:17 +02:00
Tor Harald Sandve
972c55ea52 Add COMPDAT to wells_group.data
Without COMPDAT the wells will be shut and thus not added to the well
collection.
2016-04-15 08:32:38 +02:00
Bård Skaflestad
b307259ce2 Merge pull request #995 from atgeirr/remove-sims
Update CMake list with deleted files, and delete files moved to opm-simulators.
2016-04-14 12:47:43 +02:00
Atgeirr Flø Rasmussen
78a927c859 Update CMake list with deleted files. 2016-04-14 11:29:17 +02:00
jokva
eacbd4f214 Merge pull request #994 from pgdr/use-eclipse3dproperties
@bska We're merging as-is for now, and we've made a note to replace `shared_ptr` and maintain (and document!) this property. Those changes will obviously be internal and you won't notice a difference.
2016-04-13 11:01:43 +02:00
Tor Harald Sandve
acade0bb5f Bugfix in setup guiderates
- Handle shut wells
- Use the groups control type to determine which phase to calculate
the guide rates from. i.e for a ORAT controlled group, calculate the
guide rates from the oil phase well potentials etc.
2016-04-12 13:05:56 +02:00
Pål Grønås Drange
284f3702a2 Using API get3DProperties() 2016-04-11 15:23:35 +02:00
Pål Grønås Drange
fee514375d Using API get3DProperties() 2016-04-11 15:13:38 +02:00
Pål Grønås Drange
1e0356d392 This commit introduces non-trivial changes as GridProperty no longer is stored as a shared pointer. This file needs a thorough read-through, and it would be nice with some documentation. 2016-04-08 16:41:41 +02:00
Pål Grønås Drange
9dbae15cc9 uses new api, made reference instead of copy 2016-04-08 16:31:59 +02:00
Pål Grønås Drange
8a7bf1ef3c Updated opm-core to use new EclipseState API in opm-parser 2016-04-08 16:30:01 +02:00
Atgeirr Flø Rasmussen
277b3a2e58 Merge pull request #993 from atgeirr/remove-unused-code
Removed SimulatorOutput class from this module.
2016-04-07 15:47:56 +02:00
Atgeirr Flø Rasmussen
90e9374a2b Renoved SimulatorOutput class from this module. 2016-04-07 15:41:40 +02:00
Atgeirr Flø Rasmussen
ccb34c14ec Merge pull request #992 from atgeirr/module-renaming
Module renaming
2016-04-06 15:37:44 +02:00
Arne Morten Kvarving
33bb10b98f fixed: use shallow clones on jenkins 2016-04-06 10:10:23 +02:00
Atgeirr Flø Rasmussen
b5cbf0ea2d Rename HAVE_DUNE_CORNERPOINT -> HAVE_OPM_GRID.
Note that this is quite strange since opm-core is upstream and not downstream
from opm-grid. However, when this file is used from opm-autodiff the macro is used.
2016-04-05 15:14:02 +02:00
Atgeirr Flø Rasmussen
2b9b1f8b05 Merge pull request #987 from qilicun/refactor-relpermDiagnostics
Refactor relperm diagnostics using OpmLog functionalities.
2016-04-04 15:04:44 +02:00
Arne Morten Kvarving
ccac8fe6ac Merge pull request #989 from akva2/jenkins_reboot
Jenkins reboot
2016-04-04 14:40:01 +02:00
Arne Morten Kvarving
7bc1ec7693 add jenkins build scripts 2016-04-04 14:36:24 +02:00
Atgeirr Flø Rasmussen
a20da3a6d2 Merge pull request #988 from totto82/gc_default
Calculate default guide rates using the well potentials
2016-04-04 14:12:48 +02:00
Tor Harald Sandve
e1298ff21b Minor fixes based on PR comments
- fix comments, typos add missing reference arguments.
2016-04-04 08:10:24 +02:00
Liu Ming
5e6e4b2a38 mistake: count warning as error. 2016-04-02 11:53:36 +08:00
Liu Ming
53485a7ae7 do not write error summary twice. 2016-04-02 11:45:18 +08:00
Tor Harald Sandve
0fb81945f6 Calculate default guide rates using the well potentials
The default guide rates are caculated using the well potentials.
The well potentials are calculated in the simulator and given as input
to the wellsManager.
2016-04-01 15:00:21 +02:00
Liu Ming
88d41057c0 refactor relperm diagnostics using OpmLog functions. 2016-04-01 12:27:03 +08:00
Atgeirr Flø Rasmussen
09c31b67ca Merge pull request #984 from totto82/bugfix_groupcontrol
BUGFIX. Call setupGuideRates before groupcontrol is applied
2016-03-31 13:28:08 +02:00
Atgeirr Flø Rasmussen
730f1e88b7 Merge pull request #977 from kjellkongsvik/Remove_OutputWriter
Remove output writer
2016-03-31 09:42:33 +02:00
Tor Harald Sandve
b8bad8b26b BUGFIX. Call setupGuideRates before groupcontrol is applied 2016-03-31 09:32:09 +02:00
Kjell W. Kongsvik
77a6c4229a Replace comment with "ifdef DISABLE_OUTPUT" 2016-03-29 14:57:58 +02:00
Kjell W. Kongsvik
8e68a4d815 Deleted all files in opm/core/io
This removes OutputWriter and eclipse, vtk, vag as this
functionality has moved to opm-output.
2016-03-29 14:57:58 +02:00
Kjell W. Kongsvik
03d5a5ba25 Commented out usage of OutputWriter in simulator 2016-03-29 14:56:25 +02:00
Kjell W. Kongsvik
9febba59a4 Commented out usage of OutputWriter in tutorials 2016-03-29 14:56:24 +02:00
Joakim Hove
ce6cdb4a47 Merge pull request #962 from joakim-hove/remove-simulator-state
Replaced SimulatorState -> SimulationDatacontainer
2016-03-29 13:16:19 +02:00
Atgeirr Flø Rasmussen
7a5e8865b5 Merge pull request #982 from dr-robertk/PR/copyable-simulator-timer
Allow SimulatorTimers to be copied.
2016-03-29 11:09:14 +02:00
Atgeirr Flø Rasmussen
e4929b7263 Implement direct fast field access. 2016-03-29 10:46:14 +02:00
Joakim Hove
c360079926 Replaced SimulatorState -> SimulationDatacontainer
Have removed the SimulatorState base class, and instead replaced with
the SimulationDatacontainer class from opm-common. The SimulatorState
objects were typcially created with a default constructor, and then
explicitly initialized with a SimulatorState::init() method. For the
SimulationDataContainer RAII is employed; the init( ) has been removed -
and there is no default constructor.
2016-03-29 10:44:49 +02:00
Robert Kloefkorn
3f63d09f86 SimulatorTimerInterface: include missing header for unique_ptr. 2016-03-29 10:42:03 +02:00
Robert Kloefkorn
a2d64e681e SimulatorTimers: added method clone to allow for copying of the objects. 2016-03-29 10:34:16 +02:00
Joakim Hove
fcd4368da4 Merge pull request #979 from jokva/missing-cassert-include
Add missing <cassert> include
2016-03-25 07:36:28 +01:00
Joakim Hove
05c2fb7c5e Merge pull request #978 from chflo/move_log_functionality
Changed include due to OpmLog changed path
2016-03-21 22:14:48 +01:00
Jørgen Kvalsvik
4f857b71fc Add missing <cassert> include 2016-03-18 15:40:57 +01:00
chflo
755873f5cc Changed include due to OpmLog changed path 2016-03-17 15:59:50 +01:00
Joakim Hove
212e3c26a4 Merge pull request #976 from qilicun/rename-ParseMode
Rename parse mode
2016-03-17 09:51:50 +01:00
Liu Ming
81f6c2dd8e rename ParseMode as ParseContext. 2016-03-17 09:57:59 +08:00
Liu Ming
0a5be9ba52 rename ParseMode in examples folder. 2016-03-17 09:46:12 +08:00
Liu Ming
d943cbfe2a rename ParseMode as ParseContext. 2016-03-17 08:56:38 +08:00
Joakim Hove
2ca569d2e4 Merge pull request #973 from andlaus/fix_PERMXYZ
Fix PERM[XYZ] output
2016-03-16 11:28:22 +01:00
Atgeirr Flø Rasmussen
6bcca2ea23 Merge pull request #972 from qilicun/solvent-diagnostics
Solvent diagnostics
2016-03-16 10:32:12 +01:00
Andreas Lauser
31aac3481d EclipseWriter: deal with the concept of active cells for PERM[XYZ]
... and also with grids that reorder their cell indices.
2016-03-14 18:03:41 +01:00
Liu Ming
897aa67b89 use two slashes for comments inside functions. 2016-03-11 17:19:39 +08:00
Liu Ming
26e18bdcc4 use error variable. 2016-03-11 17:15:32 +08:00
Liu Ming
aa32349f19 fix saturation family bug. 2016-03-11 17:13:40 +08:00
Liu Ming
eafa6e2d9a fix indentation and fluid system issues. 2016-03-11 17:03:31 +08:00
Liu Ming
47fefe9e3a Merge remote branch 'remotes/opm/master' into solvent-diagnostics 2016-03-10 14:38:22 +08:00
Liu Ming
b7972eb01c Add solvent saturation functions support. 2016-03-10 14:32:43 +08:00
Liu Ming
95d65222fa Add solvent to fluid system. 2016-03-10 11:17:18 +08:00
Atgeirr Flø Rasmussen
3e8d6b521f Merge pull request #971 from andlaus/fix_thpres_defaults
threshold pressures: consider the saturated case and fix a typo
2016-03-09 09:48:37 +01:00
Andreas Lauser
c635d84d37 threshold pressures: consider the saturated case and fix a typo
the typo was caused the surface density of the oil phase to be used
instead of the one of gas. This caused the density to be off by a
factor of typically about 900.

using saturated FVFs does not change much, but it does not hurt
because it is also done that way in the simulator.

This makes the defaults for the threshold pressures reasonable again,
but for some reason they are not exactly the same as in the old
implementation. (although the differences are very tolerable.)

On the question why only "Model 2" is affected by this: the other
decks don't use threshold pressures (SPE-X) or do not default any
values (Norne).
2016-03-08 14:52:09 +01:00
Atgeirr Flø Rasmussen
bd91cf6e72 Merge pull request #970 from andlaus/fix_R_in_viscosity
BlackoilPropertiesFromDeck: properly calculate the Rs and Rv values for viscosity
2016-03-08 11:28:53 +01:00
Andreas Lauser
dfda345661 BlackoilPropertiesFromDeck: properly calculate the Rs and Rv values for viscosity
the dissolution factors used for the viscosities were always zero so
far. this was not discovered earlier because flow is completely
unaffected by this since the only place where this class is used in
flow is the equilibration code and the equilibration code does not
need phase viscosities.

thanks to @atgeirr for finding this.
2016-03-08 11:07:20 +01:00
Atgeirr Flø Rasmussen
41faabe61a Merge pull request #955 from andlaus/opm-material_blackoil_PVT
replace the blackoil PVT classes by the ones of opm-material
2016-03-07 13:40:24 +01:00
Andreas Lauser
23088f987f replace the blackoil PVT classes by the ones of opm-material
the opm-material classes are the ones which are now used by
opm-autodiff and this patch makes it much easier to keep the opm-core
and opm-autodiff results consistent. Also, the opm-material classes
seem to be a bit faster than the opm-core ones (see
https://github.com/OPM/opm-autodiff/pull/576)

I ran the usual array of tests with `flow`: SPE1, SPE3, SPE9 and Norne
all produce the same results at the identical runtime (modulo noise)
and also "Model 2" seems to work.
2016-03-05 19:11:44 +01:00
Joakim Hove
0c05fc4dc0 Merge pull request #966 from jokva/initconfig-equil
Remove Equil + EquilWrapper, replace with upstream
2016-03-04 18:18:57 +01:00
Atgeirr Flø Rasmussen
eb0f59f96d Merge pull request #965 from atgeirr/remove-unused-parameter
Remove unused 'restart' parameter from SimulatorTimer::init().
2016-03-04 11:22:01 +01:00
Atgeirr Flø Rasmussen
72b9bdabf4 Merge pull request #969 from atgeirr/master
Fix minor issues with RelpermDiagnostics
2016-03-04 09:14:50 +01:00
Atgeirr Flø Rasmussen
9a83cbaddf Only include normal (not _impl.hpp) header from client code. 2016-03-04 09:12:43 +01:00
Atgeirr Flø Rasmussen
2a4ca8a34e Only .cpp files should include config.h. 2016-03-04 09:10:19 +01:00
Atgeirr Flø Rasmussen
54ac4bd5e4 Include template implementation file. 2016-03-04 09:09:52 +01:00
Atgeirr Flø Rasmussen
10468bafab Merge pull request #968 from qilicun/template-grid
make grid as template parameter.
2016-03-04 08:30:58 +01:00
Liu Ming
58f53cae2a make grid as template parameter. 2016-03-04 09:09:38 +08:00
Atgeirr Flø Rasmussen
a703bfbcf1 Merge pull request #958 from qilicun/rename_logfile
use standard filename for output log file.
2016-03-02 08:29:20 +01:00
Liu Ming
e12ca5a825 change .LOG to .SATFUNCLOG. 2016-03-02 14:58:37 +08:00
Jørgen Kvalsvik
27a240ae7f Remove Equil + EquilWrapper, replace with upstream
Upstream (opm-parser) now provides a better Equil + EquilRecord, and
simultaneously deprecated EquilWrapper. This patch fixes the resulting
breakage.

One important note: The new Equil does not expose integers for live
oil/wet gas initialization procedure methods, but rather booleans
through constRs/constRv methods. This is how the variable behaves
according to the Eclipse reference manual (EQUIL keyword section).

Code has been updated to reflect this.
2016-03-01 09:59:54 +01:00
Joakim Hove
85232bb355 Merge pull request #964 from atgeirr/fix-sign-warning
Silence sign comparison warning.
2016-02-29 14:48:48 +01:00
Atgeirr Flø Rasmussen
5c2257cafa Remove unused 'restart' parameter from SimulatorTimer::init(). 2016-02-29 11:03:08 +01:00
Atgeirr Flø Rasmussen
01df431198 Silence sign comparison warning. 2016-02-29 10:58:43 +01:00
Bård Skaflestad
8f042081f7 Merge pull request #963 from jokva/missing-headers-parser-695
Add missing opm-parser headers
2016-02-26 07:39:55 -06:00
Jørgen Kvalsvik
82472a1dfd Add missing opm-parser headers
opm-parser pull #695
https://github.com/OPM/opm-parser/pull/695
2016-02-26 11:49:40 +01:00
Bård Skaflestad
893e6c851f Merge pull request #954 from joakim-hove/set-component
Changes in SimulatorState:
2016-02-24 07:11:36 -06:00
Joakim Hove
df6e6a2347 Replaced TwoPhaseState -> SimulatorState 2016-02-22 22:03:43 +01:00
Joakim Hove
6ca10ea57d Added SimulatorState::getCellData() 2016-02-22 22:03:42 +01:00
Joakim Hove
6c5fae2f9d Added free function initSaturation().
The state argument is of type SimulatorState& - and no longer a template
parameter.
2016-02-22 22:03:41 +01:00
Joakim Hove
a214c10595 Changes in SimulatorState:
1. Added method setCellDataComponent()
 2. Removed setFirstSat()

Implemented saturation initialisation using setCellDataComponent()
instead of setFirstSat(). This way the template<class Props> has been
removed from the SimulatorState class.
2016-02-22 08:42:04 +01:00
Bård Skaflestad
089229adf4 Merge pull request #959 from andlaus/fix_build
Fix build
2016-02-21 12:47:22 -06:00
Andreas Lauser
377b844862 fix build breakage of the unit tests due to OPM/opm-parser#687
While the patch is quite trivial (some forgotten 'const'), the havoc
was caused because I usually configure my modules with --disable-tests
(to get much better turn-around times when switching all modules from
debug to optimization flags) and the usual way to force them to
compile ('make test-suite') does not work for opm-core...
2016-02-21 17:35:33 +01:00
Andreas Lauser
c709e347c3 fix some recent deprecation warnings
these are caused by OPM/opm-parser#687. While they are harmless, they
are certainly annoying. (that's their point!)
2016-02-21 17:29:43 +01:00
Atgeirr Flø Rasmussen
be1ea358ff Merge pull request #953 from andlaus/const_gridproperties
fix the build
2016-02-19 11:46:32 +01:00
Atgeirr Flø Rasmussen
0297d6c657 Merge pull request #957 from joakim-hove/cmp-template
Using template for cmp::vector_equal()
2016-02-19 11:41:07 +01:00
Joakim Hove
58f355935f Using template for cmp::vector_equal() 2016-02-19 07:57:02 +01:00
Liu Ming
61ebad5bba use standard filename for output log file. 2016-02-19 09:35:15 +08:00
Joakim Hove
7909311749 Merge pull request #952 from jokva/unique-auto-deck
Change Deck access methods/types to references
2016-02-18 23:17:17 +01:00
Jørgen Kvalsvik
b8edc8b5b4 Change Deck access methods/types to references
opm-parser#677 changes the return types for the Deck family of classes.
This patch fixes all broken code from that patch set.

https://github.com/OPM/opm-parser/pull/677
2016-02-18 08:50:26 +01:00
Joakim Hove
1661ac8f58 Merge pull request #956 from jokva/remove-unused-wrapper
Remove unused Wrapper includes from Deck/Utility
2016-02-17 17:10:43 +01:00
Jørgen Kvalsvik
62d7c7bed2 Remove unused Wrapper includes from Deck/Utility 2016-02-17 14:46:15 +01:00
Atgeirr Flø Rasmussen
dc918fcff9 Merge pull request #947 from andlaus/fix_wet_gas_pvt_extrapolation
PvtLiveGas: do not special case in the extrapolation code
2016-02-16 12:44:53 +01:00
Andreas Lauser
8f0d81db2f fix the build
it broke because EclipseState::get*GridProperty() now returns a
pointer to a constant object.
2016-02-15 15:06:05 +01:00
Joakim Hove
6515b57632 Merge pull request #950 from joakim-hove/simulatorstate-refactor
Removed opm_memcmp_double() - use cmp from common.
2016-02-15 12:55:53 +01:00
Joakim Hove
5172652e73 Removed opm_memcmp_double() - use cmp from common. 2016-02-14 21:41:51 +01:00
Joakim Hove
88aad94f54 Merge pull request #951 from jepebe/travis
Travis support
2016-02-08 12:07:26 +01:00
Jean-Paul Balabanian
ab3ea52384 Added Travis support 2016-02-08 06:56:30 +01:00
Bård Skaflestad
279799ee80 Merge pull request #949 from joakim-hove/build-fixup
Build fixup
2016-02-04 11:46:56 -06:00
Joakim Hove
9b1efd7810 Revert: Removed unused SimulatorState comparison.
This reverts commit 5ce1d84ac1.
2016-02-04 18:39:40 +01:00
Joakim Hove
b241fde63c Revert: Removed unused SimulatorState::setFirstSat 2016-02-04 18:39:39 +01:00
Joakim Hove
4e46bb3fa4 Merge pull request #948 from joakim-hove/simulatorstate-remove-unused
Simulatorstate remove unused
2016-02-04 15:57:59 +01:00
Joakim Hove
5ce1d84ac1 Removed unused SimulatorState comparison. 2016-02-03 05:54:24 +01:00
Joakim Hove
df0d11b8de Removed unused SimulatorState::setFirstSat() 2016-02-03 05:51:05 +01:00
Andreas Lauser
e6c89a595b PvtLiveGas: do not special case in the extrapolation code
at least, don't special case that much. This caused a discrepancy with
the opm-material PVT relations for Norne after 23 report steps. (which
takes an hour or two to get to with debugging options on my machine.)
As you can probably imagine, finding this was *a lot* of fun...
2016-01-28 14:42:10 +01:00
Bård Skaflestad
6365167109 Merge pull request #946 from jokva/clean-up-header
Improve includes from opm-parser
2016-01-26 15:58:25 +01:00
Bård Skaflestad
d738138afa Merge pull request #943 from qilicun/update_relperm_diagnostics
Update relperm diagnostics
2016-01-26 15:12:28 +01:00
Jørgen Kvalsvik
697763a4b9 Improve includes from opm-parser
Adopting to opm-parser PR#661, add previously missing includes.

https://github.com/OPM/opm-parser/pull/661
2016-01-26 13:30:58 +01:00
Joakim Hove
282cac57ea Merge pull request #945 from joakim-hove/simulator-state-no-grid
Removed SimulatorState::init( UnstructureGrid& )
2016-01-25 17:49:05 +01:00
Joakim Hove
ba1c06d415 Removed SimulatorState::init( UnstructureGrid& ) 2016-01-25 07:30:03 +01:00
Liu Ming
10baa52828 Omit some usages of to_string function. 2016-01-25 11:18:56 +08:00
Liu Ming
56868d8a6e Add more parser mode options. 2016-01-25 11:13:19 +08:00
Liu Ming
9e9287f20d change headline to saturation functions diagnostics. 2016-01-25 11:00:23 +08:00
Liu Ming
039f9ce1cc Format output and add SATNUM for scaled saturation endpoints. 2016-01-25 10:58:50 +08:00
Liu Ming
229282c310 fix bugs: counter warning as error. 2016-01-25 09:38:55 +08:00
Liu Ming
009f1b101b Merge remote branch 'remotes/opm/master' into update_relperm_diagnostics
Conflicts:
	opm/core/props/satfunc/RelpermDiagnostics.cpp
2016-01-22 13:04:01 +08:00
Bård Skaflestad
1686b45221 Merge pull request #944 from jokva/fix-header-include-parser656
Fixes includes wrt opm-parser PR-656
2016-01-21 11:13:32 +01:00
Jørgen Kvalsvik
c7349b5586 Fixes includes wrt opm-parser PR-656
Several files stopped compiling due to relying on opm-parser headers
doing includes. From opm-parser PR-656
https://github.com/OPM/opm-parser/pull/656 this assumption is no longer
valid.
2016-01-21 09:42:51 +01:00
Liu Ming
8e397ef7ce fix typo. 2016-01-21 16:10:31 +08:00
Liu Ming
ce0ec1e466 remove comments. 2016-01-21 14:04:01 +08:00
Liu Ming
dd9b607c99 make const as more as possible 2016-01-21 14:01:02 +08:00
Liu Ming
743f17169d saturation region should start with 1. 2016-01-21 13:47:57 +08:00
Liu Ming
c02c93ce1b fix formatting and grammar issues. 2016-01-21 13:45:32 +08:00
Liu Ming
2f2bd8a955 Add region number for output and output summary msg to streamLog 2016-01-18 11:10:51 +08:00
Liu Ming
682d0a7d1f change error to warning due to eclipse manual. 2016-01-18 11:10:36 +08:00
Liu Ming
3bce4e72b9 Add region number for unscaled endpoints. 2016-01-18 11:10:26 +08:00
Liu Ming
5e234fcd21 1. use scaled_messages_ to store scaled endpoints infor.
2. format the terminal output messages.
2016-01-18 11:10:14 +08:00
Liu Ming
1f809cf3d5 Add counter for numbering warning, error, proble, and bugs. 2016-01-18 11:10:04 +08:00
Liu Ming
3e143907d3 For that break clipse rules should raise an error. 2016-01-18 11:09:50 +08:00
Liu Ming
f38fe6d91b add cell index for scaled endpoints error messages output. 2016-01-18 11:09:02 +08:00
dr-robertk
b26eb3827f Merge pull request #937 from chflo/OPM_251_support_restart
OPM-251: Prepare for restart
2016-01-15 14:44:06 -07:00
Joakim Hove
bbcc39805d Merge pull request #942 from qilicun/debug_relperm
fix relperm diagnostics tests issue.
2016-01-11 09:21:10 +01:00
Liu Ming
5d50776d1b fix relperm diagnostics tests issue. 2016-01-11 16:05:33 +08:00
Joakim Hove
a35520a65d Merge pull request #939 from joakim-hove/table-column
Table column
2016-01-08 15:29:10 +01:00
Joakim Hove
a6deb02d04 Changed to use new table api from opm-parser. 2016-01-08 14:47:09 +01:00
Atgeirr Flø Rasmussen
1b9be6d4bd Merge pull request #940 from chflo/OPM-163
OPM-163: Use EclipseState instead of Deck for PvtInterface
2016-01-08 13:36:17 +01:00
chflo
ca60041332 OPM-163: Use EclipseState instead of Deck for PvtInterface 2016-01-07 16:36:28 +01:00
Joakim Hove
a566ac608d Added TableColumn based overloads. 2016-01-06 09:19:47 +01:00
Joakim Hove
65ff9bb75b Removed erroneous test data. 2016-01-05 11:47:20 +01:00
chflo
c003900145 OPM-251: Support for restart 2016-01-04 16:11:21 +01:00
Atgeirr Flø Rasmussen
1a8b38dcc9 Merge pull request #936 from atgeirr/silence-warnings
Silence warnings in test programs.
2015-12-14 15:26:35 +01:00
Atgeirr Flø Rasmussen
576d24a070 Silence warnings in test programs. 2015-12-14 15:25:27 +01:00
Atgeirr Flø Rasmussen
125c27462d Merge pull request #928 from totto82/minpv_pinch
compatibility of MINPV and PINCH
2015-12-14 11:33:20 +01:00
Tor Harald Sandve
8827ca0794 Bugfix. Fix face direction in the pinchprocessor 2015-12-14 10:48:26 +01:00
Atgeirr Flø Rasmussen
cc07dc80b7 Merge pull request #934 from totto82/residualSaturations
Add method to access the materialLawManager
2015-12-11 13:08:39 +01:00
Tor Harald Sandve
7689f80a7f Add method to access the materialLawManager 2015-12-11 12:50:54 +01:00
Atgeirr Flø Rasmussen
a819d314f8 Merge pull request #929 from qilicun/relpermDiagnostics
Relperm diagnostics
2015-12-09 10:11:26 +01:00
Liu Ming
8605675199 make the constructor as explicit. 2015-12-09 16:51:07 +08:00
Tor Harald Sandve
43abdf5946 Adapt to changes in the NNC class 2015-12-08 13:03:15 +01:00
Tor Harald Sandve
c208d32498 BUGfix. Use correct facedirection 2015-12-08 12:57:43 +01:00
Tor Harald Sandve
7e4bff4a18 Hardcode usage of opmfil
The opmfil option in the minpv-processor will be used regardless of
OPMFIL input in the deck.
2015-12-08 11:04:54 +01:00
Tor Harald Sandve
3d7ce4ece2 Cleanup after rebase
- cleanup of some rebase mess
- Added comments
- Use the maxDp for the NNCs
- remove misplaced break in the pinchprocessor
2015-12-08 09:50:07 +01:00
Tor Harald Sandve
b8f54e4e59 Ignore segments with no active cells above or below. 2015-12-08 09:25:35 +01:00
Tor Harald Sandve
97525de43a Adapt to changed API in the pinch-processor 2015-12-08 09:25:35 +01:00
Tor Harald Sandve
a7c1810029 Calculate thresholdPressures for the NNCs 2015-12-08 09:25:35 +01:00
Tor Harald Sandve
97466d988b Fix to account for the combination of minpv and pinch 2015-12-08 09:21:51 +01:00
Tor Harald Sandve
dec23df301 Add option for not including the removed volume in the MinpvProcessor
The volume in cells with pore volume less than the minpv threshold is
removed if minpvMode is ECLStd while it is added to the underlying cell
if minpvMode is OpmFil
2015-12-08 09:21:51 +01:00
Liu Ming
ef203a1d04 Merge remote branch 'remotes/opm/master' into relpermDiagnostics
Conflicts:
	CMakeLists_files.cmake
2015-12-08 16:08:02 +08:00
Liu Ming
8d393ac816 remove unused object. 2015-12-08 16:02:36 +08:00
Atgeirr Flø Rasmussen
e8ab4341f1 Merge pull request #933 from atgeirr/silence-warnings
Silence some warnings.
2015-12-07 13:31:13 +01:00
Bård Skaflestad
51111aa845 Merge pull request #932 from joakim-hove/test-norne-pvt
Added regression test for Norne PVT.
2015-12-03 17:07:02 +01:00
Joakim Hove
1de19dd47d Added out-of-range tests. 2015-12-03 16:19:43 +01:00
Joakim Hove
130f222cb0 Added regression test for norne PvtLiveOil PVT. 2015-12-03 14:16:04 +01:00
Liu Ming
4790c2a2eb Add simple tests. 2015-12-02 10:59:13 +08:00
Liu Ming
252af19e4b Use OpmLog to output messages.
return messages and opmLog.
2015-12-02 10:58:06 +08:00
Atgeirr Flø Rasmussen
fc20fe5be9 Silence some warnings. 2015-12-01 13:36:08 +01:00
Liu Ming
944e1565fd rename variables and remove some unnecessary check and comments. 2015-12-01 13:49:49 +08:00
Liu Ming
780292875a remove unused functions and comments, add documentations to diagnosis(). 2015-11-30 10:52:34 +08:00
Liu Ming
91e14bec36 1. remove eclState from phaseCheck_ function.
2. rename messager_ to messages_.
3. change 0 and 1 to 0.0 and 1.0
4. change unsigned to int.
2015-11-30 10:42:57 +08:00
Liu Ming
544c7c24f9 reorder function and make more whitespace. 2015-11-30 10:26:59 +08:00
Liu Ming
5cfc3961db make enum as private members. 2015-11-30 10:20:43 +08:00
Liu Ming
6d06c36f64 1. Move implemtation to .cpp file.
2. Delete constructors.
3. Add config.h
2015-11-30 10:11:43 +08:00
Bård Skaflestad
d4ca0d8c00 Merge pull request #931 from andlaus/fix_build
fix build for newish boost versions
2015-11-27 16:17:27 +01:00
Andreas Lauser
4cded211b0 fix build for newish boost versions
my boost is 1.58. once more, boost seemed to have become more picky on
where a semicolon must be placed and where not.
2015-11-27 16:09:01 +01:00
Atgeirr Flø Rasmussen
ec25abb15f Merge pull request #930 from totto82/cellDepth
Use cell depths based on averaging cell corners
2015-11-27 10:17:49 +01:00
Liu Ming
05ebcc2067 Fix bugs and remove reptetitive messagers. 2015-11-27 10:47:04 +08:00
Liu Ming
839d2e0471 Add NEXUS scaled endpoints consistency check. 2015-11-26 16:32:17 +08:00
Liu Ming
e600383589 Check scaled endpoints mobility. 2015-11-26 15:40:40 +08:00
Liu Ming
df6043ace6 add endpoints scaling consistency check. 2015-11-26 15:22:51 +08:00
Tor Harald Sandve
fd0dbe1d48 Use cell depths based on averaging cell corners 2015-11-24 10:17:12 +01:00
Liu Ming
89d688d0f8 make use of fluidSystem. 2015-11-20 11:04:50 +08:00
Liu Ming
9428c829c3 unify the output messages. 2015-11-20 10:57:13 +08:00
Liu Ming
57f4348f6d clear up unused functions. Make some functions ad private member. 2015-11-19 16:24:09 +08:00
Liu Ming
c128e218da use commandline instead of paramGroup. 2015-11-19 16:08:26 +08:00
Liu Ming
8810a47215 fix typo and output message. 2015-11-19 13:51:03 +08:00
Liu Ming
9e7d287212 use more relax ParseMode. 2015-11-19 13:31:19 +08:00
Liu Ming
4d2c656a72 clear message output. 2015-11-19 13:31:02 +08:00
Liu Ming
5938bbc74b solve git cherry-pick conflict. 2015-11-19 11:05:43 +08:00
Liu Ming
26b680970f Use messager container to store error message.
Conflicts:

	opm/core/props/satfunc/RelpermDiagnostics.hpp
2015-11-19 11:00:21 +08:00
Liu Ming
1db1bf6fd6 initial RelpermDiagnostics. 2015-11-19 09:21:00 +08:00
Atgeirr Flø Rasmussen
84b3bcc6ea Merge pull request #907 from andlaus/thpress_from_initial
implement determining the threshold pressure from the initial condition
2015-11-17 09:03:02 +01:00
Andreas Lauser
e7d57bd0e6 thresholdPressures(): move the code which calculates the maximum gravity corrected pressure difference between EQLNUM regions to its own function
requested by [at]atgeirr
2015-11-13 15:36:50 +01:00
Atgeirr Flø Rasmussen
556e24f008 Merge pull request #922 from blattms/return_mask_for_updateOwnerMask
Return a constant reference to the mask for ParallelISTLInformation::updateOwnerMask
2015-11-13 15:20:35 +01:00
Andreas Lauser
dc9f73e94d thresholdPressures(): split several long lines
as requested by [at]atgeirr
2015-11-13 15:13:28 +01:00
Andreas Lauser
ec0f28c176 thresholdPressures(): constify all local variables which can be made constant
I have doubts if this will change anything in the binaries (and in my
personal opinion, these 'const's look quite ugly and are sometimes a
(small) annoyance when debugging), but I don't mind using the coding
style used by most of the rest of opm-core here.
2015-11-13 15:13:15 +01:00
Atgeirr Flø Rasmussen
d9dfd852f5 Merge pull request #927 from atgeirr/fix-rename-error
Follow class renaming.
2015-11-13 11:39:12 +01:00
Atgeirr Flø Rasmussen
909f62ef4b Follow class renaming. 2015-11-13 11:37:53 +01:00
Atgeirr Flø Rasmussen
9f7a1be749 Merge pull request #921 from dr-robertk/PR/adaptive-timestepping-revision
AdaptiveTimeStepping: allow for more flexible error computation in the future.
2015-11-12 17:23:11 +01:00
Bård Skaflestad
14a4b00695 Merge pull request #926 from andlaus/update_cdash_drop_site
cdash: update dropsite
2015-11-11 20:28:43 +01:00
Andreas Lauser
e2ec1c8547 cdash: update dropsite 2015-11-11 16:47:09 +01:00
Robert Kloefkorn
e5d3b3e10f timeError --> relativeChange. 2015-11-10 09:53:40 -07:00
Robert Kloefkorn
23c27cc826 AdaptiveTimeStepping: pass object to compute time error to time step control. This
allows us to shift the computation of the error to the physical model.
2015-11-10 09:45:07 -07:00
Atgeirr Flø Rasmussen
6ac19ac961 Merge pull request #920 from totto82/interpolation_points
Change the number of integration points in the initialization
2015-11-09 16:52:30 +01:00
Andreas Lauser
e49e9bd9b9 THPRES: only update the threshold pressure between regions if the saturation of the upstream cell is larger than the residual saturation
before it was 0. Again, thanks to [at]totto82 for the suggestion.
2015-11-05 15:39:29 +01:00
Andreas Lauser
f4fcb616be THPRES: change the sign of the gravity correction
we're correcting the pressure at the cell center depths to get the
pressure at the face depth, not the other way around. This is
confusing...

thanks to [at]totto82 for discovering this.
2015-11-05 12:29:19 +01:00
Andreas Lauser
6a9e11a4e1 fix a compressed vs logically Cartesian cell index bug
PVTNUM is for logically Cartesian indices, but was accessed by
compressed ones.
2015-11-05 12:29:19 +01:00
Andreas Lauser
547b701a57 implement determining the threshold pressure from the initial condition
This needs to be done if a equilibration region transition is
mentioned by the THPRES keyword, but no value is given for this record
in the third item. (it seems that this is used quite frequently.)

Also, the approach taken by this patch also does not collide with the
restart machinery as far as I can see. This is because the initial
condition is applied by the simulator before the state at the restart
time is loaded. (I interpreted the code that way, but I could be
wrong, could anyone verify this?)

since it is pretty elaborate to calculate initial condition, this
patch is pretty messy. I also do not know if Eclipse does include
capillary pressure in this calculation or not (this patch does). Huge
kudos go to [at]totto82 for reviewing, testing and debugging this.
2015-11-05 12:29:19 +01:00
Markus Blatt
8d253606fc Return a constant reference to the mask for ParallelISTLInformation::updateOwnerMask
Thus we can actually access the mask in external code. This is for
example needed when calculating averages in RateConverter of opm-autodiff.
2015-11-02 15:02:32 +01:00
Tor Harald Sandve
7542aca827 Change the number of integration points in the initialization
The number is changed from 100->2000 to increase accuracy.
2015-10-30 08:14:10 +01:00
Atgeirr Flø Rasmussen
bdd5104bc5 Merge pull request #919 from blattms/fixes-wells-with-perforations-in-overlap
Fixes well manager for wells crossing into cells that overlap.
2015-10-28 13:23:35 +01:00
Atgeirr Flø Rasmussen
11cd4d56ad Merge pull request #918 from blattms/allow-zero-initialization-of-rock-properties
Allow the rock properties to be zero initialized without a deck.
2015-10-28 13:21:16 +01:00
Markus Blatt
b12708785c Make constructor taking one argument explicit. 2015-10-28 13:19:42 +01:00
Markus Blatt
bd760d3e61 Added comment about 9 entries in permeability tensor. 2015-10-28 13:14:56 +01:00
Markus Blatt
de66419e38 Renamed well_index to well_index_on_proc and added comment.
This should prevent misunderstandings about what the
well_index_on_proc is. It is not the well_index according to
the eclipse state (on open wells count) but the index of the
wells that are stored on this process' domain.
2015-10-28 13:09:12 +01:00
Atgeirr Flø Rasmussen
6dc67229f1 Merge pull request #917 from blattms/fix-copy-owner-to-all
[bugfix] Fixes copyOwnerToAll.
2015-10-28 11:34:27 +01:00
Markus Blatt
4dbb517d92 Fix grammar and spelling in warning. 2015-10-27 14:26:01 +01:00
Markus Blatt
5676bd4573 Fixes well manager for wells crossing into cells that overlap.
In the parallel run there are cases where wells perforate cells
that are neighbors of overlap/halo cells. On other process only
parts of the well are seen as perforations. These wells should be
ignored there. While the well was indeed ignored, the perforations
found where mistakenly added to the well found due not clearing the
wellperf_data[well_index]. This commit now does this clearing and
results in the right handling of wells for e.g. SPE9.
2015-10-27 14:02:26 +01:00
Markus Blatt
de6cf63e50 Allow the rock properties to be zero initialized without a deck.
This is needed in parallel runs where the rock properties will not
be read from the deck but be communicated from a master process. Nevertheless
we need to be able to initialize the data structures with the correct
container size. In addition we need to be able to change the container values
from opm-autodiff's BlackoilPropsDataHandle.
2015-10-26 23:52:24 +01:00
Markus Blatt
8b7ccd9b19 [bugfix] Fixes copyOwnerToAll.
Previously, we copied owner/overlap to all which is clearly wrong.
Now we copy from owner to all as the function name says.
2015-10-26 23:45:12 +01:00
Atgeirr Flø Rasmussen
21412edc97 Merge pull request #915 from akva2/fix_equil
fix Equilibration test by adding some fuzz
2015-10-26 12:43:42 +01:00
Arne Morten Kvarving
b20c21feb8 fix Equilibration test by adding some fuzz
Backports parts of a7b1e69a45
2015-10-26 11:21:26 +01:00
dr-robertk
d43e447852 Merge pull request #912 from atgeirr/bump-version
Bump version and unify format of dune.module.
2015-10-23 15:08:32 +02:00
Atgeirr Flø Rasmussen
7df248d2d6 Remove version.[ch] files. 2015-10-23 13:32:13 +02:00
Atgeirr Flø Rasmussen
40220994c7 Bump version and unify format of dune.module. 2015-10-23 13:18:47 +02:00
343 changed files with 7353 additions and 56443 deletions

View File

@ -13,47 +13,44 @@
# cmake/Modules/${project}-prereqs.cmake Dependencies #
# #
###########################################################################
# Mandatory call to project
project(opm-core C CXX)
cmake_minimum_required (VERSION 2.8)
# additional search modules
set( OPM_COMMON_ROOT "" CACHE PATH "Root directory containing OPM related cmake modules")
option(SIBLING_SEARCH "Search for other modules in sibling directories?" ON)
if(NOT OPM_COMMON_ROOT)
find_package(opm-common QUIET)
if(SIBLING_SEARCH AND NOT opm-common_DIR)
# guess the sibling dir
get_filename_component(_leaf_dir_name ${PROJECT_BINARY_DIR} NAME)
get_filename_component(_parent_full_dir ${PROJECT_BINARY_DIR} DIRECTORY)
get_filename_component(_parent_dir_name ${_parent_full_dir} NAME)
#Try if <module-name>/<build-dir> is used
get_filename_component(_modules_dir ${_parent_full_dir} DIRECTORY)
if(IS_DIRECTORY ${_modules_dir}/opm-common/${_leaf_dir_name})
set(opm-common_DIR ${_modules_dir}/opm-common/${_leaf_dir_name})
else()
string(REPLACE ${PROJECT_NAME} opm-common _opm_common_leaf ${_leaf_dir_name})
if(NOT _leaf_dir_name STREQUAL _opm_common_leaf
AND IS_DIRECTORY ${_parent_full_dir}/${_opm_common_leaf})
# We are using build directories named <prefix><module-name><postfix>
set(opm-common_DIR ${_parent_full_dir}/${_opm_common_leaf})
elseif(IS_DIRECTORY ${_parent_full_dir}/opm-common)
# All modules are in a common build dir
set(opm-common_DIR "${_parent_full_dir}/opm-common}")
endif()
endif()
endif()
if(opm-common_DIR AND NOT IS_DIRECTORY ${opm-common_DIR})
message(WARNING "Value ${opm-common_DIR} passed to variable"
" opm-common_DIR is not a directory")
endif()
if (opm-common_FOUND)
include(OpmInit)
else()
unset(opm-common_FOUND)
find_package(opm-common REQUIRED)
if (NOT OPM_COMMON_ROOT AND SIBLING_SEARCH)
set(OPM_COMMON_ROOT ${PROJECT_SOURCE_DIR}/../opm-common)
endif()
if (OPM_COMMON_ROOT)
list( APPEND CMAKE_MODULE_PATH "${OPM_COMMON_ROOT}/cmake/Modules")
include (OpmInit OPTIONAL RESULT_VARIABLE OPM_INIT)
set( OPM_MACROS_ROOT ${OPM_COMMON_ROOT} )
endif()
if (NOT OPM_INIT)
message( "" )
message( " /---------------------------------------------------------------------------------\\")
message( " | Could not locate the opm build macros. The opm build macros |")
message( " | are in a separate repository - instructions to proceed: |")
message( " | |")
message( " | 1. Clone the repository: git clone git@github.com:OPM/opm-common.git |")
message( " | |")
message( " | 2. Run cmake in the current project with -DOPM_COMMON_ROOT=<path>/opm-common |")
message( " | |")
message( " \\---------------------------------------------------------------------------------/")
message( "" )
message( FATAL_ERROR "Could not find OPM Macros")
endif()
endif()
include(OpmInit)
# not the same location as most of the other projects; this hook overrides
macro (dir_hook)
@ -84,24 +81,7 @@ macro (sources_hook)
${PROJECT_SOURCE_DIR}/${opm-core_DIR}/core/linalg/LinearSolverIstl.cpp
)
endif (NOT dune-istl_FOUND)
if (NOT SuiteSparse_FOUND)
list (REMOVE_ITEM opm-core_SOURCES
${PROJECT_SOURCE_DIR}/${opm-core_DIR}/core/linalg/call_umfpack.c
${PROJECT_SOURCE_DIR}/${opm-core_DIR}/core/linalg/LinearSolverUmfpack.cpp
)
list (REMOVE_ITEM examples_SOURCES
${PROJECT_SOURCE_DIR}/tutorials/tutorial2.cpp
${PROJECT_SOURCE_DIR}/tutorials/tutorial3.cpp
${PROJECT_SOURCE_DIR}/tutorials/tutorial4.cpp
)
endif (NOT SuiteSparse_FOUND)
if (NOT PETSC_FOUND)
list (REMOVE_ITEM opm-core_SOURCES
${PROJECT_SOURCE_DIR}/${opm-core_DIR}/core/linalg/call_petsc.c
${PROJECT_SOURCE_DIR}/${opm-core_DIR}/core/linalg/LinearSolverPetsc.cpp
)
endif (NOT PETSC_FOUND)
if ((NOT MPI_FOUND) OR (NOT DUNE_ISTL_FOUND))
list (REMOVE_ITEM tests_SOURCES
${PROJECT_SOURCE_DIR}/tests/test_parallel_linearsolver.cpp

View File

@ -29,188 +29,92 @@
# originally generated with the command:
# find opm -name '*.c*' -printf '\t%p\n' | sort
list (APPEND MAIN_SOURCE_FILES
opm/core/grid/GridHelpers.cpp
opm/core/grid/GridManager.cpp
opm/core/grid/GridUtilities.cpp
opm/core/grid/grid.c
opm/core/grid/cart_grid.c
opm/core/grid/cornerpoint_grid.c
opm/core/grid/cpgpreprocess/facetopology.c
opm/core/grid/cpgpreprocess/geometry.c
opm/core/grid/cpgpreprocess/preprocess.c
opm/core/grid/cpgpreprocess/uniquepoints.c
opm/core/io/eclipse/EclipseGridInspector.cpp
opm/core/io/eclipse/EclipseWriter.cpp
opm/core/io/eclipse/EclipseReader.cpp
opm/core/io/eclipse/EclipseWriteRFTHandler.cpp
opm/core/io/eclipse/writeECLData.cpp
opm/core/io/OutputWriter.cpp
opm/core/io/vag/vag.cpp
opm/core/io/vtk/writeVtkData.cpp
opm/core/linalg/LinearSolverFactory.cpp
opm/core/linalg/LinearSolverInterface.cpp
opm/core/linalg/LinearSolverIstl.cpp
opm/core/linalg/LinearSolverUmfpack.cpp
opm/core/linalg/LinearSolverPetsc.cpp
opm/core/linalg/call_umfpack.c
opm/core/linalg/sparse_sys.c
opm/core/pressure/CompressibleTpfa.cpp
opm/core/pressure/FlowBCManager.cpp
opm/core/pressure/IncompTpfa.cpp
opm/core/pressure/IncompTpfaSinglePhase.cpp
opm/core/pressure/cfsh.c
opm/core/pressure/flow_bc.c
opm/core/pressure/fsh.c
opm/core/pressure/fsh_common_impl.c
opm/core/pressure/ifsh.c
opm/core/pressure/mimetic/hybsys.c
opm/core/pressure/mimetic/hybsys_global.c
opm/core/pressure/mimetic/mimetic.c
opm/core/pressure/msmfem/coarse_conn.c
opm/core/pressure/msmfem/coarse_sys.c
opm/core/pressure/msmfem/dfs.c
opm/core/pressure/msmfem/hash_set.c
opm/core/pressure/msmfem/ifsh_ms.c
opm/core/pressure/msmfem/partition.c
opm/core/pressure/tpfa/cfs_tpfa.c
opm/core/pressure/tpfa/cfs_tpfa_residual.c
opm/core/pressure/tpfa/compr_bc.c
opm/core/pressure/tpfa/compr_quant.c
opm/core/pressure/tpfa/compr_quant_general.c
opm/core/pressure/tpfa/compr_source.c
opm/core/pressure/tpfa/ifs_tpfa.c
opm/core/pressure/tpfa/TransTpfa.cpp
opm/core/pressure/tpfa/trans_tpfa.c
opm/core/pressure/legacy_well.c
opm/core/props/BlackoilPropertiesBasic.cpp
opm/core/props/BlackoilPropertiesFromDeck.cpp
opm/core/props/IncompPropertiesBasic.cpp
opm/core/props/IncompPropertiesFromDeck.cpp
opm/core/props/IncompPropertiesSinglePhase.cpp
opm/core/props/pvt/BlackoilPvtProperties.cpp
opm/core/props/pvt/PvtPropertiesBasic.cpp
opm/core/props/pvt/PvtPropertiesIncompFromDeck.cpp
opm/core/props/pvt/PvtDead.cpp
opm/core/props/pvt/PvtDeadSpline.cpp
opm/core/props/pvt/PvtInterface.cpp
opm/core/props/pvt/PvtLiveGas.cpp
opm/core/props/pvt/PvtLiveOil.cpp
opm/core/props/rock/RockBasic.cpp
opm/core/props/rock/RockCompressibility.cpp
opm/core/props/rock/RockFromDeck.cpp
opm/core/props/satfunc/SaturationPropsBasic.cpp
opm/core/props/satfunc/SaturationPropsFromDeck.cpp
opm/core/simulator/AdaptiveSimulatorTimer.cpp
opm/core/simulator/BlackoilState.cpp
opm/core/simulator/TimeStepControl.cpp
opm/core/simulator/SimulatorCompressibleTwophase.cpp
opm/core/simulator/SimulatorIncompTwophase.cpp
opm/core/simulator/SimulatorOutput.cpp
opm/core/simulator/SimulatorReport.cpp
opm/core/simulator/SimulatorState.cpp
opm/core/simulator/SimulatorTimer.cpp
opm/core/flowdiagnostics/AnisotropicEikonal.cpp
opm/core/flowdiagnostics/DGBasis.cpp
opm/core/flowdiagnostics/FlowDiagnostics.cpp
opm/core/flowdiagnostics/TofReorder.cpp
opm/core/flowdiagnostics/TofDiscGalReorder.cpp
opm/core/transport/TransportSolverTwophaseInterface.cpp
opm/core/transport/implicit/TransportSolverTwophaseImplicit.cpp
opm/core/transport/implicit/transport_source.c
opm/core/transport/minimal/spu_explicit.c
opm/core/transport/minimal/spu_implicit.c
opm/core/transport/reorder/TransportSolverCompressibleTwophaseReorder.cpp
opm/core/transport/reorder/ReorderSolverInterface.cpp
opm/core/transport/reorder/TransportSolverTwophaseReorder.cpp
opm/core/transport/reorder/reordersequence.cpp
opm/core/transport/reorder/tarjan.c
opm/core/utility/compressedToCartesian.cpp
opm/core/utility/Event.cpp
opm/core/utility/MonotCubicInterpolator.cpp
opm/core/utility/StopWatch.cpp
opm/core/utility/VelocityInterpolation.cpp
opm/core/utility/WachspressCoord.cpp
opm/core/utility/miscUtilities.cpp
opm/core/utility/opm_memcmp_double.c
opm/core/utility/miscUtilitiesBlackoil.cpp
opm/core/utility/NullStream.cpp
opm/core/utility/parameters/Parameter.cpp
opm/core/utility/parameters/ParameterGroup.cpp
opm/core/utility/parameters/ParameterTools.cpp
opm/core/utility/parameters/ParameterXML.cpp
opm/core/utility/parameters/tinyxml/tinystr.cpp
opm/core/utility/parameters/tinyxml/tinyxml.cpp
opm/core/utility/parameters/tinyxml/tinyxmlerror.cpp
opm/core/utility/parameters/tinyxml/tinyxmlparser.cpp
opm/core/utility/parameters/tinyxml/xmltest.cpp
opm/core/version.c
opm/core/wells/InjectionSpecification.cpp
opm/core/wells/ProductionSpecification.cpp
opm/core/wells/WellCollection.cpp
opm/core/wells/WellsGroup.cpp
opm/core/wells/WellsManager.cpp
opm/core/wells/wells.c
opm/core/wells/well_controls.c
opm/core/flowdiagnostics/AnisotropicEikonal.cpp
opm/core/flowdiagnostics/DGBasis.cpp
opm/core/flowdiagnostics/FlowDiagnostics.cpp
opm/core/flowdiagnostics/TofDiscGalReorder.cpp
opm/core/flowdiagnostics/TofReorder.cpp
opm/core/linalg/LinearSolverFactory.cpp
opm/core/linalg/LinearSolverInterface.cpp
opm/core/linalg/LinearSolverIstl.cpp
opm/core/linalg/LinearSolverPetsc.cpp
opm/core/linalg/LinearSolverUmfpack.cpp
opm/core/linalg/call_umfpack.c
opm/core/linalg/sparse_sys.c
opm/core/pressure/CompressibleTpfa.cpp
opm/core/pressure/FlowBCManager.cpp
opm/core/pressure/IncompTpfa.cpp
opm/core/pressure/IncompTpfaSinglePhase.cpp
opm/core/pressure/flow_bc.c
opm/core/pressure/mimetic/mimetic.c
opm/core/pressure/msmfem/dfs.c
opm/core/pressure/msmfem/partition.c
opm/core/pressure/tpfa/cfs_tpfa_residual.c
opm/core/pressure/tpfa/ifs_tpfa.c
opm/core/props/BlackoilPropertiesBasic.cpp
opm/core/props/BlackoilPropertiesFromDeck.cpp
opm/core/props/IncompPropertiesBasic.cpp
opm/core/props/IncompPropertiesFromDeck.cpp
opm/core/props/IncompPropertiesSinglePhase.cpp
opm/core/props/pvt/PvtPropertiesBasic.cpp
opm/core/props/pvt/PvtPropertiesIncompFromDeck.cpp
opm/core/props/rock/RockBasic.cpp
opm/core/props/rock/RockCompressibility.cpp
opm/core/props/rock/RockFromDeck.cpp
opm/core/props/satfunc/RelpermDiagnostics.cpp
opm/core/props/satfunc/SaturationPropsBasic.cpp
opm/core/props/satfunc/SaturationPropsFromDeck.cpp
opm/core/simulator/BlackoilState.cpp
opm/core/simulator/TwophaseState.cpp
opm/core/simulator/SimulatorReport.cpp
opm/core/transport/TransportSolverTwophaseInterface.cpp
opm/core/transport/reorder/ReorderSolverInterface.cpp
opm/core/transport/reorder/TransportSolverCompressibleTwophaseReorder.cpp
opm/core/transport/reorder/TransportSolverTwophaseReorder.cpp
opm/core/transport/reorder/reordersequence.cpp
opm/core/transport/reorder/tarjan.c
opm/core/utility/miscUtilities.cpp
opm/core/utility/miscUtilitiesBlackoil.cpp
opm/core/wells/InjectionSpecification.cpp
opm/core/wells/ProductionSpecification.cpp
opm/core/wells/WellCollection.cpp
opm/core/wells/WellsGroup.cpp
opm/core/wells/WellsManager.cpp
opm/core/wells/well_controls.c
opm/core/wells/wells.c
)
# originally generated with the command:
# find tests -name '*.cpp' -a ! -wholename '*/not-unit/*' -printf '\t%p\n' | sort
list (APPEND TEST_SOURCE_FILES
tests/test_writenumwells.cpp
tests/test_readWriteWellStateData.cpp
tests/test_EclipseWriter.cpp
tests/test_EclipseWriteRFTHandler.cpp
tests/test_compressedpropertyaccess.cpp
tests/test_dgbasis.cpp
tests/test_cartgrid.cpp
tests/test_ug.cpp
tests/test_cubic.cpp
tests/test_event.cpp
tests/test_flowdiagnostics.cpp
tests/test_nonuniformtablelinear.cpp
tests/test_parallelistlinformation.cpp
tests/test_sparsevector.cpp
tests/test_sparsetable.cpp
#tests/test_thresholdpressure.cpp
tests/test_velocityinterpolation.cpp
tests/test_quadratures.cpp
tests/test_uniformtablelinear.cpp
tests/test_wells.cpp
tests/test_wachspresscoord.cpp
tests/test_column_extract.cpp
tests/test_geom2d.cpp
tests/test_linearsolver.cpp
tests/test_parallel_linearsolver.cpp
tests/test_param.cpp
tests/test_blackoilfluid.cpp
tests/test_satfunc.cpp
tests/test_shadow.cpp
tests/test_equil.cpp
tests/test_regionmapping.cpp
tests/test_units.cpp
tests/test_blackoilstate.cpp
tests/test_parser.cpp
tests/test_wellsmanager.cpp
tests/test_wellcontrols.cpp
tests/test_wellsgroup.cpp
tests/test_wellcollection.cpp
tests/test_timer.cpp
tests/test_minpvprocessor.cpp
tests/test_pinchprocessor.cpp
tests/test_gridutilities.cpp
tests/test_anisotropiceikonal.cpp
tests/test_stoppedwells.cpp
tests/test_relpermdiagnostics.cpp
tests/test_norne_pvt.cpp
)
# originally generated with the command:
# find tests -name '*.xml' -a ! -wholename '*/not-unit/*' -printf '\t%p\n' | sort
# find tests -name '*.param' -a ! -wholename '*/not-unit/*' -printf '\t%p\n' | sort
list (APPEND TEST_DATA_FILES
tests/extratestdata.xml
tests/testdata.xml
tests/liveoil.DATA
tests/capillary.DATA
tests/capillary_overlap.DATA
tests/compressed_gridproperty.data
tests/capillarySwatinit.DATA
tests/deadfluids.DATA
tests/equil_livegas.DATA
tests/equil_liveoil.DATA
@ -224,32 +128,23 @@ list (APPEND TEST_DATA_FILES
tests/satfuncEPS_D.DATA
tests/testBlackoilState1.DATA
tests/testBlackoilState2.DATA
tests/testBlackoilState3.DATA
tests/testPinch1.DATA
tests/wells_manager_data.data
tests/wells_manager_data_expanded.data
tests/wells_manager_data_wellSTOP.data
tests/wells_group.data
tests/TESTTIMER.DATA
tests/CORNERPOINT_ACTNUM.DATA
tests/wells_stopped.data
)
tests/relpermDiagnostics.DATA
tests/norne_pvt.data
)
# originally generated with the command:
# find tutorials examples -name '*.c*' -printf '\t%p\n' | sort
# find examples -name '*.c*' -printf '\t%p\n' | sort
list (APPEND EXAMPLE_SOURCE_FILES
examples/compute_eikonal_from_files.cpp
examples/compute_initial_state.cpp
examples/compute_tof.cpp
examples/compute_tof_from_files.cpp
examples/mirror_grid.cpp
examples/sim_2p_comp_reorder.cpp
examples/sim_2p_incomp.cpp
examples/wells_example.cpp
tutorials/tutorial1.cpp
tutorials/tutorial2.cpp
tutorials/tutorial3.cpp
tutorials/tutorial4.cpp
examples/diagnose_relperm.cpp
)
# originally generated with the command:
@ -266,199 +161,90 @@ list (APPEND ATTIC_FILES
# programs listed here will not only be compiled, but also marked for
# installation
list (APPEND PROGRAM_SOURCE_FILES
examples/mirror_grid.cpp
examples/sim_2p_comp_reorder.cpp
examples/sim_2p_incomp.cpp
)
# originally generated with the command:
# find opm -name '*.h*' -a ! -name '*-pch.hpp' -printf '\t%p\n' | sort
list (APPEND PUBLIC_HEADER_FILES
opm/core/doxygen_main.hpp
opm/core/grid.h
opm/core/grid/CellQuadrature.hpp
opm/core/grid/ColumnExtract.hpp
opm/core/grid/FaceQuadrature.hpp
opm/core/grid/GridHelpers.hpp
opm/core/grid/GridManager.hpp
opm/core/grid/GridUtilities.hpp
opm/core/grid/MinpvProcessor.hpp
opm/core/grid/PinchProcessor.hpp
opm/core/grid/cart_grid.h
opm/core/grid/cornerpoint_grid.h
opm/core/grid/cpgpreprocess/facetopology.h
opm/core/grid/cpgpreprocess/geometry.h
opm/core/grid/cpgpreprocess/preprocess.h
opm/core/grid/cpgpreprocess/uniquepoints.h
opm/core/io/eclipse/CornerpointChopper.hpp
opm/core/io/eclipse/EclipseIOUtil.hpp
opm/core/io/eclipse/EclipseGridInspector.hpp
opm/core/io/eclipse/EclipseUnits.hpp
opm/core/io/eclipse/EclipseWriter.hpp
opm/core/io/eclipse/EclipseReader.hpp
opm/core/io/eclipse/EclipseWriteRFTHandler.hpp
opm/core/io/eclipse/writeECLData.hpp
opm/core/io/OutputWriter.hpp
opm/core/io/vag/vag.hpp
opm/core/io/vtk/writeVtkData.hpp
opm/core/linalg/LinearSolverFactory.hpp
opm/core/linalg/LinearSolverInterface.hpp
opm/core/linalg/LinearSolverIstl.hpp
opm/core/linalg/LinearSolverUmfpack.hpp
opm/core/linalg/LinearSolverPetsc.hpp
opm/core/linalg/ParallelIstlInformation.hpp
opm/core/linalg/blas_lapack.h
opm/core/linalg/call_umfpack.h
opm/core/linalg/sparse_sys.h
opm/core/version.h
opm/core/wells.h
opm/core/well_controls.h
opm/core/pressure/CompressibleTpfa.hpp
opm/core/pressure/FlowBCManager.hpp
opm/core/pressure/IncompTpfa.hpp
opm/core/pressure/IncompTpfaSinglePhase.hpp
opm/core/pressure/flow_bc.h
opm/core/pressure/fsh.h
opm/core/pressure/fsh_common_impl.h
opm/core/pressure/legacy_well.h
opm/core/pressure/mimetic/hybsys.h
opm/core/pressure/mimetic/hybsys_global.h
opm/core/pressure/mimetic/mimetic.h
opm/core/pressure/msmfem/coarse_conn.h
opm/core/pressure/msmfem/coarse_sys.h
opm/core/pressure/msmfem/dfs.h
opm/core/pressure/msmfem/hash_set.h
opm/core/pressure/msmfem/ifsh_ms.h
opm/core/pressure/msmfem/partition.h
opm/core/pressure/tpfa/cfs_tpfa.h
opm/core/pressure/tpfa/cfs_tpfa_residual.h
opm/core/pressure/tpfa/compr_bc.h
opm/core/pressure/tpfa/compr_quant.h
opm/core/pressure/tpfa/compr_quant_general.h
opm/core/pressure/tpfa/compr_source.h
opm/core/pressure/tpfa/ifs_tpfa.h
opm/core/pressure/tpfa/TransTpfa.hpp
opm/core/pressure/tpfa/TransTpfa_impl.hpp
opm/core/pressure/tpfa/trans_tpfa.h
opm/core/props/BlackoilPhases.hpp
opm/core/props/BlackoilPropertiesBasic.hpp
opm/core/props/BlackoilPropertiesFromDeck.hpp
opm/core/props/BlackoilPropertiesInterface.hpp
opm/core/props/IncompPropertiesBasic.hpp
opm/core/props/IncompPropertiesFromDeck.hpp
opm/core/props/IncompPropertiesInterface.hpp
opm/core/props/IncompPropertiesShadow.hpp
opm/core/props/IncompPropertiesShadow_impl.hpp
opm/core/props/IncompPropertiesSinglePhase.hpp
opm/core/props/phaseUsageFromDeck.hpp
opm/core/props/pvt/BlackoilPvtProperties.hpp
opm/core/props/pvt/PvtPropertiesBasic.hpp
opm/core/props/pvt/PvtPropertiesIncompFromDeck.hpp
opm/core/props/pvt/PvtConstCompr.hpp
opm/core/props/pvt/PvtDead.hpp
opm/core/props/pvt/PvtDeadSpline.hpp
opm/core/props/pvt/PvtInterface.hpp
opm/core/props/pvt/PvtLiveGas.hpp
opm/core/props/pvt/PvtLiveOil.hpp
opm/core/props/pvt/ThermalWaterPvtWrapper.hpp
opm/core/props/pvt/ThermalOilPvtWrapper.hpp
opm/core/props/pvt/ThermalGasPvtWrapper.hpp
opm/core/props/rock/RockBasic.hpp
opm/core/props/rock/RockCompressibility.hpp
opm/core/props/rock/RockFromDeck.hpp
opm/core/props/satfunc/SaturationPropsBasic.hpp
opm/core/props/satfunc/SaturationPropsFromDeck.hpp
opm/core/props/satfunc/SaturationPropsInterface.hpp
opm/core/simulator/AdaptiveSimulatorTimer.hpp
opm/core/simulator/AdaptiveTimeStepping.hpp
opm/core/simulator/AdaptiveTimeStepping_impl.hpp
opm/core/simulator/BlackoilState.hpp
opm/core/simulator/BlackoilStateToFluidState.hpp
opm/core/simulator/EquilibrationHelpers.hpp
opm/core/simulator/ExplicitArraysFluidState.hpp
opm/core/simulator/ExplicitArraysSatDerivativesFluidState.hpp
opm/core/simulator/TimeStepControl.hpp
opm/core/simulator/SimulatorCompressibleTwophase.hpp
opm/core/simulator/SimulatorIncompTwophase.hpp
opm/core/simulator/SimulatorOutput.hpp
opm/core/simulator/SimulatorReport.hpp
opm/core/simulator/SimulatorState.hpp
opm/core/simulator/SimulatorTimerInterface.hpp
opm/core/simulator/SimulatorTimer.hpp
opm/core/simulator/TimeStepControlInterface.hpp
opm/core/simulator/TwophaseState.hpp
opm/core/simulator/TwophaseState_impl.hpp
opm/core/simulator/WellState.hpp
opm/core/simulator/initState.hpp
opm/core/simulator/initState_impl.hpp
opm/core/simulator/initStateEquil.hpp
opm/core/simulator/initStateEquil_impl.hpp
opm/core/flowdiagnostics/AnisotropicEikonal.hpp
opm/core/flowdiagnostics/DGBasis.hpp
opm/core/flowdiagnostics/FlowDiagnostics.hpp
opm/core/flowdiagnostics/TofReorder.hpp
opm/core/flowdiagnostics/TofDiscGalReorder.hpp
opm/core/transport/TransportSolverTwophaseInterface.hpp
opm/core/transport/implicit/CSRMatrixBlockAssembler.hpp
opm/core/transport/implicit/CSRMatrixUmfpackSolver.hpp
opm/core/transport/implicit/ImplicitAssembly.hpp
opm/core/transport/implicit/ImplicitTransport.hpp
opm/core/transport/implicit/JacobianSystem.hpp
opm/core/transport/implicit/NormSupport.hpp
opm/core/transport/implicit/SinglePointUpwindTwoPhase.hpp
opm/core/transport/implicit/TransportSolverTwophaseImplicit.hpp
opm/core/transport/implicit/SimpleFluid2pWrappingProps.hpp
opm/core/transport/implicit/SimpleFluid2pWrappingProps_impl.hpp
opm/core/transport/implicit/transport_source.h
opm/core/transport/minimal/spu_explicit.h
opm/core/transport/minimal/spu_implicit.h
opm/core/transport/reorder/TransportSolverCompressibleTwophaseReorder.hpp
opm/core/transport/reorder/ReorderSolverInterface.hpp
opm/core/transport/reorder/TransportSolverTwophaseReorder.hpp
opm/core/transport/reorder/reordersequence.h
opm/core/transport/reorder/tarjan.h
opm/core/utility/Average.hpp
opm/core/utility/CompressedPropertyAccess.hpp
opm/core/utility/compressedToCartesian.hpp
opm/core/utility/DataMap.hpp
opm/core/utility/Event.hpp
opm/core/utility/Event_impl.hpp
opm/core/utility/Factory.hpp
opm/core/utility/MonotCubicInterpolator.hpp
opm/core/utility/opm_memcmp_double.h
opm/core/utility/NonuniformTableLinear.hpp
opm/core/utility/NullStream.hpp
opm/core/utility/RegionMapping.hpp
opm/core/utility/RootFinders.hpp
opm/core/utility/SparseTable.hpp
opm/core/utility/SparseVector.hpp
opm/core/utility/StopWatch.hpp
opm/core/utility/UniformTableLinear.hpp
opm/core/utility/Units.hpp
opm/core/utility/VelocityInterpolation.hpp
opm/core/utility/WachspressCoord.hpp
opm/core/utility/buildUniformMonotoneTable.hpp
opm/core/utility/have_boost_redef.hpp
opm/core/utility/linearInterpolation.hpp
opm/core/utility/miscUtilities.hpp
opm/core/utility/miscUtilities_impl.hpp
opm/core/utility/miscUtilitiesBlackoil.hpp
opm/core/utility/parameters/Parameter.hpp
opm/core/utility/parameters/ParameterGroup.hpp
opm/core/utility/parameters/ParameterGroup_impl.hpp
opm/core/utility/parameters/ParameterMapItem.hpp
opm/core/utility/parameters/ParameterRequirement.hpp
opm/core/utility/parameters/ParameterStrings.hpp
opm/core/utility/parameters/ParameterTools.hpp
opm/core/utility/parameters/ParameterXML.hpp
opm/core/utility/parameters/tinyxml/tinystr.h
opm/core/utility/parameters/tinyxml/tinyxml.h
opm/core/utility/share_obj.hpp
opm/core/utility/thresholdPressures.hpp
opm/core/wells/InjectionSpecification.hpp
opm/core/wells/ProductionSpecification.hpp
opm/core/wells/WellCollection.hpp
opm/core/wells/WellsGroup.hpp
opm/core/wells/WellsManager.hpp
opm/core/wells/WellsManager_impl.hpp
opm/core/doxygen_main.hpp
opm/core/flowdiagnostics/AnisotropicEikonal.hpp
opm/core/flowdiagnostics/DGBasis.hpp
opm/core/flowdiagnostics/FlowDiagnostics.hpp
opm/core/flowdiagnostics/TofDiscGalReorder.hpp
opm/core/flowdiagnostics/TofReorder.hpp
opm/core/linalg/LinearSolverFactory.hpp
opm/core/linalg/LinearSolverInterface.hpp
opm/core/linalg/LinearSolverIstl.hpp
opm/core/linalg/LinearSolverPetsc.hpp
opm/core/linalg/LinearSolverUmfpack.hpp
opm/core/linalg/ParallelIstlInformation.hpp
opm/core/linalg/call_umfpack.h
opm/core/linalg/sparse_sys.h
opm/core/pressure/CompressibleTpfa.hpp
opm/core/pressure/FlowBCManager.hpp
opm/core/pressure/IncompTpfa.hpp
opm/core/pressure/flow_bc.h
opm/core/pressure/legacy_well.h
opm/core/pressure/mimetic/mimetic.h
opm/core/pressure/msmfem/dfs.h
opm/core/pressure/msmfem/partition.h
opm/core/pressure/tpfa/cfs_tpfa_residual.h
opm/core/pressure/tpfa/compr_quant_general.h
opm/core/pressure/tpfa/compr_source.h
opm/core/pressure/tpfa/ifs_tpfa.h
opm/core/props/BlackoilPhases.hpp
opm/core/props/BlackoilPropertiesBasic.hpp
opm/core/props/BlackoilPropertiesFromDeck.hpp
opm/core/props/BlackoilPropertiesInterface.hpp
opm/core/props/IncompPropertiesBasic.hpp
opm/core/props/IncompPropertiesFromDeck.hpp
opm/core/props/IncompPropertiesInterface.hpp
opm/core/props/IncompPropertiesShadow.hpp
opm/core/props/IncompPropertiesShadow_impl.hpp
opm/core/props/IncompPropertiesSinglePhase.hpp
opm/core/props/phaseUsageFromDeck.hpp
opm/core/props/pvt/PvtPropertiesBasic.hpp
opm/core/props/pvt/PvtPropertiesIncompFromDeck.hpp
opm/core/props/pvt/ThermalGasPvtWrapper.hpp
opm/core/props/pvt/ThermalOilPvtWrapper.hpp
opm/core/props/pvt/ThermalWaterPvtWrapper.hpp
opm/core/props/rock/RockBasic.hpp
opm/core/props/rock/RockCompressibility.hpp
opm/core/props/rock/RockFromDeck.hpp
opm/core/props/satfunc/RelpermDiagnostics.hpp
opm/core/props/satfunc/SaturationPropsBasic.hpp
opm/core/props/satfunc/SaturationPropsFromDeck.hpp
opm/core/props/satfunc/SaturationPropsInterface.hpp
opm/core/props/satfunc/RelpermDiagnostics_impl.hpp
opm/core/simulator/BlackoilState.hpp
opm/core/simulator/BlackoilStateToFluidState.hpp
opm/core/simulator/EquilibrationHelpers.hpp
opm/core/simulator/ExplicitArraysFluidState.hpp
opm/core/simulator/ExplicitArraysSatDerivativesFluidState.hpp
opm/core/simulator/SimulatorReport.hpp
opm/core/simulator/TwophaseState.hpp
opm/core/simulator/WellState.hpp
opm/core/simulator/initState.hpp
opm/core/simulator/initStateEquil.hpp
opm/core/simulator/initStateEquil_impl.hpp
opm/core/simulator/initState_impl.hpp
opm/core/transport/TransportSolverTwophaseInterface.hpp
opm/core/transport/reorder/ReorderSolverInterface.hpp
opm/core/transport/reorder/TransportSolverCompressibleTwophaseReorder.hpp
opm/core/transport/reorder/TransportSolverTwophaseReorder.hpp
opm/core/transport/reorder/reordersequence.h
opm/core/transport/reorder/tarjan.h
opm/core/utility/initHydroCarbonState.hpp
opm/core/utility/miscUtilities.hpp
opm/core/utility/miscUtilitiesBlackoil.hpp
opm/core/utility/miscUtilities_impl.hpp
opm/core/well_controls.h
opm/core/wells.h
opm/core/wells/InjectionSpecification.hpp
opm/core/wells/ProductionSpecification.hpp
opm/core/wells/WellCollection.hpp
opm/core/wells/WellsGroup.hpp
opm/core/wells/WellsManager.hpp
opm/core/wells/DynamicListEconLimited.hpp
opm/core/wells/WellsManager_impl.hpp
)

View File

@ -2,6 +2,6 @@
set(CTEST_PROJECT_NAME "${${project}_NAME}")
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "opm-project.org")
set(CTEST_DROP_LOCATION "/CDash/submit.php?project=${${project}_NAME}")
set(CTEST_DROP_SITE "cdash.opm-project.org")
set(CTEST_DROP_LOCATION "/submit.php?project=${${project}_NAME}")
set(CTEST_DROP_SITE_CDASH TRUE)

View File

@ -1,5 +1,7 @@
Open Porous Media Core Library
==============================
# Open Porous Media Core Library
THIS MODULE IS DEPRECATED.
The code is now integrated in the other modules.
These are release notes for opm-core.

35
configure vendored
View File

@ -1,35 +0,0 @@
#!/bin/sh
# this file is supposed to be located in the source directory
src_dir=$(dirname $0)
# scan the arguments and set this if build macros could be specified
mod_dir=
for OPT in "$@"; do
case "$OPT" in
--with-opm-common=*)
# remove everything before equal sign and assign the rest
mod_dir=${OPT#*=}
# tilde expansion; note that doing eval may have side effects
mod_dir=$(eval echo $mod_dir)
# absolute path
[ -d "$mod_dir" ] && mod_dir=$(cd $mod_dir ; pwd)
;;
esac
done
# if it isn't specified, the look around in other known places
conf_file=cmake/Scripts/configure
if [ -z "$mod_dir" ]; then
if [ -r "$src_dir/$conf_file" ]; then
mod_dir="$src_dir"
fi
fi
# terminate with error message here if the module directory is not found
if [ ! -r "$mod_dir/$conf_file" ]; then
echo Build macros not located in \"$mod_dir\", use --with-opm-common= to specify! 1>&2
exit 1
fi
# forward to the corresponding script in the cmake/Scripts/ directory
exec "$mod_dir/$conf_file" --src-dir="$src_dir" "$@"

27
debian/control vendored
View File

@ -3,12 +3,14 @@ Priority: extra
Maintainer: Arne Morten Kvarving <arne.morten.kvarving@sintef.no>
Build-Depends: build-essential, debhelper (>= 9), libboost-filesystem-dev,
libboost-system-dev, libboost-date-time-dev, libboost-test-dev,
libsuperlu3-dev, gfortran, libsuitesparse-dev, pkg-config,
libsuperlu3-dev (>= 3.0) | libsuperlu-dev (>= 4.3), gfortran, libsuitesparse-dev, pkg-config,
libdune-common-dev, libdune-istl-dev, cmake, libtinyxml-dev, bc,
libert.ecl-dev, git, zlib1g-dev, libtool, doxygen, libopm-parser-dev,
libecl-dev, git, zlib1g-dev, libtool, doxygen, libopm-parser-dev,
libopm-material-dev, texlive-latex-extra, texlive-latex-recommended,
ghostscript, libboost-iostreams-dev, libopm-common-dev,
libopm-material-dev
libopm-material-dev, libopenmpi-dev, mpi-default-bin,
libtrilinos-zoltan-dev, libopm-output-dev,
libopm-grid-dev, libdune-geometry-dev, libdune-grid-dev
Standards-Version: 3.9.2
Section: libs
Homepage: http://opm-project.org
@ -53,25 +55,6 @@ Description: OPM core library
* Utilities (input and output processing, unit conversion)
* Wells (basic well handling)
Package: libopm-core1-bin
Section: science
Pre-Depends: ${misc:Pre-Depends}, multiarch-support
Architecture: any
Multi-Arch: same
Depends: ${shlibs:Depends}, ${misc:Depends}
Provides: libopm-core-bin
Description: OPM core library -- applications
The OPM core library is the core library within OPM and contains
* Eclipse deck input and preprosessing
* Fluid properties (basic PVT models and rock properties)
* Grid handling (cornerpoint grids, unstructured grid interface)
* Linear Algebra (interface to different linear solvers)
* Pressure solvers (various discretization schemes, flow models)
* Simulators (some basic examples of simulators based on sequential splitting schemes)
* Transport solvers (various discretization schemes, flow models)
* Utilities (input and output processing, unit conversion)
* Wells (basic well handling)
Package: libopm-core1-doc
Section: doc
Architecture: all

2
debian/docs vendored
View File

@ -1,2 +1,2 @@
README
README.md
COPYING

View File

@ -1 +0,0 @@
usr/bin/*

View File

@ -3,3 +3,4 @@ usr/lib/*/lib*.so
usr/lib/dunecontrol/*
usr/lib/*/pkgconfig/*
usr/share/cmake/*
usr/share/opm/cmake/Modules/*

3
debian/rules vendored
View File

@ -8,6 +8,7 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
export OMPI_MCA_plm_rsh_agent=/bin/false
%:
dh $@
@ -20,7 +21,7 @@ override_dh_auto_build:
# consider using -DUSE_VERSIONED_DIR=ON if backporting
override_dh_auto_configure:
dh_auto_configure --buildsystem=cmake -- -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSTRIP_DEBUGGING_SYMBOLS=ON -DBUILD_SHARED_LIBS=1 -DCMAKE_INSTALL_DOCDIR=share/doc/libopm-core1 -DWHOLE_PROG_OPTIM=ON -DUSE_RUNPATH=OFF
dh_auto_configure --buildsystem=cmake -- -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_MPI=1 -DSTRIP_DEBUGGING_SYMBOLS=ON -DBUILD_SHARED_LIBS=1 -DCMAKE_INSTALL_DOCDIR=share/doc/libopm-core1 -DWHOLE_PROG_OPTIM=ON -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF
override_dh_auto_install:
dh_auto_install -- install-html

View File

@ -1,7 +1,13 @@
####################################################################
# Dune module information file: This file gets parsed by dunecontrol
# and by the CMake build scripts.
####################################################################
Module: opm-core
Description: Open Porous Media Initiative Core Library
# if you change this, make sure to also change opm/core/version.h
Version: 1.1
Label: 2013.10
Version: 2018.04-pre
Label: 2018.04-pre
Maintainer: atgeirr@sintef.no
Depends: dune-common (>= 2.2) dune-istl (>= 2.2) opm-common opm-parser opm-material
MaintainerName: Atgeirr F. Rasmussen
Url: http://opm-project.org
Depends: dune-common (>= 2.4) dune-istl (>= 2.4) opm-common opm-parser opm-grid opm-output opm-material

View File

@ -19,7 +19,7 @@
#if HAVE_CONFIG_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
@ -34,6 +34,7 @@
#include <memory>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <numeric>
#include <iterator>
@ -41,7 +42,7 @@
namespace
{
void warnIfUnusedParams(const Opm::parameter::ParameterGroup& param)
void warnIfUnusedParams(const Opm::ParameterGroup& param)
{
if (param.anyUnused()) {
std::cout << "-------------------- Warning: unused parameters: --------------------\n";
@ -60,7 +61,7 @@ try
{
using namespace Opm;
parameter::ParameterGroup param(argc, argv);
ParameterGroup param(argc, argv);
// Read grid.
GridManager grid_manager(param.get<std::string>("grid_filename"));

View File

@ -1,5 +1,6 @@
/*
Copyright 2014 SINTEF ICT, Applied Mathematics.
Copyright 2017 IRIS
This file is part of the Open Porous Media project (OPM).
@ -18,7 +19,7 @@
*/
#if HAVE_CONFIG_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
@ -27,18 +28,24 @@
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/simulator/initStateEquil.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/props/BlackoilPropertiesFromDeck.hpp>
#include <opm/core/props/BlackoilPhases.hpp>
#include <opm/core/props/phaseUsageFromDeck.hpp>
#include <opm/core/simulator/BlackoilState.hpp>
#include <opm/core/utility/compressedToCartesian.hpp>
#include <opm/parser/eclipse/Parser/ParseMode.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
namespace
{
void warnIfUnusedParams(const Opm::parameter::ParameterGroup& param)
void warnIfUnusedParams(const Opm::ParameterGroup& param)
{
if (param.anyUnused()) {
std::cout << "-------------------- Unused parameters: --------------------\n";
@ -68,12 +75,36 @@ namespace
std::copy(data.begin(), data.end(), std::ostream_iterator<double>(file, "\n"));
}
/// Convert saturations from a vector of individual phase saturation vectors
/// to an interleaved format where all values for a given cell come before all
/// values for the next cell, all in a single vector.
template <class FluidSystem>
void convertSats(std::vector<double>& sat_interleaved, const std::vector< std::vector<double> >& sat, const Opm::PhaseUsage& pu)
{
assert(sat.size() == 3);
const auto nc = sat[0].size();
const auto np = sat_interleaved.size() / nc;
for (size_t c = 0; c < nc; ++c) {
if ( FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
const int opos = pu.phase_pos[Opm::BlackoilPhases::Liquid];
const std::vector<double>& sat_p = sat[ FluidSystem::oilPhaseIdx];
sat_interleaved[np*c + opos] = sat_p[c];
}
if ( FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
const int wpos = pu.phase_pos[Opm::BlackoilPhases::Aqua];
const std::vector<double>& sat_p = sat[ FluidSystem::waterPhaseIdx];
sat_interleaved[np*c + wpos] = sat_p[c];
}
if ( FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
const int gpos = pu.phase_pos[Opm::BlackoilPhases::Vapour];
const std::vector<double>& sat_p = sat[ FluidSystem::gasPhaseIdx];
sat_interleaved[np*c + gpos] = sat_p[c];
}
}
}
} // anon namespace
// ----------------- Main program -----------------
int
main(int argc, char** argv)
@ -82,22 +113,53 @@ try
using namespace Opm;
// Setup.
parameter::ParameterGroup param(argc, argv);
ParameterGroup param(argc, argv);
std::cout << "--------------- Reading parameters ---------------" << std::endl;
const std::string deck_filename = param.get<std::string>("deck_filename");
Opm::ParseMode parseMode;
Opm::ParserPtr parser(new Opm::Parser() );
Opm::DeckConstPtr deck = parser->parseFile(deck_filename , parseMode);
Opm::EclipseStateConstPtr eclipseState(new Opm::EclipseState(deck, parseMode));
Opm::ParseContext parseContext;
Opm::Parser parser;
const Opm::Deck& deck = parser.parseFile(deck_filename , parseContext);
const Opm::EclipseState eclipseState(deck, parseContext);
const double grav = param.getDefault("gravity", unit::gravity);
GridManager gm(deck);
GridManager gm(eclipseState.getInputGrid());
const UnstructuredGrid& grid = *gm.c_grid();
BlackoilPropertiesFromDeck props(deck, eclipseState, grid, param);
warnIfUnusedParams(param);
// Create material law manager.
std::vector<int> compressedToCartesianIdx
= Opm::compressedToCartesian(grid.number_of_cells, grid.global_cell);
typedef FluidSystems::BlackOil<double> FluidSystem;
// Forward declaring the MaterialLawManager template.
typedef Opm::ThreePhaseMaterialTraits<double,
/*wettingPhaseIdx=*/FluidSystem::waterPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::oilPhaseIdx,
/*gasPhaseIdx=*/FluidSystem::gasPhaseIdx> MaterialTraits;
typedef Opm::EclMaterialLawManager<MaterialTraits> MaterialLawManager;
MaterialLawManager materialLawManager = MaterialLawManager();
materialLawManager.initFromDeck(deck, eclipseState, compressedToCartesianIdx);
// Initialisation.
BlackoilState state;
initStateEquil(grid, props, deck, eclipseState, grav, state);
//initBlackoilSurfvolUsingRSorRV(UgGridHelpers::numCells(grid), props, state);
BlackoilState state( UgGridHelpers::numCells(grid) , UgGridHelpers::numFaces(grid), 3);
FluidSystem::initFromDeck(deck, eclipseState);
PhaseUsage pu = phaseUsageFromDeck(deck);
typedef EQUIL::DeckDependent::InitialStateComputer<FluidSystem> ISC;
ISC isc(materialLawManager, eclipseState, grid, grav);
const bool oil = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx);
const int oilpos = FluidSystem::oilPhaseIdx;
const int waterpos = FluidSystem::waterPhaseIdx;
const int ref_phase = oil ? oilpos : waterpos;
state.pressure() = isc.press()[ref_phase];
convertSats<FluidSystem>(state.saturation(), isc.saturation(), pu);
state.gasoilratio() = isc.rs();
state.rv() = isc.rv();
// Output.
const std::string output_dir = param.getDefault<std::string>("output_dir", "output");

View File

@ -1,349 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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/>.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <opm/core/grid.h>
#include <opm/core/grid/GridManager.hpp>
#include <opm/core/wells.h>
#include <opm/core/wells/WellsManager.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/utility/SparseTable.hpp>
#include <opm/core/utility/StopWatch.hpp>
#include <opm/core/utility/Units.hpp>
#include <opm/core/utility/miscUtilities.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/props/IncompPropertiesSinglePhase.hpp>
#include <opm/core/linalg/LinearSolverFactory.hpp>
#include <opm/core/pressure/IncompTpfaSinglePhase.hpp>
#include <opm/core/flowdiagnostics/FlowDiagnostics.hpp>
#include <opm/core/flowdiagnostics/TofReorder.hpp>
#include <opm/core/flowdiagnostics/TofDiscGalReorder.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Parser/ParseMode.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <memory>
#include <boost/filesystem.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
namespace
{
const static double alq_invalid = -std::numeric_limits<double>::max();
const static int vfp_invalid = -std::numeric_limits<int>::max();
void warnIfUnusedParams(const Opm::parameter::ParameterGroup& param)
{
if (param.anyUnused()) {
std::cout << "-------------------- Unused parameters: --------------------\n";
param.displayUsage();
std::cout << "----------------------------------------------------------------" << std::endl;
}
}
void buildTracerheadsFromWells(const Wells& wells,
const bool trace_injectors,
Opm::SparseTable<int>& tracerheads)
{
tracerheads.clear();
const int num_wells = wells.number_of_wells;
const WellType wanted_type = trace_injectors ? INJECTOR : PRODUCER;
for (int w = 0; w < num_wells; ++w) {
if (wells.type[w] != wanted_type) {
continue;
}
tracerheads.appendRow(wells.well_cells + wells.well_connpos[w],
wells.well_cells + wells.well_connpos[w + 1]);
}
}
void setBhpWells(Wells& wells)
{
const int num_wells = wells.number_of_wells;
for (int w = 0; w < num_wells; ++w) {
WellControls* ctrl = wells.ctrls[w];
const double target = (wells.type[w] == INJECTOR) ? 200*Opm::unit::barsa : 100*Opm::unit::barsa;
const double distr[3] = { 1.0, 0.0, 0.0 }; // Large enough irrespective of #phases.
well_controls_add_new(BHP, target,
alq_invalid, vfp_invalid,
distr, ctrl);
well_controls_set_current(ctrl, well_controls_get_num(ctrl) - 1);
}
}
void computeTransportSourceSinglePhase(const UnstructuredGrid& grid,
const std::vector<double>& src,
const std::vector<double>& faceflux,
const double inflow_frac,
const Wells* wells,
const std::vector<double>& well_perfrates,
std::vector<double>& transport_src)
{
using namespace Opm;
int nc = grid.number_of_cells;
transport_src.resize(nc);
// Source term and boundary contributions.
for (int c = 0; c < nc; ++c) {
transport_src[c] = 0.0;
transport_src[c] += src[c] > 0.0 ? inflow_frac*src[c] : src[c];
for (int hf = grid.cell_facepos[c]; hf < grid.cell_facepos[c + 1]; ++hf) {
int f = grid.cell_faces[hf];
const int* f2c = &grid.face_cells[2*f];
double bdy_influx = 0.0;
if (f2c[0] == c && f2c[1] == -1) {
bdy_influx = -faceflux[f];
} else if (f2c[0] == -1 && f2c[1] == c) {
bdy_influx = faceflux[f];
}
if (bdy_influx != 0.0) {
transport_src[c] += bdy_influx > 0.0 ? inflow_frac*bdy_influx : bdy_influx;
}
}
}
// Well contributions.
if (wells) {
const int nw = wells->number_of_wells;
for (int w = 0; w < nw; ++w) {
for (int perf = wells->well_connpos[w]; perf < wells->well_connpos[w + 1]; ++perf) {
const int perf_cell = wells->well_cells[perf];
double perf_rate = well_perfrates[perf];
if (perf_rate > 0.0) {
// perf_rate is a total inflow rate, we want a water rate.
if (wells->type[w] != INJECTOR) {
std::cout << "**** Warning: crossflow in well "
<< w << " perf " << perf - wells->well_connpos[w]
<< " ignored. Rate was "
<< perf_rate/Opm::unit::day << " m^3/day." << std::endl;
perf_rate = 0.0;
} else {
perf_rate *= inflow_frac;
}
}
transport_src[perf_cell] += perf_rate;
}
}
}
}
} // anon namespace
// ----------------- Main program -----------------
int
main(int argc, char** argv)
try
{
using namespace Opm;
std::cout << "\n================ Test program for incompressible tof computations ===============\n\n";
parameter::ParameterGroup param(argc, argv);
std::cout << "--------------- Reading parameters ---------------" << std::endl;
// Read the deck.
std::string deck_filename = param.get<std::string>("deck_filename");
Parser parser;
ParseMode parseMode;
DeckConstPtr deck = parser.parseFile(deck_filename , parseMode);
EclipseStateConstPtr eclipseState = std::make_shared<EclipseState>(deck , parseMode);
// Grid init
GridManager grid_manager(deck);
const UnstructuredGrid& grid = *grid_manager.c_grid();
// Rock and fluid init
IncompPropertiesSinglePhase props(deck, eclipseState, grid);
// Wells init.
WellsManager wells_manager(eclipseState , 0, grid, props.permeability());
std::shared_ptr<Wells> my_wells(clone_wells(wells_manager.c_wells()), destroy_wells);
setBhpWells(*my_wells);
const Wells& wells = *my_wells;
// Pore volume.
std::vector<double> porevol;
computePorevolume(grid, props.porosity(), porevol);
int num_cells = grid.number_of_cells;
// Linear solver.
LinearSolverFactory linsolver(param);
// Pressure solver.
Opm::IncompTpfaSinglePhase psolver(grid, props, linsolver, wells);
// Choice of tof solver.
bool use_dg = param.getDefault("use_dg", false);
bool use_multidim_upwind = false;
// Need to initialize dg solver here, since it uses parameters now.
std::unique_ptr<Opm::TofDiscGalReorder> dg_solver;
if (use_dg) {
dg_solver.reset(new Opm::TofDiscGalReorder(grid, param));
} else {
use_multidim_upwind = param.getDefault("use_multidim_upwind", false);
}
bool compute_tracer = param.getDefault("compute_tracer", false);
// Write parameters used for later reference.
bool output = param.getDefault("output", true);
std::ofstream epoch_os;
std::string output_dir;
if (output) {
output_dir =
param.getDefault("output_dir", std::string("output"));
boost::filesystem::path fpath(output_dir);
try {
create_directories(fpath);
}
catch (...) {
OPM_THROW(std::runtime_error, "Creating directories failed: " << fpath);
}
param.writeParam(output_dir + "/simulation.param");
}
// Check if we have misspelled anything
warnIfUnusedParams(param);
// Main solvers.
Opm::time::StopWatch pressure_timer;
double ptime = 0.0;
Opm::time::StopWatch transport_timer;
double ttime = 0.0;
Opm::time::StopWatch total_timer;
total_timer.start();
std::cout << "\n\n================ Starting main solvers ===============" << std::endl;
// Solve pressure.
std::vector<double> press;
std::vector<double> flux;
std::vector<double> bhp;
std::vector<double> wellrates;
pressure_timer.start();
psolver.solve(press, flux, bhp, wellrates);
pressure_timer.stop();
double pt = pressure_timer.secsSinceStart();
std::cout << "Pressure solver took: " << pt << " seconds." << std::endl;
ptime += pt;
// Process transport sources (to include bdy terms and well flows).
std::vector<double> src(num_cells, 0.0);
std::vector<double> transport_src;
computeTransportSourceSinglePhase(grid, src, flux, 1.0,
&wells, wellrates, transport_src);
std::string tof_filenames[2] = { output_dir + "/ftof.txt", output_dir + "/btof.txt" };
std::string tracer_filenames[2] = { output_dir + "/ftracer.txt", output_dir + "/btracer.txt" };
std::vector<double> tracers[2];
// We compute tof twice, direction == 0 is from injectors, 1 is from producers.
for (int direction = 0; direction < 2; ++direction) {
// Turn direction of flux and flip source terms if starting from producers.
if (direction == 1) {
for (auto it = flux.begin(); it != flux.end(); ++it) {
(*it) = -(*it);
}
for (auto it = transport_src.begin(); it != transport_src.end(); ++it) {
(*it) = -(*it);
}
}
// Solve time-of-flight.
transport_timer.start();
std::vector<double> tof;
std::vector<double> tracer;
Opm::SparseTable<int> tracerheads;
if (compute_tracer) {
buildTracerheadsFromWells(wells, direction == 0, tracerheads);
}
if (use_dg) {
if (compute_tracer) {
dg_solver->solveTofTracer(flux.data(), porevol.data(), transport_src.data(), tracerheads, tof, tracer);
} else {
dg_solver->solveTof(flux.data(), porevol.data(), transport_src.data(), tof);
}
} else {
Opm::TofReorder tofsolver(grid, use_multidim_upwind);
if (compute_tracer) {
tofsolver.solveTofTracer(flux.data(), porevol.data(), transport_src.data(), tracerheads, tof, tracer);
} else {
tofsolver.solveTof(flux.data(), porevol.data(), transport_src.data(), tof);
}
}
transport_timer.stop();
double tt = transport_timer.secsSinceStart();
if (direction == 0) {
std::cout << "Forward ";
} else {
std::cout << "Backward ";
}
std::cout << "time-of-flight/tracer solve took: " << tt << " seconds." << std::endl;
ttime += tt;
// Output.
if (output) {
std::string tof_filename = tof_filenames[direction];
std::ofstream tof_stream(tof_filename.c_str());
tof_stream.precision(16);
std::copy(tof.begin(), tof.end(), std::ostream_iterator<double>(tof_stream, "\n"));
if (compute_tracer) {
std::string tracer_filename = tracer_filenames[direction];
std::ofstream tracer_stream(tracer_filename.c_str());
tracer_stream.precision(16);
const int nt = tracer.size()/num_cells;
for (int i = 0; i < nt*num_cells; ++i) {
tracer_stream << tracer[i] << (((i + 1) % nt == 0) ? '\n' : ' ');
}
tracers[direction] = tracer;
}
}
}
// If we have tracers, compute well pairs.
if (compute_tracer) {
auto wp = Opm::computeWellPairs(wells, porevol, tracers[0], tracers[1]);
std::string wellpair_filename = output_dir + "/wellpairs.txt";
std::ofstream wellpair_stream(wellpair_filename.c_str());
const int nwp = wp.size();
for (int ii = 0; ii < nwp; ++ii) {
wellpair_stream << std::get<0>(wp[ii]) << ' ' << std::get<1>(wp[ii]) << ' ' << std::get<2>(wp[ii]) << '\n';
}
}
total_timer.stop();
std::cout << "\n\n================ End of simulation ===============\n"
<< "Total time taken: " << total_timer.secsSinceStart()
<< "\n Pressure time: " << ptime
<< "\n Tof/tracer time: " << ttime << std::endl;
}
catch (const std::exception &e) {
std::cerr << "Program threw an exception: " << e.what() << "\n";
throw;
}

View File

@ -18,12 +18,10 @@
*/
#if HAVE_CONFIG_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <opm/core/pressure/FlowBCManager.hpp>
#include <opm/core/grid.h>
#include <opm/core/grid/GridManager.hpp>
#include <opm/core/wells.h>
@ -42,7 +40,6 @@
#include <opm/core/simulator/TwophaseState.hpp>
#include <opm/core/simulator/WellState.hpp>
#include <opm/core/simulator/initState.hpp>
#include <opm/core/pressure/IncompTpfa.hpp>
#include <opm/core/flowdiagnostics/TofReorder.hpp>
#include <opm/core/flowdiagnostics/TofDiscGalReorder.hpp>
@ -54,11 +51,11 @@
#include <vector>
#include <numeric>
#include <iterator>
#include <fstream>
namespace
{
void warnIfUnusedParams(const Opm::parameter::ParameterGroup& param)
void warnIfUnusedParams(const Opm::ParameterGroup& param)
{
if (param.anyUnused()) {
std::cout << "-------------------- Warning: unused parameters: --------------------\n";
@ -77,7 +74,7 @@ try
{
using namespace Opm;
parameter::ParameterGroup param(argc, argv);
ParameterGroup param(argc, argv);
// Read grid.
GridManager grid_manager(param.get<std::string>("grid_filename"));

View File

@ -0,0 +1,105 @@
/*
Copyright 2015 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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <opm/core/grid.h>
#include <opm/core/grid/GridManager.hpp>
#include <opm/core/props/satfunc/RelpermDiagnostics.hpp>
#include <opm/core/props/satfunc/RelpermDiagnostics_impl.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/utility/StopWatch.hpp>
#include <opm/core/utility/miscUtilities.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/common/OpmLog/EclipsePRTLog.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <memory>
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
#include <iterator>
void usage() {
std::cout << std::endl <<
"Usage: diagnose_relperm <eclipseFile>" << std::endl;
}
// ----------------- Main program -----------------
int
main(int argc, char** argv)
try
{
using namespace Opm;
if (argc <= 1) {
usage();
exit(1);
}
const char* eclipseFilename = argv[1];
Parser parser;
Opm::ParseContext parseContext({{ ParseContext::PARSE_RANDOM_SLASH , InputError::IGNORE },
{ ParseContext::PARSE_UNKNOWN_KEYWORD, InputError::IGNORE},
{ ParseContext::PARSE_RANDOM_TEXT, InputError::IGNORE},
{ ParseContext::UNSUPPORTED_SCHEDULE_GEO_MODIFIER, InputError::IGNORE},
{ ParseContext::UNSUPPORTED_COMPORD_TYPE, InputError::IGNORE},
{ ParseContext::UNSUPPORTED_INITIAL_THPRES, InputError::IGNORE},
{ ParseContext::INTERNAL_ERROR_UNINITIALIZED_THPRES, InputError::IGNORE}
});
Opm::Deck deck = parser.parseFile(eclipseFilename, parseContext);
Opm::EclipseState eclState( deck, parseContext );
GridManager gm(eclState.getInputGrid());
const UnstructuredGrid& grid = *gm.c_grid();
using boost::filesystem::path;
path fpath(eclipseFilename);
std::string baseName;
if (boost::to_upper_copy(path(fpath.extension()).string())== ".DATA") {
baseName = path(fpath.stem()).string();
} else {
baseName = path(fpath.filename()).string();
}
std::string logFile = baseName + ".SATFUNCLOG";
std::shared_ptr<EclipsePRTLog> prtLog = std::make_shared<EclipsePRTLog>(logFile, Log::DefaultMessageTypes);
OpmLog::addBackend( "ECLIPSEPRTLOG" , prtLog );
prtLog->setMessageFormatter(std::make_shared<SimpleMessageFormatter>(true, false));
std::shared_ptr<StreamLog> streamLog = std::make_shared<EclipsePRTLog>(std::cout, Log::DefaultMessageTypes);
OpmLog::addBackend( "STREAMLOG" , streamLog );
streamLog->setMessageLimiter(std::make_shared<MessageLimiter>(10));
streamLog->setMessageFormatter(std::make_shared<SimpleMessageFormatter>(true, true));
RelpermDiagnostics diagnostic;
diagnostic.diagnosis(eclState, deck, grid);
}
catch (const std::exception &e) {
std::cerr << "Program threw an exception: " << e.what() << "\n";
throw;
}

View File

@ -1,402 +0,0 @@
/*
Copyright 2014 Statoil ASA.
Copyright 2014 Andreas Lauser.
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 "config.h"
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Parser/ParseMode.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <iostream>
#include <fstream>
/**
* @file mirror_grid.cpp
* @brief Mirror grid taken from grdecl file
*
* The input grid is mirrored in either the x- or y-direction, resulting in a periodic grid.
*
*/
/// Print init message in new grid filename
void printInitMessage(std::ofstream& out, const char* origfilename, std::string direction) {
std::ifstream infile;
infile.open(origfilename, std::ios::in);
if (!infile) {
std::cerr << "Can't open input file " << origfilename << std::endl;
exit(1);
}
// Print init message and copy comments from original grid file
out << "-- This grdecl file is generated from OPM application 'mirror_grid.cpp'." << std::endl
<< "-- The grid '" << origfilename << "' is mirrored around itself in the " << direction << " direction." << std::endl
<< "-- Thus, the resulting grid should be periodic in the " << direction << "-direction." << std::endl
<< "-- Original comments taken from '" << origfilename << "':" << std::endl;
std::string nextInLine;
while (getline(infile, nextInLine)) {
if (nextInLine.substr(0,2) == "--") {
out << nextInLine << std::endl;
}
else {
break;
}
}
out << std::endl;
}
/// Write keyword values to file
template <class T>
void printKeywordValues(std::ofstream& out, std::string keyword, std::vector<T> values, int nCols) {
out << keyword << std::endl;
int col = 0;
typename std::vector<T>::iterator iter;
for (iter = values.begin(); iter != values.end(); ++iter) {
out << *iter << " ";
++col;
// Break line for every nCols entry.
if (col == nCols) {
out << std::endl;
col = 0;
}
}
if (col != 0)
out << std::endl;
out << "/" << std::endl << std::endl;
}
// forward declaration
std::vector<double> getMapaxesValues(Opm::DeckConstPtr deck);
/// Mirror keyword MAPAXES in deck
void mirror_mapaxes(Opm::DeckConstPtr deck, std::string direction, std::ofstream& out) {
// Assumes axis aligned with x/y-direction
std::cout << "Warning: Keyword MAPAXES not fully understood. Result should be verified manually." << std::endl;
if (deck->hasKeyword("MAPAXES")) {
std::vector<double> mapaxes = getMapaxesValues(deck);
std::vector<double> mapaxes_mirrored = mapaxes;
// Double the length of the coordinate axis
if (direction == "x") {
mapaxes_mirrored[4] = (mapaxes[4]-mapaxes[2])*2 + mapaxes[2];
}
else if (direction == "y") {
mapaxes_mirrored[1] = (mapaxes[1]-mapaxes[3])*2 + mapaxes[3];
}
printKeywordValues(out, "MAPAXES", mapaxes_mirrored, 2);
}
}
/// Mirror keyword SPECGRID in deck
void mirror_specgrid(Opm::DeckConstPtr deck, std::string direction, std::ofstream& out) {
// We only need to multiply the dimension by 2 in the correct direction.
Opm::DeckRecordConstPtr specgridRecord = deck->getKeyword("SPECGRID")->getRecord(0);
std::vector<int> dimensions(3);
dimensions[0] = specgridRecord->getItem("NX")->getInt(0);
dimensions[1] = specgridRecord->getItem("NY")->getInt(0);
dimensions[2] = specgridRecord->getItem("NZ")->getInt(0);
if (direction == "x") {dimensions[0] *= 2;}
else if (direction == "y") {dimensions[1] *= 2;}
else {std::cerr << "Direction should be either x or y" << std::endl; exit(1);}
out << "SPECGRID" << std::endl << dimensions[0] << " " << dimensions[1] << " " << dimensions[2] << " "
<< specgridRecord->getItem("NUMRES")->getInt(0) << " "
<< specgridRecord->getItem("COORD_TYPE")->getString(0) << " "
<< std::endl << "/" << std::endl << std::endl;
}
/// Mirror keyword COORD in deck
void mirror_coord(Opm::DeckConstPtr deck, std::string direction, std::ofstream& out) {
// We assume uniform spacing in x and y directions and parallel top and bottom faces
Opm::DeckRecordConstPtr specgridRecord = deck->getKeyword("SPECGRID")->getRecord(0);
std::vector<int> dimensions(3);
dimensions[0] = specgridRecord->getItem("NX")->getInt(0);
dimensions[1] = specgridRecord->getItem("NY")->getInt(0);
dimensions[2] = specgridRecord->getItem("NZ")->getInt(0);
std::vector<double> coord = deck->getKeyword("COORD")->getRawDoubleData();
const int entries_per_pillar = 6;
std::vector<double> coord_mirrored;
// Handle the two directions differently due to ordering of the pillars.
if (direction == "x") {
// Total entries in mirrored ZCORN. Number of pillars times 6
const int entries = (2*dimensions[0] + 1) * (dimensions[1] + 1) * entries_per_pillar;
// Entries per line in x-direction. Number of pillars in x-direction times 6
const int entries_per_line = entries_per_pillar*(dimensions[0] + 1);
coord_mirrored.assign(entries, 0.0);
// Distance between pillars in x-directiion
const double spacing = coord[entries_per_pillar]-coord[0];
std::vector<double>::iterator it_new = coord_mirrored.begin();
std::vector<double>::iterator it_orig;
// Loop through each pillar line in the x-direction
for (it_orig = coord.begin(); it_orig != coord.end(); it_orig += entries_per_line) {
// Copy old pillars
copy(it_orig, it_orig + entries_per_line, it_new);
// Add new pillars in between
it_new += entries_per_line;
std::vector<double> next_vec(it_orig + entries_per_line - entries_per_pillar, it_orig + entries_per_line);
for (int r=0; r < dimensions[0]; ++r) {
next_vec[0] += spacing;
next_vec[3] += spacing;
copy(next_vec.begin(), next_vec.end(), it_new);
it_new += entries_per_pillar;
}
}
}
else if (direction == "y") {
// Total entries in mirrored ZCORN. Number of pillars times 6
const int entries = (dimensions[0] + 1) * (2*dimensions[1] + 1) * entries_per_pillar;
// Entries per line in y-direction. Number of pillars in y-direction times 6
const int entries_per_line = entries_per_pillar*(dimensions[0] + 1);
coord_mirrored.assign(entries, 0.0);
// Distance between pillars in y-directiion
const double spacing = coord[entries_per_line + 1]-coord[1];
std::vector<double>::iterator it_new = coord_mirrored.begin();
// Copy old pillars
copy(coord.begin(), coord.end(), it_new);
// Add new pillars at the end
it_new += coord.size();
std::vector<double> next_vec(coord.end() - entries_per_line, coord.end());
for ( ; it_new != coord_mirrored.end(); it_new += entries_per_line) {
for (int i = 1; i < entries_per_line; i += 3) {
next_vec[i] += spacing;
}
copy(next_vec.begin(), next_vec.end(), it_new);
}
}
else {
std::cerr << "Direction should be either x or y" << std::endl;
exit(1);
}
// Write new COORD values to output file
printKeywordValues(out, "COORD", coord_mirrored, 6);
}
/// Mirror keyword ZCORN in deck
void mirror_zcorn(Opm::DeckConstPtr deck, std::string direction, std::ofstream& out) {
Opm::DeckRecordConstPtr specgridRecord = deck->getKeyword("SPECGRID")->getRecord(0);
std::vector<int> dimensions(3);
dimensions[0] = specgridRecord->getItem("NX")->getInt(0);
dimensions[1] = specgridRecord->getItem("NY")->getInt(0);
dimensions[2] = specgridRecord->getItem("NZ")->getInt(0);
std::vector<double> zcorn = deck->getKeyword("ZCORN")->getRawDoubleData();
std::vector<double> zcorn_mirrored;
// Handle the two directions differently due to ordering of the pillars.
if (direction == "x") {
// Total entries in mirrored ZCORN. Eight corners per cell.
const int entries = dimensions[0]*2*dimensions[1]*dimensions[2]*8;
zcorn_mirrored.assign(entries, 0.0);
// Entries per line in x-direction. Two for each cell.
const int entries_per_line = dimensions[0]*2;
std::vector<double>::iterator it_new = zcorn_mirrored.begin();
std::vector<double>::iterator it_orig = zcorn.begin();
// Loop through each line and copy old corner-points and add new (which are the old reversed)
for ( ; it_orig != zcorn.end(); it_orig += entries_per_line) {
std::vector<double> next_vec(it_orig, it_orig + entries_per_line);
std::vector<double> next_reversed = next_vec;
reverse(next_reversed.begin(), next_reversed.end());
// Copy old corner-points
copy(it_orig, it_orig + entries_per_line, it_new);
it_new += entries_per_line;
// Add new corner-points
copy(next_reversed.begin(), next_reversed.end(), it_new);
it_new += entries_per_line;
}
}
else if (direction == "y") {
// Total entries in mirrored ZCORN. Eight corners per cell.
const int entries = dimensions[0]*dimensions[1]*2*dimensions[2]*8;
zcorn_mirrored.assign(entries, 0.0);
// Entries per line in x-direction. Two for each cell.
const int entries_per_line_x = dimensions[0]*2;
// Entries per layer of corner-points. Four for each cell
const int entries_per_layer = dimensions[0]*dimensions[1]*4;
std::vector<double>::iterator it_new = zcorn_mirrored.begin();
std::vector<double>::iterator it_orig = zcorn.begin();
// Loop through each layer and copy old corner-points and add new (which are the old reordered)
for ( ; it_orig != zcorn.end(); it_orig += entries_per_layer) {
// Copy old corner-points
copy(it_orig, it_orig + entries_per_layer, it_new);
it_new += entries_per_layer;
// Add new corner-points
std::vector<double> next_vec(it_orig, it_orig + entries_per_layer);
std::vector<double> next_reordered(entries_per_layer, 0.0);
std::vector<double>::iterator it_next = next_vec.end();
std::vector<double>::iterator it_reordered = next_reordered.begin();
// Reorder next entries
for ( ; it_reordered != next_reordered.end(); it_reordered += entries_per_line_x) {
copy(it_next - entries_per_line_x, it_next, it_reordered);
it_next -= entries_per_line_x;
}
copy(next_reordered.begin(), next_reordered.end(), it_new);
it_new += entries_per_layer;
}
}
else {
std::cerr << "Direction should be either x or y" << std::endl;
exit(1);
}
// Write new ZCORN values to output file
printKeywordValues(out, "ZCORN", zcorn_mirrored, 8);
}
std::vector<int> getKeywordValues(std::string keyword, Opm::DeckConstPtr deck, int /*dummy*/) {
return deck->getKeyword(keyword)->getIntData();
}
std::vector<double> getKeywordValues(std::string keyword, Opm::DeckConstPtr deck, double /*dummy*/) {
return deck->getKeyword(keyword)->getRawDoubleData();
}
std::vector<double> getMapaxesValues(Opm::DeckConstPtr deck)
{
Opm::DeckRecordConstPtr mapaxesRecord = deck->getKeyword("MAPAXES")->getRecord(0);
std::vector<double> result;
for (size_t itemIdx = 0; itemIdx < mapaxesRecord->size(); ++itemIdx) {
Opm::DeckItemConstPtr curItem = mapaxesRecord->getItem(itemIdx);
for (size_t dataItemIdx = 0; dataItemIdx < curItem->size(); ++dataItemIdx) {
result.push_back(curItem->getRawDouble(dataItemIdx));
}
}
return result;
}
/// Mirror keywords that have one value for each cell
template <class T>
void mirror_celldata(std::string keyword, Opm::DeckConstPtr deck, std::string direction, std::ofstream& out) {
if ( ! deck->hasKeyword(keyword)) {
std::cout << "Ignoring keyword " << keyword << " as it was not found." << std::endl;
return;
}
// Get data from eclipse deck
Opm::DeckRecordConstPtr specgridRecord = deck->getKeyword("SPECGRID")->getRecord(0);
std::vector<int> dimensions(3);
dimensions[0] = specgridRecord->getItem("NX")->getInt(0);
dimensions[1] = specgridRecord->getItem("NY")->getInt(0);
dimensions[2] = specgridRecord->getItem("NZ")->getInt(0);
std::vector<T> values = getKeywordValues(keyword, deck, T(0.0));
std::vector<T> values_mirrored(2*dimensions[0]*dimensions[1]*dimensions[2], 0.0);
// Handle the two directions differently due to ordering of the pillars.
if (direction == "x") {
typename std::vector<T>::iterator it_orig = values.begin();
typename std::vector<T>::iterator it_new = values_mirrored.begin();
// Loop through each line and copy old cell data and add new (which are the old reversed)
for ( ; it_orig != values.end(); it_orig += dimensions[0]) {
// Copy old cell data
copy(it_orig, it_orig + dimensions[0], it_new);
it_new += dimensions[0];
// Add new cell data
std::vector<double> next_vec(it_orig, it_orig + dimensions[0]);
std::vector<double> next_reversed = next_vec;
reverse(next_reversed.begin(), next_reversed.end());
copy(next_reversed.begin(), next_reversed.end(), it_new);
it_new += dimensions[0];
}
}
else if (direction =="y") {
typename std::vector<T>::iterator it_orig = values.begin();
typename std::vector<T>::iterator it_new = values_mirrored.begin();
// Entries per layer
const int entries_per_layer = dimensions[0]*dimensions[1];
// Loop through each layer and copy old cell data and add new (which are the old reordered)
for ( ; it_orig != values.end(); it_orig += entries_per_layer) {
// Copy old cell data
copy(it_orig, it_orig + entries_per_layer, it_new);
it_new += entries_per_layer;
// Add new cell data
std::vector<T> next_vec(it_orig, it_orig + entries_per_layer);
std::vector<T> next_reordered(entries_per_layer, 0.0);
typename std::vector<T>::iterator it_next = next_vec.end();
typename std::vector<T>::iterator it_reordered = next_reordered.begin();
// Reorder next entries
for ( ; it_reordered != next_reordered.end(); it_reordered += dimensions[0]) {
copy(it_next - dimensions[0], it_next, it_reordered);
it_next -= dimensions[0];
}
copy(next_reordered.begin(), next_reordered.end(), it_new);
it_new += entries_per_layer;
}
}
else {
std::cerr << "Direction should be either x or y" << std::endl;
exit(1);
}
// Write new keyword values to output file
printKeywordValues(out, keyword, values_mirrored, 8);
}
int main(int argc, char** argv)
{
// Set output precision
int decimals = 16;
// Process input parameters
if (argc != 3) {
std::cout << "Usage: mirror_grid filename.grdecl direction" << std::endl;
std::cout << "(replace direction with either x or y)" << std::endl;
exit(1);
}
const char* eclipsefilename = argv[1];
std::string direction(argv[2]);
if ( ! ((direction == "x") || (direction == "y")) ) {
std::cerr << "Unrecognized input parameter for direction: '" << direction
<< "'. Should be either x or y (maybe also z later)." << std::endl;
exit(1);
}
// Parse grdecl file
std::cout << "Parsing grid file '" << eclipsefilename << "' ..." << std::endl;
Opm::ParserPtr parser(new Opm::Parser);
Opm::ParseMode parseMode;
Opm::DeckConstPtr deck(parser->parseFile(eclipsefilename , parseMode));
if ( ! (deck->hasKeyword("SPECGRID") && deck->hasKeyword("COORD") && deck->hasKeyword("ZCORN")) ) {
std::cerr << "Grid file " << eclipsefilename << "are missing keywords SPECGRID, COORD or ZCORN!" << std::endl;
exit(1);
}
// Create new grid file
std::string mirrored_eclipsefilename = std::string(eclipsefilename);
std::string::size_type last_dot = mirrored_eclipsefilename.find_last_of('.');
mirrored_eclipsefilename = mirrored_eclipsefilename.substr(0, last_dot) + "_mirrored-" + direction + ".grdecl";
std::ofstream outfile;
outfile.open(mirrored_eclipsefilename.c_str(), std::ios::out | std::ios::trunc);
if (!outfile) {
std::cerr << "Can't open output file " << mirrored_eclipsefilename << std::endl;
exit(1);
}
outfile.precision(decimals);
outfile.setf(std::ios::fixed);
// Print init message
printInitMessage(outfile, eclipsefilename, direction);
// Mirror keywords
mirror_mapaxes(deck, direction, outfile);
mirror_specgrid(deck, direction, outfile);
mirror_coord(deck, direction, outfile);
mirror_zcorn(deck, direction, outfile);
mirror_celldata<int>("ACTNUM", deck, direction, outfile);
mirror_celldata<double>("PERMX", deck, direction, outfile);
mirror_celldata<double>("PERMY", deck, direction, outfile);
mirror_celldata<double>("PERMZ", deck, direction, outfile);
mirror_celldata<double>("PORO", deck, direction, outfile);
mirror_celldata<int>("SATNUM", deck, direction, outfile);
mirror_celldata<double>("NTG", deck, direction, outfile);
mirror_celldata<double>("SWCR", deck, direction, outfile);
mirror_celldata<double>("SOWCR", deck, direction, outfile);
}

View File

@ -1,287 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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/>.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <opm/core/pressure/FlowBCManager.hpp>
#include <opm/core/grid.h>
#include <opm/core/grid/GridManager.hpp>
#include <opm/core/wells.h>
#include <opm/core/wells/WellsManager.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/simulator/initState.hpp>
#include <opm/core/simulator/SimulatorReport.hpp>
#include <opm/core/simulator/SimulatorTimer.hpp>
#include <opm/core/utility/miscUtilities.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/props/BlackoilPropertiesBasic.hpp>
#include <opm/core/props/BlackoilPropertiesFromDeck.hpp>
#include <opm/core/props/rock/RockCompressibility.hpp>
#include <opm/core/linalg/LinearSolverFactory.hpp>
#include <opm/core/simulator/BlackoilState.hpp>
#include <opm/core/simulator/WellState.hpp>
#include <opm/core/simulator/SimulatorCompressibleTwophase.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Parser/ParseMode.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <memory>
#include <boost/filesystem.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
namespace
{
void warnIfUnusedParams(const Opm::parameter::ParameterGroup& param)
{
if (param.anyUnused()) {
std::cout << "-------------------- Unused parameters: --------------------\n";
param.displayUsage();
std::cout << "----------------------------------------------------------------" << std::endl;
}
}
} // anon namespace
// ----------------- Main program -----------------
int
main(int argc, char** argv)
try
{
using namespace Opm;
std::cout << "\n================ Test program for weakly compressible two-phase flow ===============\n\n";
parameter::ParameterGroup param(argc, argv, false);
std::cout << "--------------- Reading parameters ---------------" << std::endl;
// If we have a "deck_filename", grid and props will be read from that.
bool use_deck = param.has("deck_filename");
EclipseStateConstPtr eclipseState;
std::unique_ptr<GridManager> grid;
std::unique_ptr<BlackoilPropertiesInterface> props;
std::unique_ptr<RockCompressibility> rock_comp;
ParserPtr parser(new Opm::Parser());
Opm::DeckConstPtr deck;
BlackoilState state;
// bool check_well_controls = false;
// int max_well_control_iterations = 0;
double gravity[3] = { 0.0 };
if (use_deck) {
ParseMode parseMode;
std::string deck_filename = param.get<std::string>("deck_filename");
deck = parser->parseFile(deck_filename , parseMode);
eclipseState.reset(new EclipseState(deck, parseMode));
// Grid init
grid.reset(new GridManager(deck));
// Rock and fluid init
props.reset(new BlackoilPropertiesFromDeck(deck, eclipseState, *grid->c_grid(), param));
// check_well_controls = param.getDefault("check_well_controls", false);
// max_well_control_iterations = param.getDefault("max_well_control_iterations", 10);
// Rock compressibility.
rock_comp.reset(new RockCompressibility(deck, eclipseState));
// Gravity.
gravity[2] = deck->hasKeyword("NOGRAV") ? 0.0 : unit::gravity;
// Init state variables (saturation and pressure).
if (param.has("init_saturation")) {
initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
} else {
initStateFromDeck(*grid->c_grid(), *props, deck, gravity[2], state);
}
initBlackoilSurfvol(*grid->c_grid(), *props, state);
} else {
// Grid init.
const int nx = param.getDefault("nx", 100);
const int ny = param.getDefault("ny", 100);
const int nz = param.getDefault("nz", 1);
const double dx = param.getDefault("dx", 1.0);
const double dy = param.getDefault("dy", 1.0);
const double dz = param.getDefault("dz", 1.0);
grid.reset(new GridManager(nx, ny, nz, dx, dy, dz));
// Rock and fluid init.
props.reset(new BlackoilPropertiesBasic(param, grid->c_grid()->dimensions, grid->c_grid()->number_of_cells));
// Rock compressibility.
rock_comp.reset(new RockCompressibility(param));
// Gravity.
gravity[2] = param.getDefault("gravity", 0.0);
// Init state variables (saturation and pressure).
initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
initBlackoilSurfvol(*grid->c_grid(), *props, state);
}
bool use_gravity = (gravity[0] != 0.0 || gravity[1] != 0.0 || gravity[2] != 0.0);
const double *grav = use_gravity ? &gravity[0] : 0;
// Initialising src
int num_cells = grid->c_grid()->number_of_cells;
std::vector<double> src(num_cells, 0.0);
if (use_deck) {
// Do nothing, wells will be the driving force, not source terms.
} else {
// Compute pore volumes, in order to enable specifying injection rate
// terms of total pore volume.
std::vector<double> porevol;
if (rock_comp->isActive()) {
computePorevolume(*grid->c_grid(), props->porosity(), *rock_comp, state.pressure(), porevol);
} else {
computePorevolume(*grid->c_grid(), props->porosity(), porevol);
}
const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
const double default_injection = use_gravity ? 0.0 : 0.1;
const double flow_per_sec = param.getDefault<double>("injected_porevolumes_per_day", default_injection)
*tot_porevol_init/unit::day;
src[0] = flow_per_sec;
src[num_cells - 1] = -flow_per_sec;
}
// Boundary conditions.
FlowBCManager bcs;
if (param.getDefault("use_pside", false)) {
int pside = param.get<int>("pside");
double pside_pressure = param.get<double>("pside_pressure");
bcs.pressureSide(*grid->c_grid(), FlowBCManager::Side(pside), pside_pressure);
}
// Linear solver.
LinearSolverFactory linsolver(param);
// Write parameters used for later reference.
bool output = param.getDefault("output", true);
std::ofstream epoch_os;
std::string output_dir;
if (output) {
output_dir =
param.getDefault("output_dir", std::string("output"));
boost::filesystem::path fpath(output_dir);
try {
create_directories(fpath);
}
catch (...) {
OPM_THROW(std::runtime_error, "Creating directories failed: " << fpath);
}
std::string filename = output_dir + "/epoch_timing.param";
epoch_os.open(filename.c_str(), std::fstream::trunc | std::fstream::out);
// open file to clean it. The file is appended to in SimulatorTwophase
filename = output_dir + "/step_timing.param";
std::fstream step_os(filename.c_str(), std::fstream::trunc | std::fstream::out);
step_os.close();
param.writeParam(output_dir + "/simulation.param");
}
std::cout << "\n\n================ Starting main simulation loop ===============\n";
SimulatorReport rep;
if (!use_deck) {
// Simple simulation without a deck.
WellsManager wells; // no wells.
SimulatorCompressibleTwophase simulator(param,
*grid->c_grid(),
*props,
rock_comp->isActive() ? rock_comp.get() : 0,
wells,
src,
bcs.c_bcs(),
linsolver,
grav);
SimulatorTimer simtimer;
simtimer.init(param);
warnIfUnusedParams(param);
WellState well_state;
well_state.init(0, state);
rep = simulator.run(simtimer, state, well_state);
} else {
// With a deck, we may have more epochs etc.
WellState well_state;
int step = 0;
SimulatorTimer simtimer;
// Use timer for last epoch to obtain total time.
Opm::TimeMapPtr timeMap(new Opm::TimeMap(deck));
simtimer.init(timeMap);
const double total_time = simtimer.totalTime();
for (size_t reportStepIdx = 0; reportStepIdx < timeMap->numTimesteps(); ++reportStepIdx) {
simtimer.setCurrentStepNum(step);
simtimer.setTotalTime(total_time);
// Report on start of report step.
std::cout << "\n\n-------------- Starting report step " << reportStepIdx << " --------------"
<< "\n (number of steps: "
<< simtimer.numSteps() - step << ")\n\n" << std::flush;
// Create new wells, well_state
WellsManager wells(eclipseState , reportStepIdx , *grid->c_grid(), props->permeability());
// @@@ HACK: we should really make a new well state and
// properly transfer old well state to it every report step,
// since number of wells may change etc.
if (reportStepIdx == 0) {
well_state.init(wells.c_wells(), state);
}
// Create and run simulator.
SimulatorCompressibleTwophase simulator(param,
*grid->c_grid(),
*props,
rock_comp->isActive() ? rock_comp.get() : 0,
wells,
src,
bcs.c_bcs(),
linsolver,
grav);
if (reportStepIdx == 0) {
warnIfUnusedParams(param);
}
SimulatorReport epoch_rep = simulator.run(simtimer, state, well_state);
if (output) {
epoch_rep.reportParam(epoch_os);
}
// Update total timing report and remember step number.
rep += epoch_rep;
step = simtimer.currentStepNum();
}
}
std::cout << "\n\n================ End of simulation ===============\n\n";
rep.report(std::cout);
if (output) {
std::string filename = output_dir + "/walltime.param";
std::fstream tot_os(filename.c_str(),std::fstream::trunc | std::fstream::out);
rep.reportParam(tot_os);
}
}
catch (const std::exception &e) {
std::cerr << "Program threw an exception: " << e.what() << "\n";
throw;
}

View File

@ -1,309 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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/>.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <opm/core/pressure/FlowBCManager.hpp>
#include <opm/core/grid.h>
#include <opm/core/grid/GridManager.hpp>
#include <opm/core/wells.h>
#include <opm/core/wells/WellsManager.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/simulator/initState.hpp>
#include <opm/core/simulator/SimulatorReport.hpp>
#include <opm/core/simulator/SimulatorTimer.hpp>
#include <opm/core/utility/miscUtilities.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/props/IncompPropertiesBasic.hpp>
#include <opm/core/props/IncompPropertiesFromDeck.hpp>
#include <opm/core/props/rock/RockCompressibility.hpp>
#include <opm/core/linalg/LinearSolverFactory.hpp>
#include <opm/core/simulator/TwophaseState.hpp>
#include <opm/core/simulator/WellState.hpp>
#include <opm/core/simulator/SimulatorIncompTwophase.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <memory>
#include <boost/filesystem.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
namespace
{
void warnIfUnusedParams(const Opm::parameter::ParameterGroup& param)
{
if (param.anyUnused()) {
std::cout << "-------------------- Unused parameters: --------------------\n";
param.displayUsage();
std::cout << "----------------------------------------------------------------" << std::endl;
}
}
} // anon namespace
// ----------------- Main program -----------------
int
main(int argc, char** argv)
try
{
using namespace Opm;
std::cout << "\n================ Test program for incompressible two-phase flow ===============\n\n";
parameter::ParameterGroup param(argc, argv, false);
std::cout << "--------------- Reading parameters ---------------" << std::endl;
#if ! HAVE_SUITESPARSE_UMFPACK_H
// This is an extra check to intercept a potentially invalid request for the
// implicit transport solver as early as possible for the user.
{
const bool use_reorder = param.getDefault("use_reorder", true);
if (!use_reorder) {
OPM_THROW(std::runtime_error, "Cannot use implicit transport solver without UMFPACK. "
"Either reconfigure opm-core with SuiteSparse/UMFPACK support and recompile, "
"or use the reordering solver (use_reorder=true).");
}
}
#endif
// If we have a "deck_filename", grid and props will be read from that.
bool use_deck = param.has("deck_filename");
EclipseStateConstPtr eclipseState;
Opm::DeckConstPtr deck;
std::unique_ptr<GridManager> grid;
std::unique_ptr<IncompPropertiesInterface> props;
std::unique_ptr<RockCompressibility> rock_comp;
TwophaseState state;
// bool check_well_controls = false;
// int max_well_control_iterations = 0;
double gravity[3] = { 0.0 };
if (use_deck) {
ParserPtr parser(new Opm::Parser());
ParseMode parseMode;
std::string deck_filename = param.get<std::string>("deck_filename");
deck = parser->parseFile(deck_filename , parseMode);
eclipseState.reset( new EclipseState(deck, parseMode));
// Grid init
grid.reset(new GridManager(deck));
// Rock and fluid init
props.reset(new IncompPropertiesFromDeck(deck, eclipseState, *grid->c_grid()));
// check_well_controls = param.getDefault("check_well_controls", false);
// max_well_control_iterations = param.getDefault("max_well_control_iterations", 10);
// Rock compressibility.
rock_comp.reset(new RockCompressibility(deck, eclipseState));
// Gravity.
gravity[2] = deck->hasKeyword("NOGRAV") ? 0.0 : unit::gravity;
// Init state variables (saturation and pressure).
if (param.has("init_saturation")) {
initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
} else {
initStateFromDeck(*grid->c_grid(), *props, deck, gravity[2], state);
}
} else {
// Grid init.
const int nx = param.getDefault("nx", 100);
const int ny = param.getDefault("ny", 100);
const int nz = param.getDefault("nz", 1);
const double dx = param.getDefault("dx", 1.0);
const double dy = param.getDefault("dy", 1.0);
const double dz = param.getDefault("dz", 1.0);
grid.reset(new GridManager(nx, ny, nz, dx, dy, dz));
// Rock and fluid init.
props.reset(new IncompPropertiesBasic(param, grid->c_grid()->dimensions, grid->c_grid()->number_of_cells));
// Rock compressibility.
rock_comp.reset(new RockCompressibility(param));
// Gravity.
gravity[2] = param.getDefault("gravity", 0.0);
// Init state variables (saturation and pressure).
initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
}
// Warn if gravity but no density difference.
bool use_gravity = (gravity[0] != 0.0 || gravity[1] != 0.0 || gravity[2] != 0.0);
if (use_gravity) {
if (props->density()[0] == props->density()[1]) {
std::cout << "**** Warning: nonzero gravity, but zero density difference." << std::endl;
}
}
const double *grav = use_gravity ? &gravity[0] : 0;
// Initialising src
int num_cells = grid->c_grid()->number_of_cells;
std::vector<double> src(num_cells, 0.0);
if (use_deck) {
// Do nothing, wells will be the driving force, not source terms.
} else {
// Compute pore volumes, in order to enable specifying injection rate
// terms of total pore volume.
std::vector<double> porevol;
if (rock_comp->isActive()) {
computePorevolume(*grid->c_grid(), props->porosity(), *rock_comp, state.pressure(), porevol);
} else {
computePorevolume(*grid->c_grid(), props->porosity(), porevol);
}
const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
const double default_injection = use_gravity ? 0.0 : 0.1;
const double flow_per_sec = param.getDefault<double>("injected_porevolumes_per_day", default_injection)
*tot_porevol_init/unit::day;
src[0] = flow_per_sec;
src[num_cells - 1] = -flow_per_sec;
}
// Boundary conditions.
FlowBCManager bcs;
if (param.getDefault("use_pside", false)) {
int pside = param.get<int>("pside");
double pside_pressure = param.get<double>("pside_pressure");
bcs.pressureSide(*grid->c_grid(), FlowBCManager::Side(pside), pside_pressure);
}
// Linear solver.
LinearSolverFactory linsolver(param);
// Write parameters used for later reference.
bool output = param.getDefault("output", true);
std::ofstream epoch_os;
std::string output_dir;
if (output) {
output_dir =
param.getDefault("output_dir", std::string("output"));
boost::filesystem::path fpath(output_dir);
try {
create_directories(fpath);
}
catch (...) {
OPM_THROW(std::runtime_error, "Creating directories failed: " << fpath);
}
std::string filename = output_dir + "/epoch_timing.param";
epoch_os.open(filename.c_str(), std::fstream::trunc | std::fstream::out);
// open file to clean it. The file is appended to in SimulatorTwophase
filename = output_dir + "/step_timing.param";
std::fstream step_os(filename.c_str(), std::fstream::trunc | std::fstream::out);
step_os.close();
param.writeParam(output_dir + "/simulation.param");
}
SimulatorReport rep;
if (!use_deck) {
std::cout << "\n\n================ Starting main simulation loop ===============\n"
<< " (number of report steps: 1)\n\n" << std::flush;
// Simple simulation without a deck.
WellsManager wells; // no wells.
SimulatorIncompTwophase simulator(param,
*grid->c_grid(),
*props,
rock_comp->isActive() ? rock_comp.get() : 0,
wells,
src,
bcs.c_bcs(),
linsolver,
grav);
SimulatorTimer simtimer;
simtimer.init(param);
warnIfUnusedParams(param);
WellState well_state;
well_state.init(0, state);
rep = simulator.run(simtimer, state, well_state);
} else {
// With a deck, we may have more epochs etc.
Opm::TimeMapConstPtr timeMap = eclipseState->getSchedule()->getTimeMap();
std::cout << "\n\n================ Starting main simulation loop ===============\n"
<< " (number of report steps: "
<< timeMap->numTimesteps() << ")\n\n" << std::flush;
WellState well_state;
int step = 0;
SimulatorTimer simtimer;
// Use timer for last epoch to obtain total time.
simtimer.init(timeMap);
const double total_time = simtimer.totalTime();
// for (size_t reportStepIdx = 0; reportStepIdx < timeMap->numTimesteps(); ++reportStepIdx) {
size_t reportStepIdx = 0; // Only handle a single, unchanging well setup.
{
// Update the timer.
simtimer.setCurrentStepNum(step);
simtimer.setTotalTime(total_time);
// Report on start of report step.
// std::cout << "\n\n-------------- Starting report step " << reportStepIdx << " --------------"
// << "\n (number of time steps: "
// << simtimer.numSteps() - step << ")\n\n" << std::flush;
// Create new wells, well_state
WellsManager wells(eclipseState , reportStepIdx , *grid->c_grid(), props->permeability());
// @@@ HACK: we should really make a new well state and
// properly transfer old well state to it every report step,
// since number of wells may change etc.
if (reportStepIdx == 0) {
well_state.init(wells.c_wells(), state);
}
// Create and run simulator.
SimulatorIncompTwophase simulator(param,
*grid->c_grid(),
*props,
rock_comp->isActive() ? rock_comp.get() : 0,
wells,
src,
bcs.c_bcs(),
linsolver,
grav);
if (reportStepIdx == 0) {
warnIfUnusedParams(param);
}
SimulatorReport epoch_rep = simulator.run(simtimer, state, well_state);
if (output) {
epoch_rep.reportParam(epoch_os);
}
// Update total timing report and remember step number.
rep += epoch_rep;
step = simtimer.currentStepNum();
}
}
std::cout << "\n\n================ End of simulation ===============\n\n";
rep.report(std::cout);
if (output) {
std::string filename = output_dir + "/walltime.param";
std::fstream tot_os(filename.c_str(),std::fstream::trunc | std::fstream::out);
rep.reportParam(tot_os);
}
}
catch (const std::exception &e) {
std::cerr << "Program threw an exception: " << e.what() << "\n";
throw;
}

View File

@ -1,144 +0,0 @@
#include "config.h"
#include <iostream>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/simulator/initState.hpp>
#include <opm/core/simulator/SimulatorTimer.hpp>
#include <opm/core/wells/WellsManager.hpp>
#include <opm/core/grid/GridManager.hpp>
#include <opm/core/pressure/IncompTpfa.hpp>
#include <opm/core/props/IncompPropertiesFromDeck.hpp>
#include <opm/core/wells.h>
#include <opm/core/grid.h>
#include <opm/core/utility/miscUtilities.hpp>
#include <opm/core/simulator/TwophaseState.hpp>
#include <opm/core/simulator/WellState.hpp>
#include <opm/core/pressure/FlowBCManager.hpp>
#include <opm/core/linalg/LinearSolverFactory.hpp>
#include <opm/core/props/rock/RockCompressibility.hpp>
#include <opm/parser/eclipse/Parser/ParseMode.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
int main(int argc, char** argv)
try
{
using namespace Opm::parameter;
using namespace Opm;
ParameterGroup parameters(argc, argv, false);
std::string file_name = parameters.getDefault<std::string > ("inputdeck", "data.data");
SimulatorTimer simtimer;
simtimer.init(parameters);
// Read input file
ParseMode parseMode;
Opm::ParserPtr parser(new Opm::Parser());
Opm::DeckConstPtr deck = parser->parseFile(file_name , parseMode);
Opm::EclipseStateConstPtr eclipseState(new Opm::EclipseState(deck , parseMode));
std::cout << "Done!" << std::endl;
// Setup grid
GridManager grid(deck);
// Define rock and fluid properties
IncompPropertiesFromDeck incomp_properties(deck, eclipseState, *grid.c_grid());
RockCompressibility rock_comp(deck, eclipseState);
// Finally handle the wells
WellsManager wells(eclipseState , 0 , *grid.c_grid(), incomp_properties.permeability());
double gravity[3] = {0.0, 0.0, parameters.getDefault<double>("gravity", 0.0)};
Opm::LinearSolverFactory linsolver(parameters);
double nl_pressure_residual_tolerance = 1e-8;
double nl_pressure_change_tolerance = 0.0;
int nl_pressure_maxiter = 100;
if (rock_comp.isActive()) {
nl_pressure_residual_tolerance = parameters.getDefault("nl_pressure_residual_tolerance", 1e-8);
nl_pressure_change_tolerance = parameters.getDefault("nl_pressure_change_tolerance", 1.0); // in Pascal
nl_pressure_maxiter = parameters.getDefault("nl_pressure_maxiter", 10);
}
std::vector<double> src;
Opm::FlowBCManager bcs;
// EXPERIMENT_ISTL
IncompTpfa pressure_solver(*grid.c_grid(), incomp_properties, &rock_comp, linsolver,
nl_pressure_residual_tolerance, nl_pressure_change_tolerance, nl_pressure_maxiter,
gravity, wells.c_wells(), src, bcs.c_bcs());
std::vector<int> all_cells;
for (int i = 0; i < grid.c_grid()->number_of_cells; i++) {
all_cells.push_back(i);
}
Opm::TwophaseState state;
initStateFromDeck(*grid.c_grid(), incomp_properties, deck, gravity[2], state);
Opm::WellState well_state;
well_state.init(wells.c_wells(), state);
pressure_solver.solve(simtimer.currentStepLength(), state, well_state);
const int np = incomp_properties.numPhases();
std::vector<double> fractional_flows(grid.c_grid()->number_of_cells*np, 0.0);
computeFractionalFlow(incomp_properties, all_cells, state.saturation(), fractional_flows);
// This will be refactored into a separate function once done
std::vector<double> well_resflows(wells.c_wells()->number_of_wells*np, 0.0);
computePhaseFlowRatesPerWell(*wells.c_wells(), well_state.perfRates(), fractional_flows, well_resflows);
// We approximate (for _testing_ that resflows = surfaceflows)
for (int wc_iter = 0; wc_iter < 10 && !wells.conditionsMet(well_state.bhp(), well_resflows, well_resflows); ++wc_iter) {
std::cout << "Conditions not met for well, trying again" << std::endl;
pressure_solver.solve(simtimer.currentStepLength(), state, well_state);
std::cout << "Solved" << std::endl;
computePhaseFlowRatesPerWell(*wells.c_wells(), well_state.perfRates(), fractional_flows, well_resflows);
}
#if 0
std::vector<double> porevol;
computePorevolume(*grid->c_grid(), incomp_properties, porevol);
TwophaseFluid fluid(incomp_properties);
TransportModel model(fluid, *grid->c_grid(), porevol, gravity[2], true);
TransportSolver tsolver(model);
TransportSource* tsrc = create_transport_source(2, 2);
double ssrc[] = {1.0, 0.0};
double ssink[] = {0.0, 1.0};
double zdummy[] = {0.0, 0.0};
{
int well_cell_index = 0;
for (int well = 0; well < wells.c_wells()->number_of_wells; ++well) {
for (int cell = wells.c_wells()->well_connpos[well]; cell < wells.c_wells()->well_connpos[well + 1]; ++cell) {
if (well_rate_per_cell[well_cell_index] > 0.0) {
append_transport_source(well_cell_index, 2, 0,
well_rate_per_cell[well_cell_index], ssrc, zdummy, tsrc);
} else if (well_rate_per_cell[well_cell_index] < 0.0) {
append_transport_source(well_cell_index, 2, 0,
well_rate_per_cell[well_cell_index], ssink, zdummy, tsrc);
}
}
}
}
tsolver.solve(*grid->c_grid(), tsrc, stepsize, ctrl, state, linsolve, rpt);
Opm::computeInjectedProduced(*props, state.saturation(), src, stepsize, injected, produced);
#endif
return 0;
}
catch (const std::exception &e) {
std::cerr << "Program threw an exception: " << e.what() << "\n";
throw;
}

14
jenkins/README.md Normal file
View File

@ -0,0 +1,14 @@
# opm-core jenkins build scripts:
**build.sh**:
This script will build dependencies, then build opm-core and execute its tests.
It also inspects the $ghbPrBuildComment environmental variable and builds
downstreams if requested. It inspects the $ghbPrBuildComment
environmental variable to obtain a pull request to use for the modules.
It is intended for pre-merge builds of pull requests.
To specify a given pull request to use for upstreams and downstreams,
trigger line needs to contain &lt;module-name&gt;=&lt;pull request number&gt;.
To build with downstreams the trigger line needs to contain 'with downstreams'.

57
jenkins/build.sh Executable file
View File

@ -0,0 +1,57 @@
#!/bin/bash
declare -a upstreams
upstreams=(opm-common
libecl
opm-parser
opm-material
opm-output
opm-grid)
declare -A upstreamRev
upstreamRev[opm-common]=master
upstreamRev[libecl]=master
upstreamRev[opm-parser]=master
upstreamRev[opm-material]=master
upstreamRev[opm-output]=master
upstreamRev[opm-grid]=master
if grep -q "opm-common=" <<< $ghprbCommentBody
then
upstreamRev[opm-common]=pull/`echo $ghprbCommentBody | sed -r 's/.*opm-common=([0-9]+).*/\1/g'`/merge
fi
# Downstream revisions
declare -a downstreams
downstreams=(ewoms
opm-simulators
opm-upscaling)
declare -A downstreamRev
downstreamRev[ewoms]=master
downstreamRev[opm-simulators]=master
downstreamRev[opm-upscaling]=master
# Clone opm-common
pushd .
mkdir -p $WORKSPACE/deps/opm-common
cd $WORKSPACE/deps/opm-common
git init .
git remote add origin https://github.com/OPM/opm-common
git fetch --depth 1 origin ${upstreamRev[opm-common]}:branch_to_build
test $? -eq 0 || exit 1
git checkout branch_to_build
popd
source $WORKSPACE/deps/opm-common/jenkins/build-opm-module.sh
parseRevisions
printHeader opm-core
# Setup opm-data
if grep -q "with downstreams" <<< $ghprbCommentBody
then
source $WORKSPACE/deps/opm-common/jenkins/setup-opm-data.sh
fi
build_module_full opm-core

49
opm-core-prereqs.cmake Normal file
View File

@ -0,0 +1,49 @@
# defines that must be present in config.h for our headers
set (opm-core_CONFIG_VAR
HAVE_ERT
HAVE_SUITESPARSE_UMFPACK_H
HAVE_DUNE_ISTL
HAVE_MPI
HAVE_PETSC
DUNE_ISTL_VERSION_MAJOR
DUNE_ISTL_VERSION_MINOR
DUNE_ISTL_VERSION_REVISION
)
# dependencies
set (opm-core_DEPS
# compile with C99 support if available
"C99"
# compile with C++0x/11 support if available
"CXX11Features REQUIRED"
# various runtime library enhancements
"Boost 1.44.0
COMPONENTS date_time filesystem system unit_test_framework REQUIRED"
# matrix library
"BLAS REQUIRED"
"LAPACK REQUIRED"
# Tim Davis' SuiteSparse archive
"SuiteSparse COMPONENTS umfpack"
# solver
"SuperLU"
# Eclipse I/O tools
"ecl REQUIRED"
# Look for MPI support
"MPI"
# PETSc numerical backend
"PETSc"
# DUNE dependency
"dune-common"
"dune-istl"
"opm-common REQUIRED"
# Parser library for ECL-type simulation models
"opm-parser REQUIRED"
# the code which implements the material laws
"opm-material REQUIRED"
# the code which implements the output routines
"opm-output REQUIRED"
# the code which implements grids
"opm-grid REQUIRED"
)
find_package_deps(opm-core)

View File

@ -48,7 +48,7 @@ creation and destruction of an UnstructuredGrid. The method
Opm::GridManager::c_grid() provides access to the underlying
UnstructuredGrid structure. This class also provides an easy way
to initialize a grid from an ECLIPSE-format input deck, via the
constructor taking an Opm::DeckConstPtr.
constructor taking an const Opm::Deck.
<h3>Well handling</h3>

View File

@ -17,6 +17,7 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <opm/core/flowdiagnostics/AnisotropicEikonal.hpp>
#include <opm/core/grid/GridUtilities.hpp>
#include <opm/core/grid.h>

View File

@ -40,7 +40,7 @@ namespace Opm
/// Construct solver.
TofDiscGalReorder::TofDiscGalReorder(const UnstructuredGrid& grid,
const parameter::ParameterGroup& param)
const ParameterGroup& param)
: grid_(grid),
use_cvi_(false),
use_limiter_(false),

View File

@ -32,9 +32,9 @@ namespace Opm
{
class IncompPropertiesInterface;
class ParameterGroup;
class VelocityInterpolationInterface;
class DGBasisInterface;
namespace parameter { class ParameterGroup; }
template <typename T> class SparseTable;
/// Implements a discontinuous Galerkin solver for
@ -72,7 +72,7 @@ namespace Opm
/// - AsSimultaneousPostProcess -- Apply to each cell independently, using un-
/// limited solution in neighbouring cells.
TofDiscGalReorder(const UnstructuredGrid& grid,
const parameter::ParameterGroup& param);
const ParameterGroup& param);
/// Solve for time-of-flight.

View File

@ -1,313 +0,0 @@
/*
Copyright 2010, 2011, 2012 SINTEF ICT, Applied Mathematics.
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_GRID_HEADER_INCLUDED
#define OPM_GRID_HEADER_INCLUDED
#include <stddef.h>
#include <stdbool.h>
/**
* \file
*
* Main OPM-Core grid data structure along with helper functions for
* construction, destruction and reading a grid representation from disk.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
---- synopsis of grid.h ----
struct UnstructuredGrid
{
int dimensions;
int number_of_cells;
int number_of_faces;
int number_of_nodes;
int *face_nodes;
int *face_nodepos;
int *face_cells;
int *cell_faces;
int *cell_facepos;
double *node_coordinates;
double *face_centroids;
double *face_areas;
double *face_normals;
double *cell_centroids;
double *cell_volumes;
int *global_cell;
int cartdims[3];
int *cell_facetag;
};
void destroy_grid(struct UnstructuredGrid *g);
struct UnstructuredGrid *
create_grid_empty(void);
struct UnstructuredGrid *
allocate_grid(size_t ndims ,
size_t ncells ,
size_t nfaces ,
size_t nfacenodes,
size_t ncellfaces,
size_t nnodes );
struct UnstructuredGrid *
read_grid(const char *fname);
---- end of synopsis of grid.h ----
*/
/**
Data structure for an unstructured grid, unstructured meaning that
any cell may have an arbitrary number of adjacent cells. The struct
contains both topological and geometrical data.
The grid consists of a set of cells, which are assumed to partion
the grid domain. A face is defined as the nonempty intersection of
(the closure of) two grid cells (the grid is a cell complex).
The topology information is limited to some adjacency relations
between cells, faces and nodes only. The data structure does not
contain any information pertaining to edges (except in 2d, where
edges are the same as faces).
The geometry information is limited to centroids, areas/volumes and
normals.
*/
struct UnstructuredGrid
{
/**
The topological and geometrical dimensionality of the
grid. Note that we do not support grids that are embedded in
higher-dimensional spaces, such as 2d grids embedded in 3d.
This number must be 2 or 3.
*/
int dimensions;
/** The number of cells in the grid. */
int number_of_cells;
/** The number of faces in the grid. */
int number_of_faces;
/** The number of nodes in the grid. */
int number_of_nodes;
/**
Contains for each face, the indices of its adjacent nodes.
The size of the array is equal to the sum over all faces of
each face's number of adjacent nodes, which also is equal to
face_nodepos[number_of_faces].
*/
int *face_nodes;
/**
For a face f, face_nodepos[f] contains the starting index
for f's nodes in the face_nodes array.
The size of the array is equal to (number_of_faces + 1).
*/
int *face_nodepos;
/**
For a face f, face_cells[2*f] and face_cells[2*f + 1] contain
the cell indices of the cells adjacent to f. The number -1
indicates the outer boundary.
The order is significant, as it gives the orientation: if
face_cells[2*f] == a and face_cells[2*f + 1] == b, f is
oriented from a to b. The inverse of this mapping is stored in
cell_faces and cell_facepos.
The size of the array is equal to (2*number_of_faces).
*/
int *face_cells;
/**
Contains for each cell, the indices of its adjacent faces.
The size of the array is equal to the sum over all cells of
each cell's number of adjacent faces, which also is equal to
cell_facepos[number_of_cells].
*/
int *cell_faces;
/**
For a cell c, cell_facepos[c] contains the starting index
for c's faces in the cell_faces array.
The size of the array is equal to (number_of_cells + 1).
*/
int *cell_facepos;
/**
Node coordinates, stored consecutively for each node. That is,
for a node i, node_coordinates[dimensions*i + d] contains the
d'th coordinate of node i.
The size of the array is equal to (dimensions*number_of_nodes).
*/
double *node_coordinates;
/**
Exact or approximate face centroids, stored consecutively for each face. That is,
for a face f, face_centroids[dimensions*f + d] contains the
d'th coordinate of f's centroid.
The size of the array is equal to (dimensions*number_of_faces).
*/
double *face_centroids;
/**
Exact or approximate face areas.
The size of the array is equal to number_of_faces.
*/
double *face_areas;
/**
Exact or approximate face normals, stored consecutively for
each face. That is, for a face f, face_normals[dimensions*f + d]
contains the d'th coordinate of f's normal.
The size of the array is equal to (dimensions*number_of_faces).
IMPORTANT: the normals are not normalized to have unit length!
They are assumed to always have length equal to the
corresponding face's area.
*/
double *face_normals;
/**
Exact or approximate cell centroids, stored consecutively for each cell. That is,
for a cell c, cell_centroids[dimensions*c + d] contains the
d'th coordinate of c's centroid.
The size of the array is equal to (dimensions*number_of_cells).
*/
double *cell_centroids;
/**
Exact or approximate cell volumes.
The size of the array is equal to number_of_cells.
*/
double *cell_volumes;
/**
If non-null, this array contains the logical cartesian indices
(in a lexicographic ordering) of each cell.
In that case, the array size is equal to number_of_cells.
This field is intended for grids that have a (possibly
degenerate) logical cartesian structure, for example
cornerpoint grids.
If null, this indicates that the element indices coincide
with the logical cartesian indices, _or_ that the grid has
no inherent Cartesian structure. Due to this ambiguity, this
field should not be used to check if the grid is Cartesian.
*/
int *global_cell;
/**
Contains the size of the logical cartesian structure (if any) of the grid.
This field is intended for grids that have a (possibly
degenerate) logical cartesian structure, for example
cornerpoint grids.
If the grid is unstructured (non-Cartesian), then at least one
of the items in the (sub-)array cartdims[0..dimensions-1]
_could_ have the value 0 to signal this.
*/
int cartdims[3];
/**
If non-null, this array contains a number for cell-face
adjacency indicating the face's position with respect to the
cell, in a logical cartesian sense. The tags are in [0, ..., 5]
meaning [I-, I+, J-, J+, K-, K+], where I, J, K are the logical
cartesian principal directions.
The structure of this array is identical to cell_faces, and
cell_facepos indices into cell_facetag as well.
If non-null, the array size is equal to
cell_facepos[number_of_cells].
This field is intended for grids that have a (possibly
degenerate) logical cartesian structure, for example
cornerpoint grids.
*/
int *cell_facetag;
};
/**
Destroy and deallocate an UnstructuredGrid and all its data.
This function assumes that all arrays of the UnstructuredGrid (if
non-null) have been individually allocated by malloc(). They will
be deallocated with free().
*/
void destroy_grid(struct UnstructuredGrid *g);
/**
Allocate and initialise an empty UnstructuredGrid.
This is the moral equivalent of a C++ default constructor.
\return Fully formed UnstructuredGrid with all fields zero or
<code>NULL</code> as appropriate. <code>NULL</code> in case of
allocation failure.
*/
struct UnstructuredGrid *
create_grid_empty(void);
/**
Allocate and initialise an UnstructuredGrid where pointers are set
to location with correct size.
\param[in] ndims Number of physical dimensions.
\param[in] ncells Number of cells.
\param[in] nfaces Number of faces.
\param[in] nfacenodes Size of mapping from faces to nodes.
\param[in] ncellfaces Size of mapping from cells to faces.
(i.e., the number of `half-faces')
\param[in] nnodes Number of Nodes.
\return Fully formed UnstructuredGrid with all fields except
<code>global_cell</code> allocated, but not filled with meaningful
values. <code>NULL</code> in case of allocation failure.
*/
struct UnstructuredGrid *
allocate_grid(size_t ndims ,
size_t ncells ,
size_t nfaces ,
size_t nfacenodes,
size_t ncellfaces,
size_t nnodes );
/**
* Import a grid from a character representation stored in file.
*
* @param[in] fname File name.
* @return Fully formed UnstructuredGrid with all fields allocated and filled.
* Returns @c NULL in case of allocation failure.
*/
struct UnstructuredGrid *
read_grid(const char *fname);
bool
grid_equal(const struct UnstructuredGrid * grid1 , const struct UnstructuredGrid * grid2);
#ifdef __cplusplus
}
#endif
#endif /* OPM_GRID_HEADER_INCLUDED */

View File

@ -1,260 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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_CELLQUADRATURE_HEADER_INCLUDED
#define OPM_CELLQUADRATURE_HEADER_INCLUDED
#include <opm/core/grid.h>
#include <opm/common/ErrorMacros.hpp>
#include <algorithm>
#include <cmath>
namespace Opm
{
namespace {
/// Calculates the determinant of a 3 x 3 matrix, represented as
/// three three-dimensional arrays.
inline double determinantOf(const double* a0,
const double* a1,
const double* a2)
{
return
a0[0] * (a1[1] * a2[2] - a2[1] * a1[2]) -
a0[1] * (a1[0] * a2[2] - a2[0] * a1[2]) +
a0[2] * (a1[0] * a2[1] - a2[0] * a1[1]);
}
/// Computes the volume of a tetrahedron consisting of 4 vertices
/// with 3-dimensional coordinates
inline double tetVolume(const double* p0,
const double* p1,
const double* p2,
const double* p3)
{
double a[3] = { p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] };
double b[3] = { p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2] };
double c[3] = { p3[0] - p0[0], p3[1] - p0[1], p3[2] - p0[2] };
return std::fabs(determinantOf(a, b, c) / 6.0);
}
/// Calculates the area of a triangle consisting of 3 vertices
/// with 2-dimensional coordinates
inline double triangleArea2d(const double* p0,
const double* p1,
const double* p2)
{
double a[2] = { p1[0] - p0[0], p1[1] - p0[1] };
double b[2] = { p2[0] - p0[0], p2[1] - p0[1] };
double a_cross_b = a[0]*b[1] - a[1]*b[0];
return 0.5*std::fabs(a_cross_b);
}
} // anonymous namespace
/// A class providing numerical quadrature for cells.
/// In general: \int_{cell} g(x) dx = \sum_{i=0}^{n-1} w_i g(x_i).
/// Note that this class does multiply weights by cell volume,
/// so weights always sum to cell volume.
///
/// Degree 1 method:
/// Midpoint (centroid) method.
/// n = 1, w_0 = cell volume, x_0 = cell centroid
///
/// Degree 2 method for 2d (but see the note):
/// Based on subdivision of the cell into triangles,
/// with the centroid as a common vertex, and the triangle
/// edge midpoint rule.
/// Triangle i consists of the centroid C, nodes N_i and N_{i+1}.
/// Its area is A_i.
/// n = 2 * nn (nn = num nodes in face)
/// For i = 0..(nn-1):
/// w_i = 1/3 A_i.
/// w_{nn+i} = 1/3 A_{i-1} + 1/3 A_i
/// x_i = (N_i + N_{i+1})/2
/// x_{nn+i} = (C + N_i)/2
/// All N and A indices are interpreted cyclic, modulus nn.
/// Note: for simplicity of implementation, we currently use
/// n = 3 * nn
/// For i = 0..(nn-1):
/// w_{3*i + {0,1,2}} = 1/3 A_i
/// x_{3*i} = (N_i + N_{i+1})/2
/// x_{3*i + {1,2}} = (C + N_{i,i+1})/2
/// This is simpler, because we can implement it easily
/// based on iteration over faces without requiring any
/// particular (cyclic) ordering.
///
/// Degree 2 method for 3d:
/// Based on subdivision of each cell face into triangles
/// with the face centroid as a common vertex, and then
/// subdividing the cell into tetrahedra with the cell
/// centroid as a common vertex. Then apply the tetrahedron
/// rule with the following 4 nodes (uniform weights):
/// a = 0.138196601125010515179541316563436
/// x_i has all barycentric coordinates = a, except for
/// the i'th coordinate which is = 1 - 3a.
/// This rule is from http://nines.cs.kuleuven.be/ecf,
/// it is the second degree 2 4-point rule for tets,
/// referenced to Stroud(1971).
/// The tetrahedra are numbered T_{i,j}, and are given by the
/// cell centroid C, the face centroid FC_i, and two nodes
/// of face i: FN_{i,j}, FN_{i,j+1}.
class CellQuadrature
{
public:
CellQuadrature(const UnstructuredGrid& grid,
const int cell,
const int degree)
: grid_(grid), cell_(cell), degree_(degree)
{
if (grid.dimensions > 3) {
OPM_THROW(std::runtime_error, "CellQuadrature only implemented for up to 3 dimensions.");
}
if (degree > 2) {
OPM_THROW(std::runtime_error, "CellQuadrature exact for polynomial degrees > 1 not implemented.");
}
}
int numQuadPts() const
{
if (degree_ < 2 || grid_.dimensions == 1) {
return 1;
}
// Degree 2 case.
if (grid_.dimensions == 2) {
return 3*(grid_.cell_facepos[cell_ + 1] - grid_.cell_facepos[cell_]);
}
assert(grid_.dimensions == 3);
int sumnodes = 0;
for (int hf = grid_.cell_facepos[cell_]; hf < grid_.cell_facepos[cell_ + 1]; ++hf) {
const int face = grid_.cell_faces[hf];
sumnodes += grid_.face_nodepos[face + 1] - grid_.face_nodepos[face];
}
return 4*sumnodes;
}
void quadPtCoord(const int index, double* coord) const
{
const int dim = grid_.dimensions;
const double* cc = grid_.cell_centroids + dim*cell_;
if (degree_ < 2) {
std::copy(cc, cc + dim, coord);
return;
}
// Degree 2 case.
if (dim == 2) {
if (index % 3 == 0) {
// Boundary midpoint. This is the face centroid.
const int hface = grid_.cell_facepos[cell_] + index/3;
const int face = grid_.cell_faces[hface];
const double* fc = grid_.face_centroids + dim*face;
std::copy(fc, fc + dim, coord);
} else {
// Interiour midpoint. This is the average of the
// cell centroid and a face node (they should
// always have two nodes in 2d).
const int hface = grid_.cell_facepos[cell_] + index/3;
const int face = grid_.cell_faces[hface];
const int nodeoff = (index % 3) - 1; // == 0 or 1
const int node = grid_.face_nodes[grid_.face_nodepos[face] + nodeoff];
const double* nc = grid_.node_coordinates + dim*node;
for (int dd = 0; dd < dim; ++dd) {
coord[dd] = 0.5*(nc[dd] + cc[dd]);
}
}
return;
}
assert(dim == 3);
int tetindex = index / 4;
const int subindex = index % 4;
const double* nc = grid_.node_coordinates;
for (int hf = grid_.cell_facepos[cell_]; hf < grid_.cell_facepos[cell_ + 1]; ++hf) {
const int face = grid_.cell_faces[hf];
const int nfn = grid_.face_nodepos[face + 1] - grid_.face_nodepos[face];
if (nfn <= tetindex) {
// Our tet is not associated with this face.
tetindex -= nfn;
continue;
}
const double* fc = grid_.face_centroids + dim*face;
const int* fnodes = grid_.face_nodes + grid_.face_nodepos[face];
const int node0 = fnodes[tetindex];
const int node1 = fnodes[(tetindex + 1) % nfn];
const double* n0c = nc + dim*node0;
const double* n1c = nc + dim*node1;
const double a = 0.138196601125010515179541316563436;
// Barycentric coordinates of our point in the tet.
double baryc[4] = { a, a, a, a };
baryc[subindex] = 1.0 - 3.0*a;
for (int dd = 0; dd < dim; ++dd) {
coord[dd] = baryc[0]*cc[dd] + baryc[1]*fc[dd] + baryc[2]*n0c[dd] + baryc[3]*n1c[dd];
}
return;
}
OPM_THROW(std::runtime_error, "Should never reach this point.");
}
double quadPtWeight(const int index) const
{
if (degree_ < 2) {
return grid_.cell_volumes[cell_];
}
// Degree 2 case.
const int dim = grid_.dimensions;
const double* cc = grid_.cell_centroids + dim*cell_;
if (dim == 2) {
const int hface = grid_.cell_facepos[cell_] + index/3;
const int face = grid_.cell_faces[hface];
const int* nptr = grid_.face_nodes + grid_.face_nodepos[face];
const double* nc0 = grid_.node_coordinates + dim*nptr[0];
const double* nc1 = grid_.node_coordinates + dim*nptr[1];
return triangleArea2d(nc0, nc1, cc)/3.0;
}
assert(dim == 3);
int tetindex = index / 4;
const double* nc = grid_.node_coordinates;
for (int hf = grid_.cell_facepos[cell_]; hf < grid_.cell_facepos[cell_ + 1]; ++hf) {
const int face = grid_.cell_faces[hf];
const int nfn = grid_.face_nodepos[face + 1] - grid_.face_nodepos[face];
if (nfn <= tetindex) {
// Our tet is not associated with this face.
tetindex -= nfn;
continue;
}
const double* fc = grid_.face_centroids + dim*face;
const int* fnodes = grid_.face_nodes + grid_.face_nodepos[face];
const int node0 = fnodes[tetindex];
const int node1 = fnodes[(tetindex + 1) % nfn];
const double* n0c = nc + dim*node0;
const double* n1c = nc + dim*node1;
return 0.25*tetVolume(cc, fc, n0c, n1c);
}
OPM_THROW(std::runtime_error, "Should never reach this point.");
}
private:
const UnstructuredGrid& grid_;
const int cell_;
const int degree_;
};
} // namespace Opm
#endif // OPM_CELLQUADRATURE_HEADER_INCLUDED

View File

@ -1,122 +0,0 @@
#include <opm/core/grid.h>
#include <vector>
#include <map>
#include <algorithm>
namespace Opm {
namespace {
/// Helper struct for extractColumn
/// Compares the underlying k-index
struct ExtractColumnCompare
{
ExtractColumnCompare(const UnstructuredGrid& g)
: grid(g)
{
// empty
}
bool operator()(const int i, const int j)
{
// Extract k-index
int index_i = grid.global_cell ? grid.global_cell[i] : i;
int k_i = index_i / grid.cartdims[0] / grid.cartdims[1];
int index_j = grid.global_cell ? grid.global_cell[j] : j;
int k_j = index_j / grid.cartdims[0] / grid.cartdims[1];
return k_i < k_j;
}
const UnstructuredGrid& grid;
};
/// Neighbourhood query.
/// \return true if two cells are neighbours.
bool neighbours(const UnstructuredGrid& grid, const int c0, const int c1)
{
for (int hf = grid.cell_facepos[c0]; hf < grid.cell_facepos[c0 + 1]; ++hf) {
const int f = grid.cell_faces[hf];
if (grid.face_cells[2*f] == c1 || grid.face_cells[2*f+1] == c1) {
return true;
}
}
return false;
}
} // anonymous namespace
/// Extract each column of the grid.
/// \note Assumes the pillars of the grid are all vertically aligned.
/// \param grid The grid from which to extract the columns.
/// \param columns will for each (i, j) where (i, j) represents a non-empty column,
//// contain the cell indices contained in the column
/// centered at (i, j) in the second variable, and i+jN in the first variable.
inline void extractColumn( const UnstructuredGrid& grid, std::vector<std::vector<int> >& columns )
{
const int* dims = grid.cartdims;
// Keeps track of column_index ---> index of vector
std::map<int, int> global_to_local;
for (int cell = 0; cell < grid.number_of_cells; ++cell) {
// Extract Cartesian coordinates
int index = grid.global_cell ? grid.global_cell[cell] : cell; // If null, assume mapping is identity.
int i_cart = index % dims[0];
int k_cart = index / dims[0] / dims[1];
int j_cart = (index - k_cart*dims[0]*dims[1])/ dims[0];
int local_index;
std::map<int, int>::iterator local_index_iterator = global_to_local.find(i_cart+j_cart*dims[0]);
if (local_index_iterator != global_to_local.end()) {
local_index = local_index_iterator->second;
} else {
local_index = columns.size();
global_to_local[i_cart+j_cart*dims[0]] = local_index;
columns.push_back(std::vector<int>());
}
columns[local_index].push_back(cell);
}
int num_cols = columns.size();
for (int col = 0; col < num_cols; ++col) {
std::sort(columns[col].begin(), columns[col].end(), ExtractColumnCompare(grid));
}
// At this point, a column may contain multiple disjoint sets of cells.
// We must split these columns into connected parts.
std::vector< std::vector<int> > new_columns;
for (int col = 0; col < num_cols; ++col) {
const int colsz = columns[col].size();
int first_of_col = 0;
for (int k = 1; k < colsz; ++k) {
const int c0 = columns[col][k-1];
const int c1 = columns[col][k];
if (!neighbours(grid, c0, c1)) {
// Must split. Move the cells [first_of_col, ... , k-1] to
// a new column, known to be connected.
new_columns.push_back(std::vector<int>());
new_columns.back().assign(columns[col].begin() + first_of_col, columns[col].begin() + k);
// The working column now starts with index k.
first_of_col = k;
}
}
if (first_of_col != 0) {
// The column was split, the working part should be
// the entire column. We erase the cells before first_of_col.
// (Could be more efficient if we instead chop off end.)
columns[col].erase(columns[col].begin(), columns[col].begin() + first_of_col);
}
}
// Must tack on the new columns to complete the set.
const int num_cols_all = num_cols + new_columns.size();
columns.resize(num_cols_all);
for (int col = num_cols; col < num_cols_all; ++col) {
columns[col].swap(new_columns[col - num_cols]);
}
}
} // namespace Opm

View File

@ -1,189 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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_FACEQUADRATURE_HEADER_INCLUDED
#define OPM_FACEQUADRATURE_HEADER_INCLUDED
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/grid.h>
#include <cmath>
namespace Opm
{
namespace {
/// Calculates the cross product of two 3-vectors, represented as
/// 3-element arrays. Calculates res = a X b. The res array must
/// already be allocated with room for 3 elements.
inline void cross(const double* a, const double* b, double* res)
{
res[0] = a[1]*b[2] - a[2]*b[1];
res[1] = a[2]*b[0] - a[0]*b[2];
res[2] = a[0]*b[1] - a[1]*b[0];
}
/// Calculates the area of a triangle consisting of 3 vertices
/// with 3-dimensional coordinates
inline double triangleArea3d(const double* p0,
const double* p1,
const double* p2)
{
double a[3] = { p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] };
double b[3] = { p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2] };
double cr[3];
cross(a, b, cr);
return 0.5*std::sqrt(cr[0]*cr[0] + cr[1]*cr[1] + cr[2]*cr[2]);
}
} // anonymous namespace
/// A class providing numerical quadrature for faces.
/// In general: \int_{face} g(x) dx = \sum_{i=0}^{n-1} w_i g(x_i).
/// Note that this class does multiply weights by face area,
/// so weights always sum to face area.
///
/// Degree 1 method:
/// Midpoint (centroid) method.
/// n = 1, w_0 = face area, x_0 = face centroid
///
/// Degree 2 method for 2d:
/// Simpson's method (actually this is degree 3).
///
/// Degree 2 method for 3d:
/// Based on subdivision of the face into triangles,
/// with the centroid as a common vertex, and the triangle
/// edge midpoint rule.
/// Triangle i consists of the centroid C, nodes N_i and N_{i+1}.
/// Its area is A_i.
/// n = 2 * nn (nn = num nodes in face)
/// For i = 0..(nn-1):
/// w_i = 1/3 A_i.
/// w_{nn+i} = 1/3 A_{i-1} + 1/3 A_i
/// x_i = (N_i + N_{i+1})/2
/// x_{nn+i} = (C + N_i)/2
/// All N and A indices are interpreted cyclic, modulus nn.
class FaceQuadrature
{
public:
FaceQuadrature(const UnstructuredGrid& grid,
const int face,
const int degree)
: grid_(grid), face_(face), degree_(degree)
{
if (grid_.dimensions > 3) {
OPM_THROW(std::runtime_error, "FaceQuadrature only implemented for up to 3 dimensions.");
}
if (degree_ > 2) {
OPM_THROW(std::runtime_error, "FaceQuadrature exact for polynomial degrees > 2 not implemented.");
}
}
int numQuadPts() const
{
if (degree_ < 2 || grid_.dimensions < 2) {
return 1;
}
// Degree 2 case.
if (grid_.dimensions == 2) {
return 3;
} else {
return 2 * (grid_.face_nodepos[face_ + 1] - grid_.face_nodepos[face_]);
}
}
void quadPtCoord(const int index, double* coord) const
{
const int dim = grid_.dimensions;
const double* fc = grid_.face_centroids + dim*face_;
if (degree_ < 2 || dim < 2) {
std::copy(fc, fc + dim, coord);
return;
}
// Degree 2 case.
const int nn = grid_.face_nodepos[face_ + 1] - grid_.face_nodepos[face_];
const int* fnodes = grid_.face_nodes + grid_.face_nodepos[face_];
const double* nc = grid_.node_coordinates;
if (dim == 2) {
assert(nn == 2);
const double* pa[3] = { nc + dim*fnodes[0], fc, nc + dim*fnodes[1] };
std::copy(pa[index], pa[index] + dim, coord);
return;
}
assert(dim == 3);
if (index < nn) {
// Boundary edge midpoint.
const int node0 = fnodes[index];
const int node1 = fnodes[(index + 1)%nn];
for (int dd = 0; dd < dim; ++dd) {
coord[dd] = 0.5*(nc[dim*node0 + dd] + nc[dim*node1 + dd]);
}
} else {
// Interiour edge midpoint.
// Recall that index is now in [nn, 2*nn).
const int node = fnodes[index - nn];
for (int dd = 0; dd < dim; ++dd) {
coord[dd] = 0.5*(nc[dim*node + dd] + fc[dd]);
}
}
}
double quadPtWeight(const int index) const
{
if (degree_ < 2) {
return grid_.face_areas[face_];
}
// Degree 2 case.
const int dim = grid_.dimensions;
if (dim == 2) {
const double simpsonw[3] = { 1.0/6.0, 4.0/6.0, 1.0/6.0 };
return grid_.face_areas[face_]*simpsonw[index];
}
assert(dim == 3);
const double* fc = grid_.face_centroids + dim*face_;
const int nn = grid_.face_nodepos[face_ + 1] - grid_.face_nodepos[face_];
const int* fnodes = grid_.face_nodes + grid_.face_nodepos[face_];
const double* nc = grid_.node_coordinates;
if (index < nn) {
// Boundary edge midpoint.
const int node0 = fnodes[index];
const int node1 = fnodes[(index + 1)%nn];
const double area = triangleArea3d(nc + dim*node1, nc + dim*node0, fc);
return area / 3.0;
} else {
// Interiour edge midpoint.
// Recall that index is now in [nn, 2*nn).
const int node0 = fnodes[(index - 1) % nn];
const int node1 = fnodes[index - nn];
const int node2 = fnodes[(index + 1) % nn];
const double area0 = triangleArea3d(nc + dim*node1, nc + dim*node0, fc);
const double area1 = triangleArea3d(nc + dim*node2, nc + dim*node1, fc);
return (area0 + area1) / 3.0;
}
}
private:
const UnstructuredGrid& grid_;
const int face_;
const int degree_;
};
} // namespace Opm
#endif // OPM_FACEQUADRATURE_HEADER_INCLUDED

View File

@ -1,153 +0,0 @@
/*
Copyright 2014, 2015 Dr. Markus Blatt - HPC-Simulation-Software & Services.
Copyright 2014 Statoil AS
Copyright 2015 NTNU
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 "config.h"
#include <opm/core/grid/GridHelpers.hpp>
namespace Opm
{
namespace UgGridHelpers
{
int numCells(const UnstructuredGrid& grid)
{
return grid.number_of_cells;
}
int numFaces(const UnstructuredGrid& grid)
{
return grid.number_of_faces;
}
int dimensions(const UnstructuredGrid& grid)
{
return grid.dimensions;
}
int numCellFaces(const UnstructuredGrid& grid)
{
return grid.cell_facepos[grid.number_of_cells];
}
const int* globalCell(const UnstructuredGrid& grid)
{
return grid.global_cell;
}
const int* cartDims(const UnstructuredGrid& grid)
{
return grid.cartdims;
}
const double* beginCellCentroids(const UnstructuredGrid& grid)
{
return grid.cell_centroids;
}
double cellCenterDepth(const UnstructuredGrid& grid, int cell_index)
{
// This method is an alternative to the method cellCentroidCoordinate(...) below.
// The cell center depth is computed as a raw average of cell corner depths.
// For cornerpoint grids, this is likely to give slightly different depths that seem
// to agree with eclipse.
assert(grid.dimensions == 3);
const int nd = 3; // Assuming 3-dimensional grid ...
const int nv = 8; // Assuming 2*4 vertices ...
double zz = 0.0;
// Traverse the bottom and top cell-face
for (int i=grid.cell_facepos[cell_index+1]-2; i<grid.cell_facepos[cell_index+1]; ++i) {
// Traverse the vertices associated with each face
assert(grid.face_nodepos[grid.cell_faces[i]+1] - grid.face_nodepos[grid.cell_faces[i]] == nv/2);
for (int j=grid.face_nodepos[grid.cell_faces[i]]; j<grid.face_nodepos[grid.cell_faces[i]+1]; ++j) {
zz += (grid.node_coordinates+nd*(grid.face_nodes[j]))[nd-1];
}
}
return zz/nv;
}
double cellCentroidCoordinate(const UnstructuredGrid& grid, int cell_index,
int coordinate)
{
return grid.cell_centroids[grid.dimensions*cell_index+coordinate];
}
const double*
cellCentroid(const UnstructuredGrid& grid, int cell_index)
{
return grid.cell_centroids+(cell_index*grid.dimensions);
}
const double* beginCellVolumes(const UnstructuredGrid& grid)
{
return grid.cell_volumes;
}
const double* endCellVolumes(const UnstructuredGrid& grid)
{
return grid.cell_volumes+numCells(grid);
}
const double* beginFaceCentroids(const UnstructuredGrid& grid)
{
return grid.face_centroids;
}
const double* faceCentroid(const UnstructuredGrid& grid, int face_index)
{
return grid.face_centroids+face_index*grid.dimensions;
}
const double* faceNormal(const UnstructuredGrid& grid, int face_index)
{
return grid.face_normals+face_index*grid.dimensions;
}
double faceArea(const UnstructuredGrid& grid, int face_index)
{
return grid.face_areas[face_index];
}
int faceTag(const UnstructuredGrid& grid,
boost::iterator_range<const int*>::const_iterator face)
{
return grid.cell_facetag[face-cell2Faces(grid)[0].begin()];
}
SparseTableView cell2Faces(const UnstructuredGrid& grid)
{
return SparseTableView(grid.cell_faces, grid.cell_facepos, numCells(grid));
}
SparseTableView face2Vertices(const UnstructuredGrid& grid)
{
return SparseTableView(grid.face_nodes, grid.face_nodepos, numFaces(grid));
}
const double* vertexCoordinates(const UnstructuredGrid& grid, int index)
{
return grid.node_coordinates+dimensions(grid)*index;
}
double cellVolume(const UnstructuredGrid& grid, int cell_index)
{
return grid.cell_volumes[cell_index];
}
FaceCellTraits<UnstructuredGrid>::Type faceCells(const UnstructuredGrid& grid)
{
return FaceCellsProxy(grid);
}
}
}

View File

@ -1,355 +0,0 @@
/*
Copyright 2014, 2015 Dr. Markus Blatt - HPC-Simulation-Software & Services
Copyright 2014 Statoil AS
Copyright 2015
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_CORE_GRIDHELPERS_HEADER_INCLUDED
#define OPM_CORE_GRIDHELPERS_HEADER_INCLUDED
#include <opm/core/grid.h>
#include <boost/range/iterator_range.hpp>
namespace Opm
{
namespace UgGridHelpers
{
/// \brief Allows viewing a sparse table consisting out of C-array
///
/// This class can be used to convert two int array (like they are
/// in UnstructuredGrid for representing the cell to faces mapping
/// as a sparse table object.
class SparseTableView
{
public:
class IntRange : public boost::iterator_range<const int*>
{
public:
typedef boost::iterator_range<const int*> BaseRowType;
typedef BaseRowType::size_type size_type;
typedef int value_type;
IntRange(const int* start_arg, const int* end_arg)
: BaseRowType(start_arg, end_arg)
{}
};
/// \brief The type of the roww.
typedef boost::iterator_range<const int*> row_type;
/// \brief Creates a sparse table view
/// \param data The array with data of the table.
/// \param offset The offsets of the rows. Row i starts
/// at offset[i] and ends a offset[i+1]
/// \param size The number of entries/rows of the table
SparseTableView(int* data, int *offset, std::size_t size_arg)
: data_(data), offset_(offset), size_(size_arg)
{}
/// \brief Get a row of the the table.
/// \param row The row index.
/// \return The corresponding row.
row_type operator[](std::size_t row) const
{
assert(row<=size());
return row_type(data_ + offset_[row], data_ + offset_[row+1]);
}
/// \brief Get the size of the table.
/// \return the number rows.
std::size_t size() const
{
return size_;
}
/// \brief Get the number of non-zero entries.
std::size_t noEntries() const
{
return offset_[size_];
}
private:
/// \brief The array with data of the table.
const int* data_;
/// \brief offset The offsets of the rows.
///
/// Row i starts at offset[i] and ends a offset[i+1]
const int* offset_;
/// \brief The size, i.e. the number of rows.
std::size_t size_;
};
/// \brief Get the number of cells of a grid.
int numCells(const UnstructuredGrid& grid);
/// \brief Get the number of faces of a grid.
int numFaces(const UnstructuredGrid& grid);
/// \brief Get the dimensions of a grid
int dimensions(const UnstructuredGrid& grid);
/// \brief Get the number of faces, where each face counts as many times as there are adjacent faces
int numCellFaces(const UnstructuredGrid& grid);
/// \brief Get the cartesion dimension of the underlying structured grid.
const int* cartDims(const UnstructuredGrid& grid);
/// \brief Get the local to global index mapping.
///
/// The global index is the index of the active cell
/// in the underlying structured grid.
const int* globalCell(const UnstructuredGrid& grid);
/// \brief Traits of the cell centroids of a grid.
///
/// This class exports two types: IteratorType, the type of the iterator
/// over the cell centroids, and the ValueTpe, the type of the cell centroid.
/// \tpatam G The type of the grid.
template<class G>
struct CellCentroidTraits
{
};
template<>
struct CellCentroidTraits<UnstructuredGrid>
{
typedef const double* IteratorType;
typedef const double* ValueType;
};
/// \brief Get an iterator over the cell centroids positioned at the first cell.
///
/// The return type needs to be usable with the functions increment, and
/// getCoordinate.
CellCentroidTraits<UnstructuredGrid>::IteratorType
beginCellCentroids(const UnstructuredGrid& grid);
/// \brief Get vertical position of cell center ("zcorn" average.)
/// \brief grid The grid.
/// \brief cell_index The index of the specific cell.
double cellCenterDepth(const UnstructuredGrid& grid, int cell_index);
/// \brief Get a coordinate of a specific cell centroid.
/// \brief grid The grid.
/// \brief cell_index The index of the specific cell.
/// \breif coordinate The coordinate index.
double cellCentroidCoordinate(const UnstructuredGrid& grid, int cell_index,
int coordinate);
/// \brief Get the centroid of a cell.
/// \param grid The grid whose cell centroid we query.
/// \param cell_index The index of the corresponding cell.
const double* cellCentroid(const UnstructuredGrid& grid, int cell_index);
/// \brief Get the volume of a cell.
/// \param grid The grid the cell belongs to.
/// \param cell_index The index of the cell.
double cellVolume(const UnstructuredGrid& grid, int cell_index);
/// \brief The mapping of the grid type to type of the iterator over
/// the cell volumes.
///
/// The value of the mapping is stored in nested type IteratorType
/// \tparam T The type of the grid.
template<class T>
struct CellVolumeIteratorTraits
{
};
template<>
struct CellVolumeIteratorTraits<UnstructuredGrid>
{
typedef const double* IteratorType;
};
/// \brief Get an iterator over the cell volumes of a grid positioned at the first cell.
const double* beginCellVolumes(const UnstructuredGrid& grid);
/// \brief Get an iterator over the cell volumes of a grid positioned after the last cell.
const double* endCellVolumes(const UnstructuredGrid& grid);
/// \brief Get the cell centroid of a face.
/// \param grid The grid whose cell centroid we query.
/// \param face_index The index of the corresponding face.
const double* faceCentroid(const UnstructuredGrid& grid, int face_index);
/// \brief Traits of the face centroids of a grid.
///
/// This class exports two types: IteratorType, the type of the iterator
/// over the face centroids, and the ValueTpe, the type of the face centroid.
/// \tpatam G The type of the grid.
template<class G>
struct FaceCentroidTraits
{
};
template<>
struct FaceCentroidTraits<UnstructuredGrid>
{
typedef const double* IteratorType;
typedef const double* ValueType;
};
/// \brief Get an iterator over the face centroids positioned at the first cell.
FaceCentroidTraits<UnstructuredGrid>::IteratorType
beginFaceCentroids(const UnstructuredGrid& grid);
/// \brief Get a coordinate of a specific face centroid.
/// \param grid The grid.
/// \param face_index The index of the specific face.
/// \param coordinate The coordinate index.
FaceCentroidTraits<UnstructuredGrid>::ValueType
faceCentroid(const UnstructuredGrid& grid, int face_index);
/// \brief Get the normal of a face.
/// \param grid The grid that the face is part of.
/// \param face_index The index of the face in the grid.
const double* faceNormal(const UnstructuredGrid& grid, int face_index);
/// \brief Get the area of a face
/// \param grid The grid that the face is part of.
/// \param face_index The index of the face in the grid.
double faceArea(const UnstructuredGrid& grid, int face_index);
/// \brief Get Eclipse Cartesian tag of a face
/// \param grid The grid that the face is part of.
/// \param cell_face The face attached to a cell as obtained from cell2Faces()
/// \return 0, 1, 2, 3, 4, 5 for I-, I+, J-, J+, K-, K+
int faceTag(const UnstructuredGrid& grid, boost::iterator_range<const int*>::const_iterator cell_face);
/// \brief Maps the grid type to the associated type of the cell to faces mapping.
///
/// Provides a type named Type.
/// \tparam T The type of the grid.
template<class T>
struct Cell2FacesTraits
{
};
template<>
struct Cell2FacesTraits<UnstructuredGrid>
{
typedef SparseTableView Type;
};
/// \brief Maps the grid type to the associated type of the face to vertices mapping.
///
/// Provides a type named Type.
/// \tparam T The type of the grid.
template<class T>
struct Face2VerticesTraits
{
};
template<>
struct Face2VerticesTraits<UnstructuredGrid>
{
typedef SparseTableView Type;
};
/// \brief Get the cell to faces mapping of a grid.
Cell2FacesTraits<UnstructuredGrid>::Type
cell2Faces(const UnstructuredGrid& grid);
/// \brief Get the face to vertices mapping of a grid.
Face2VerticesTraits<UnstructuredGrid>::Type
face2Vertices(const UnstructuredGrid& grid);
/// \brief Get the coordinates of a vertex of the grid.
/// \param grid The grid the vertex is part of.
/// \param index The index identifying the vertex.
const double* vertexCoordinates(const UnstructuredGrid& grid, int index);
class FaceCellsProxy
{
public:
FaceCellsProxy(const UnstructuredGrid& grid)
: face_cells_(grid.face_cells)
{}
int operator()(int face_index, int local_index) const
{
return face_cells_[2*face_index+local_index];
}
private:
const int* face_cells_;
};
/// \brief Traits of the face to attached cell mappping of a grid.
///
/// Exports the type Type, the type of the mapping
/// \tparam T The type of the grid
template<class T>
struct FaceCellTraits
{};
template<>
struct FaceCellTraits<UnstructuredGrid>
{
typedef FaceCellsProxy Type;
};
/// \brief Get the face to cell mapping of a grid.
FaceCellTraits<UnstructuredGrid>::Type faceCells(const UnstructuredGrid& grid);
/// \brief Increment an iterator over an array that reresents a dense row-major
/// matrix with dims columns
/// \param cc The iterator.
/// \param i The nzumber of rows to increment
/// \param dim The number of columns of the matrix.
template<class T>
T* increment(T* cc, int i, int dim)
{
return cc+(i*dim);
}
/// \brief Increment an iterator over an array that reresents a dense row-major
/// matrix with dims columns
/// \param cc The iterator.
/// \param i The nzumber of rows to increment
template<class T>
T increment(const T& t, int i, int)
{
return t+i;
}
/// \brief Get the i-th corrdinate of a centroid.
/// \param cc The array with the coordinates.
/// \param i The index of the coordinate.
/// \tparam T The type of the coordinate of the centroid.
template<class T>
double getCoordinate(T* cc, int i)
{
return cc[i];
}
/// \brief Get the i-th corrdinate of an array.
/// \param t The iterator over the centroids
/// \brief i The index of the coordinate.
/// \tparam T The type of the iterator representing the centroid.
/// Its value_type has to provide an operator[] to access the coordinates.
template<class T>
double getCoordinate(T t, int i)
{
return (*t)[i];
}
} // end namespace UGGridHelpers
} // end namespace OPM
#endif

View File

@ -1,232 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <opm/core/grid/GridManager.hpp>
#include <opm/core/grid.h>
#include <opm/core/grid/cart_grid.h>
#include <opm/core/grid/cornerpoint_grid.h>
#include <opm/core/grid/MinpvProcessor.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <array>
#include <algorithm>
#include <numeric>
namespace Opm
{
/// Construct a 3d corner-point grid from a deck.
GridManager::GridManager(Opm::EclipseGridConstPtr eclipseGrid)
: ug_(0)
{
initFromEclipseGrid(eclipseGrid, std::vector<double>());
}
GridManager::GridManager(Opm::DeckConstPtr deck)
: ug_(0)
{
auto eclipseGrid = std::make_shared<const Opm::EclipseGrid>(deck);
initFromEclipseGrid(eclipseGrid, std::vector<double>());
}
GridManager::GridManager(Opm::EclipseGridConstPtr eclipseGrid,
const std::vector<double>& poreVolumes)
: ug_(0)
{
initFromEclipseGrid(eclipseGrid, poreVolumes);
}
/// Construct a 2d cartesian grid with cells of unit size.
GridManager::GridManager(int nx, int ny)
{
ug_ = create_grid_cart2d(nx, ny, 1.0, 1.0);
if (!ug_) {
OPM_THROW(std::runtime_error, "Failed to construct grid.");
}
}
GridManager::GridManager(int nx, int ny,double dx, double dy)
{
ug_ = create_grid_cart2d(nx, ny, dx, dy);
if (!ug_) {
OPM_THROW(std::runtime_error, "Failed to construct grid.");
}
}
/// Construct a 3d cartesian grid with cells of unit size.
GridManager::GridManager(int nx, int ny, int nz)
{
ug_ = create_grid_cart3d(nx, ny, nz);
if (!ug_) {
OPM_THROW(std::runtime_error, "Failed to construct grid.");
}
}
/// Construct a 3d cartesian grid with cells of size [dx, dy, dz].
GridManager::GridManager(int nx, int ny, int nz,
double dx, double dy, double dz)
{
ug_ = create_grid_hexa3d(nx, ny, nz, dx, dy, dz);
if (!ug_) {
OPM_THROW(std::runtime_error, "Failed to construct grid.");
}
}
/// Construct a grid from an input file.
/// The file format used is currently undocumented,
/// and is therefore only suited for internal use.
GridManager::GridManager(const std::string& input_filename)
{
ug_ = read_grid(input_filename.c_str());
if (!ug_) {
OPM_THROW(std::runtime_error, "Failed to read grid from file " << input_filename);
}
}
/// Destructor.
GridManager::~GridManager()
{
destroy_grid(ug_);
}
/// Access the managed UnstructuredGrid.
/// The method is named similarly to c_str() in std::string,
/// to make it clear that we are returning a C-compatible struct.
const UnstructuredGrid* GridManager::c_grid() const
{
return ug_;
}
// Construct corner-point grid from EclipseGrid.
void GridManager::initFromEclipseGrid(Opm::EclipseGridConstPtr eclipseGrid,
const std::vector<double>& poreVolumes)
{
struct grdecl g;
std::vector<int> actnum;
std::vector<double> coord;
std::vector<double> zcorn;
std::vector<double> mapaxes;
g.dims[0] = eclipseGrid->getNX();
g.dims[1] = eclipseGrid->getNY();
g.dims[2] = eclipseGrid->getNZ();
eclipseGrid->exportMAPAXES( mapaxes );
eclipseGrid->exportCOORD( coord );
eclipseGrid->exportZCORN( zcorn );
eclipseGrid->exportACTNUM( actnum );
g.coord = coord.data();
g.zcorn = zcorn.data();
g.actnum = actnum.data();
g.mapaxes = mapaxes.data();
if (!poreVolumes.empty() && (eclipseGrid->getMinpvMode() != MinpvMode::ModeEnum::Inactive)) {
MinpvProcessor mp(g.dims[0], g.dims[1], g.dims[2]);
const double minpv_value = eclipseGrid->getMinpvValue();
mp.process(poreVolumes, minpv_value, actnum, zcorn.data());
}
const double z_tolerance = eclipseGrid->isPinchActive() ?
eclipseGrid->getPinchThresholdThickness() : 0.0;
ug_ = create_grid_cornerpoint(&g, z_tolerance);
if (!ug_) {
OPM_THROW(std::runtime_error, "Failed to construct grid.");
}
}
void GridManager::createGrdecl(Opm::DeckConstPtr deck, struct grdecl &grdecl)
{
// Extract data from deck.
const std::vector<double>& zcorn = deck->getKeyword("ZCORN")->getSIDoubleData();
const std::vector<double>& coord = deck->getKeyword("COORD")->getSIDoubleData();
const int* actnum = NULL;
if (deck->hasKeyword("ACTNUM")) {
actnum = &(deck->getKeyword("ACTNUM")->getIntData()[0]);
}
std::array<int, 3> dims;
if (deck->hasKeyword("DIMENS")) {
Opm::DeckKeywordConstPtr dimensKeyword = deck->getKeyword("DIMENS");
dims[0] = dimensKeyword->getRecord(0)->getItem(0)->getInt(0);
dims[1] = dimensKeyword->getRecord(0)->getItem(1)->getInt(0);
dims[2] = dimensKeyword->getRecord(0)->getItem(2)->getInt(0);
} else if (deck->hasKeyword("SPECGRID")) {
Opm::DeckKeywordConstPtr specgridKeyword = deck->getKeyword("SPECGRID");
dims[0] = specgridKeyword->getRecord(0)->getItem(0)->getInt(0);
dims[1] = specgridKeyword->getRecord(0)->getItem(1)->getInt(0);
dims[2] = specgridKeyword->getRecord(0)->getItem(2)->getInt(0);
} else {
OPM_THROW(std::runtime_error, "Deck must have either DIMENS or SPECGRID.");
}
// Collect in input struct for preprocessing.
grdecl.zcorn = &zcorn[0];
grdecl.coord = &coord[0];
grdecl.actnum = actnum;
grdecl.dims[0] = dims[0];
grdecl.dims[1] = dims[1];
grdecl.dims[2] = dims[2];
if (deck->hasKeyword("MAPAXES")) {
Opm::DeckKeywordConstPtr mapaxesKeyword = deck->getKeyword("MAPAXES");
Opm::DeckRecordConstPtr mapaxesRecord = mapaxesKeyword->getRecord(0);
// memleak alert: here we need to make sure that C code
// can properly take ownership of the grdecl.mapaxes
// object. if it is not freed, it will result in a
// memleak...
double *cWtfMapaxes = static_cast<double*>(malloc(sizeof(double)*mapaxesRecord->size()));
for (unsigned i = 0; i < mapaxesRecord->size(); ++i)
cWtfMapaxes[i] = mapaxesRecord->getItem(i)->getSIDouble(0);
grdecl.mapaxes = cWtfMapaxes;
} else
grdecl.mapaxes = NULL;
}
} // namespace Opm

View File

@ -1,101 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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_GRIDMANAGER_HEADER_INCLUDED
#define OPM_GRIDMANAGER_HEADER_INCLUDED
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <string>
struct UnstructuredGrid;
struct grdecl;
namespace Opm
{
/// This class manages an Opm::UnstructuredGrid in the sense that it
/// encapsulates creation and destruction of the grid.
/// The following grid types can be constructed:
/// - 3d corner-point grids (from deck input)
/// - 3d tensor grids (from deck input)
/// - 2d cartesian grids
/// - 3d cartesian grids
/// The resulting UnstructuredGrid is available through the c_grid() method.
class GridManager
{
public:
/// Construct a 3d corner-point grid or tensor grid from a deck.
explicit GridManager(Opm::DeckConstPtr deck);
/// Construct a grid from an EclipseState::EclipseGrid instance.
explicit GridManager(Opm::EclipseGridConstPtr eclipseGrid);
/// Construct a grid from an EclipseState::EclipseGrid instance,
/// giving an explicit set of pore volumes to be used for MINPV
/// considerations.
/// \input[in] eclipseGrid encapsulates a corner-point grid given from a deck
/// \input[in] poreVolumes one element per logical cartesian grid element
GridManager(Opm::EclipseGridConstPtr eclipseGrid,
const std::vector<double>& poreVolumes);
/// Construct a 2d cartesian grid with cells of unit size.
GridManager(int nx, int ny);
/// Construct a 2d cartesian grid with cells of size [dx, dy].
GridManager(int nx, int ny, double dx, double dy);
/// Construct a 3d cartesian grid with cells of unit size.
GridManager(int nx, int ny, int nz);
/// Construct a 3d cartesian grid with cells of size [dx, dy, dz].
GridManager(int nx, int ny, int nz,
double dx, double dy, double dz);
/// Construct a grid from an input file.
/// The file format used is currently undocumented,
/// and is therefore only suited for internal use.
explicit GridManager(const std::string& input_filename);
/// Destructor.
~GridManager();
/// Access the managed UnstructuredGrid.
/// The method is named similarly to c_str() in std::string,
/// to make it clear that we are returning a C-compatible struct.
const UnstructuredGrid* c_grid() const;
static void createGrdecl(Opm::DeckConstPtr deck, struct grdecl &grdecl);
private:
// Disable copying and assignment.
GridManager(const GridManager& other);
GridManager& operator=(const GridManager& other);
// Construct corner-point grid from EclipseGrid.
void initFromEclipseGrid(Opm::EclipseGridConstPtr eclipseGrid,
const std::vector<double>& poreVolumes);
// The managed UnstructuredGrid.
UnstructuredGrid* ug_;
};
} // namespace Opm
#endif // OPM_GRIDMANAGER_HEADER_INCLUDED

View File

@ -1,133 +0,0 @@
/*
Copyright 2014 SINTEF ICT, Applied Mathematics.
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/core/grid/GridUtilities.hpp>
#include <opm/core/grid/GridHelpers.hpp>
#include <opm/common/utility/platform_dependent/disable_warnings.h>
#include <boost/math/constants/constants.hpp>
#include <opm/common/utility/platform_dependent/reenable_warnings.h>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
namespace Opm
{
/// For each cell, find indices of all other cells sharing a vertex with it.
/// \param[in] grid A grid object.
/// \return A table of neighbour cell-indices by cell.
SparseTable<int> cellNeighboursAcrossVertices(const UnstructuredGrid& grid)
{
// 1. Create vertex->cell mapping. We do this by iterating
// over all faces, and adding both its cell neighbours
// to each of its vertices' data.
using namespace UgGridHelpers;
const int num_vertices = grid.number_of_nodes;
std::vector<std::set<int>> v2c(num_vertices);
const int num_faces = numFaces(grid);
const auto fc = faceCells(grid);
for (int face = 0; face < num_faces; ++face) {
for (int nodepos = grid.face_nodepos[face]; nodepos < grid.face_nodepos[face + 1]; ++nodepos) {
const int vertex = grid.face_nodes[nodepos];
for (int face_nb = 0; face_nb < 2; ++face_nb) {
const int face_nb_cell = fc(face, face_nb);
if (face_nb_cell >= 0) {
v2c[vertex].insert(face_nb_cell);
}
}
}
}
// 2. For each cell, iterate over its faces, iterate over
// their vertices, and collect all those vertices' cell
// neighbours. Add as row to sparse table.
SparseTable<int> cell_nb;
const int num_cells = numCells(grid);
const auto c2f = cell2Faces(grid);
// Reserve sufficient room for cartesian grids in 2 and 3
// dimensions. Note that this is not a limit, just an
// optimization similar to std::vector.
cell_nb.reserve(num_cells, (dimensions(grid) == 2 ? 8 : 26) * num_cells);
std::set<int> nb;
for (int cell = 0; cell < num_cells; ++cell) {
nb.clear();
const auto cell_faces = c2f[cell];
const int num_cell_faces = cell_faces.size();
for (int local_face = 0; local_face < num_cell_faces; ++local_face) {
const int face = cell_faces[local_face];
for (int nodepos = grid.face_nodepos[face]; nodepos < grid.face_nodepos[face + 1]; ++nodepos) {
const int vertex = grid.face_nodes[nodepos];
nb.insert(v2c[vertex].begin(), v2c[vertex].end());
}
}
nb.erase(cell);
cell_nb.appendRow(nb.begin(), nb.end());
}
// 3. Done. Return.
return cell_nb;
}
/// For each cell, order the (cell) neighbours counterclockwise.
/// \param[in] grid A 2d grid object.
/// \param[in, out] nb A cell-cell neighbourhood table, such as from cellNeighboursAcrossVertices().
void orderCounterClockwise(const UnstructuredGrid& grid,
SparseTable<int>& nb)
{
if (grid.dimensions != 2) {
OPM_THROW(std::logic_error, "Cannot use orderCounterClockwise in " << grid.dimensions << " dimensions.");
}
const int num_cells = grid.number_of_cells;
if (nb.size() != num_cells) {
OPM_THROW(std::logic_error, "Inconsistent arguments for orderCounterClockwise().");
}
// For each cell, compute each neighbour's angle with the x axis,
// sort that to find the correct permutation of the neighbours.
typedef std::pair<double, int> AngleAndPos;
std::vector<AngleAndPos> angle_and_pos;
std::vector<int> original;
for (int cell = 0; cell < num_cells; ++cell) {
const int num_nb = nb[cell].size();
angle_and_pos.clear();
angle_and_pos.resize(num_nb);
for (int ii = 0; ii < num_nb; ++ii) {
const int cell2 = nb[cell][ii];
const double v[2] = { grid.cell_centroids[2*cell2] - grid.cell_centroids[2*cell],
grid.cell_centroids[2*cell2 + 1] - grid.cell_centroids[2*cell + 1] };
// The formula below gives an angle in [0, 2*pi] with the positive x axis.
const double angle = boost::math::constants::pi<double>() - std::atan2(v[1], -v[0]);
angle_and_pos[ii] = std::make_pair(angle, ii);
}
original.assign(nb[cell].begin(), nb[cell].end());
std::sort(angle_and_pos.begin(), angle_and_pos.end());
for (int ii = 0; ii < num_nb; ++ii) {
nb[cell][ii] = original[angle_and_pos[ii].second];
}
}
}
} // namespace Opm

View File

@ -1,42 +0,0 @@
/*
Copyright 2014 SINTEF ICT, Applied Mathematics.
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_GRIDUTILITIES_HEADER_INCLUDED
#define OPM_GRIDUTILITIES_HEADER_INCLUDED
#include <opm/core/grid.h>
#include <opm/core/utility/SparseTable.hpp>
namespace Opm
{
/// For each cell, find indices of all cells sharing a vertex with it.
/// \param[in] grid A grid object.
/// \return A table of neighbour cell-indices by cell.
SparseTable<int> cellNeighboursAcrossVertices(const UnstructuredGrid& grid);
/// For each cell, order the (cell) neighbours counterclockwise.
/// \param[in] grid A 2d grid object.
/// \param[in, out] nb A cell-cell neighbourhood table, such as from vertexNeighbours().
void orderCounterClockwise(const UnstructuredGrid& grid,
SparseTable<int>& nb);
} // namespace Opm
#endif // OPM_GRIDUTILITIES_HEADER_INCLUDED

View File

@ -1,169 +0,0 @@
/*
Copyright 2014 SINTEF ICT, Applied Mathematics.
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_MINPVPROCESSOR_HEADER_INCLUDED
#define OPM_MINPVPROCESSOR_HEADER_INCLUDED
#include <opm/common/ErrorMacros.hpp>
#include <array>
namespace Opm
{
/// \brief Transform a corner-point grid ZCORN field to account for MINPV processing.
class MinpvProcessor
{
public:
/// \brief Create a processor.
/// \param[in] nx logical cartesian number of cells in I-direction
/// \param[in] ny logical cartesian number of cells in J-direction
/// \param[in] nz logical cartesian number of cells in K-direction
MinpvProcessor(const int nx, const int ny, const int nz);
/// Change zcorn so that it respects the minpv property.
/// \param[in] pv pore volumes of all logical cartesian cells
/// \param[in] minpv minimum pore volume to accept a cell
/// \param[in] actnum active cells, inactive cells are not considered
/// \param[in, out] zcorn ZCORN array to be manipulated
/// After processing, all cells that have lower pore volume than minpv
/// will have the zcorn numbers changed so they are zero-thickness. Any
/// cell below will be changed to include the deleted volume.
void process(const std::vector<double>& pv,
const double minpv,
const std::vector<int>& actnum,
double* zcorn) const;
private:
std::array<int,8> cornerIndices(const int i, const int j, const int k) const;
std::array<double, 8> getCellZcorn(const int i, const int j, const int k, const double* z) const;
void setCellZcorn(const int i, const int j, const int k, const std::array<double, 8>& cellz, double* z) const;
std::array<int, 3> dims_;
std::array<int, 3> delta_;
};
inline MinpvProcessor::MinpvProcessor(const int nx, const int ny, const int nz)
{
// Not doing init-list init since bracket-init not available
// for all compilers we support (gcc 4.4).
dims_[0] = nx;
dims_[1] = ny;
dims_[2] = nz;
delta_[0] = 1;
delta_[1] = 2*nx;
delta_[2] = 4*nx*ny;
}
inline void MinpvProcessor::process(const std::vector<double>& pv,
const double minpv,
const std::vector<int>& actnum,
double* zcorn) const
{
// Algorithm:
// 1. Process each column of cells (with same i and j
// coordinates) from top (low k) to bottom (high k).
// 2. For each cell 'c' visited, check if its pore volume
// pv[c] is less than minpv.
// 3. If below the minpv threshold, move the lower four
// zcorn associated with the cell c to coincide with
// the upper four (so it becomes degenerate). Also move
// the higher four zcorn associated with the cell below
// to these values (so it gains the deleted volume).
// Check for sane input sizes.
const size_t log_size = dims_[0] * dims_[1] * dims_[2];
if (pv.size() != log_size) {
OPM_THROW(std::runtime_error, "Wrong size of PORV input, must have one element per logical cartesian cell.");
}
if (!actnum.empty() && actnum.size() != log_size) {
OPM_THROW(std::runtime_error, "Wrong size of ACTNUM input, must have one element per logical cartesian cell.");
}
// Main loop.
for (int kk = 0; kk < dims_[2]; ++kk) {
for (int jj = 0; jj < dims_[1]; ++jj) {
for (int ii = 0; ii < dims_[0]; ++ii) {
const int c = ii + dims_[0] * (jj + dims_[1] * kk);
if (pv[c] < minpv && (actnum.empty() || actnum[c])) {
// Move deeper (higher k) coordinates to lower k coordinates.
std::array<double, 8> cz = getCellZcorn(ii, jj, kk, zcorn);
for (int count = 0; count < 4; ++count) {
cz[count + 4] = cz[count];
}
setCellZcorn(ii, jj, kk, cz, zcorn);
// Check if there is a cell below.
if (pv[c] > 0.0 && kk < dims_[2] - 1) {
// Set lower k coordinates of cell below to upper cells's coordinates.
std::array<double, 8> cz_below = getCellZcorn(ii, jj, kk + 1, zcorn);
for (int count = 0; count < 4; ++count) {
cz_below[count] = cz[count];
}
setCellZcorn(ii, jj, kk + 1, cz_below, zcorn);
}
}
}
}
}
}
inline std::array<int,8> MinpvProcessor::cornerIndices(const int i, const int j, const int k) const
{
const int ix = 2*(i*delta_[0] + j*delta_[1] + k*delta_[2]);
std::array<int, 8> ixs = {{ ix, ix + delta_[0],
ix + delta_[1], ix + delta_[1] + delta_[0],
ix + delta_[2], ix + delta_[2] + delta_[0],
ix + delta_[2] + delta_[1], ix + delta_[2] + delta_[1] + delta_[0] }};
return ixs;
}
// Returns the eight z-values associated with a given cell.
// The ordering is such that i runs fastest. That is, with
// L = low and H = high:
// {LLL, HLL, LHL, HHL, LLH, HLH, LHH, HHH }.
inline std::array<double, 8> MinpvProcessor::getCellZcorn(const int i, const int j, const int k, const double* z) const
{
const std::array<int, 8> ixs = cornerIndices(i, j, k);
std::array<double, 8> cellz;
for (int count = 0; count < 8; ++count) {
cellz[count] = z[ixs[count]];
}
return cellz;
}
inline void MinpvProcessor::setCellZcorn(const int i, const int j, const int k, const std::array<double, 8>& cellz, double* z) const
{
const std::array<int, 8> ixs = cornerIndices(i, j, k);
for (int count = 0; count < 8; ++count) {
z[ixs[count]] = cellz[count];
}
}
} // namespace Opm
#endif // OPM_MINPVPROCESSOR_HEADER_INCLUDED

View File

@ -1,496 +0,0 @@
/*
Copyright 2015 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_PINCHPROCESSOR_HEADER_INCLUDED
#define OPM_PINCHPROCESSOR_HEADER_INCLUDED
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/grid/GridHelpers.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/NNC.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/FaceDir.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/PinchMode.hpp>
#include <opm/core/utility/Units.hpp>
#include <array>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <limits>
namespace Opm
{
template <class Grid>
class PinchProcessor
{
public:
/// \brief Create a Pinch processor.
/// \param[in] minpvValue value in MINPV keyword
/// \param[in] thickness item 2 in PINCH keyword
/// \param[in] transMode item 4 in PINCH keyword
/// \param[in] multzMode item 5 in PINCH keyword
PinchProcessor(const double minpvValue,
const double thickness,
const PinchMode::ModeEnum transMode,
const PinchMode::ModeEnum multzMode);
/// Generate NNCs for cells which pv is less than MINPV.
/// \param[in] Grid cpgrid or unstructured grid
/// \param[in] htrans half cell transmissibility, size is number of cellfaces.
/// \param[in] multz Z+ transmissibility multiplier for all active cells
/// \param[in] pv pore volume for all the cartesian cells
/// \param[in] nnc non-neighbor connection class
/// Algorithm:
/// 1. Mark all the cells which pv less than minpvValue.
/// 2. Find out proper pinchouts column and associate top and bottom cells.
/// 3. Compute transmissibility for nncs.
/// 4. Apply multz due to different multz options.
void process(const Grid& grid,
const std::vector<double>& htrans,
const std::vector<int>& actnum,
const std::vector<double>& multz,
const std::vector<double>& pv,
NNC& nnc);
private:
double minpvValue_;
double thickness_;
PinchMode::ModeEnum transMode_;
PinchMode::ModeEnum multzMode_;
/// Mark minpved cells.
std::vector<int> getMinpvCells_(const std::vector<int>& actnum,
const std::vector<double>& pv);
/// Get the interface for two cells.
int interface_(const Grid& grid,
const int cellIdx1,
const int cellIdx2);
/// Get the proper face for one cell.
int interface_(const Grid& grid,
const int cellIdx,
const Opm::FaceDir::DirEnum& faceDir);
/// Get pinchouts column.
std::vector<std::vector<int> >
getPinchoutsColumn_(const Grid& grid,
const std::vector<int>& actnum,
const std::vector<double>& pv);
/// Get global cell index.
int getGlobalIndex_(const int i, const int j, const int k, const int* dims);
/// Get cartesian index.
std::array<int, 3> getCartIndex_(const int idx,
const int* dims);
/// Compute transmissibility for nnc.
std::vector<double> transCompute_(const Grid& grid,
const std::vector<double>& htrans,
const std::vector<int>& pinCells,
const std::vector<int>& pinFaces);
/// Get map between half-trans index and the pair of face index and cell index.
std::vector<int> getHfIdxMap_(const Grid& grid);
/// Get active cell index.
int getActiveCellIdx_(const Grid& grid,
const int globalIdx);
/// Item 4 in PINCH keyword.
void transTopbot_(const Grid& grid,
const std::vector<double>& htrans,
const std::vector<int>& actnum,
const std::vector<double>& multz,
const std::vector<double>& pv,
NNC& nnc);
/// Item 5 in PINCH keyword.
std::unordered_multimap<int, double> multzOptions_(const Grid& grid,
const std::vector<int>& pinCells,
const std::vector<int>& pinFaces,
const std::vector<double>& multz,
const std::vector<std::vector<int> >& seg);
/// Apply multz vector to face transmissibility.
void applyMultz_(std::vector<double>& trans,
const std::unordered_multimap<int, double>& multzmap);
};
template <class Grid>
inline PinchProcessor<Grid>::PinchProcessor(const double minpv,
const double thickness,
const PinchMode::ModeEnum transMode,
const PinchMode::ModeEnum multzMode)
{
minpvValue_ = minpv;
thickness_ = thickness;
transMode_ = transMode;
multzMode_ = multzMode;
}
template <class Grid>
inline int PinchProcessor<Grid>::getGlobalIndex_(const int i, const int j, const int k, const int* dims)
{
return i + dims[0] * (j + dims[1] * k);
}
template <class Grid>
inline std::array<int, 3> PinchProcessor<Grid>::getCartIndex_(const int idx,
const int* dims)
{
std::array<int, 3> ijk;
ijk[0] = (idx % dims[0]);
ijk[1] = ((idx / dims[0]) % dims[1]);
ijk[2] = ((idx / dims[0]) / dims[1]);
return ijk;
}
template<class Grid>
inline int PinchProcessor<Grid>::interface_(const Grid& grid,
const int cellIdx1,
const int cellIdx2)
{
const auto cell_faces = Opm::UgGridHelpers::cell2Faces(grid);
int commonFace = -1;
const int actCellIdx1 = getActiveCellIdx_(grid, cellIdx1);
const int actCellIdx2 = getActiveCellIdx_(grid, cellIdx2);
const auto cellFacesRange1 = cell_faces[actCellIdx1];
const auto cellFacesRange2 = cell_faces[actCellIdx2];
for (const auto& f1 : cellFacesRange1) {
for (const auto& f2 : cellFacesRange2) {
if (f1 == f2) {
commonFace = f1;
break;
}
}
}
if (commonFace == -1) {
const auto dims = Opm::UgGridHelpers::cartDims(grid);
const auto ijk1 = getCartIndex_(cellIdx1, dims);
const auto ijk2 = getCartIndex_(cellIdx2, dims);
OPM_THROW(std::logic_error, "Couldn't find the common face for cell "
<< cellIdx1<< "("<<ijk1[0]<<","<<ijk1[1]<<","<<ijk1[2]<<")"
<< " and " << cellIdx2<<"("<<ijk2[0]<<","<<ijk2[1]<<","<<ijk2[2]<<")");
}
return commonFace;
}
template<class Grid>
inline int PinchProcessor<Grid>::interface_(const Grid& grid,
const int cellIdx,
const Opm::FaceDir::DirEnum& faceDir)
{
const auto actCellIdx = getActiveCellIdx_(grid, cellIdx);
const auto cell_faces = Opm::UgGridHelpers::cell2Faces(grid);
const auto cellFacesRange = cell_faces[actCellIdx];
int faceIdx = -1;
for (auto cellFaceIter = cellFacesRange.begin(); cellFaceIter != cellFacesRange.end(); ++cellFaceIter) {
int tag = Opm::UgGridHelpers::faceTag(grid, cellFaceIter);
if ( (faceDir == Opm::FaceDir::ZMinus && tag == 4) || (faceDir == Opm::FaceDir::ZPlus && tag == 5) ) {
faceIdx = *cellFaceIter;
}
}
if (faceIdx == -1) {
OPM_THROW(std::logic_error, "Couldn't find the face for cell ." << cellIdx);
}
return faceIdx;
}
template<class Grid>
inline std::vector<int> PinchProcessor<Grid>::getMinpvCells_(const std::vector<int>& actnum,
const std::vector<double>& pv)
{
std::vector<int> minpvCells(pv.size(), 0);
for (int idx = 0; idx < static_cast<int>(pv.size()); ++idx) {
if (actnum[idx]) {
if (pv[idx] < minpvValue_) {
minpvCells[idx] = 1;
}
}
}
return minpvCells;
}
template<class Grid>
inline std::vector<int> PinchProcessor<Grid>::getHfIdxMap_(const Grid& grid)
{
std::vector<int> hf_ix(2*Opm::UgGridHelpers::numFaces(grid), -1);
const auto& f2c = Opm::UgGridHelpers::faceCells(grid);
const auto& cf = Opm::UgGridHelpers::cell2Faces(grid);
for (int c = 0, i = 0; c < Opm::UgGridHelpers::numCells(grid); ++c) {
for (const auto& f: cf[c]) {
const auto off = 0 + (f2c(f, 0) != c);
hf_ix[2*f + off] = i++;
}
}
return hf_ix;
}
template<class Grid>
inline int PinchProcessor<Grid>::getActiveCellIdx_(const Grid& grid,
const int globalIdx)
{
const int nc = Opm::UgGridHelpers::numCells(grid);
const int* global_cell = Opm::UgGridHelpers::globalCell(grid);
int idx = -1;
for (int i = 0; i < nc; ++i) {
if (global_cell[i] == globalIdx) {
idx = i;
break;
}
}
return idx;
}
template<class Grid>
inline std::vector<double> PinchProcessor<Grid>::transCompute_(const Grid& grid,
const std::vector<double>& htrans,
const std::vector<int>& pinCells,
const std::vector<int>& pinFaces)
{
const int nc = Opm::UgGridHelpers::numCells(grid);
const int nf = Opm::UgGridHelpers::numFaces(grid);
std::vector<double> trans(nf, 0);
int cellFaceIdx = 0;
auto cell_faces = Opm::UgGridHelpers::cell2Faces(grid);
const auto& hfmap = getHfIdxMap_(grid);
const auto& f2c = Opm::UgGridHelpers::faceCells(grid);
for (int cellIdx = 0; cellIdx < nc; ++cellIdx) {
auto cellFacesRange = cell_faces[cellIdx];
for (auto cellFaceIter = cellFacesRange.begin(); cellFaceIter != cellFacesRange.end(); ++cellFaceIter, ++cellFaceIdx) {
const int faceIdx = *cellFaceIter;
const auto pos = std::find(pinFaces.begin(), pinFaces.end(), faceIdx);
if (pos == pinFaces.end()) {
trans[faceIdx] += 1. / htrans[cellFaceIdx];
} else {
const int idx1 = std::distance(std::begin(pinFaces), pos);
int idx2;
if (idx1 % 2 == 0) {
idx2 = idx1 + 1;
} else {
idx2 = idx1 - 1;
}
const int f1 = hfmap[2*pinFaces[idx1] + (f2c(pinFaces[idx1], 0) != getActiveCellIdx_(grid, pinCells[idx1]))];
const int f2 = hfmap[2*pinFaces[idx2] + (f2c(pinFaces[idx2], 0) != getActiveCellIdx_(grid, pinCells[idx2]))];
trans[faceIdx] = (1. / htrans[f1] + 1. / htrans[f2]);
trans[pinFaces[idx2]] = trans[faceIdx];
}
}
}
for (auto f = 0; f < nf; ++f) {
trans[f] = 1. / trans[f];
}
return trans;
}
template<class Grid>
inline std::vector<std::vector<int>> PinchProcessor<Grid>::getPinchoutsColumn_(const Grid& grid,
const std::vector<int>& actnum,
const std::vector<double>& pv)
{
const int* dims = Opm::UgGridHelpers::cartDims(grid);
std::vector<int> minpvCells = getMinpvCells_(actnum, pv);
std::vector<std::vector<int>> segment;
for (int z = 0; z < dims[2]; ++z) {
for (int y = 0; y < dims[1]; ++y) {
for (int x = 0; x < dims[0]; ++x) {
const int c = getGlobalIndex_(x, y, z, dims);
std::vector<int> seg;
if (minpvCells[c]) {
seg.push_back(c);
minpvCells[c] = 0;
for (int zz = z+1; zz < dims[2]; ++zz) {
const int cc = getGlobalIndex_(x, y, zz, dims);
if (minpvCells[cc]) {
seg.push_back(cc);
minpvCells[cc] = 0;
} else {
break;
}
}
segment.push_back(seg);
}
}
}
}
return segment;
}
template<class Grid>
inline void PinchProcessor<Grid>::transTopbot_(const Grid& grid,
const std::vector<double>& htrans,
const std::vector<int>& actnum,
const std::vector<double>& multz,
const std::vector<double>& pv,
NNC& nnc)
{
const int* dims = Opm::UgGridHelpers::cartDims(grid);
std::vector<int> pinFaces;
std::vector<int> pinCells;
std::vector<std::vector<int> > newSeg;
auto minpvSeg = getPinchoutsColumn_(grid, actnum, pv);
for (auto& seg : minpvSeg) {
std::array<int, 3> ijk1 = getCartIndex_(seg.front(), dims);
std::array<int, 3> ijk2 = getCartIndex_(seg.back(), dims);
auto tmp = seg;
if ((ijk1[2]-1) >= 0 && (ijk2[2]+1) < dims[2]) {
int topCell = getGlobalIndex_(ijk1[0], ijk1[1], ijk1[2]-1, dims);
int botCell = getGlobalIndex_(ijk2[0], ijk2[1], ijk2[2]+1, dims);
/// for any segments, we need to find the active top and bottom cells.
/// if the original segment's top and bottom is inactive, we need to lookup
/// the column until they're found otherwise just ignore this segment.
if (!actnum[topCell]) {
seg.insert(seg.begin(), topCell);
for (int topk = ijk1[2]-2; topk > 0; --topk) {
topCell = getGlobalIndex_(ijk1[0], ijk1[1], topk, dims);
if (actnum[topCell]) {
break;
} else {
auto it = seg.begin();
seg.insert(it, topCell);
}
}
pinFaces.push_back(interface_(grid, topCell, Opm::FaceDir::ZPlus));
} else {
pinFaces.push_back(interface_(grid, topCell, seg.front()));
}
tmp.insert(tmp.begin(), topCell);
newSeg.push_back(tmp);
pinCells.push_back(topCell);
if (!actnum[botCell]) {
seg.push_back(botCell);
for (int botk = ijk2[2]+2; botk < dims[2]; ++botk) {
botCell = getGlobalIndex_(ijk2[0], ijk2[1], botk, dims);
if (actnum[botCell]) {
break;
} else {
seg.push_back(botCell);
}
}
pinFaces.push_back(interface_(grid, botCell, Opm::FaceDir::ZMinus));
} else {
pinFaces.push_back(interface_(grid, seg.back(), botCell));
}
pinCells.push_back(botCell);
}
}
auto faceTrans = transCompute_(grid, htrans, pinCells, pinFaces);
auto multzmap = multzOptions_(grid, pinCells, pinFaces, multz, newSeg);
applyMultz_(faceTrans, multzmap);
for (int i = 0; i < static_cast<int>(pinCells.size())/2; ++i) {
nnc.addNNC(static_cast<int>(pinCells[2*i]), static_cast<int>(pinCells[2*i+1]), faceTrans[pinFaces[2*i]]);
}
}
template<class Grid>
inline std::unordered_multimap<int, double> PinchProcessor<Grid>::multzOptions_(const Grid& grid,
const std::vector<int>& pinCells,
const std::vector<int>& pinFaces,
const std::vector<double>& multz,
const std::vector<std::vector<int> >& segs)
{
std::unordered_multimap<int, double> multzmap;
if (multzMode_ == PinchMode::ModeEnum::TOP) {
for (int i = 0; i < static_cast<int>(pinFaces.size())/2; ++i) {
multzmap.insert(std::make_pair(pinFaces[2*i], multz[getActiveCellIdx_(grid, pinCells[2*i])]));
multzmap.insert(std::make_pair(pinFaces[2*i+1],multz[getActiveCellIdx_(grid, pinCells[2*i])]));
}
} else if (multzMode_ == PinchMode::ModeEnum::ALL) {
for (auto& seg : segs) {
//find the min multz in seg cells.
auto multzValue = std::numeric_limits<double>::max();
for (auto& cellIdx : seg) {
auto activeIdx = getActiveCellIdx_(grid, cellIdx);
if (activeIdx != -1) {
multzValue = std::min(multzValue, multz[activeIdx]);
}
}
//find the right face.
auto index = std::distance(std::begin(pinCells), std::find(pinCells.begin(), pinCells.end(), seg.front()));
multzmap.insert(std::make_pair(pinFaces[index], multzValue));
multzmap.insert(std::make_pair(pinFaces[index+1], multzValue));
}
}
return multzmap;
}
template<class Grid>
inline void PinchProcessor<Grid>::applyMultz_(std::vector<double>& trans,
const std::unordered_multimap<int, double>& multzmap)
{
for (auto& x : multzmap) {
trans[x.first] *= x.second;
}
}
template<class Grid>
inline void PinchProcessor<Grid>::process(const Grid& grid,
const std::vector<double>& htrans,
const std::vector<int>& actnum,
const std::vector<double>& multz,
const std::vector<double>& pv,
NNC& nnc)
{
transTopbot_(grid, htrans, actnum, multz, pv, nnc);
}
} // namespace Opm
#endif // OPM_PINCHPROCESSOR_HEADER_INCLUDED

View File

@ -1,708 +0,0 @@
/*===========================================================================
//
// File: cart_grid.c
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
//==========================================================================*/
/*
Copyright 2011 SINTEF ICT, Applied Mathematics.
Copyright 2011 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 "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <opm/core/grid.h>
#include <opm/core/grid/cornerpoint_grid.h>
#include <opm/core/grid/cart_grid.h>
static struct UnstructuredGrid *allocate_cart_grid_3d(int nx, int ny, int nz);
static void fill_cart_topology_3d(struct UnstructuredGrid *G);
static void fill_cart_geometry_3d(struct UnstructuredGrid *G,
const double *x,
const double *y,
const double *z);
static void
fill_layered_geometry_3d(struct UnstructuredGrid *G,
const double *x,
const double *y,
const double *z,
const double *depthz);
struct UnstructuredGrid *
create_grid_cart3d(int nx, int ny, int nz)
{
return create_grid_hexa3d(nx, ny, nz, 1.0, 1.0, 1.0);
}
struct UnstructuredGrid *
create_grid_hexa3d(int nx, int ny, int nz,
double dx, double dy, double dz)
{
int i;
double *x, *y, *z;
struct UnstructuredGrid *G;
x = malloc((nx + 1) * sizeof *x);
y = malloc((ny + 1) * sizeof *y);
z = malloc((nz + 1) * sizeof *z);
if ((x == NULL) || (y == NULL) || (z == NULL)) {
G = NULL;
} else {
for (i = 0; i < nx + 1; i++) { x[i] = i * dx; }
for (i = 0; i < ny + 1; i++) { y[i] = i * dy; }
for (i = 0; i < nz + 1; i++) { z[i] = i * dz; }
G = create_grid_tensor3d(nx, ny, nz, x, y, z,
(const double *) NULL);
}
free(z); free(y); free(x);
return G;
}
/* --------------------------------------------------------------------- */
static struct UnstructuredGrid *allocate_cart_grid_2d(int nx, int ny);
static void fill_cart_topology_2d(struct UnstructuredGrid *G);
static void fill_cart_geometry_2d(struct UnstructuredGrid *G,
const double *x,
const double *y);
struct UnstructuredGrid*
create_grid_cart2d(int nx, int ny, double dx, double dy)
{
int i;
double *x, *y;
struct UnstructuredGrid *G;
x = malloc((nx + 1) * sizeof *x);
y = malloc((ny + 1) * sizeof *y);
if ((x == NULL) || (y == NULL)) {
G = NULL;
} else {
for (i = 0; i < nx + 1; i++) { x[i] = i*dx; }
for (i = 0; i < ny + 1; i++) { y[i] = i*dy; }
G = create_grid_tensor2d(nx, ny, x, y);
}
free(y); free(x);
return G;
}
/* --------------------------------------------------------------------- */
struct UnstructuredGrid *
create_grid_tensor2d(int nx, int ny, const double *x, const double *y)
{
struct UnstructuredGrid *G;
G = allocate_cart_grid_2d(nx, ny);
if (G != NULL)
{
fill_cart_topology_2d(G);
fill_cart_geometry_2d(G, x, y);
}
return G;
}
/* --------------------------------------------------------------------- */
struct UnstructuredGrid *
create_grid_tensor3d(int nx ,
int ny ,
int nz ,
const double *x ,
const double *y ,
const double *z ,
const double *depthz)
{
struct UnstructuredGrid *G;
G = allocate_cart_grid_3d(nx, ny, nz);
if (G != NULL)
{
fill_cart_topology_3d(G);
if (depthz == NULL) {
fill_cart_geometry_3d(G, x, y, z);
}
else {
fill_layered_geometry_3d(G, x, y, z, depthz);
}
}
return G;
}
/* --------------------------------------------------------------------- */
/* Static functions follow: */
/* --------------------------------------------------------------------- */
static struct UnstructuredGrid *
allocate_cart_grid(size_t ndims ,
size_t ncells,
size_t nfaces,
size_t nnodes)
{
size_t nfacenodes, ncellfaces;
nfacenodes = nfaces * (2 * (ndims - 1));
ncellfaces = ncells * (2 * ndims);
return allocate_grid(ndims, ncells, nfaces,
nfacenodes, ncellfaces, nnodes);
}
static struct UnstructuredGrid*
allocate_cart_grid_3d(int nx, int ny, int nz)
{
struct UnstructuredGrid *G;
int Nx, Ny, Nz;
int nxf, nyf, nzf;
int ncells, nfaces, nnodes;
Nx = nx + 1;
Ny = ny + 1;
Nz = nz +1;
nxf = Nx * ny * nz;
nyf = nx * Ny * nz;
nzf = nx * ny * Nz;
ncells = nx * ny * nz ;
nfaces = nxf + nyf + nzf;
nnodes = Nx * Ny * Nz ;
G = allocate_cart_grid(3, ncells, nfaces, nnodes);
if (G != NULL)
{
G->dimensions = 3 ;
G->cartdims[0] = nx;
G->cartdims[1] = ny;
G->cartdims[2] = nz;
G->number_of_cells = ncells;
G->number_of_faces = nfaces;
G->number_of_nodes = nnodes;
}
return G;
}
/* --------------------------------------------------------------------- */
static void
fill_cart_topology_3d(struct UnstructuredGrid *G)
{
int nx, ny, nz;
int Nx, Ny;
int nxf, nyf;
int i,j,k;
int *cfaces, *cfacepos, *fnodes, *fnodepos, *fcells;
nx = G->cartdims[0];
ny = G->cartdims[1];
nz = G->cartdims[2];
Nx = nx+1;
Ny = ny+1;
nxf = Nx*ny*nz;
nyf = nx*Ny*nz;
cfaces = G->cell_faces;
cfacepos = G->cell_facepos;
cfacepos[0] = 0;
for (k=0; k<nz; ++k) {
for (j=0; j<ny; ++j) {
for (i=0; i<nx; ++i) {
*cfaces++ = i+ Nx*(j+ ny* k );
*cfaces++ = i+1+Nx*(j+ ny* k );
*cfaces++ = i+ nx*(j+ Ny* k ) +nxf;
*cfaces++ = i+ nx*(j+1+Ny* k ) +nxf;
*cfaces++ = i+ nx*(j+ ny* k ) +nxf+nyf;
*cfaces++ = i+ nx*(j+ ny*(k+1)) +nxf+nyf;
cfacepos[1] = cfacepos[0]+6;
++cfacepos;
}
}
}
for (k = 0; k < nx * ny * nz; ++k) {
for (i = 0; i < 6; ++i) {
G->cell_facetag[k*6 + i] = i;
}
}
fnodes = G->face_nodes;
fnodepos = G->face_nodepos;
fcells = G->face_cells;
fnodepos[0] = 0;
/* Faces with x-normal */
for (k=0; k<nz; ++k) {
for (j=0; j<ny; ++j) {
for (i=0; i<nx+1; ++i) {
*fnodes++ = i+Nx*(j + Ny * k );
*fnodes++ = i+Nx*(j+1 + Ny * k );
*fnodes++ = i+Nx*(j+1 + Ny *(k+1));
*fnodes++ = i+Nx*(j + Ny *(k+1));
fnodepos[1] = fnodepos[0] + 4;
++fnodepos;
if (i==0) {
*fcells++ = -1;
*fcells++ = i+nx*(j+ny*k);
}
else if (i == nx) {
*fcells++ = i-1+nx*(j+ny*k);
*fcells++ = -1;
}
else {
*fcells++ = i-1 + nx*(j+ny*k);
*fcells++ = i + nx*(j+ny*k);
}
}
}
}
/* Faces with y-normal */
for (k=0; k<nz; ++k) {
for (j=0; j<ny+1; ++j) {
for (i=0; i<nx; ++i) {
*fnodes++ = i+ Nx*(j + Ny * k );
*fnodes++ = i + Nx*(j + Ny *(k+1));
*fnodes++ = i+1 + Nx*(j + Ny *(k+1));
*fnodes++ = i+1 + Nx*(j + Ny * k );
fnodepos[1] = fnodepos[0] + 4;
++fnodepos;
if (j==0) {
*fcells++ = -1;
*fcells++ = i+nx*(j+ny*k);
}
else if (j == ny) {
*fcells++ = i+nx*(j-1+ny*k);
*fcells++ = -1;
}
else {
*fcells++ = i+nx*(j-1+ny*k);
*fcells++ = i+nx*(j+ny*k);
}
}
}
}
/* Faces with z-normal */
for (k=0; k<nz+1; ++k) {
for (j=0; j<ny; ++j) {
for (i=0; i<nx; ++i) {
*fnodes++ = i+ Nx*(j + Ny * k);
*fnodes++ = i+1 + Nx*(j + Ny * k);
*fnodes++ = i+1 + Nx*(j+1 + Ny * k);
*fnodes++ = i+ Nx*(j+1 + Ny * k);
fnodepos[1] = fnodepos[0] + 4;
++fnodepos;
if (k==0) {
*fcells++ = -1;
*fcells++ = i+nx*(j+ny*k);
}
else if (k == nz) {
*fcells++ = i+nx*(j+ny*(k-1));
*fcells++ = -1;
}
else {
*fcells++ = i+nx*(j+ny*(k-1));
*fcells++ = i+nx*(j+ny*k);
}
}
}
}
}
/* --------------------------------------------------------------------- */
static void
fill_cart_geometry_3d(struct UnstructuredGrid *G,
const double *x,
const double *y,
const double *z)
{
int nx, ny, nz;
int i,j,k;
double dx, dy, dz;
double *coord, *ccentroids, *cvolumes;
double *fnormals, *fcentroids, *fareas;
nx = G->cartdims[0];
ny = G->cartdims[1];
nz = G->cartdims[2];
ccentroids = G->cell_centroids;
cvolumes = G->cell_volumes;
for (k=0; k<nz; ++k) {
for (j=0; j<ny; ++j) {
for (i=0; i<nx; ++i) {
*ccentroids++ = (x[i] + x[i + 1]) / 2.0;
*ccentroids++ = (y[j] + y[j + 1]) / 2.0;
*ccentroids++ = (z[k] + z[k + 1]) / 2.0;
dx = x[i + 1] - x[i];
dy = y[j + 1] - y[j];
dz = z[k + 1] - z[k];
*cvolumes++ = dx * dy * dz;
}
}
}
fnormals = G->face_normals;
fcentroids = G->face_centroids;
fareas = G->face_areas;
/* Faces with x-normal */
for (k=0; k<nz; ++k) {
for (j=0; j<ny; ++j) {
for (i=0; i<nx+1; ++i) {
dy = y[j + 1] - y[j];
dz = z[k + 1] - z[k];
*fnormals++ = dy * dz;
*fnormals++ = 0;
*fnormals++ = 0;
*fcentroids++ = x[i];
*fcentroids++ = (y[j] + y[j + 1]) / 2.0;
*fcentroids++ = (z[k] + z[k + 1]) / 2.0;
*fareas++ = dy * dz;
}
}
}
/* Faces with y-normal */
for (k=0; k<nz; ++k) {
for (j=0; j<ny+1; ++j) {
for (i=0; i<nx; ++i) {
dx = x[i + 1] - x[i];
dz = z[k + 1] - z[k];
*fnormals++ = 0;
*fnormals++ = dx * dz;
*fnormals++ = 0;
*fcentroids++ = (x[i] + x[i + 1]) / 2.0;
*fcentroids++ = y[j];
*fcentroids++ = (z[k] + z[k + 1]) / 2.0;
*fareas++ = dx * dz;
}
}
}
/* Faces with z-normal */
for (k=0; k<nz+1; ++k) {
for (j=0; j<ny; ++j) {
for (i=0; i<nx; ++i) {
dx = x[i + 1] - x[i];
dy = y[j + 1] - y[j];
*fnormals++ = 0;
*fnormals++ = 0;
*fnormals++ = dx * dy;
*fcentroids++ = (x[i] + x[i + 1]) / 2.0;
*fcentroids++ = (y[j] + y[j + 1]) / 2.0;
*fcentroids++ = z[k];
*fareas++ = dx * dy;
}
}
}
coord = G->node_coordinates;
for (k=0; k<nz+1; ++k) {
for (j=0; j<ny+1; ++j) {
for (i=0; i<nx+1; ++i) {
*coord++ = x[i];
*coord++ = y[j];
*coord++ = z[k];
}
}
}
}
/* ---------------------------------------------------------------------- */
static void
fill_layered_geometry_3d(struct UnstructuredGrid *G,
const double *x,
const double *y,
const double *z,
const double *depthz)
{
int i , j , k ;
int nx, ny, nz;
const double *depth;
double *coord;
nx = G->cartdims[0]; ny = G->cartdims[1]; nz = G->cartdims[2];
coord = G->node_coordinates;
for (k = 0; k < nz + 1; k++) {
depth = depthz;
for (j = 0; j < ny + 1; j++) {
for (i = 0; i < nx + 1; i++) {
*coord++ = x[i];
*coord++ = y[j];
*coord++ = z[k] + *depth++;
}
}
}
compute_geometry(G);
}
/* --------------------------------------------------------------------- */
static struct UnstructuredGrid*
allocate_cart_grid_2d(int nx, int ny)
{
int nxf, nyf;
int Nx , Ny ;
int ncells, nfaces, nnodes;
struct UnstructuredGrid *G;
Nx = nx + 1;
Ny = ny + 1;
nxf = Nx * ny;
nyf = nx * Ny;
ncells = nx * ny ;
nfaces = nxf + nyf;
nnodes = Nx * Ny ;
G = allocate_cart_grid(2, ncells, nfaces, nnodes);
if (G != NULL)
{
G->dimensions = 2 ;
G->cartdims[0] = nx;
G->cartdims[1] = ny;
G->cartdims[2] = 1 ;
G->number_of_cells = ncells;
G->number_of_faces = nfaces;
G->number_of_nodes = nnodes;
}
return G;
}
/* --------------------------------------------------------------------- */
static void
fill_cart_topology_2d(struct UnstructuredGrid *G)
{
int i,j;
int nx, ny;
int nxf;
int Nx;
int *fnodes, *fnodepos, *fcells, *cfaces, *cfacepos;
cfaces = G->cell_faces;
cfacepos = G->cell_facepos;
nx = G->cartdims[0];
ny = G->cartdims[1];
Nx = nx + 1;
nxf = Nx * ny;
cfacepos[0] = 0;
for (j=0; j<ny; ++j) {
for (i=0; i<nx; ++i) {
*cfaces++ = i+ Nx*j;
*cfaces++ = i+ nx*j +nxf;
*cfaces++ = i+1+Nx*j;
*cfaces++ = i+ nx*(j+1)+nxf;
cfacepos[1] = cfacepos[0]+4;
++cfacepos;
}
}
for (j = 0; j < nx * ny; ++j) {
G->cell_facetag[j*4 + 0] = 0;
G->cell_facetag[j*4 + 1] = 2;
G->cell_facetag[j*4 + 2] = 1;
G->cell_facetag[j*4 + 3] = 3;
}
fnodes = G->face_nodes;
fnodepos = G->face_nodepos;
fcells = G->face_cells;
fnodepos[0] = 0;
/* Faces with x-normal */
for (j=0; j<ny; ++j) {
for (i=0; i<nx+1; ++i) {
*fnodes++ = i+Nx*j;
*fnodes++ = i+Nx*(j+1);
fnodepos[1] = fnodepos[0] + 2;
++fnodepos;
if (i==0) {
*fcells++ = -1;
*fcells++ = i+nx*j;
}
else if (i == nx) {
*fcells++ = i-1+nx*j;
*fcells++ = -1;
}
else {
*fcells++ = i-1 + nx*j;
*fcells++ = i + nx*j;
}
}
}
/* Faces with y-normal */
for (j=0; j<ny+1; ++j) {
for (i=0; i<nx; ++i) {
*fnodes++ = i+1 + Nx*j;
*fnodes++ = i+ Nx*j;
fnodepos[1] = fnodepos[0] + 2;
++fnodepos;
if (j==0) {
*fcells++ = -1;
*fcells++ = i+nx*j;
}
else if (j == ny) {
*fcells++ = i+nx*(j-1);
*fcells++ = -1;
}
else {
*fcells++ = i+nx*(j-1);
*fcells++ = i+nx*j;
}
}
}
}
/* --------------------------------------------------------------------- */
static void
fill_cart_geometry_2d(struct UnstructuredGrid *G,
const double *x,
const double *y)
{
int i,j;
int nx, ny;
double dx, dy;
double *coord, *ccentroids, *cvolumes;
double *fnormals, *fcentroids, *fareas;
nx = G->cartdims[0];
ny = G->cartdims[1];
ccentroids = G->cell_centroids;
cvolumes = G->cell_volumes;
for (j=0; j<ny; ++j) {
for (i=0; i<nx; ++i) {
*ccentroids++ = (x[i] + x[i + 1]) / 2.0;
*ccentroids++ = (y[j] + y[j + 1]) / 2.0;
dx = x[i + 1] - x[i];
dy = y[j + 1] - y[j];
*cvolumes++ = dx * dy;
}
}
fnormals = G->face_normals;
fcentroids = G->face_centroids;
fareas = G->face_areas;
/* Faces with x-normal */
for (j=0; j<ny; ++j) {
for (i=0; i<nx+1; ++i) {
dy = y[j + 1] - y[j];
*fnormals++ = dy;
*fnormals++ = 0;
*fcentroids++ = x[i];
*fcentroids++ = (y[j] + y[j + 1]) / 2.0;
*fareas++ = dy;
}
}
/* Faces with y-normal */
for (j=0; j<ny+1; ++j) {
for (i=0; i<nx; ++i) {
dx = x[i + 1] - x[i];
*fnormals++ = 0;
*fnormals++ = dx;
*fcentroids++ = (x[i] + x[i + 1]) / 2.0;
*fcentroids++ = y[j];
*fareas++ = dx;
}
}
coord = G->node_coordinates;
for (j=0; j<ny+1; ++j) {
for (i=0; i<nx+1; ++i) {
*coord++ = x[i];
*coord++ = y[j];
}
}
}

View File

@ -1,172 +0,0 @@
/*===========================================================================
//
// File: cart_grid.h
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
//==========================================================================*/
/*
Copyright 2011 SINTEF ICT, Applied Mathematics.
Copyright 2011 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_CART_GRID_H_HEADER
#define OPM_CART_GRID_H_HEADER
/**
* \file
* Routines to construct fully formed grid structures from a simple Cartesian
* (i.e., tensor product) description.
*
* The cells are lexicographically ordered with the @c i index cycling the most
* rapidly, followed by the @c j index and then, in three space dimensions, the
* @c k (`layer') index as the least rapidly cycling index.
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* Form geometrically Cartesian grid in two space dimensions with equally
* sized cells.
*
* @param[in] nx Number of cells in @c x direction.
* @param[in] ny Number of cells in @c y direction.
* @param[in] dx Length, in meters, of each cell's @c x extent.
* @param[in] dy Length, in meters, of each cell's @c y extent.
*
* @return Fully formed grid structure containing valid geometric primitives.
* Must be destroyed using function destroy_grid().
*/
struct UnstructuredGrid *
create_grid_cart2d(int nx, int ny, double dx, double dy);
/**
* Form geometrically Cartesian grid in three space dimensions with unit-sized
* cells.
*
* @param[in] nx Number of cells in @c x direction.
* @param[in] ny Number of cells in @c y direction.
* @param[in] nz Number of cells in @c z direction.
*
* @return Fully formed grid structure containing valid geometric primitives.
* Must be destroyed using function destroy_grid().
*/
struct UnstructuredGrid *
create_grid_cart3d(int nx, int ny, int nz);
/**
* Form geometrically Cartesian grid in three space dimensions with equally
* sized cells.
*
* Each cell has physical size (volume) \f$\mathit{dx}\times \mathit{dy}\times
* \mathit{dz}\f$.
*
* @param[in] nx Number of cells in @c x direction.
* @param[in] ny Number of cells in @c y direction.
* @param[in] nz Number of cells in @c z direction.
*
* @param[in] dx Length, in meters, of each cell's @c x extent.
* @param[in] dy Length, in meters, of each cell's @c y extent.
* @param[in] dz Length, in meters, of each cell's @c z extent.
*
* @return Fully formed grid structure containing valid geometric primitives.
* Must be destroyed using function destroy_grid().
*/
struct UnstructuredGrid *
create_grid_hexa3d(int nx, int ny, int nz,
double dx, double dy, double dz);
/**
* Form tensor product (Cartesian) grid in two space dimensions.
*
* The size (volume) of cell \f$(i,j)\f$ is
* \f[
* v_{ij} = (x_{i+1} - x_i)\cdot (y_{j+1} - y_j)
* \f]
* Similar relations hold for the cell and interface centroids as well as the
* interface areas and normal vectors. In other words, cell \f$(i,j)\f$ is the
* convex hull bounded by the tensor product of nodes \f$x_i\f$, \f$x_{i+1}\f$,
* \f$y_j\f$, and \f$y_{j+1}\f$.
*
* @param[in] nx Number of cells in @c x direction.
* @param[in] ny Number of cells in @c y direction.
*
* @param[in] x Position along @c x axis of each grid line with constant @c x
* coordinate. Array of size <CODE>nx + 1</CODE>.
* @param[in] y Position along @c y axis of each grid line with constant @c y
* coordinate. Array of size <CODE>ny + 1</CODE>.
*
* @return Fully formed grid structure containing valid geometric primitives.
* Must be destroyed using function destroy_grid().
*/
struct UnstructuredGrid *
create_grid_tensor2d(int nx, int ny,
const double *x , const double *y );
/**
* Form tensor product (i.e., topologically Cartesian) grid in three space
* dimensions--possibly with a variable top-layer topography.
*
* If @c depthz is @c NULL, then geometric information such as volumes and
* centroids is calculated from analytic expressions. Otherwise, these values
* are computed using function compute_geometry().
*
* @param[in] nx Number of cells in @c x direction.
* @param[in] ny Number of cells in @c y direction.
* @param[in] nz Number of cells in @c z direction.
*
* @param[in] x Position along @c x axis of each grid line with constant @c x
* coordinate. Array of size <CODE>nx + 1</CODE>.
* @param[in] y Position along @c y axis of each grid line with constant @c y
* coordinate. Array of size <CODE>ny + 1</CODE>.
* @param[in] z Distance (depth) from top-layer measured along the @c z axis of
* each grid line with constant @c z coordinate. Array of size
* <CODE>nz + 1</CODE>.
*
* @param[in] depthz
* Top-layer topography specification. If @c NULL, interpreted as
* horizontal top-layer at <CODE>z=0</CODE>. Otherwise, must be
* an array of size <CODE>(nx + 1) * (ny + 1)</CODE>, ordered
* lexicographically, that defines the depth of each top-layer
* pillar vertex.
*
* @return Fully formed grid structure containing valid geometric primitives.
* Must be destroyed using function destroy_grid().
*/
struct UnstructuredGrid *
create_grid_tensor3d(int nx ,
int ny ,
int nz ,
const double *x ,
const double *y ,
const double *z ,
const double *depthz);
#ifdef __cplusplus
}
#endif
#endif /* OPM_CART_GRID_H_HEADER */

View File

@ -1,235 +0,0 @@
/*===========================================================================
//
// File: cgridinterface.c
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
//==========================================================================*/
/*
Copyright 2011 SINTEF ICT, Applied Mathematics.
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <opm/core/grid/cornerpoint_grid.h>
#include <opm/core/grid/cpgpreprocess/geometry.h>
#include <opm/core/grid/cpgpreprocess/preprocess.h>
#include <opm/core/grid.h>
static int
fill_cell_topology(struct processed_grid *pg,
struct UnstructuredGrid *g )
{
int f, c1, c2, tag;
size_t c, nc, nhf;
nc = g->number_of_cells;
g->cell_facepos = malloc((nc + 1) * sizeof *g->cell_facepos);
if (g->cell_facepos != NULL) {
/* Allocate and initialise compressed cell-to-face topology. */
for (c = 0; c < nc + 1; c++) { g->cell_facepos[c] = 0; }
for (f = 0; f < g->number_of_faces; f++) {
c1 = g->face_cells[2*f + 0];
c2 = g->face_cells[2*f + 1];
if (c1 >= 0) { g->cell_facepos[c1 + 1] += 1; }
if (c2 >= 0) { g->cell_facepos[c2 + 1] += 1; }
}
for (c = 1; c <= nc; c++) {
g->cell_facepos[0] += g->cell_facepos[c];
g->cell_facepos[c] = g->cell_facepos[0] - g->cell_facepos[c];
}
nhf = g->cell_facepos[0];
g->cell_facepos[0] = 0;
g->cell_faces = malloc(nhf * sizeof *g->cell_faces );
g->cell_facetag = malloc(nhf * sizeof *g->cell_facetag);
if ((g->cell_faces == NULL) || (g->cell_facetag == NULL)) {
free(g->cell_facetag); g->cell_facetag = NULL;
free(g->cell_faces); g->cell_faces = NULL;
free(g->cell_facepos); g->cell_facepos = NULL;
}
}
if (g->cell_facepos != NULL) {
/* Compute final cell-to-face mapping and half-face tags.
*
* Process relies on preprocess() producing neighbourship
* definitions for which the normals point (logically) in the
* positive I,J,K directions *and* from ->face_cells[2*f+0] to
* ->face_cells[2*f+1] (i.e., from first to second cell of
* interface 'f'--be it internal or outer).
*
* For instance, a "LEFT" connection (pg->face_tag==LEFT==0)
* for which the normal points into the cell (i.e., when
* ->face_cells[2*f+1] >= 0), is a half-face of type 0.
*
* Simlarly, a "TOP" connection (pg->face_tag==TOP==2) for
* which the normal points out of the cell (i.e., when
* ->face_cells[2*f+0] >= 0), is a half-face of type 5. */
for (f = 0; f < g->number_of_faces; f++) {
tag = 2 * pg->face_tag[f]; /* [0, 2, 4] */
c1 = g->face_cells[2*f + 0];
c2 = g->face_cells[2*f + 1];
if (c1 >= 0) {
g->cell_faces [ g->cell_facepos[c1 + 1] ] = f;
g->cell_facetag [ g->cell_facepos[c1 + 1] ] = tag + 1;
g->cell_facepos[c1 + 1] += 1;
}
if (c2 >= 0) {
g->cell_faces [ g->cell_facepos[c2 + 1] ] = f;
g->cell_facetag [ g->cell_facepos[c2 + 1] ] = tag + 0;
g->cell_facepos[c2 + 1] += 1;
}
}
}
return g->cell_facepos != NULL;
}
static int
allocate_geometry(struct UnstructuredGrid *g)
{
int ok;
size_t nc, nf, nd;
assert (g->dimensions == 3);
nc = g->number_of_cells;
nf = g->number_of_faces;
nd = 3;
g->face_areas = malloc(nf * 1 * sizeof *g->face_areas);
g->face_centroids = malloc(nf * nd * sizeof *g->face_centroids);
g->face_normals = malloc(nf * nd * sizeof *g->face_normals);
g->cell_volumes = malloc(nc * 1 * sizeof *g->cell_volumes);
g->cell_centroids = malloc(nc * nd * sizeof *g->cell_centroids);
ok = g->face_areas != NULL;
ok += g->face_centroids != NULL;
ok += g->face_normals != NULL;
ok += g->cell_volumes != NULL;
ok += g->cell_centroids != NULL;
return ok == 5;
}
void compute_geometry(struct UnstructuredGrid *g)
{
assert (g != NULL);
if (g!=NULL)
{
assert (g->face_centroids != NULL);
assert (g->face_normals != NULL);
assert (g->face_areas != NULL);
assert (g->cell_centroids != NULL);
assert (g->cell_volumes != NULL);
compute_face_geometry(g->dimensions , g->node_coordinates,
g->number_of_faces, g->face_nodepos,
g->face_nodes, g->face_normals,
g->face_centroids, g->face_areas);
compute_cell_geometry(g->dimensions, g->node_coordinates,
g->face_nodepos, g->face_nodes,
g->face_cells, g->face_normals,
g->face_centroids, g->number_of_cells,
g->cell_facepos, g->cell_faces,
g->cell_centroids, g->cell_volumes);
}
}
struct UnstructuredGrid *
create_grid_cornerpoint(const struct grdecl *in, double tol)
{
struct UnstructuredGrid *g;
int ok;
struct processed_grid pg;
g = create_grid_empty();
if (g == NULL)
{
return NULL;
}
process_grdecl(in, tol, &pg);
/*
* Convert "struct processed_grid" to "struct UnstructuredGrid".
*
* In particular, convey resource ownership from 'pg' to 'g'.
* Consequently, memory resources obtained in process_grdecl()
* will be released in destroy_grid().
*/
g->dimensions = 3;
g->number_of_nodes = pg.number_of_nodes;
g->number_of_faces = pg.number_of_faces;
g->number_of_cells = pg.number_of_cells;
g->node_coordinates = pg.node_coordinates;
g->face_nodes = pg.face_nodes;
g->face_nodepos = pg.face_ptr;
g->face_cells = pg.face_neighbors;
/* Explicitly relinquish resource references conveyed to 'g'. This
* is needed to avoid creating dangling references in the
* free_processed_grid() call. */
pg.node_coordinates = NULL;
pg.face_nodes = NULL;
pg.face_ptr = NULL;
pg.face_neighbors = NULL;
/* allocate and fill g->cell_faces/g->cell_facepos and
* g->cell_facetag as well as the geometry-related fields. */
ok = fill_cell_topology(&pg, g);
ok = ok && allocate_geometry(g);
if (!ok)
{
destroy_grid(g);
g = NULL;
}
else
{
compute_geometry(g);
g->cartdims[0] = pg.dimensions[0];
g->cartdims[1] = pg.dimensions[1];
g->cartdims[2] = pg.dimensions[2];
g->global_cell = pg.local_cell_index;
/* Explicitly relinquish resource references conveyed to 'g'.
* This is needed to avoid creating dangling references in the
* free_processed_grid() call. */
pg.local_cell_index = NULL;
}
free_processed_grid(&pg);
return g;
}

View File

@ -1,103 +0,0 @@
/*===========================================================================
//
// File: preprocess.h
//
// Created: Fri Jun 19 08:43:04 2009
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
// $Date: 2010-08-27 19:12:16 +0200 (Fri, 27 Aug 2010) $
//
// $Revision: 930 $
//
//==========================================================================*/
/*
Copyright 2010, 2011, 2012 SINTEF ICT, Applied Mathematics.
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_CORNERPOINT_GRID_HEADER_INCLUDED
#define OPM_CORNERPOINT_GRID_HEADER_INCLUDED
/**
* \file
* Routines to form a complete UnstructuredGrid from a corner-point
* specification.
*/
#include <opm/core/grid.h>
#include <opm/core/grid/cpgpreprocess/preprocess.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Construct grid representation from corner-point specification of a
* particular geological model.
*
* Pinched cells will be removed irrespective of any explicit "active" map
* in the geological model input specification. Geometric primitives such
* as cell barycenters (i.e., centroids), volumes and interface areas are
* computed internally using function compute_geometry(). The caller does
* not need to compute this information separately.
*
* @param[in] in Corner-point specification. If "actnum" is NULL, then the
* specification is interpreted as if all cells are initially
* active.
*
* @param[in] tol Absolute tolerance of node-coincidence.
*
* @return Fully formed grid data structure that manages the grid defined by
* the input corner-point specification. Must be destroyed using function
* destroy_grid().
*/
struct UnstructuredGrid *
create_grid_cornerpoint(const struct grdecl *in, double tol);
/**
* Compute derived geometric primitives in a grid.
*
* This function computes values for each of the following quantities
* - Quantities pertaining to interfaces (connections, faces)
* -# Barycenters (centroids), <CODE>g->dimensions</CODE> scalars per face
* stored sequentially in <CODE>g->face_centroids</CODE>.
* -# Areas, one scalar per face stored sequentially in
* <CODE>g->face_areas</CODE>.
* -# Normals, <CODE>g->dimensions</CODE> scalars per face stored
* sequentially in <CODE>g->face_normals</CODE>. The Euclidian norm of
* each normal is equal to the corresponding face's area.
*
* - Quantities pertaining to cells (volumes)
* -# Barycenters (centroids), <CODE>g->dimensions</CODE> scalars per cell
* stored sequentially in <CODE>g->cell_centroids</CODE>.
* -# Volumes, one scalar per cell stored sequentially in
* <CODE>g->cell_volumes</CODE>.
*
* These fields must be allocated prior to calling compute_geometry().
*
* @param[in,out] g Grid structure.
*/
void compute_geometry(struct UnstructuredGrid *g);
#ifdef __cplusplus
}
#endif
#endif /* OPM_CORNERPOINT_GRID_HEADER_INCLUDED */

View File

@ -1,369 +0,0 @@
/*===========================================================================
//
// File: facetopology.c
//
// Created: Fri Jun 19 08:46:53 2009
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
// $Date$
//
// $Revision$
//
//===========================================================================*/
/*
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010 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 "config.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "preprocess.h"
#include "facetopology.h"
/* No checking of input arguments in this code! */
#define MIN(i,j) ((i)<(j) ? (i) : (j))
#define MAX(i,j) ((i)>(j) ? (i) : (j))
#define DEBUG 1
/*------------------------------------------------------*/
/* */
/* */
/* Find connections for each pair of pillars */
/* */
/* */
/* */
/*------------------------------------------------------*/
/* Determine face topology first, then compute intersection. */
/* All intersections that occur are present in the final face geometry.*/
static int *
computeFaceTopology(const int *a1, const int *a2,
const int *b1, const int *b2,
int intersect[4], int *faces)
{
int mask[8];
int k;
int *f;
for (k = 0; k < 8; k++) { mask[k] = -1; }
/* Which pillar points should we use? */
if (a1[1] > b1[1]){ mask[0] = b1[1]; } else { mask[0] = a1[1]; }
if (a2[1] > b2[1]){ mask[2] = b2[1]; } else { mask[2] = a2[1]; }
if (a2[0] > b2[0]){ mask[4] = a2[0]; } else { mask[4] = b2[0]; }
if (a1[0] > b1[0]){ mask[6] = a1[0]; } else { mask[6] = b1[0]; }
#if DEBUG
/* Illegal situations */
if (mask [0] == mask[2] ||
mask [0] == mask[4] ||
mask [2] == mask[6] ||
mask [4] == mask[6]){
fprintf(stderr, "Illegal Partial pinch!\n");
}
#endif
/* Partial pinch of face */
if (mask[0] == mask[6]){
mask[6] = -1;
}
if (mask[2] == mask[4]){
mask[4] = -1;
}
/* Get shape of face: */
/* each new intersection will be part of the new face, */
/* but not all pillar points. This is encoded in mask. */
mask[1] = intersect[3]; /* top-top */
mask[3] = -1;
mask[5] = intersect[0]; /* bottom-bottom*/
mask[7] = -1;
/* bottom-top */
if (intersect[1] != -1){
if(a1[0] > b1[1]){ /* intersection[1] left of (any) intersection[0] */
mask[0] = -1;
mask[6] = -1;
mask[7] = intersect[1];
}
else{
mask[2] = -1;
mask[4] = -1;
mask[3] = intersect[1];
}
}
/* top-bottom */
if (intersect[2] != -1){
if(a1[1] < b1[0]){ /* intersection[2] left of (any) intersection[3] */
mask[0] = -1;
mask[6] = -1;
mask[7] = intersect[2];
}
else{
mask[2] = -1;
mask[4] = -1;
mask[3] = intersect[2];
}
}
f = faces;
for (k=7; k>=0; --k){
if(mask[k] != -1){
*f++ = mask[k];
}
}
#if DEBUG>1
/* Check for repeated nodes:*/
int i;
fprintf(stderr, "face: ");
for (i=0; i<8; ++i){
fprintf(stderr, "%d ", mask[i]);
for (k=0; k<8; ++k){
if (i!=k && mask[i] != -1 && mask[i] == mask[k]){
fprintf(stderr, "Repeated node in faulted face\n");
}
}
}
fprintf(stderr, "\n");
#endif
return f;
}
/* a) If we assume that the index increase when z increase for each
pillar (but only separately), we can use only the point indices,
since we only need to compare z-values on one pillar at a time.
b) We assume input is preprocessed such that no intersections occur
on the first and last lines, for instance by padding the grid with
extra cells. This is convenient in the identification of (unique)
intersections.
*/
#define LINE_INTERSECTION(a1, a2, b1, b2) \
(((a1 > b1) && (a2 < b2)) || \
((a1 < b1) && (a2 > b2)))
static int
faceintersection(const int *a1, const int *a2,
const int *b1, const int *b2)
{
return
MAX(a1[0], b1[0]) < MIN(a1[1], b1[1]) ||
MAX(a2[0], b2[0]) < MIN(a2[1], b2[1]) ||
LINE_INTERSECTION(a1[0], a2[0], b1[0], b2[0]) ||
LINE_INTERSECTION(a1[1], a2[1], b1[1], b2[1]);
}
#define MEANINGFUL_FACE(i, j) \
(! ((a1[i] == INT_MIN) && (b1[j] == INT_MIN)) && \
! ((a1[i+1] == INT_MAX) && (b1[j+1] == INT_MAX)))
/* work should be pointer to 2n ints initialised to zero . */
void findconnections(int n, int *pts[4],
int *intersectionlist,
int *work,
struct processed_grid *out)
{
/* vectors of point numbers for faces a(b) on pillar 1(2) */
int *a1 = pts[0];
int *a2 = pts[1];
int *b1 = pts[2];
int *b2 = pts[3];
/* Intersection record for top line and bottomline of a */
int *itop = work;
int *ibottom = work + n;
int *f = out->face_nodes + out->face_ptr[out->number_of_faces];
int *c = out->face_neighbors + 2*out->number_of_faces;
int k1 = 0;
int k2 = 0;
int i,j=0;
int intersect[4];
int *tmp;
/* for (i=0; i<2*n; work[i++]=-1); */
for (i = 0; i < 4; i++) { intersect[i] = -1; }
for (i = 0; i < n - 1; ++i) {
/* pinched a-cell */
if ((a1[i] == a1[i + 1]) &&
(a2[i] == a2[i + 1])) {
continue;
}
while ((j < n-1) &&
((b1[j] < a1[i + 1]) ||
(b2[j] < a2[i + 1])))
{
/* pinched b-cell */
if ((b1[j] == b1[j + 1]) &&
(b2[j] == b2[j + 1])) {
itop[j+1] = itop[j];
++j;
continue;
}
/* --------------------------------------------------------- */
/* face a(i,i+1) and face b(j,j+1) have nonzero intersection */
/* --------------------------------------------------------- */
if (faceintersection(a1+i, a2+i, b1+j, b2+j)){
/* Completely matching faces */
if (((a1[i] == b1[j]) && (a1[i+1] == b1[j+1])) &&
((a2[i] == b2[j]) && (a2[i+1] == b2[j+1]))) {
if (MEANINGFUL_FACE(i, j)) {
int cell_a = i%2 != 0 ? (i-1)/2 : -1;
int cell_b = j%2 != 0 ? (j-1)/2 : -1;
if (cell_a != -1 || cell_b != -1){
*c++ = cell_a;
*c++ = cell_b;
/* face */
*f++ = a1[i];
*f++ = a2[i];
/* avoid duplicating nodes in pinched faces */
if (a2[i+1] != a2[i]) { *f++ = a2[i+1]; }
if (a1[i+1] != a1[i]) { *f++ = a1[i+1]; }
out->face_ptr[++out->number_of_faces] = f - out->face_nodes;
}
else{
;
}
}
}
/* Non-matching faces */
else{
/* Find new intersection */
if (LINE_INTERSECTION(a1[i+1], a2[i+1],
b1[j+1], b2[j+1])) {
itop[j+1] = out->number_of_nodes++;
/* store point numbers of intersecting lines */
*intersectionlist++ = a1[i+1];
*intersectionlist++ = a2[i+1];
*intersectionlist++ = b1[j+1];
*intersectionlist++ = b2[j+1];
}else{
itop[j+1] = -1;
}
/* Update intersection record */
intersect[0] = ibottom[j ]; /* i x j */
intersect[1] = ibottom[j+1]; /* i x j+1 */
intersect[2] = itop[j ]; /* i+1 x j */
intersect[3] = itop[j+1]; /* i+1 x j+1 */
/* Add face to list of faces if no INT_MIN or
* INT_MAX appear in a or b. */
if (MEANINGFUL_FACE(i,j)) {
/*
Even indices refer to space between cells,
odd indices refer to cells
*/
int cell_a = i%2 != 0 ? (i-1)/2 : -1;
int cell_b = j%2 != 0 ? (j-1)/2 : -1;
if (cell_a != -1 || cell_b != -1){
*c++ = cell_a;
*c++ = cell_b;
f = computeFaceTopology(a1+i, a2+i, b1+j, b2+j, intersect, f);
out->face_ptr[++out->number_of_faces] = f - out->face_nodes;
}
else{
;
}
}
}
}
/* Update candidates for restart of j for in next i-iteration */
if (b1[j] < a1[i+1]) { k1 = j; }
if (b2[j] < a2[i+1]) { k2 = j; }
j = j+1;
}
/* Swap intersection records: top line of a[i,i+1] is bottom
* line of a[i+1,i+2] */
tmp = itop; itop = ibottom; ibottom = tmp;
/* Zero out the "new" itop */
for(j=0;j<n; ++j) { itop[j]=-1; }
/* Set j to appropriate start position for next i */
j = MIN(k1, k2);
}
}
/* Local Variables: */
/* c-basic-offset:4 */
/* End: */

View File

@ -1,48 +0,0 @@
/*===========================================================================
//
// File: facetopology.h
//
// Created: Fri Jun 19 08:47:10 2009
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
// $Date$
//
// $Revision$
//
//===========================================================================*/
/*
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010 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_FACETOPOLOGY_HEADER
#define OPM_FACETOPOLOGY_HEADER
void findconnections(int n, int *pts[4],
int *intersectionlist,
int *work,
struct processed_grid *out);
#endif /* OPM_FACETOPOLOGY_HEADER */
/* Local Variables: */
/* c-basic-offset:4 */
/* End: */

View File

@ -1,460 +0,0 @@
/*
* Copyright 2010 (c) SINTEF ICT, Applied Mathematics.
* Jostein R. Natvig <Jostein.R.Natvig at sintef.no>
*/
#include "config.h"
#include <math.h>
#include <stdio.h>
#include "geometry.h"
#include <assert.h>
/* ------------------------------------------------------------------ */
static void
cross(const double u[3], const double v[3], double w[3])
/* ------------------------------------------------------------------ */
{
w[0] = u[1]*v[2]-u[2]*v[1];
w[1] = u[2]*v[0]-u[0]*v[2];
w[2] = u[0]*v[1]-u[1]*v[0];
}
/* ------------------------------------------------------------------ */
static double
norm(const double w[3])
/* ------------------------------------------------------------------ */
{
return sqrt(w[0]*w[0] + w[1]*w[1] + w[2]*w[2]);
}
/* ------------------------------------------------------------------ */
static void
compute_face_geometry_3d(double *coords, int nfaces,
int *nodepos, int *facenodes, double *fnormals,
double *fcentroids, double *fareas)
/* ------------------------------------------------------------------ */
{
/* Assume 3D for now */
const int ndims = 3;
int f;
double x[3];
double u[3];
double v[3];
double w[3];
int i,k;
int node;
double cface[3] = {0};
double n[3] = {0};
double twothirds = 0.666666666666666666666666666667;
double a;
int num_face_nodes;
double area;
/*#pragma omp parallel for */
/*#pragma omp parallel for shared(fnormals,fcentroids,fareas)*/
#pragma omp parallel for default(none) \
private(f,x,u,v,w,i,k,node,cface,n,a,num_face_nodes,area) \
shared(fnormals,fcentroids,fareas \
,coords, nfaces, nodepos, facenodes, twothirds)
for (f=0; f<nfaces; ++f)
{
for(i=0; i<ndims; ++i) x[i] = 0.0;
for(i=0; i<ndims; ++i) n[i] = 0.0;
for(i=0; i<ndims; ++i) cface[i] = 0.0;
/* average node */
for(k=nodepos[f]; k<nodepos[f+1]; ++k)
{
node = facenodes[k];
for (i=0; i<ndims; ++i) x[i] += coords[3*node+i];
}
num_face_nodes = nodepos[f+1] - nodepos[f];
for(i=0; i<ndims; ++i) x[i] /= num_face_nodes;
/* compute first vector u (to the last node in the face) */
node = facenodes[nodepos[f+1]-1];
for(i=0; i<ndims; ++i) u[i] = coords[3*node+i] - x[i];
area=0.0;
/* Compute triangular contrib. to face normal and face centroid*/
for(k=nodepos[f]; k<nodepos[f+1]; ++k)
{
node = facenodes[k];
for (i=0; i<ndims; ++i) v[i] = coords[3*node+i] - x[i];
cross(u,v,w);
a = 0.5*norm(w);
area += a;
/* if(!(a>0))
{
fprintf(stderr, "Internal error in compute_face_geometry.");
}
*/
/* face normal */
for (i=0; i<ndims; ++i) n[i] += w[i];
/* face centroid */
for (i=0; i<ndims; ++i)
cface[i] += a*(x[i]+twothirds*0.5*(u[i]+v[i]));
/* Store v in u for next iteration */
for (i=0; i<ndims; ++i) u[i] = v[i];
}
/* Store face normal and face centroid */
for (i=0; i<ndims; ++i)
{
/* normal is scaled with face area */
fnormals [3*f+i] = 0.5*n[i];
fcentroids[3*f+i] = cface[i]/area;
}
fareas[f] = area;
}
}
/* ------------------------------------------------------------------ */
static void
compute_edge_geometry_2d(
/* in */ double *node_coords,
/* in */ int num_edges,
/* in */ int *edge_node_pos,
/* in */ int *edge_nodes,
/* out */ double *edge_normals,
/* out */ double *edge_midpoints,
/* out */ double *edge_lengths)
{
const int num_dims = 2;
/* offsets to each of the nodes in a compacted edge */
const int a_ofs = 0;
const int b_ofs = 1;
/* offsets to each dimension is a compacted point */
const int x_ofs = 0;
const int y_ofs = 1;
int edge; /* edge index */
int a_nod, b_nod; /* node indices */
double a_x, a_y, b_x, b_y; /* node coordinates */
double v_x, v_y; /* vector elements */
/* decompose each edge into a tuple (a,b) between two points and
* compute properties for that face. hopefully the host has enough
* cache pages to keep both input and output at the same time, and
* registers for all the local variables */
for (edge = 0; edge < num_edges; ++edge)
{
/* an edge in 2D can only have starting and ending point
* check that there are exactly two nodes till the next edge */
assert (edge_node_pos[edge + 1] - edge_node_pos[edge] == num_dims);
/* get the first and last point on the edge */
a_nod = edge_nodes[edge_node_pos[edge] + a_ofs];
b_nod = edge_nodes[edge_node_pos[edge] + b_ofs];
/* extract individual coordinates for the points */
a_x = node_coords[a_nod * num_dims + x_ofs];
a_y = node_coords[a_nod * num_dims + y_ofs];
b_x = node_coords[b_nod * num_dims + x_ofs];
b_y = node_coords[b_nod * num_dims + y_ofs];
/* compute edge center -- average of node coordinates */
edge_midpoints[edge * num_dims + x_ofs] = (a_x + b_x) * 0.5;
edge_midpoints[edge * num_dims + y_ofs] = (a_y + b_y) * 0.5;
/* vector from first to last point */
v_x = b_x - a_x;
v_y = b_y - a_y;
/* two-dimensional (unary) cross product analog that makes the
* "triple" (dot-cross) product zero, i.e. it's a normal; the
* direction of this vector is such that it will be pointing
* inwards when enumerating nodes clock-wise */
edge_normals[edge * num_dims + x_ofs] = +v_y;
edge_normals[edge * num_dims + y_ofs] = -v_x;
/* Euclidian norm in two dimensions is magnitude of edge */
edge_lengths[edge] = sqrt(v_x*v_x + v_y*v_y);
}
}
/* ------------------------------------------------------------------ */
void
compute_face_geometry(int ndims, double *coords, int nfaces,
int *nodepos, int *facenodes, double *fnormals,
double *fcentroids, double *fareas)
/* ------------------------------------------------------------------ */
{
if (ndims == 3)
{
compute_face_geometry_3d(coords, nfaces, nodepos, facenodes,
fnormals, fcentroids, fareas);
}
else if (ndims == 2)
{
/* two-dimensional interfaces are called 'edges' */
compute_edge_geometry_2d(coords, nfaces, nodepos, facenodes,
fnormals, fcentroids, fareas);
}
else
{
assert(0);
}
}
/* ------------------------------------------------------------------ */
static void
compute_cell_geometry_3d(double *coords,
int *nodepos, int *facenodes, int *neighbors,
double *fnormals,
double *fcentroids,
int ncells, int *facepos, int *cellfaces,
double *ccentroids, double *cvolumes)
/* ------------------------------------------------------------------ */
{
const int ndims = 3;
int i,k, f,c;
int face,node;
double x[3];
double u[3];
double v[3];
double w[3];
double xcell[3];
double ccell[3];
double cface[3] = {0};
int num_faces;
double volume;
double tet_volume, subnormal_sign;
double twothirds = 0.666666666666666666666666666667;
#pragma omp parallel for default(none) \
private(i,k,f,c,face,node,x,u,v,w,xcell \
,ccell ,cface,num_faces,volume, tet_volume, subnormal_sign) \
shared(coords,nodepos,facenodes,neighbors,twothirds, \
fnormals,fcentroids,facepos,cellfaces,ccentroids,cvolumes) \
firstprivate(ncells)
for (c=0; c<ncells; ++c)
{
for(i=0; i<ndims; ++i) xcell[i] = 0.0;
for(i=0; i<ndims; ++i) ccell[i] = 0.0;
/*
* Approximate cell center as average of face centroids
*/
for(f=facepos[c]; f<facepos[c+1]; ++f)
{
face = cellfaces[f];
for (i=0; i<ndims; ++i) xcell[i] += fcentroids[3*face+i];
}
num_faces = facepos[c+1] - facepos[c];
for(i=0; i<ndims; ++i) xcell[i] /= num_faces;
/*
* For all faces, add tetrahedron's volume and centroid to
* 'cvolume' and 'ccentroid'.
*/
volume=0.0;
for(f=facepos[c]; f<facepos[c+1]; ++f)
{
int num_face_nodes;
for(i=0; i<ndims; ++i) x[i] = 0.0;
for(i=0; i<ndims; ++i) cface[i] = 0.0;
face = cellfaces[f];
/* average face node x */
for(k=nodepos[face]; k<nodepos[face+1]; ++k)
{
node = facenodes[k];
for (i=0; i<ndims; ++i) x[i] += coords[3*node+i];
}
num_face_nodes = nodepos[face+1] - nodepos[face];
for(i=0; i<ndims; ++i) x[i] /= num_face_nodes;
/* compute first vector u (to the last node in the face) */
node = facenodes[nodepos[face+1]-1];
for(i=0; i<ndims; ++i) u[i] = coords[3*node+i] - x[i];
/* Compute triangular contributions to face normal and face centroid */
for(k=nodepos[face]; k<nodepos[face+1]; ++k)
{
node = facenodes[k];
for (i=0; i<ndims; ++i) v[i] = coords[3*node+i] - x[i];
cross(u,v,w);
tet_volume = 0.0;
for(i=0; i<ndims; ++i){
tet_volume += w[i]*(x[i]-xcell[i]);
}
tet_volume *= 0.5 / 3;
subnormal_sign=0.0;
for(i=0; i<ndims; ++i){
subnormal_sign += w[i]*fnormals[3*face+i];
}
if(subnormal_sign < 0.0){
tet_volume = -tet_volume;
}
if(!(neighbors[2*face+0]==c)){
tet_volume = -tet_volume;
}
volume += tet_volume;
/* face centroid of triangle */
for (i=0; i<ndims; ++i) cface[i] = (x[i]+(twothirds)*0.5*(u[i]+v[i]));
/* Cell centroid */
for (i=0; i<ndims; ++i) ccell[i] += tet_volume * 3/4.0*(cface[i] - xcell[i]);
/* Store v in u for next iteration */
for (i=0; i<ndims; ++i) u[i] = v[i];
}
}
for (i=0; i<ndims; ++i) ccentroids[3*c+i] = xcell[i] + ccell[i]/volume;
cvolumes[c] = volume;
}
}
/* ------------------------------------------------------------------ */
static void
compute_cell_geometry_2d(
/* in */ double *node_coords,
/* in */ int *edge_node_pos,
/* in */ int *edge_nodes,
/* in */ double *edge_midpoints,
/* in */ int num_cells,
/* in */ int *cell_edge_pos,
/* in */ int *cell_edges,
/* out */ double *cell_centers,
/* out */ double *cell_areas)
{
const int num_dims = 2;
/* offsets to each of the nodes in a compacted edge */
const int a_ofs = 0;
const int b_ofs = 1;
/* offsets to each dimension is a compacted point */
const int x_ofs = 0;
const int y_ofs = 1;
int cell; /* cell index */
int num_nodes; /* number of vertices in current cell */
int edge_ndx; /* relative edge index within cell */
int edge; /* absolute cell index */
double center_x; /* x-coordinate for cell barycenter */
double center_y; /* y-coordinate for cell barycenter */
double area; /* (accumulated) cell area */
int a_nod, b_nod; /* node indices for edge start and end points */
double a_x, a_y,
b_x, b_y; /* vectors from center to edge points */
for (cell = 0; cell < num_cells; ++cell)
{
/* since the cell is a closed polygon, each point serves as the starting
* point of one edge and the ending point of another; thus there is as
* many vertices as there are edges */
num_nodes = cell_edge_pos[cell + 1] - cell_edge_pos[cell];
/* to enumerate all vertices of a cell, we would have to expand the
* edges and then remove duplicates. however, the centroid of each
* edge contains half of the two vertices that are incident on it. if
* we instead sum all the face centroids, we get the sum of all the
* vertices */
center_x = 0.;
center_y = 0.;
for (edge_ndx = cell_edge_pos[cell];
edge_ndx < cell_edge_pos[cell + 1]; ++edge_ndx)
{
edge = cell_edges[edge_ndx];
center_x += edge_midpoints[edge * num_dims + x_ofs];
center_y += edge_midpoints[edge * num_dims + y_ofs];
}
center_x /= (double) num_nodes;
center_y /= (double) num_nodes;
cell_centers[cell * num_dims + x_ofs] = center_x;
cell_centers[cell * num_dims + y_ofs] = center_y;
/* triangulate the polygon by introducing the cell center and then new
* internal edges from this center to the vertices. the total area of
* the cell is the sum of area of these sub-triangles */
area = 0.;
for (edge_ndx = cell_edge_pos[cell];
edge_ndx < cell_edge_pos[cell + 1]; ++edge_ndx)
{
/* indirect lookup of edge index (from array that contains all the
* edge indices for a certain cell) */
edge = cell_edges[edge_ndx];
/* get the first and last point on the edge */
a_nod = edge_nodes[edge_node_pos[edge] + a_ofs];
b_nod = edge_nodes[edge_node_pos[edge] + b_ofs];
/* vector from center to each of the nodes */
a_x = node_coords[a_nod * num_dims + x_ofs] - center_x;
a_y = node_coords[a_nod * num_dims + y_ofs] - center_y;
b_x = node_coords[b_nod * num_dims + x_ofs] - center_x;
b_y = node_coords[b_nod * num_dims + y_ofs] - center_y;
/* two-dimensional (binary) cross product analog that has length
* equal to the parallelogram spanned by the two vectors (but which
* is a scalar). the sign tells us the orientation between the nodes
* a and b, but we are not interested in that, just the area */
area += fabs(a_x * b_y - a_y * b_x);
}
/* we summed parallelograms which are twice the size of the triangles
* that make up the cell; divide out the half for all terms here */
area *= 0.5;
cell_areas[cell] = area;
}
}
/* ------------------------------------------------------------------ */
void
compute_cell_geometry(int ndims, double *coords,
int *nodepos, int *facenodes, int *neighbors,
double *fnormals,
double *fcentroids,
int ncells, int *facepos, int *cellfaces,
double *ccentroids, double *cvolumes)
/* ------------------------------------------------------------------ */
{
if (ndims == 3)
{
compute_cell_geometry_3d(coords, nodepos, facenodes,
neighbors, fnormals, fcentroids, ncells,
facepos, cellfaces, ccentroids, cvolumes);
}
else if (ndims == 2)
{
compute_cell_geometry_2d(coords, nodepos, facenodes, fcentroids,
ncells, facepos, cellfaces, ccentroids,
cvolumes);
}
else
{
assert(0);
}
}

View File

@ -1,19 +0,0 @@
/*
* Copyright 2010 (c) SINTEF ICT, Applied Mathematics.
* Jostein R. Natvig <Jostein.R.Natvig at sintef.no>
*/
#ifndef MRST_GEOMETRY_H_INCLUDED
#define MRST_GEOMETRY_H_INCLUDED
void compute_face_geometry(int ndims, double *coords, int nfaces,
int *nodepos, int *facenodes,
double *fnormals, double *fcentroids,
double *fareas);
void compute_cell_geometry(int ndims, double *coords,
int *nodepos, int *facenodes, int *neighbours,
double *fnormals,
double *fcentroids, int ncells,
int *facepos, int *cellfaces,
double *ccentroids, double *cvolumes);
#endif /* MRST_GEOMETRY_H_INCLUDED */

View File

@ -1,956 +0,0 @@
/*===========================================================================
//
// File: preprocess.c
//
// Created: Fri Jun 19 08:42:39 2009
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
// $Date$
//
// $Revision$
//
//==========================================================================*/
/*
Copyright 2009, 2010, 2011, 2012 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010, 2011, 2012 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 "config.h"
#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "preprocess.h"
#include "uniquepoints.h"
#include "facetopology.h"
#define MIN(i,j) ((i)<(j) ? (i) : (j))
#define MAX(i,j) ((i)>(j) ? (i) : (j))
static void
compute_cell_index(const int dims[3], int i, int j, int *neighbors, int len);
static int
checkmemory(int nz, struct processed_grid *out, int **intersections);
static void
process_vertical_faces(int direction,
int **intersections,
int *plist, int *work,
struct processed_grid *out);
static void
process_horizontal_faces(int **intersections,
int *plist,
struct processed_grid *out);
static int
linearindex(const int dims[3], int i, int j, int k)
{
assert (0 <= i);
assert (0 <= j);
assert (0 <= k);
assert (i < dims[0]);
assert (j < dims[1]);
assert (k < dims[2]);
return i + dims[0]*(j + dims[1]*k);
}
/*-----------------------------------------------------------------
Given a vector <field> with k index running faster than i running
faster than j, and Cartesian dimensions <dims>, find pointers to the
(i-1, j-1, 0), (i-1, j, 0), (i, j-1, 0) and (i, j, 0) elements of
field. */
static void
igetvectors(int dims[3], int i, int j, int *field, int *v[])
{
int im = MAX(1, i ) - 1;
int ip = MIN(dims[0], i+1) - 1;
int jm = MAX(1, j ) - 1;
int jp = MIN(dims[1], j+1) - 1;
v[0] = field + dims[2]*(im + dims[0]* jm);
v[1] = field + dims[2]*(im + dims[0]* jp);
v[2] = field + dims[2]*(ip + dims[0]* jm);
v[3] = field + dims[2]*(ip + dims[0]* jp);
}
/*-----------------------------------------------------------------
Special purpose
Convert from k-index to Cartesian index i+nx*(j+ny*k) for every
other element in neighbors.
*/
static void
compute_cell_index(const int dims[3], int i, int j,
int *neighbors, int len)
{
int k;
if (((i < 0) || (i >= dims[0])) || /* 'i' outside [0, dims[0]) */
((j < 0) || (j >= dims[1]))) { /* 'j' outside [0, dims[1]) */
for (k = 0; k < len; k += 2) {
neighbors[k] = -1; /* Neighbour is outside domain */
}
}
else {
for (k = 0; k < len; k += 2) {
if (neighbors[k] != -1) {
neighbors[k] = linearindex(dims, i, j, neighbors[k]);
}
}
}
}
/*-----------------------------------------------------------------
Ensure there's sufficient memory */
static int
checkmemory(int nz, struct processed_grid *out, int **intersections)
{
int r, m, n, ok;
/* Ensure there is enough space to manage the (pathological) case
* of every single cell on one side of a fault connecting to all
* cells on the other side of the fault (i.e., an all-to-all cell
* connectivity pairing). */
r = (2*nz + 2) * (2*nz + 2);
m = out->m;
n = out->n;
if (out->number_of_faces + r > m) {
m += MAX(m / 2, 2 * r);
}
if (out->face_ptr[out->number_of_faces] + 6*r > n) {
n += MAX(n / 2, 12 * r);
}
ok = m == out->m;
if (! ok) {
void *p1, *p2, *p3, *p4;
p1 = realloc(*intersections , 4*m * sizeof **intersections);
p2 = realloc(out->face_neighbors, 2*m * sizeof *out->face_neighbors);
p3 = realloc(out->face_ptr , (m+1) * sizeof *out->face_ptr);
p4 = realloc(out->face_tag , 1*m * sizeof *out->face_tag);
if (p1 != NULL) { *intersections = p1; }
if (p2 != NULL) { out->face_neighbors = p2; }
if (p3 != NULL) { out->face_ptr = p3; }
if (p4 != NULL) { out->face_tag = p4; }
ok = (p1 != NULL) && (p2 != NULL) && (p3 != NULL) && (p4 != NULL);
if (ok) { out->m = m; }
}
if (ok && (n != out->n)) {
void *p1;
p1 = realloc(out->face_nodes, n * sizeof *out->face_nodes);
ok = p1 != NULL;
if (ok) {
out->face_nodes = p1;
out->n = n;
}
}
return ok;
}
/*-----------------------------------------------------------------
For each vertical face (i.e. i or j constant),
-find point numbers for the corners and
-cell neighbors.
-new points on faults defined by two intgersecting lines.
direction == 0 : constant-i faces.
direction == 1 : constant-j faces.
*/
static void
process_vertical_faces(int direction,
int **intersections,
int *plist, int *work,
struct processed_grid *out)
{
int i,j;
int *cornerpts[4];
int d[3];
int f;
enum face_tag tag[] = { LEFT, BACK };
int *tmp;
int nx = out->dimensions[0];
int ny = out->dimensions[1];
int nz = out->dimensions[2];
int startface;
int num_intersections;
int *ptr;
int len;
assert ((direction == 0) || (direction == 1));
d[0] = 2 * (nx + 0);
d[1] = 2 * (ny + 0);
d[2] = 2 * (nz + 1);
for (j = 0; j < ny + direction; ++j) {
for (i = 0; i < nx + (1 - direction); ++i) {
if (! checkmemory(nz, out, intersections)) {
fprintf(stderr,
"Could not allocate enough space in "
"process_vertical_faces()\n");
exit(1);
}
/* Vectors of point numbers */
igetvectors(d, 2*i + direction, 2*j + (1 - direction),
plist, cornerpts);
if (direction == 1) {
/* 1 3 0 1 */
/* ---> */
/* 0 2 2 3 */
/* rotate clockwise */
tmp = cornerpts[1];
cornerpts[1] = cornerpts[0];
cornerpts[0] = cornerpts[2];
cornerpts[2] = cornerpts[3];
cornerpts[3] = tmp;
}
/* int startface = ftab->position; */
startface = out->number_of_faces;
/* int num_intersections = *npoints - npillarpoints; */
num_intersections = out->number_of_nodes -
out->number_of_nodes_on_pillars;
/* Establish new connections (faces) along pillar pair. */
findconnections(2*nz + 2, cornerpts,
*intersections + 4*num_intersections,
work, out);
/* Start of ->face_neighbors[] for this set of connections. */
ptr = out->face_neighbors + 2*startface;
/* Total number of cells (both sides) connected by this
* set of connections (faces). */
len = 2*out->number_of_faces - 2*startface;
/* Derive inter-cell connectivity (i.e. ->face_neighbors)
* of global (uncompressed) cells for this set of
* connections (faces). */
compute_cell_index(out->dimensions, i-1+direction, j-direction, ptr , len);
compute_cell_index(out->dimensions, i , j , ptr + 1, len);
/* Tag the new faces */
f = startface;
for (; f < out->number_of_faces; ++f) {
out->face_tag[f] = tag[direction];
}
}
}
}
/*-----------------------------------------------------------------
For each horizontal face (i.e. k constant),
-find point numbers for the corners and
-cell neighbors.
Also define map from logically Cartesian
cell index to local cell index 0, ..., #<active cells>. Exclude
cells that are have collapsed coordinates. (This includes cells with
ACTNUM==0)
*/
static void
process_horizontal_faces(int **intersections,
int *plist,
struct processed_grid *out)
{
int i,j,k;
int nx = out->dimensions[0];
int ny = out->dimensions[1];
int nz = out->dimensions[2];
int *cell = out->local_cell_index;
int cellno = 0;
int *f, *n, *c[4];
int prevcell, thiscell;
int idx;
/* dimensions of plist */
int d[3];
d[0] = 2*nx;
d[1] = 2*ny;
d[2] = 2+2*nz;
for(j=0; j<ny; ++j) {
for (i=0; i<nx; ++i) {
if (! checkmemory(nz, out, intersections)) {
fprintf(stderr,
"Could not allocate enough space in "
"process_horizontal_faces()\n");
exit(1);
}
f = out->face_nodes + out->face_ptr[out->number_of_faces];
n = out->face_neighbors + 2*out->number_of_faces;
/* Vectors of point numbers */
igetvectors(d, 2*i+1, 2*j+1, plist, c);
prevcell = -1;
for (k = 1; k<nz*2+1; ++k){
/* Skip if space between face k and face k+1 is collapsed. */
/* Note that inactive cells (with ACTNUM==0) have all been */
/* collapsed in finduniquepoints. */
if (c[0][k] == c[0][k+1] && c[1][k] == c[1][k+1] &&
c[2][k] == c[2][k+1] && c[3][k] == c[3][k+1]){
/* If the pinch is a cell: */
if (k%2){
idx = linearindex(out->dimensions, i,j,(k-1)/2);
cell[idx] = -1;
}
}
else{
if (k%2){
/* Add face */
*f++ = c[0][k];
*f++ = c[2][k];
*f++ = c[3][k];
*f++ = c[1][k];
out->face_tag[ out->number_of_faces] = TOP;
out->face_ptr[++out->number_of_faces] = f - out->face_nodes;
thiscell = linearindex(out->dimensions, i,j,(k-1)/2);
*n++ = prevcell;
*n++ = prevcell = thiscell;
cell[thiscell] = cellno++;
}
else{
if (prevcell != -1){
/* Add face */
*f++ = c[0][k];
*f++ = c[2][k];
*f++ = c[3][k];
*f++ = c[1][k];
out->face_tag[ out->number_of_faces] = TOP;
out->face_ptr[++out->number_of_faces] = f - out->face_nodes;
*n++ = prevcell;
*n++ = prevcell = -1;
}
}
}
}
}
}
out->number_of_cells = cellno;
}
/*-----------------------------------------------------------------
On input,
L points to 4 ints that indirectly refers to points in c.
c points to array of coordinates [x0,y0,z0,x1,y1,z1,...,xn,yn,zn].
pt points to array of 3 doubles.
On output,
pt holds coordinates to intersection between lines given by point
numbers L[0]-L[1] and L[2]-L[3].
*/
static void approximate_intersection_pt(int *L, double *c, double *pt)
{
double a;
double z0, z1, z2, z3;
double b1, b2;
double x1, y1;
double x2, y2;
double z;
/* no intersection on pillars expected here! */
assert (L[0] != L[2]);
assert (L[1] != L[3]);
z0 = c[3*L[0] + 2];
z1 = c[3*L[1] + 2];
z2 = c[3*L[2] + 2];
z3 = c[3*L[3] + 2];
/* find parameter a where lines L0L1 and L2L3 have same
* z-coordinate */
if (fabs((z1 - z0) - (z3 - z2)) > 0.0) {
a = (z2 - z0) / ((z1 - z0) - (z3 - z2));
} else {
a = 0;
}
/* the corresponding z-coordinate is */
z = z0*(1.0 - a) + z1*a;
/* find point (x1, y1, z) on pillar 1 */
b1 = (z2 - z) / (z2 - z0);
b2 = (z - z0) / (z2 - z0);
x1 = c[3*L[0] + 0]*b1 + c[3*L[2] + 0]*b2;
y1 = c[3*L[0] + 1]*b1 + c[3*L[2] + 1]*b2;
/* find point (x2, y2, z) on pillar 2 */
b1 = (z - z3) / (z1 - z3);
b2 = (z1 - z) / (z1 - z3);
x2 = c[3*L[1] + 0]*b1 + c[3*L[3] + 0]*b2;
y2 = c[3*L[1] + 1]*b1 + c[3*L[3] + 1]*b2;
/* horizontal lines are by definition ON the bilinear surface
spanned by L0, L1, L2 and L3. find point (x, y, z) on
horizontal line between point (x1, y1, z) and (x2, y2, z).*/
pt[0] = x1*(1.0 - a) + x2*a;
pt[1] = y1*(1.0 - a) + y2*a;
pt[2] = z;
}
/*-----------------------------------------------------------------
Compute x,y and z coordinates for points on each pillar. Then,
append x,y and z coordinates for extra points on faults. */
static void
compute_intersection_coordinates(int *intersections,
struct processed_grid *out)
{
int n = out->number_of_nodes;
int np = out->number_of_nodes_on_pillars;
int k;
double *pt;
int *itsct = intersections;
/* Make sure the space allocated for nodes match the number of
* node. */
void *p = realloc (out->node_coordinates, 3*n*sizeof(double));
if (p) {
out->node_coordinates = p;
}
else {
fprintf(stderr, "Could not allocate extra space for intersections\n");
}
/* Append intersections */
pt = out->node_coordinates + 3*np;
for (k=np; k<n; ++k){
approximate_intersection_pt(itsct, out->node_coordinates, pt);
pt += 3;
itsct += 4;
}
}
/* ------------------------------------------------------------------ */
static int*
copy_and_permute_actnum(int nx, int ny, int nz, const int *in, int *out)
/* ------------------------------------------------------------------ */
{
int i,j,k;
int *ptr = out;
/* Permute actnum such that values of each vertical stack of cells
* are adjacent in memory, i.e.,
*
* out = [in(0,0,:), in(1,0,:),..., in(nx-1, ny-1,:)]
*
* in MATLAB pseudo-code.
*/
if (in != NULL) {
for (j = 0; j < ny; ++j) {
for (i = 0; i < nx; ++i) {
for (k = 0; k < nz; ++k) {
*ptr++ = in[i + nx*(j + ny*k)];
}
}
}
}
else {
/* No explicit ACTNUM. Assume all cells active. */
for (i = 0; i < nx * ny * nz; i++) {
out[ i ] = 1;
}
}
return out;
}
/* ------------------------------------------------------------------ */
static double*
copy_and_permute_zcorn(int nx, int ny, int nz, const double *in,
double sign, double *out)
/* ------------------------------------------------------------------ */
{
int i,j,k;
double *ptr = out;
/* Permute zcorn such that values of each vertical stack of cells
* are adjacent in memory, i.e.,
out = [in(0,0,:), in(1,0,:),..., in(2*nx-1, 2*ny-1,:)]
in Matlab pseudo-code.
*/
for (j=0; j<2*ny; ++j){
for (i=0; i<2*nx; ++i){
for (k=0; k<2*nz; ++k){
*ptr++ = sign * in[i+2*nx*(j+2*ny*k)];
}
}
}
return out;
}
/* ------------------------------------------------------------------ */
static int
get_zcorn_sign(int nx, int ny, int nz, const int *actnum,
const double *zcorn, int *error)
/* ------------------------------------------------------------------ */
{
/* Ensure that zcorn (i.e., depth) is strictly nondecreasing in
the k-direction. This is required by the processign algorithm.
1) if z(i,j,k) <= z(i,j,k+1) for all (i,j,k), return 1.0
2) if -z(i,j,k) <=-z(i,j,k+1) for all (i,j,k), return -1.0
3) if (1) and (2) fails, return -1.0, and set *error = 1.
*/
int sign;
int i, j, k;
int c1, c2;
double z1, z2;
for (sign = 1; sign>-2; sign = sign - 2)
{
*error = 0;
for (j=0; j<2*ny; ++j){
for (i=0; i<2*nx; ++i){
for (k=0; k<2*nz-1; ++k){
z1 = sign*zcorn[i+2*nx*(j+2*ny*(k))];
z2 = sign*zcorn[i+2*nx*(j+2*ny*(k+1))];
c1 = i/2 + nx*(j/2 + ny*(k/2));
c2 = i/2 + nx*(j/2 + ny*((k+1)/2));
assert (c1 < (nx * ny * nz));
assert (c2 < (nx * ny * nz));
if (((actnum == NULL) ||
(actnum[c1] && actnum[c2]))
&& (z2 < z1)) {
fprintf(stderr, "\nZCORN should be strictly "
"nondecreasing along pillars!\n");
*error = 1;
goto end;
}
}
}
}
end:
if (!*error){
break;
}
}
if (*error){
fprintf(stderr, "Attempt to reverse sign in ZCORN failed.\n"
"Grid definition may be broken\n");
}
return sign;
}
static void
ind2sub(const size_t nx,
const size_t ny,
const size_t nz,
size_t c ,
size_t *i, size_t *j, size_t *k)
{
assert (c < (nx * ny * nz));
#if defined(NDEBUG)
(void) nz;
#endif
*i = c % nx; c /= nx;
*j = c % ny;
*k = c / ny;
}
/* ---------------------------------------------------------------------- */
static double
vert_size(const struct grdecl *in,
const size_t c ,
const size_t off[8])
/* ---------------------------------------------------------------------- */
{
size_t i, j, k, nx, ny, start;
double dz;
const double *zcorn;
nx = in->dims[ 0 ];
ny = in->dims[ 1 ];
ind2sub(nx, ny, in->dims[ 2 ], c, &i, &j, &k);
zcorn = in->zcorn;
start = (2 * i) + (2 * nx)*((2 * j) + (2 * ny)*(2 * k));
for (k = 0, dz = 0.0; (! (fabs(dz) > 0)) && (k < 4); k++) {
dz = zcorn[start + off[k + 4]] - zcorn[start + off[k]];
}
return dz;
}
/* ---------------------------------------------------------------------- */
static int
is_lefthanded(const struct grdecl *in)
/* ---------------------------------------------------------------------- */
{
int active, searching;
size_t nx, ny, nz, c;
size_t origin, imax, jmax;
size_t off[8];
double dx[2], dy[2], dz, triple;
const double *pt_coord;
nx = in->dims[0];
ny = in->dims[1];
nz = in->dims[2];
off[0] = 0;
off[1] = off[0] + 1;
off[2] = off[0] + (2 * nx);
off[3] = off[2] + 1;
off[4] = off[0] + ((2 * nx) * (2 * ny));
off[5] = off[4] + 1;
off[6] = off[4] + (2 * nx);
off[7] = off[6] + 1;
pt_coord = in->coord;
origin = 0;
imax = (nx + 0) * 1 * (2 * 3);
jmax = (nx + 1) * (ny + 0) * (2 * 3);
dx[0] = pt_coord[imax + 0] - pt_coord[origin + 0];
dy[0] = pt_coord[imax + 1] - pt_coord[origin + 1];
dx[1] = pt_coord[jmax + 0] - pt_coord[origin + 0];
dy[1] = pt_coord[jmax + 1] - pt_coord[origin + 1];
c = 0; dz = 0.0;
do {
active = (in->actnum == NULL) || (in->actnum[c] != 0);
if (active) {
dz = vert_size(in, c, off);
}
searching = ! (active && (fabs(dz) > 0.0));
c += 1;
} while (searching && (c < (nx * ny * nz)));
assert (! searching); /* active && (fabs(dz) > 0) */
/* Compute vector triple product to distinguish left-handed (<0)
* from right-handed (>0) coordinate systems. */
triple = dz * (dx[0]*dy[1] - dx[1]*dy[0]);
assert (fabs(triple) > 0.0);
return triple < 0.0;
}
/* ---------------------------------------------------------------------- */
static void
reverse_face_nodes(struct processed_grid *out)
/* ---------------------------------------------------------------------- */
{
int f, t, *i, *j;
for (f = 0; f < out->number_of_faces; f++) {
i = out->face_nodes + (out->face_ptr[f + 0] + 0);
j = out->face_nodes + (out->face_ptr[f + 1] - 1);
assert (i <= j);
while (i < j) {
t = *i;
*i = *j;
*j = t;
i += 1;
j -= 1;
}
}
}
/*-----------------------------------------------------------------
Public interface
*/
void process_grdecl(const struct grdecl *in,
double tolerance,
struct processed_grid *out)
{
struct grdecl g;
size_t i;
int sign, error, left_handed;
int cellnum;
int *actnum, *iptr;
int *global_cell_index;
double *zcorn;
const size_t BIGNUM = 64;
const int nx = in->dims[0];
const int ny = in->dims[1];
const int nz = in->dims[2];
const size_t nc = ((size_t) nx) * ((size_t) ny) * ((size_t) nz);
/* internal work arrays */
int *work;
int *plist;
int *intersections;
/* -----------------------------------------------------------------*/
/* Initialize output structure:
1) allocate space for grid topology (which may need to be
increased)
2) set Cartesian imensions
*/
out->m = (int) (BIGNUM / 3);
out->n = (int) BIGNUM;
out->face_neighbors = malloc( BIGNUM * sizeof *out->face_neighbors);
out->face_nodes = malloc( out->n * sizeof *out->face_nodes);
out->face_ptr = malloc((out->m + 1) * sizeof *out->face_ptr);
out->face_tag = malloc( out->m * sizeof *out->face_tag);
out->face_ptr[0] = 0;
out->dimensions[0] = in->dims[0];
out->dimensions[1] = in->dims[1];
out->dimensions[2] = in->dims[2];
out->number_of_faces = 0;
out->number_of_nodes = 0;
out->number_of_cells = 0;
out->node_coordinates = NULL;
out->local_cell_index = malloc(nc * sizeof *out->local_cell_index);
/* Do actual work here:*/
/* -----------------------------------------------------------------*/
/* For each pillar, compare zcorn values for adjacent cells to
* find the unique node z-coordinates specified by the input.
* While here, enumerate unique points and assign point numbers
* (in plist) for each cornerpoint cell. In other words, plist has
* 8 node numbers for each cornerpoint cell.*/
/* initialize grdecl structure "g" that will be processd by
* "finduniquepoints" */
g.dims[0] = in->dims[0];
g.dims[1] = in->dims[1];
g.dims[2] = in->dims[2];
actnum = malloc (nc * sizeof *actnum);
g.actnum = copy_and_permute_actnum(nx, ny, nz, in->actnum, actnum);
zcorn = malloc (nc * 8 * sizeof *zcorn);
sign = get_zcorn_sign(nx, ny, nz, in->actnum, in->zcorn, &error);
g.zcorn = copy_and_permute_zcorn(nx, ny, nz, in->zcorn, sign, zcorn);
g.coord = in->coord;
/* allocate space for cornerpoint numbers plus INT_MIN (INT_MAX)
* padding */
plist = malloc(8 * (nc + ((size_t)nx)*((size_t)ny)) * sizeof *plist);
finduniquepoints(&g, plist, tolerance, out);
free (zcorn);
free (actnum);
/* Determine if coordinate system is left handed or not. */
left_handed = is_lefthanded(in);
if (left_handed) {
/* Reflect Y coordinates about XZ plane to create right-handed
* coordinate system whilst processing intersections. */
for (i = 1; i < ((size_t) 3) * out->number_of_nodes; i += 3) {
out->node_coordinates[i] = -out->node_coordinates[i];
}
}
/* -----------------------------------------------------------------*/
/* Find face topology and face-to-cell connections */
/* internal */
work = malloc(2 * ((size_t) (2*nz + 2)) * sizeof *work);
for(i = 0; i < ((size_t)4) * (nz + 1); ++i) { work[i] = -1; }
/* internal array to store intersections */
intersections = malloc(BIGNUM* sizeof(*intersections));
process_vertical_faces (0, &intersections, plist, work, out);
process_vertical_faces (1, &intersections, plist, work, out);
process_horizontal_faces ( &intersections, plist, out);
free (plist);
free (work);
/* -----------------------------------------------------------------*/
/* (re)allocate space for and compute coordinates of nodes that
* arise from intersecting cells (faults) */
compute_intersection_coordinates(intersections, out);
free (intersections);
/* -----------------------------------------------------------------*/
/* Enumerate compressed cells:
-make array [0...#cells-1] of global cell numbers
-make [0...nx*ny*nz-1] array of local cell numbers,
lexicographically ordered, used to remap out->face_neighbors
*/
global_cell_index = malloc(nc * sizeof *global_cell_index);
cellnum = 0;
for (i = 0; i < nc; ++i) {
if (out->local_cell_index[i] != -1) {
global_cell_index[cellnum] = (int) i;
out->local_cell_index[i] = cellnum;
cellnum++;
}
}
/* Remap out->face_neighbors */
iptr = out->face_neighbors;
for (i = 0; i < ((size_t) 2) * out->number_of_faces; ++i, ++iptr) {
if (*iptr != -1){
*iptr = out->local_cell_index[*iptr];
}
}
free(out->local_cell_index);
out->local_cell_index = global_cell_index;
/* Reflect Y coordinate back to original position if left-handed
* coordinate system was detected and handled earlier. */
if (left_handed) {
for (i = 1; i < ((size_t) 3) * out->number_of_nodes; i += 3) {
out->node_coordinates[i] = -out->node_coordinates[i];
}
}
/* if sign==-1 in ZCORN preprocessing, the sign of the
* z-coordinate need to change before we finish */
if (sign == -1)
{
for (i = 2; i < ((size_t) 3) * out->number_of_nodes; i += 3)
out->node_coordinates[i] *= sign;
}
/* If an odd number of coordinate reflections were applied, the
* processing routines--especially facetopology()--will produce
* node orderings that lead to normals pointing from 2 to 1.
* Reverse nodes to reestablish expected normal direction (and
* positive cell volumes). */
if (left_handed ^ (sign == -1)) {
reverse_face_nodes(out);
}
}
/*-------------------------------------------------------*/
void free_processed_grid(struct processed_grid *g)
{
if( g ){
free ( g->face_nodes );
free ( g->face_ptr );
free ( g->face_tag );
free ( g->face_neighbors );
free ( g->node_coordinates );
free ( g->local_cell_index );
}
}
/* Local Variables: */
/* c-basic-offset:4 */
/* End: */

View File

@ -1,154 +0,0 @@
/*===========================================================================
//
// File: preprocess.h
//
// Created: Fri Jun 19 08:43:04 2009
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
// $Date$
//
// $Revision$
//
//==========================================================================*/
/*
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010 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_PREPROCESS_HEADER
#define OPM_PREPROCESS_HEADER
/**
* \file
* Low-level corner-point processing routines and supporting data structures.
*
* User code should typically employ higher-level routines such as
* create_grid_cornerpoint() in order to construct fully formed UnstructuredGrid
* data structures from a corner-point specification. Incidentally, the routines
* provided by this module are used to implement function
* create_grid_cornerpoint().
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* Raw corner-point specification of a particular geological model.
*/
struct grdecl {
int dims[3]; /**< Cartesian box dimensions. */
const double *coord; /**< Pillar end-points. */
const double *zcorn; /**< Corner-point depths. */
const int *actnum; /**< Explicit "active" map. May be NULL.*/
const double *mapaxes; /**< 6 Element rotation vector - can be NULL. */
};
/**
* Connection taxonomy.
*/
enum face_tag {
LEFT, /**< Connection topologically parallel to J-K plane. */
BACK, /**< Connection topologically parallel to I-K plane. */
TOP /**< Connection topologically parallel to I-J plane. */
};
/**
* Result structure representing minimal derived topology and geometry of
* a geological model in corner-point format.
*/
struct processed_grid {
int m; /**< Upper bound on "number_of_faces". For internal use in
function process_grid()'s memory management. */
int n; /**< Upper bound on "number_of_nodes". For internal use in
function process_grid()'s memory management. */
int dimensions[3]; /**< Cartesian box dimensions. */
int number_of_faces; /**< Total number of unique grid faces
(i.e., connections). */
int *face_nodes; /**< Node (vertex) numbers of each face,
stored sequentially. */
int *face_ptr; /**< Start position for each face's
`face_nodes'. */
int *face_neighbors; /**< Global cell numbers. Two elements per
face, stored sequentially. */
enum face_tag *face_tag; /**< Classification of grid's individual
connections (faces). */
int number_of_nodes; /**< Number of unique grid vertices. */
int number_of_nodes_on_pillars; /**< Total number of unique cell
vertices that lie on pillars. */
double *node_coordinates; /**< Vertex coordinates. Three doubles
(\f$x\f$, \f$y\f$, \f$z\f$) per vertex,
stored sequentially. */
int number_of_cells; /**< Number of active grid cells. */
int *local_cell_index; /**< Deceptively named local-to-global cell
index mapping. */
};
/**
* Construct a prototypical grid representation from a corner-point
* specification.
*
* Pinched cells will be removed irrespective of any explicit "active" map
* in the geological model input specification. On input, the result
* structure "out" must point to a valid management structure. In other
* words, the result structure must point to a region of memory that is
* typically backed by automatic or allocated (dynamic) storage duration.
*
* @param[in] g Corner-point specification. If "actnum" is NULL, then
* the specification is interpreted as if all cells are
* initially active.
* @param[in] tol Absolute tolerance of node-coincidence.
* @param[in,out] out Minimal grid representation featuring face-to-cell
* neighbourship definition, vertex geometry, face's
* constituent vertices, and local-to-global cell
* mapping.
*/
void process_grdecl(const struct grdecl *g ,
double tol,
struct processed_grid *out);
/**
* Release memory resources acquired in previous grid processing using
* function process_grdecl().
*
* Note: This function releases the resources associated to the individual
* fields of the processed_grid, but does not free() the structure itself.
*
* @param[in,out] g Prototypical grid representation obtained in an earlier
* call to function process_grdecl().
*/
void free_processed_grid(struct processed_grid *g);
#ifdef __cplusplus
}
#endif
#endif /* OPM_PREPROCESS_HEADER */
/* Local Variables: */
/* c-basic-offset:4 */
/* End: */

View File

@ -1,383 +0,0 @@
/*===========================================================================
//
// File: uniquepoints.c
//
// Created: Fri Jun 19 08:46:05 2009
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
// $Date$
//
// $Revision$
//
//==========================================================================*/
/*
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010 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 "config.h"
#include <assert.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "preprocess.h"
#include "uniquepoints.h"
#define MIN(i,j) (((i) < (j)) ? (i) : (j))
#define MAX(i,j) (((i) > (j)) ? (i) : (j))
/*-----------------------------------------------------------------
Compare function passed to qsortx */
static int compare(const void *a, const void *b)
{
const double a0 = *(const double*) a;
const double b0 = *(const double*) b;
/* { -1, a < b
* compare(a,b) = { 0, a = b
* { 1, a > b */
return (a0 > b0) - (a0 < b0);
}
/*-----------------------------------------------------------------
Creat sorted list of z-values in zcorn with actnum==1x */
static int createSortedList(double *list, int n, int m,
const double *z[], const int *a[])
{
int i,j;
double *ptr = list;
for (i=0; i<n; ++i){
for (j=0; j<m; ++j){
if (a[j][i/2]) *ptr++ = z[j][i];
/* else fprintf(stderr, "skipping point in inactive cell\n"); */
}
}
qsort(list, ptr-list, sizeof(double), compare);
return ptr-list;
}
/*-----------------------------------------------------------------
Remove points less than <tolerance> apart in <list> of increasing
doubles. */
static int uniquify(int n, double *list, double tolerance)
{
int i;
int pos;
double val;
assert (!(tolerance < 0.0));
if (n<1) return 0;
pos = 0;
val = list[pos++];/* Keep first value */
for (i=1; i<n; ++i){
if (val + tolerance < list [i]){
val = list[i];
list[pos++] = val;
}
}
/*
Preserve outer z-boundary.
This operation is a no-op in the case
list[pos-2] + tolerance < list[n-1].
If, however, the second to last point is less than <tolerance>
away from the last point (list[n-1]), we remove this
second-to-last point as it cannot be distinguished from "final"
point.
*/
list[pos-1] = list[n-1];
return pos;
}
/*-----------------------------------------------------------------
Along single pillar: */
static int assignPointNumbers(int begin,
int end,
const double *zlist,
int n,
const double *zcorn,
const int *actnum,
int *plist,
double tolerance)
{
/* n - number of cells */
/* zlist - list of len unique z-values */
/* start - number of unique z-values processed before. */
int i, k;
/* All points should now be within tolerance of a listed point. */
const double *z = zcorn;
const int *a = actnum;
int *p = plist;
k = begin;
*p++ = INT_MIN; /* Padding to ease processing of faults */
for (i=0; i<n; ++i){
/* Skip inactive cells */
if (!a[i/2]) {
p[0] = p[-1]; /* Inactive cells are collapsed leaving
* void space.*/
++p;
continue;
}
/* Find next k such that zlist[k] < z[i] < zlist[k+1] */
while ((k < end) && (zlist[k] + tolerance < z[i])){
k++;
}
/* assert (k < len && z[i] - zlist[k] <= tolerance) */
if ((k == end) || ( zlist[k] + tolerance < z[i])){
fprintf(stderr, "Cannot associate zcorn values with given list\n");
fprintf(stderr, "of z-coordinates to given tolerance\n");
return 0;
}
*p++ = k;
}
*p++ = INT_MAX;/* Padding to ease processing of faults */
return 1;
}
/* ---------------------------------------------------------------------- */
static void
vector_positions(const int dims[3] ,
const int i ,
const int j ,
size_t start[4])
/* ---------------------------------------------------------------------- */
{
size_t im, ip, jm, jp;
im = MAX(1, i ) - 1;
jm = MAX(1, j ) - 1;
ip = MIN(dims[0], i+1) - 1;
jp = MIN(dims[1], j+1) - 1;
start[ 0 ] = dims[2] * (im + dims[0]*jm);
start[ 1 ] = dims[2] * (im + dims[0]*jp);
start[ 2 ] = dims[2] * (ip + dims[0]*jm);
start[ 3 ] = dims[2] * (ip + dims[0]*jp);
}
/*-----------------------------------------------------------------
Given a vector <field> with k index running faster than i running
faster than j, and Cartesian dimensions <dims>, find pointers to the
(i-1, j-1, 0), (i-1, j, 0), (i, j-1, 0) and (i, j, 0) elements of
field. */
static void igetvectors(const int dims[3], int i, int j,
const int *field, const int *v[])
{
size_t p, start[4];
vector_positions(dims, i, j, start);
for (p = 0; p < 4; p++) {
v[p] = field + start[p];
}
}
/*-----------------------------------------------------------------
Given a vector <field> with k index running faster than i running
faster than j, and Cartesian dimensions <dims>, find pointers to the
(i-1, j-1, 0), (i-1, j, 0), (i, j-1, 0) and (i, j, 0) elements of
field. */
static void dgetvectors(const int dims[3], int i, int j,
const double *field, const double *v[])
{
size_t p, start[4];
vector_positions(dims, i, j, start);
for (p = 0; p < 4; p++) {
v[p] = field + start[p];
}
}
/*-----------------------------------------------------------------
Given a z coordinate, find x and y coordinates on line defined by
coord. Coord points to a vector of 6 doubles [x0,y0,z0,x1,y1,z1].
*/
static void interpolate_pillar(const double *coord, double *pt)
{
double a;
if (fabs(coord[5] - coord[2]) > 0) {
a = (pt[2] - coord[2]) / (coord[5] - coord[2]);
} else {
a = 0;
}
#if 0
pt[0] = coord[0] + a*(coord[3]-coord[0]);
pt[1] = coord[1] + a*(coord[4]-coord[1]);
#else
pt[0] = (1.0 - a)*coord[0] + a*coord[3];
pt[1] = (1.0 - a)*coord[1] + a*coord[4];
#endif
}
/*-----------------------------------------------------------------
Assign point numbers p such that "zlist(p)==zcorn". Assume that
coordinate number is arranged in a sequence such that the natural
index is (k,i,j) */
int finduniquepoints(const struct grdecl *g,
/* return values: */
int *plist, /* list of point numbers on
* each pillar*/
double tolerance,
struct processed_grid *out)
{
const int nx = out->dimensions[0];
const int ny = out->dimensions[1];
const int nz = out->dimensions[2];
const int nc = g->dims[0]*g->dims[1]*g->dims[2];
/* zlist may need extra space temporarily due to simple boundary
* treatement */
int npillarpoints = 8*(nx+1)*(ny+1)*nz;
int npillars = (nx+1)*(ny+1);
double *zlist = malloc(npillarpoints*sizeof *zlist);
int *zptr = malloc((npillars+1)*sizeof *zptr);
int i,j,k;
int d1[3];
int len = 0;
double *zout = zlist;
int pos = 0;
double *pt;
const double *z[4];
const int *a[4];
int *p;
int pix, cix;
int zix;
const double *coord = g->coord;
d1[0] = 2*g->dims[0];
d1[1] = 2*g->dims[1];
d1[2] = 2*g->dims[2];
out->node_coordinates = malloc (3*8*nc*sizeof(*out->node_coordinates));
zptr[pos++] = zout - zlist;
pt = out->node_coordinates;
/* Loop over pillars, find unique points on each pillar */
for (j=0; j < g->dims[1]+1; ++j){
for (i=0; i < g->dims[0]+1; ++i){
/* Get positioned pointers for actnum and zcorn data */
igetvectors(g->dims, i, j, g->actnum, a);
dgetvectors(d1, 2*i, 2*j, g->zcorn, z);
len = createSortedList( zout, d1[2], 4, z, a);
len = uniquify (len, zout, tolerance);
/* Assign unique points */
for (k=0; k<len; ++k){
pt[2] = zout[k];
interpolate_pillar(coord, pt);
pt += 3;
}
/* Increment pointer to sparse table of unique zcorn
* values */
zout = zout + len;
zptr[pos++] = zout - zlist;
coord += 6;
}
}
out->number_of_nodes_on_pillars = zptr[pos-1];
out->number_of_nodes = zptr[pos-1];
/* Loop over all vertical sets of zcorn values, assign point
* numbers */
p = plist;
for (j=0; j < 2*g->dims[1]; ++j){
for (i=0; i < 2*g->dims[0]; ++i){
/* pillar index */
pix = (i+1)/2 + (g->dims[0]+1)*((j+1)/2);
/* cell column position */
cix = g->dims[2]*((i/2) + (j/2)*g->dims[0]);
/* zcorn column position */
zix = 2*g->dims[2]*(i+2*g->dims[0]*j);
if (!assignPointNumbers(zptr[pix], zptr[pix+1], zlist,
2*g->dims[2],
g->zcorn + zix, g->actnum + cix,
p, tolerance)){
fprintf(stderr, "Something went wrong in assignPointNumbers");
return 0;
}
p += 2 + 2*g->dims[2];
}
}
free(zptr);
free(zlist);
return 1;
}
/* Local Variables: */
/* c-basic-offset:4 */
/* End: */

View File

@ -1,47 +0,0 @@
/*===========================================================================
//
// File: uniquepoints.h
//
// Created: Fri Jun 19 08:46:30 2009
//
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
//
// $Date$
//
// $Revision$
//
//==========================================================================*/
/*
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010 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_UNIQUEPOINTS_HEADER
#define OPM_UNIQUEPOINTS_HEADER
int finduniquepoints(const struct grdecl *g, /* input */
int *p, /* for each z0 in zcorn, z0 = z[p0] */
double t, /* tolerance*/
struct processed_grid *out);
#endif /* OPM_UNIQUEPOINTS_HEADER */
/* Local Variables: */
/* c-basic-offset:4 */
/* End: */

View File

@ -1,609 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <opm/core/grid.h>
#include <opm/core/utility/opm_memcmp_double.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
void
destroy_grid(struct UnstructuredGrid *g)
{
if (g!=NULL)
{
free(g->face_nodes);
free(g->face_nodepos);
free(g->face_cells);
free(g->cell_facepos);
free(g->cell_faces);
free(g->node_coordinates);
free(g->face_centroids);
free(g->face_areas);
free(g->face_normals);
free(g->cell_centroids);
free(g->cell_volumes);
free(g->global_cell);
free(g->cell_facetag);
}
free(g);
}
struct UnstructuredGrid *
create_grid_empty(void)
{
struct UnstructuredGrid *G, g = { 0 };
G = malloc(1 * sizeof *G);
if (G != NULL) {
*G = g;
}
return G;
}
struct UnstructuredGrid *
allocate_grid(size_t ndims ,
size_t ncells ,
size_t nfaces ,
size_t nfacenodes,
size_t ncellfaces,
size_t nnodes )
{
size_t nel;
struct UnstructuredGrid *G;
G = create_grid_empty();
if (G != NULL) {
/* Grid fields ---------------------------------------- */
G->dimensions = ndims;
G->number_of_cells = ncells;
G->number_of_faces = nfaces;
G->number_of_nodes = nnodes;
/* Node fields ---------------------------------------- */
nel = nnodes * ndims;
G->node_coordinates = malloc(nel * sizeof *G->node_coordinates);
/* Face fields ---------------------------------------- */
nel = nfacenodes;
G->face_nodes = malloc(nel * sizeof *G->face_nodes);
nel = nfaces + 1;
G->face_nodepos = malloc(nel * sizeof *G->face_nodepos);
nel = 2 * nfaces;
G->face_cells = malloc(nel * sizeof *G->face_cells);
nel = nfaces * ndims;
G->face_centroids = malloc(nel * sizeof *G->face_centroids);
nel = nfaces * ndims;
G->face_normals = malloc(nel * sizeof *G->face_normals);
nel = nfaces * 1;
G->face_areas = malloc(nel * sizeof *G->face_areas);
/* Cell fields ---------------------------------------- */
nel = ncellfaces;
G->cell_faces = malloc(nel * sizeof *G->cell_faces);
G->cell_facetag = malloc(nel * sizeof *G->cell_facetag);
nel = ncells + 1;
G->cell_facepos = malloc(nel * sizeof *G->cell_facepos);
nel = ncells * ndims;
G->cell_centroids = malloc(nel * sizeof *G->cell_centroids);
nel = ncells * 1;
G->cell_volumes = malloc(nel * sizeof *G->cell_volumes);
if ((G->node_coordinates == NULL) ||
(G->face_nodes == NULL) ||
(G->face_nodepos == NULL) ||
(G->face_cells == NULL) ||
(G->face_centroids == NULL) ||
(G->face_normals == NULL) ||
(G->face_areas == NULL) ||
(G->cell_faces == NULL) ||
(G->cell_facetag == NULL) ||
(G->cell_facepos == NULL) ||
(G->cell_centroids == NULL) ||
(G->cell_volumes == NULL) )
{
destroy_grid(G);
G = NULL;
}
}
return G;
}
#define GRID_NMETA 6
#define GRID_NDIMS 0
#define GRID_NCELLS 1
#define GRID_NFACES 2
#define GRID_NNODES 3
#define GRID_NFACENODES 4
#define GRID_NCELLFACES 5
static void
input_error(FILE *fp, const char * const err)
{
int save_errno = errno;
if (ferror(fp)) {
fprintf(stderr, "%s: %s\n", err, strerror(save_errno));
clearerr(fp);
}
else if (feof(fp)) {
fprintf(stderr, "%s: End-of-file\n", err);
}
errno = save_errno;
}
static struct UnstructuredGrid *
allocate_grid_from_file(FILE *fp, int *has_tag, int *has_indexmap)
{
struct UnstructuredGrid *G;
int save_errno;
unsigned long tmp;
size_t dimens[GRID_NMETA], i;
save_errno = errno;
i = 0;
while ((i < GRID_NMETA) && (fscanf(fp, " %lu", &tmp) == 1)) {
dimens[i] = tmp;
i += 1;
}
if (i == GRID_NMETA) {
if (fscanf(fp, "%d %d", has_tag, has_indexmap) == 2) {
G = allocate_grid(dimens[GRID_NDIMS] ,
dimens[GRID_NCELLS] ,
dimens[GRID_NFACES] ,
dimens[GRID_NFACENODES],
dimens[GRID_NCELLFACES],
dimens[GRID_NNODES] );
if (G != NULL) {
if (! *has_tag) {
free(G->cell_facetag);
G->cell_facetag = NULL;
}
if (*has_indexmap) {
G->global_cell =
malloc(dimens[GRID_NCELLS] * sizeof *G->global_cell);
/* Allocation failure checked elsewhere. */
}
G->number_of_cells = (int) dimens[GRID_NCELLS];
G->number_of_faces = (int) dimens[GRID_NFACES];
G->number_of_nodes = (int) dimens[GRID_NNODES];
G->dimensions = (int) dimens[GRID_NDIMS];
i = 0;
while ((i < dimens[GRID_NDIMS]) &&
(fscanf(fp, "%d", & G->cartdims[ i ]) == 1)) {
i += 1;
}
if (i < dimens[GRID_NDIMS]) {
input_error(fp, "Unable to read Cartesian dimensions");
destroy_grid(G);
G = NULL;
}
else {
/* Account for dimens[GRID_DIMS] < 3 */
size_t n = (sizeof G->cartdims) / (sizeof G->cartdims[0]);
for (; i < n; i++) { G->cartdims[ i ] = 1; }
}
}
}
else {
input_error(fp, "Unable to read grid predicates");
G = NULL;
}
}
else {
input_error(fp, "Unable to read grid dimensions");
G = NULL;
}
errno = save_errno;
return G;
}
static int
read_grid_nodes(FILE *fp, struct UnstructuredGrid *G)
{
int save_errno;
size_t i, n;
save_errno = errno;
n = G->dimensions;
n *= G->number_of_nodes;
i = 0;
while ((i < n) &&
(fscanf(fp, " %lf", & G->node_coordinates[ i ]) == 1)) {
i += 1;
}
if (i < n) {
input_error(fp, "Unable to read node coordinates");
}
errno = save_errno;
return i == n;
}
static int
read_grid_faces(FILE *fp, struct UnstructuredGrid *G)
{
int save_errno, ok;
size_t nf, nfn, i;
save_errno = errno;
nf = G->number_of_faces;
/* G->face_nodepos */
i = 0;
while ((i < nf + 1) &&
(fscanf(fp, " %d", & G->face_nodepos[ i ]) == 1)) {
i += 1;
}
ok = i == nf + 1;
if (! ok) {
input_error(fp, "Unable to read node indirection array");
}
else {
/* G->face_nodes */
nfn = G->face_nodepos[ nf ];
i = 0;
while ((i < nfn) && (fscanf(fp, " %d", & G->face_nodes[ i ]) == 1)) {
i += 1;
}
ok = i == nfn;
if (! ok) {
input_error(fp, "Unable to read face-nodes");
}
}
if (ok) {
/* G->face_cells */
i = 0;
while ((i < 2 * nf) && (fscanf(fp, " %d", & G->face_cells[ i ]) == 1)) {
i += 1;
}
ok = i == 2 * nf;
if (! ok) {
input_error(fp, "Unable to read neighbourship");
}
}
if (ok) {
/* G->face_areas */
i = 0;
while ((i < nf) && (fscanf(fp, " %lf", & G->face_areas[ i ]) == 1)) {
i += 1;
}
ok = i == nf;
if (! ok) {
input_error(fp, "Unable to read face areas");
}
}
if (ok) {
/* G->face_centroids */
size_t n;
n = G->dimensions;
n *= nf;
i = 0;
while ((i < n) && (fscanf(fp, " %lf", & G->face_centroids[ i ]) == 1)) {
i += 1;
}
ok = i == n;
if (! ok) {
input_error(fp, "Unable to read face centroids");
}
}
if (ok) {
/* G->face_normals */
size_t n;
n = G->dimensions;
n *= nf;
i = 0;
while ((i < n) && (fscanf(fp, " %lf", & G->face_normals[ i ]) == 1)) {
i += 1;
}
ok = i == n;
if (! ok) {
input_error(fp, "Unable to read face normals");
}
}
errno = save_errno;
return ok;
}
static int
read_grid_cells(FILE *fp, int has_tag, int has_indexmap,
struct UnstructuredGrid *G)
{
int save_errno, ok;
size_t nc, ncf, i;
save_errno = errno;
nc = G->number_of_cells;
/* G->cell_facepos */
i = 0;
while ((i < nc + 1) && (fscanf(fp, " %d", & G->cell_facepos[ i ]) == 1)) {
i += 1;
}
ok = i == nc + 1;
if (! ok) {
input_error(fp, "Unable to read face indirection array");
}
else {
/* G->cell_faces (and G->cell_facetag if applicable) */
ncf = G->cell_facepos[ nc ];
i = 0;
if (has_tag) {
assert (G->cell_facetag != NULL);
while ((i < ncf) &&
(fscanf(fp, " %d %d",
& G->cell_faces [ i ],
& G->cell_facetag[ i ]) == 2)) {
i += 1;
}
}
else {
while ((i < ncf) &&
(fscanf(fp, " %d", & G->cell_faces[ i ]) == 1)) {
i += 1;
}
}
ok = i == ncf;
if (! ok) {
input_error(fp, "Unable to read cell-faces");
}
}
if (ok) {
/* G->global_cell if applicable */
if (has_indexmap) {
i = 0;
if (G->global_cell != NULL) {
while ((i < nc) &&
(fscanf(fp, " %d", & G->global_cell[ i ]) == 1)) {
i += 1;
}
}
else {
int discard;
while ((i < nc) && (fscanf(fp, " %d", & discard) == 1)) {
i += 1;
}
}
}
else {
assert (G->global_cell == NULL);
i = nc;
}
ok = i == nc;
if (! ok) {
input_error(fp, "Unable to read global cellmap");
}
}
if (ok) {
/* G->cell_volumes */
i = 0;
while ((i < nc) && (fscanf(fp, " %lf", & G->cell_volumes[ i ]) == 1)) {
i += 1;
}
ok = i == nc;
if (! ok) {
input_error(fp, "Unable to read cell volumes");
}
}
if (ok) {
/* G->cell_centroids */
size_t n;
n = G->dimensions;
n *= nc;
i = 0;
while ((i < n) && (fscanf(fp, " %lf", & G->cell_centroids[ i ]) == 1)) {
i += 1;
}
ok = i == n;
if (! ok) {
input_error(fp, "Unable to read cell centroids");
}
}
errno = save_errno;
return ok;
}
struct UnstructuredGrid *
read_grid(const char *fname)
{
struct UnstructuredGrid *G;
FILE *fp;
int save_errno;
int has_tag, has_indexmap, ok;
save_errno = errno;
fp = fopen(fname, "rt");
if (fp != NULL) {
G = allocate_grid_from_file(fp, & has_tag, & has_indexmap);
ok = G != NULL;
if (ok) { ok = read_grid_nodes(fp, G); }
if (ok) { ok = read_grid_faces(fp, G); }
if (ok) { ok = read_grid_cells(fp, has_tag, has_indexmap, G); }
if (! ok) {
destroy_grid(G);
G = NULL;
}
fclose(fp);
}
else {
G = NULL;
}
errno = save_errno;
return G;
}
bool
grid_equal(const struct UnstructuredGrid * grid1 , const struct UnstructuredGrid * grid2) {
if ((grid1->dimensions == grid2->dimensions) &&
(grid1->number_of_cells == grid2->number_of_cells) &&
(grid1->number_of_faces == grid2->number_of_faces) &&
(grid1->number_of_nodes == grid2->number_of_nodes)) {
// Exact integer comparisons
{
if (memcmp(grid1->face_nodepos , grid2->face_nodepos , (grid1->number_of_faces + 1) * sizeof * grid1->face_nodepos) != 0)
return false;
if (memcmp(grid1->face_nodes , grid2->face_nodes , grid1->face_nodepos[grid1->number_of_faces] * sizeof * grid1->face_nodes) != 0)
return false;
if (memcmp(grid1->face_cells , grid2->face_cells , 2 * grid1->number_of_faces * sizeof * grid1->face_cells) != 0)
return false;
if (memcmp(grid1->cell_faces , grid2->cell_faces , grid1->cell_facepos[grid1->number_of_cells] * sizeof * grid1->cell_faces) != 0)
return false;
if (memcmp(grid1->cell_facepos , grid2->cell_facepos , (grid1->number_of_cells + 1) * sizeof * grid1->cell_facepos) != 0)
return false;
if (grid1->global_cell && grid2->global_cell) {
if (memcmp(grid1->global_cell , grid2->global_cell , grid1->number_of_cells * sizeof * grid1->global_cell) != 0)
return false;
} else if (grid1->global_cell != grid2->global_cell)
return false;
if (grid1->cell_facetag && grid2->cell_facetag) {
if (memcmp(grid1->cell_facetag , grid2->cell_facetag , grid1->cell_facepos[grid1->number_of_cells] * sizeof * grid1->cell_facetag) != 0)
return false;
} else if (grid1->cell_facetag != grid2->cell_facetag)
return false;
}
// Floating point comparisons.
{
if (opm_memcmp_double( grid1->node_coordinates , grid2->node_coordinates , grid1->dimensions * grid1->number_of_nodes) != 0)
return false;
if (opm_memcmp_double( grid1->face_centroids , grid2->face_centroids , grid1->dimensions * grid1->number_of_faces) != 0)
return false;
if (opm_memcmp_double( grid1->face_areas , grid2->face_areas , grid1->number_of_faces) != 0)
return false;
if (opm_memcmp_double( grid1->face_normals , grid2->face_normals , grid1->dimensions * grid1->number_of_faces) != 0)
return false;
if (opm_memcmp_double( grid1->cell_centroids , grid2->cell_centroids , grid1->dimensions * grid1->number_of_cells) != 0)
return false;
if (opm_memcmp_double( grid1->cell_volumes , grid2->cell_volumes , grid1->number_of_cells) != 0)
return false;
}
return true;
} else
return false;
}

View File

@ -1,103 +0,0 @@
#include "OutputWriter.hpp"
#include <opm/core/grid.h>
#include <opm/core/io/eclipse/EclipseWriter.hpp>
#include <opm/core/utility/parameters/Parameter.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <forward_list>
#include <map>
#include <memory> // unique_ptr
using namespace std;
using namespace Opm;
using namespace Opm::parameter;
namespace {
/// Multiplexer over a list of output writers
struct MultiWriter : public OutputWriter {
/// Shorthand for a list of owned output writers
typedef forward_list <unique_ptr <OutputWriter> > writers_t;
typedef writers_t::iterator it_t;
typedef unique_ptr <writers_t> ptr_t;
/// Adopt a list of writers
MultiWriter (ptr_t writers) : writers_ (std::move (writers)) { }
/// Forward the call to all writers
virtual void writeInit(const SimulatorTimerInterface &timer) {
for (it_t it = writers_->begin (); it != writers_->end (); ++it) {
(*it)->writeInit (timer);
}
}
virtual void writeTimeStep(const SimulatorTimerInterface& timer,
const SimulatorState& reservoirState,
const WellState& wellState,
bool isSubstep) {
for (it_t it = writers_->begin (); it != writers_->end(); ++it) {
(*it)->writeTimeStep (timer, reservoirState, wellState, isSubstep);
}
}
private:
ptr_t writers_;
};
/// Psuedo-constructor, can appear in template
template <typename Format> unique_ptr <OutputWriter>
create (const ParameterGroup& params,
std::shared_ptr <const EclipseState> eclipseState,
const Opm::PhaseUsage &phaseUsage,
std::shared_ptr <const UnstructuredGrid> grid) {
return unique_ptr <OutputWriter> (new Format (params,
eclipseState,
phaseUsage,
grid->number_of_cells,
grid->global_cell));
}
/// Map between keyword in configuration and the corresponding
/// constructor function (type) that should be called when detected.
/// The writer must have a constructor which takes params and parser.
///
/// If you want to add more possible writer formats, just add them
/// to the list below!
typedef map <const char*, unique_ptr <OutputWriter> (*)(
const ParameterGroup&,
std::shared_ptr <const EclipseState> eclipseState,
const Opm::PhaseUsage &phaseUsage,
std::shared_ptr <const UnstructuredGrid>)> map_t;
map_t FORMATS = {
{ "output_ecl", &create <EclipseWriter> },
};
} // anonymous namespace
unique_ptr <OutputWriter>
OutputWriter::create (const ParameterGroup& params,
std::shared_ptr <const EclipseState> eclipseState,
const Opm::PhaseUsage &phaseUsage,
std::shared_ptr <const UnstructuredGrid> grid) {
// allocate a list which will be filled with writers. this list
// is initially empty (no output).
MultiWriter::ptr_t list (new MultiWriter::writers_t ());
// loop through the map and see if we can find the key that is
// specified there
typedef map_t::iterator map_it_t;
for (map_it_t it = FORMATS.begin (); it != FORMATS.end(); ++it) {
// keyword which would indicate that this format should be used
const std::string name (it->first);
// invoke the constructor for the type if we found the keyword
// and put the pointer to this writer onto the list
if (params.getDefault <bool> (name, false)) {
list->push_front (it->second (params, eclipseState, phaseUsage, grid));
}
}
// create a multiplexer from the list of formats we found
return unique_ptr <OutputWriter> (new MultiWriter (std::move (list)));
}

View File

@ -1,118 +0,0 @@
/*
Copyright (c) 2013 Uni Research AS
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_OUTPUT_WRITER_HPP
#define OPM_OUTPUT_WRITER_HPP
#include <memory> // unique_ptr, shared_ptr
#include <opm/core/simulator/SimulatorTimerInterface.hpp>
struct UnstructuredGrid;
namespace Opm {
// forward declaration
class EclipseState;
namespace parameter { class ParameterGroup; }
class SimulatorState;
class WellState;
struct PhaseUsage;
/*!
* Interface for writing non-compositional (blackoil, two-phase) simulation
* state to files.
*
* Use the create() function to setup a chain of writer based on the
* configuration values, e.g.
*
* \example
* \code{.cpp}
* ParameterGroup params (argc, argv, false);
* auto parser = std::make_shared <const Deck> (
* params.get <string> ("deck_filename"));
*
* std::unique_ptr <OutputWriter> writer =
* OutputWriter::create (params, parser);
*
* // before the first timestep
* writer->writeInit (timer);
*
* // after each timestep
* writer->writeTimeStep (timer, state, wellState);
*
* \endcode
*/
class OutputWriter {
public:
/// Allow derived classes to be used in the unique_ptr that is returned
/// from the create() method. (Every class that should be delete'd should
/// have a proper constructor, and if the base class isn't virtual then
/// the compiler won't call the right one when the unique_ptr goes out of
/// scope).
virtual ~OutputWriter () { }
/**
* Write the static data (grid, PVT curves, etc) to disk.
*
* This routine should be called before the first timestep (i.e. when
* timer.currentStepNum () == 0)
*/
virtual void writeInit(const SimulatorTimerInterface &timer) = 0;
/*!
* \brief Write a blackoil reservoir state to disk for later inspection with
* visualization tools like ResInsight
*
* \param[in] timer The timer providing time, time step, etc. information
* \param[in] reservoirState The thermodynamic state of the reservoir
* \param[in] wellState The production/injection data for all wells
*
* This routine should be called after the timestep has been advanced,
* i.e. timer.currentStepNum () > 0.
*/
virtual void writeTimeStep(const SimulatorTimerInterface& timer,
const SimulatorState& reservoirState,
const WellState& wellState,
bool isSubstep) = 0;
/*!
* Create a suitable set of output formats based on configuration.
*
* @param params Configuration properties. This function will setup a
* multiplexer of applicable output formats based on the
* desired configuration values.
*
* @param deck Input deck used to set up the simulation.
*
* @param eclipseState The internalized input deck.
*
* @return Pointer to a multiplexer to all applicable output formats.
*
* @see Opm::share_obj
*/
static std::unique_ptr <OutputWriter>
create (const parameter::ParameterGroup& params,
std::shared_ptr <const EclipseState> eclipseState,
const Opm::PhaseUsage &phaseUsage,
std::shared_ptr <const UnstructuredGrid> grid);
};
} // namespace Opm
#endif /* OPM_OUTPUT_WRITER_HPP */

View File

@ -1,459 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_CORNERPOINTCHOPPER_HEADER_INCLUDED
#define OPM_CORNERPOINTCHOPPER_HEADER_INCLUDED
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Parser/ParseMode.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/Deck/DeckDoubleItem.hpp>
#include <opm/parser/eclipse/Deck/DeckIntItem.hpp>
#include <opm/parser/eclipse/Deck/DeckStringItem.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdexcept>
#include <memory>
namespace Opm
{
class CornerPointChopper
{
public:
CornerPointChopper(const std::string& file)
{
Opm::ParseMode parseMode;
Opm::ParserPtr parser(new Opm::Parser());
deck_ = parser->parseFile(file , parseMode);
metricUnits_.reset(Opm::UnitSystem::newMETRIC());
Opm::DeckRecordConstPtr specgridRecord = deck_->getKeyword("SPECGRID")->getRecord(0);
dims_[0] = specgridRecord->getItem("NX")->getInt(0);
dims_[1] = specgridRecord->getItem("NY")->getInt(0);
dims_[2] = specgridRecord->getItem("NZ")->getInt(0);
int layersz = 8*dims_[0]*dims_[1];
const std::vector<double>& ZCORN = deck_->getKeyword("ZCORN")->getRawDoubleData();
botmax_ = *std::max_element(ZCORN.begin(), ZCORN.begin() + layersz/2);
topmin_ = *std::min_element(ZCORN.begin() + dims_[2]*layersz - layersz/2,
ZCORN.begin() + dims_[2]*layersz);
abszmax_ = *std::max_element(ZCORN.begin(), ZCORN.end());
abszmin_ = *std::min_element(ZCORN.begin(), ZCORN.end());
std::cout << "Parsed grdecl file with dimensions ("
<< dims_[0] << ", " << dims_[1] << ", " << dims_[2] << ")" << std::endl;
}
const int* dimensions() const
{
return dims_;
}
const int* newDimensions() const
{
return new_dims_;
}
const std::pair<double, double> zLimits() const
{
return std::make_pair(botmax_, topmin_);
}
const std::pair<double, double> abszLimits() const
{
return std::make_pair(abszmin_, abszmax_);
}
void verifyInscribedShoebox(int imin, int ilen, int imax,
int jmin, int jlen, int jmax,
double zmin, double zlen, double zmax)
{
if (imin < 0) {
std::cerr << "Error! imin < 0 (imin = " << imin << ")\n";
throw std::runtime_error("Inconsistent user input.");
}
if (ilen > dims_[0]) {
std::cerr << "Error! ilen larger than grid (ilen = " << ilen <<")\n";
throw std::runtime_error("Inconsistent user input.");
}
if (imax > dims_[0]) {
std::cerr << "Error! imax larger than input grid (imax = " << imax << ")\n";
throw std::runtime_error("Inconsistent user input.");
}
if (jmin < 0) {
std::cerr << "Error! jmin < 0 (jmin = " << jmin << ")\n";
throw std::runtime_error("Inconsistent user input.");
}
if (jlen > dims_[1]) {
std::cerr << "Error! jlen larger than grid (jlen = " << jlen <<")\n";
throw std::runtime_error("Inconsistent user input.");
}
if (jmax > dims_[1]) {
std::cerr << "Error! jmax larger than input grid (jmax = " << jmax << ")\n";
throw std::runtime_error("Inconsistent user input.");
}
if (zmin < abszmin_) {
std::cerr << "Error! zmin ("<< zmin << ") less than minimum ZCORN value ("<< abszmin_ << ")\n";
throw std::runtime_error("Inconsistent user input.");
}
if (zmax > abszmax_) {
std::cerr << "Error! zmax ("<< zmax << ") larger than maximal ZCORN value ("<< abszmax_ << ")\n";
throw std::runtime_error("Inconsistent user input.");
}
if (zlen > (abszmax_ - abszmin_)) {
std::cerr << "Error! zlen ("<< zlen <<") larger than maximal ZCORN (" << abszmax_ << ") minus minimal ZCORN ("<< abszmin_ <<")\n";
throw std::runtime_error("Inconsistent user input.");
}
}
void chop(int imin, int imax, int jmin, int jmax, double zmin, double zmax, bool resettoorigin=true)
{
new_dims_[0] = imax - imin;
new_dims_[1] = jmax - jmin;
// Filter the coord field
const std::vector<double>& COORD = deck_->getKeyword("COORD")->getRawDoubleData();
int num_coord = COORD.size();
if (num_coord != 6*(dims_[0] + 1)*(dims_[1] + 1)) {
std::cerr << "Error! COORD size (" << COORD.size() << ") not consistent with SPECGRID\n";
throw std::runtime_error("Inconsistent COORD and SPECGRID.");
}
int num_new_coord = 6*(new_dims_[0] + 1)*(new_dims_[1] + 1);
double x_correction = COORD[6*((dims_[0] + 1)*jmin + imin)];
double y_correction = COORD[6*((dims_[0] + 1)*jmin + imin) + 1];
new_COORD_.resize(num_new_coord, 1e100);
for (int j = jmin; j < jmax + 1; ++j) {
for (int i = imin; i < imax + 1; ++i) {
int pos = (dims_[0] + 1)*j + i;
int new_pos = (new_dims_[0] + 1)*(j-jmin) + (i-imin);
// Copy all 6 coordinates for a pillar.
std::copy(COORD.begin() + 6*pos, COORD.begin() + 6*(pos + 1), new_COORD_.begin() + 6*new_pos);
if (resettoorigin) {
// Substract lowest x value from all X-coords, similarly for y, and truncate in z-direction
new_COORD_[6*new_pos] -= x_correction;
new_COORD_[6*new_pos + 1] -= y_correction;
new_COORD_[6*new_pos + 2] = 0;
new_COORD_[6*new_pos + 3] -= x_correction;
new_COORD_[6*new_pos + 4] -= y_correction;
new_COORD_[6*new_pos + 5] = zmax-zmin;
}
}
}
// Get the z limits, check if they must be changed to make a shoe-box.
// This means that zmin must be greater than or equal to the highest
// coordinate of the bottom surface, while zmax must be less than or
// equal to the lowest coordinate of the top surface.
int layersz = 8*dims_[0]*dims_[1];
const std::vector<double>& ZCORN = deck_->getKeyword("ZCORN")->getRawDoubleData();
int num_zcorn = ZCORN.size();
if (num_zcorn != layersz*dims_[2]) {
std::cerr << "Error! ZCORN size (" << ZCORN.size() << ") not consistent with SPECGRID\n";
throw std::runtime_error("Inconsistent ZCORN and SPECGRID.");
}
zmin = std::max(zmin, botmax_);
zmax = std::min(zmax, topmin_);
if (zmin >= zmax) {
std::cerr << "Error: zmin >= zmax (zmin = " << zmin << ", zmax = " << zmax << ")\n";
throw std::runtime_error("zmin >= zmax");
}
std::cout << "Chopping subsample, i: (" << imin << "--" << imax << ") j: (" << jmin << "--" << jmax << ") z: (" << zmin << "--" << zmax << ")" << std::endl;
// We must find the maximum and minimum k value for the given z limits.
// First, find the first layer with a z-coordinate strictly above zmin.
int kmin = -1;
for (int k = 0; k < dims_[2]; ++k) {
double layer_max = *std::max_element(ZCORN.begin() + k*layersz, ZCORN.begin() + (k + 1)*layersz);
if (layer_max > zmin) {
kmin = k;
break;
}
}
// Then, find the last layer with a z-coordinate strictly below zmax.
int kmax = -1;
for (int k = dims_[2]; k > 0; --k) {
double layer_min = *std::min_element(ZCORN.begin() + (k - 1)*layersz, ZCORN.begin() + k*layersz);
if (layer_min < zmax) {
kmax = k;
break;
}
}
new_dims_[2] = kmax - kmin;
// Filter the ZCORN field, build mapping from new to old cells.
double z_origin_correction = 0.0;
if (resettoorigin) {
z_origin_correction = zmin;
}
new_ZCORN_.resize(8*new_dims_[0]*new_dims_[1]*new_dims_[2], 1e100);
new_to_old_cell_.resize(new_dims_[0]*new_dims_[1]*new_dims_[2], -1);
int cellcount = 0;
int delta[3] = { 1, 2*dims_[0], 4*dims_[0]*dims_[1] };
int new_delta[3] = { 1, 2*new_dims_[0], 4*new_dims_[0]*new_dims_[1] };
for (int k = kmin; k < kmax; ++k) {
for (int j = jmin; j < jmax; ++j) {
for (int i = imin; i < imax; ++i) {
new_to_old_cell_[cellcount++] = dims_[0]*dims_[1]*k + dims_[0]*j + i;
int old_ix = 2*(i*delta[0] + j*delta[1] + k*delta[2]);
int new_ix = 2*((i-imin)*new_delta[0] + (j-jmin)*new_delta[1] + (k-kmin)*new_delta[2]);
int old_indices[8] = { old_ix, old_ix + delta[0],
old_ix + delta[1], old_ix + delta[1] + delta[0],
old_ix + delta[2], old_ix + delta[2] + delta[0],
old_ix + delta[2] + delta[1], old_ix + delta[2] + delta[1] + delta[0] };
int new_indices[8] = { new_ix, new_ix + new_delta[0],
new_ix + new_delta[1], new_ix + new_delta[1] + new_delta[0],
new_ix + new_delta[2], new_ix + new_delta[2] + new_delta[0],
new_ix + new_delta[2] + new_delta[1], new_ix + new_delta[2] + new_delta[1] + new_delta[0] };
for (int cc = 0; cc < 8; ++cc) {
new_ZCORN_[new_indices[cc]] = std::min(zmax, std::max(zmin, ZCORN[old_indices[cc]])) - z_origin_correction;
}
}
}
}
filterIntegerField("ACTNUM", new_ACTNUM_);
filterDoubleField("PORO", new_PORO_);
filterDoubleField("NTG", new_NTG_);
filterDoubleField("SWCR", new_SWCR_);
filterDoubleField("SOWCR", new_SOWCR_);
filterDoubleField("PERMX", new_PERMX_);
filterDoubleField("PERMY", new_PERMY_);
filterDoubleField("PERMZ", new_PERMZ_);
filterIntegerField("SATNUM", new_SATNUM_);
}
/// Return a sub-deck with fields corresponding to the selected subset.
Opm::DeckConstPtr subDeck()
{
Opm::DeckPtr subDeck(new Opm::Deck);
Opm::DeckKeywordPtr specGridKw(new Opm::DeckKeyword("SPECGRID"));
Opm::DeckRecordPtr specGridRecord(new Opm::DeckRecord());
Opm::DeckIntItemPtr nxItem(new Opm::DeckIntItem("NX"));
Opm::DeckIntItemPtr nyItem(new Opm::DeckIntItem("NY"));
Opm::DeckIntItemPtr nzItem(new Opm::DeckIntItem("NZ"));
Opm::DeckIntItemPtr numresItem(new Opm::DeckIntItem("NUMRES"));
Opm::DeckStringItemPtr coordTypeItem(new Opm::DeckStringItem("COORD_TYPE"));
nxItem->push_back(new_dims_[0]);
nyItem->push_back(new_dims_[1]);
nzItem->push_back(new_dims_[2]);
numresItem->push_back(1);
coordTypeItem->push_back("F");
specGridRecord->addItem(nxItem);
specGridRecord->addItem(nyItem);
specGridRecord->addItem(nzItem);
specGridRecord->addItem(numresItem);
specGridRecord->addItem(coordTypeItem);
specGridKw->addRecord(specGridRecord);
subDeck->addKeyword(specGridKw);
addDoubleKeyword_(subDeck, "COORD", /*dimension=*/"Length", new_COORD_);
addDoubleKeyword_(subDeck, "ZCORN", /*dimension=*/"Length", new_ZCORN_);
addIntKeyword_(subDeck, "ACTNUM", new_ACTNUM_);
addDoubleKeyword_(subDeck, "PORO", /*dimension=*/"1", new_PORO_);
addDoubleKeyword_(subDeck, "NTG", /*dimension=*/"1", new_NTG_);
addDoubleKeyword_(subDeck, "SWCR", /*dimension=*/"1", new_SWCR_);
addDoubleKeyword_(subDeck, "SOWCR", /*dimension=*/"1", new_SOWCR_);
addDoubleKeyword_(subDeck, "PERMX", /*dimension=*/"Permeability", new_PERMX_);
addDoubleKeyword_(subDeck, "PERMY", /*dimension=*/"Permeability", new_PERMY_);
addDoubleKeyword_(subDeck, "PERMZ", /*dimension=*/"Permeability", new_PERMZ_);
addIntKeyword_(subDeck, "SATNUM", new_SATNUM_);
return subDeck;
}
void writeGrdecl(const std::string& filename)
{
// Output new versions of SPECGRID, COORD, ZCORN, ACTNUM, PERMX, PORO, SATNUM.
std::ofstream out(filename.c_str());
if (!out) {
std::cerr << "Could not open file " << filename << "\n";
throw std::runtime_error("Could not open output file.");
}
out << "SPECGRID\n" << new_dims_[0] << ' ' << new_dims_[1] << ' ' << new_dims_[2]
<< " 1 F\n/\n\n";
out.precision(15);
out.setf(std::ios::scientific);
outputField(out, new_COORD_, "COORD", /* nl = */ 3);
outputField(out, new_ZCORN_, "ZCORN", /* nl = */ 4);
outputField(out, new_ACTNUM_, "ACTNUM");
outputField(out, new_PORO_, "PORO", 4);
if (hasNTG()) {outputField(out, new_NTG_, "NTG", 4);}
if (hasSWCR()) {outputField(out, new_SWCR_, "SWCR", 4);}
if (hasSOWCR()) {outputField(out, new_SOWCR_, "SOWCR", 4);}
outputField(out, new_PERMX_, "PERMX", 4);
outputField(out, new_PERMY_, "PERMY", 4);
outputField(out, new_PERMZ_, "PERMZ", 4);
outputField(out, new_SATNUM_, "SATNUM");
}
bool hasNTG() const {return !new_NTG_.empty(); }
bool hasSWCR() const {return !new_SWCR_.empty(); }
bool hasSOWCR() const {return !new_SOWCR_.empty(); }
private:
Opm::DeckConstPtr deck_;
std::shared_ptr<Opm::UnitSystem> metricUnits_;
double botmax_;
double topmin_;
double abszmin_;
double abszmax_;
std::vector<double> new_COORD_;
std::vector<double> new_ZCORN_;
std::vector<int> new_ACTNUM_;
std::vector<double> new_PORO_;
std::vector<double> new_NTG_;
std::vector<double> new_SWCR_;
std::vector<double> new_SOWCR_;
std::vector<double> new_PERMX_;
std::vector<double> new_PERMY_;
std::vector<double> new_PERMZ_;
std::vector<int> new_SATNUM_;
int dims_[3];
int new_dims_[3];
std::vector<int> new_to_old_cell_;
void addDoubleKeyword_(Opm::DeckPtr subDeck,
const std::string& keywordName,
const std::string& dimensionString,
const std::vector<double>& data)
{
if (data.empty())
return;
Opm::DeckKeywordPtr dataKw(new Opm::DeckKeyword(keywordName));
Opm::DeckRecordPtr dataRecord(new Opm::DeckRecord());
Opm::DeckDoubleItemPtr dataItem(new Opm::DeckDoubleItem("DATA"));
for (size_t i = 0; i < data.size(); ++i) {
dataItem->push_back(data[i]);
}
std::shared_ptr<const Dimension> dimension = metricUnits_->parse(dimensionString);
dataItem->push_backDimension(/*active=*/dimension, /*default=*/dimension);
dataRecord->addItem(dataItem);
dataKw->addRecord(dataRecord);
subDeck->addKeyword(dataKw);
}
void addIntKeyword_(Opm::DeckPtr subDeck,
const std::string& keywordName,
const std::vector<int>& data)
{
if (data.empty())
return;
Opm::DeckKeywordPtr dataKw(new Opm::DeckKeyword(keywordName));
Opm::DeckRecordPtr dataRecord(new Opm::DeckRecord());
Opm::DeckIntItemPtr dataItem(new Opm::DeckIntItem("DATA"));
for (size_t i = 0; i < data.size(); ++i) {
dataItem->push_back(data[i]);
}
dataRecord->addItem(dataItem);
dataKw->addRecord(dataRecord);
subDeck->addKeyword(dataKw);
}
template <typename T>
void outputField(std::ostream& os,
const std::vector<T>& field,
const std::string& keyword,
const typename std::vector<T>::size_type nl = 20)
{
if (field.empty()) return;
os << keyword << '\n';
typedef typename std::vector<T>::size_type sz_t;
const sz_t n = field.size();
for (sz_t i = 0; i < n; ++i) {
os << field[i]
<< (((i + 1) % nl == 0) ? '\n' : ' ');
}
if (n % nl != 0) {
os << '\n';
}
os << "/\n\n";
}
template <typename T>
void filterField(const std::vector<T>& field,
std::vector<T>& output_field)
{
int sz = new_to_old_cell_.size();
output_field.resize(sz);
for (int i = 0; i < sz; ++i) {
output_field[i] = field[new_to_old_cell_[i]];
}
}
void filterDoubleField(const std::string& keyword, std::vector<double>& output_field)
{
if (deck_->hasKeyword(keyword)) {
const std::vector<double>& field = deck_->getKeyword(keyword)->getRawDoubleData();
filterField(field, output_field);
}
}
void filterIntegerField(const std::string& keyword, std::vector<int>& output_field)
{
if (deck_->hasKeyword(keyword)) {
const std::vector<int>& field = deck_->getKeyword(keyword)->getIntData();
filterField(field, output_field);
}
}
};
}
#endif // OPM_CORNERPOINTCHOPPER_HEADER_INCLUDED

View File

@ -1,347 +0,0 @@
//===========================================================================
//
// File: EclipseGridInspector.C
//
// Created: Mon Jun 2 12:17:51 2008
//
// Author: Atgeirr F Rasmussen <atgeirr@sintef.no>
//
// $Date$
//
// $Revision$
//
// Revision: $Id: EclipseGridInspector.C,v 1.2 2008/08/18 14:16:13 atgeirr Exp $
//
//===========================================================================
/*
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010 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/>.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <opm/core/io/eclipse/EclipseGridInspector.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <stdexcept>
#include <numeric>
#include <cmath>
#include <cfloat>
#include <algorithm>
#include <array>
#include <iostream>
namespace Opm
{
EclipseGridInspector::EclipseGridInspector(Opm::DeckConstPtr deck)
: deck_(deck)
{
init_();
}
void EclipseGridInspector::init_()
{
if (!deck_->hasKeyword("COORD")) {
OPM_THROW(std::runtime_error, "Needed field \"COORD\" is missing in file");
}
if (!deck_->hasKeyword("ZCORN")) {
OPM_THROW(std::runtime_error, "Needed field \"ZCORN\" is missing in file");
}
if (deck_->hasKeyword("SPECGRID")) {
Opm::DeckRecordConstPtr specgridRecord =
deck_->getKeyword("SPECGRID")->getRecord(0);
logical_gridsize_[0] = specgridRecord->getItem("NX")->getInt(0);
logical_gridsize_[1] = specgridRecord->getItem("NY")->getInt(0);
logical_gridsize_[2] = specgridRecord->getItem("NZ")->getInt(0);
} else if (deck_->hasKeyword("DIMENS")) {
Opm::DeckRecordConstPtr dimensRecord =
deck_->getKeyword("DIMENS")->getRecord(0);
logical_gridsize_[0] = dimensRecord->getItem("NX")->getInt(0);
logical_gridsize_[1] = dimensRecord->getItem("NY")->getInt(0);
logical_gridsize_[2] = dimensRecord->getItem("NZ")->getInt(0);
} else {
OPM_THROW(std::runtime_error, "Found neither SPECGRID nor DIMENS in file. At least one is needed.");
}
}
/**
Return the dip slopes for the cell relative to xy-plane in x- and y- direction.
Dip slope is average rise in positive x-direction over cell length in x-direction.
Similarly for y.
Current implementation is for vertical pillars, but is not difficult to fix.
@returns a std::pair<double,double> with x-dip in first component and y-dip in second.
*/
std::pair<double,double> EclipseGridInspector::cellDips(int i, int j, int k) const
{
checkLogicalCoords(i, j, k);
const std::vector<double>& pillc =
deck_->getKeyword("COORD")->getSIDoubleData();
int num_pillars = (logical_gridsize_[0] + 1)*(logical_gridsize_[1] + 1);
if (6*num_pillars != int(pillc.size())) {
throw std::runtime_error("Wrong size of COORD field.");
}
const std::vector<double>& z =
deck_->getKeyword("ZCORN")->getSIDoubleData();
int num_cells = logical_gridsize_[0]*logical_gridsize_[1]*logical_gridsize_[2];
if (8*num_cells != int(z.size())) {
throw std::runtime_error("Wrong size of ZCORN field");
}
// Pick ZCORN-value for all 8 corners of the given cell
std::array<double, 8> cellz = cellZvals(i, j, k);
// Compute rise in positive x-direction for all four edges (and then find mean)
// Current implementation is for regularly placed and vertical pillars!
int numxpill = logical_gridsize_[0] + 1;
int pix = i + j*numxpill;
double cell_xlength = pillc[6*(pix + 1)] - pillc[6*pix];
flush(std::cout);
double xrise[4] = { (cellz[1] - cellz[0])/cell_xlength, // LLL -> HLL
(cellz[3] - cellz[2])/cell_xlength, // LHL -> HHL
(cellz[5] - cellz[4])/cell_xlength, // LLH -> HLH
(cellz[7] - cellz[6])/cell_xlength}; // LHH -> HHH
double cell_ylength = pillc[6*(pix + numxpill) + 1] - pillc[6*pix + 1];
double yrise[4] = { (cellz[2] - cellz[0])/cell_ylength, // LLL -> LHL
(cellz[3] - cellz[1])/cell_ylength, // HLL -> HHL
(cellz[6] - cellz[4])/cell_ylength, // LLH -> LHH
(cellz[7] - cellz[5])/cell_ylength}; // HLH -> HHH
// Now ignore those edges that touch the global top or bottom surface
// of the entire grdecl model. This is to avoid bias, as these edges probably
// don't follow an overall dip for the model if it exists.
int x_edges = 4;
int y_edges = 4;
std::array<double, 6> gridlimits = getGridLimits();
double zmin = gridlimits[4];
double zmax = gridlimits[5];
// LLL -> HLL
if ((cellz[1] == zmin) || (cellz[0] == zmin)) {
xrise[0] = 0; x_edges--;
}
// LHL -> HHL
if ((cellz[2] == zmin) || (cellz[3] == zmin)) {
xrise[1] = 0; x_edges--;
}
// LLH -> HLH
if ((cellz[4] == zmax) || (cellz[5] == zmax)) {
xrise[2] = 0; x_edges--;
}
// LHH -> HHH
if ((cellz[6] == zmax) || (cellz[7] == zmax)) {
xrise[3] = 0; x_edges--;
}
// LLL -> LHL
if ((cellz[0] == zmin) || (cellz[2] == zmin)) {
yrise[0] = 0; y_edges--;
}
// HLL -> HHL
if ((cellz[1] == zmin) || (cellz[3] == zmin)) {
yrise[1] = 0; y_edges--;
}
// LLH -> LHH
if ((cellz[6] == zmax) || (cellz[4] == zmax)) {
yrise[2] = 0; y_edges--;
}
// HLH -> HHH
if ((cellz[7] == zmax) || (cellz[5] == zmax)) {
yrise[3] = 0; y_edges--;
}
return std::make_pair( (xrise[0] + xrise[1] + xrise[2] + xrise[3])/x_edges,
(yrise[0] + yrise[1] + yrise[2] + yrise[3])/y_edges);
}
/**
Wrapper for cellDips(i, j, k).
*/
std::pair<double,double> EclipseGridInspector::cellDips(int cell_idx) const
{
std::array<int, 3> idxs = cellIdxToLogicalCoords(cell_idx);
return cellDips(idxs[0], idxs[1], idxs[2]);
}
std::array<int, 3> EclipseGridInspector::cellIdxToLogicalCoords(int cell_idx) const
{
int i,j,k; // Position of cell in cell hierarchy
int horIdx = (cell_idx+1) - int(std::floor(((double)(cell_idx+1))/((double)(logical_gridsize_[0]*logical_gridsize_[1]))))*logical_gridsize_[0]*logical_gridsize_[1]; // index in the corresponding horizon
if (horIdx == 0) {
horIdx = logical_gridsize_[0]*logical_gridsize_[1];
}
i = horIdx - int(std::floor(((double)horIdx)/((double)logical_gridsize_[0])))*logical_gridsize_[0];
if (i == 0) {
i = logical_gridsize_[0];
}
j = (horIdx-i)/logical_gridsize_[0]+1;
k = ((cell_idx+1)-logical_gridsize_[0]*(j-1)-1)/(logical_gridsize_[0]*logical_gridsize_[1])+1;
std::array<int, 3> a = {{i-1, j-1, k-1}};
return a; //std::array<int, 3> {{i-1, j-1, k-1}};
}
double EclipseGridInspector::cellVolumeVerticalPillars(int i, int j, int k) const
{
// Checking parameters and obtaining values from parser.
checkLogicalCoords(i, j, k);
const std::vector<double>& pillc =
deck_->getKeyword("COORD")->getSIDoubleData();
int num_pillars = (logical_gridsize_[0] + 1)*(logical_gridsize_[1] + 1);
if (6*num_pillars != int(pillc.size())) {
throw std::runtime_error("Wrong size of COORD field.");
}
const std::vector<double>& z =
deck_->getKeyword("ZCORN")->getSIDoubleData();
int num_cells = logical_gridsize_[0]*logical_gridsize_[1]*logical_gridsize_[2];
if (8*num_cells != int(z.size())) {
throw std::runtime_error("Wrong size of ZCORN field");
}
// Computing the base area as half the 2d cross product of the diagonals.
int numxpill = logical_gridsize_[0] + 1;
int pix = i + j*numxpill;
double px[4] = { pillc[6*pix],
pillc[6*(pix + 1)],
pillc[6*(pix + numxpill)],
pillc[6*(pix + numxpill + 1)] };
double py[4] = { pillc[6*pix + 1],
pillc[6*(pix + 1) + 1],
pillc[6*(pix + numxpill) + 1],
pillc[6*(pix + numxpill + 1) + 1] };
double diag1[2] = { px[3] - px[0], py[3] - py[0] };
double diag2[2] = { px[2] - px[1], py[2] - py[1] };
double area = 0.5*(diag1[0]*diag2[1] - diag1[1]*diag2[0]);
// Computing the average of the z-differences along each pillar.
int delta[3] = { 1,
2*logical_gridsize_[0],
4*logical_gridsize_[0]*logical_gridsize_[1] };
int ix = 2*(i*delta[0] + j*delta[1] + k*delta[2]);
double cellz[8] = { z[ix], z[ix + delta[0]],
z[ix + delta[1]], z[ix + delta[1] + delta[0]],
z[ix + delta[2]], z[ix + delta[2] + delta[0]],
z[ix + delta[2] + delta[1]], z[ix + delta[2] + delta[1] + delta[0]] };
double diffz[4] = { cellz[4] - cellz[0],
cellz[5] - cellz[1],
cellz[6] - cellz[2],
cellz[7] - cellz[3] };
double averzdiff = 0.25*std::accumulate(diffz, diffz + 4, 0.0);
return averzdiff*area;
}
double EclipseGridInspector::cellVolumeVerticalPillars(int cell_idx) const
{
std::array<int, 3> idxs = cellIdxToLogicalCoords(cell_idx);
return cellVolumeVerticalPillars(idxs[0], idxs[1], idxs[2]);
}
void EclipseGridInspector::checkLogicalCoords(int i, int j, int k) const
{
if (i < 0 || i >= logical_gridsize_[0])
throw std::runtime_error("First coordinate out of bounds");
if (j < 0 || j >= logical_gridsize_[1])
throw std::runtime_error("Second coordinate out of bounds");
if (k < 0 || k >= logical_gridsize_[2])
throw std::runtime_error("Third coordinate out of bounds");
}
std::array<double, 6> EclipseGridInspector::getGridLimits() const
{
if (! (deck_->hasKeyword("COORD") && deck_->hasKeyword("ZCORN") && deck_->hasKeyword("SPECGRID")) ) {
throw std::runtime_error("EclipseGridInspector: Grid does not have SPECGRID, COORD, and ZCORN, can't find dimensions.");
}
std::vector<double> coord = deck_->getKeyword("COORD")->getSIDoubleData();
std::vector<double> zcorn = deck_->getKeyword("ZCORN")->getSIDoubleData();
double xmin = +DBL_MAX;
double xmax = -DBL_MAX;
double ymin = +DBL_MAX;
double ymax = -DBL_MAX;
int pillars = (logical_gridsize_[0]+1) * (logical_gridsize_[1]+1);
for (int pillarindex = 0; pillarindex < pillars; ++pillarindex) {
if (coord[pillarindex * 6 + 0] > xmax)
xmax = coord[pillarindex * 6 + 0];
if (coord[pillarindex * 6 + 0] < xmin)
xmin = coord[pillarindex * 6 + 0];
if (coord[pillarindex * 6 + 1] > ymax)
ymax = coord[pillarindex * 6 + 1];
if (coord[pillarindex * 6 + 1] < ymin)
ymin = coord[pillarindex * 6 + 1];
if (coord[pillarindex * 6 + 3] > xmax)
xmax = coord[pillarindex * 6 + 3];
if (coord[pillarindex * 6 + 3] < xmin)
xmin = coord[pillarindex * 6 + 3];
if (coord[pillarindex * 6 + 4] > ymax)
ymax = coord[pillarindex * 6 + 4];
if (coord[pillarindex * 6 + 4] < ymin)
ymin = coord[pillarindex * 6 + 4];
}
std::array<double, 6> gridlimits = {{ xmin, xmax, ymin, ymax,
*min_element(zcorn.begin(), zcorn.end()),
*max_element(zcorn.begin(), zcorn.end()) }};
return gridlimits;
}
std::array<int, 3> EclipseGridInspector::gridSize() const
{
std::array<int, 3> retval = {{ logical_gridsize_[0],
logical_gridsize_[1],
logical_gridsize_[2] }};
return retval;
}
std::array<double, 8> EclipseGridInspector::cellZvals(int i, int j, int k) const
{
// Get the zcorn field.
const std::vector<double>& z = deck_->getKeyword("ZCORN")->getSIDoubleData();
int num_cells = logical_gridsize_[0]*logical_gridsize_[1]*logical_gridsize_[2];
if (8*num_cells != int(z.size())) {
throw std::runtime_error("Wrong size of ZCORN field");
}
// Make the coordinate array.
int delta[3] = { 1,
2*logical_gridsize_[0],
4*logical_gridsize_[0]*logical_gridsize_[1] };
int ix = 2*(i*delta[0] + j*delta[1] + k*delta[2]);
std::array<double, 8> cellz = {{ z[ix], z[ix + delta[0]],
z[ix + delta[1]], z[ix + delta[1] + delta[0]],
z[ix + delta[2]], z[ix + delta[2] + delta[0]],
z[ix + delta[2] + delta[1]], z[ix + delta[2] + delta[1] + delta[0]] }};
return cellz;
}
} // namespace Opm

View File

@ -1,103 +0,0 @@
//===========================================================================
//
// File: EclipseGridInspector.h
//
// Created: Mon Jun 2 09:46:08 2008
//
// Author: Atgeirr F Rasmussen <atgeirr@sintef.no>
//
// $Date$
//
// Revision: $Id: EclipseGridInspector.h,v 1.2 2008/08/18 14:16:12 atgeirr Exp $
//
//===========================================================================
/*
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010 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_ECLIPSEGRIDINSPECTOR_HEADER
#define OPM_ECLIPSEGRIDINSPECTOR_HEADER
#include <vector>
#include <array>
#include <opm/parser/eclipse/Deck/Deck.hpp>
namespace Opm
{
/**
@brief A class for inspecting the contents of an eclipse file.
Given an Eclipse deck, this class may be used to answer certain
queries about its contents.
@author Atgeirr F. Rasmussen <atgeirr@sintef.no>
@date 2008/06/02 09:46:08
*/
class EclipseGridInspector
{
public:
/// Constructor taking a parser as argument.
/// The parser must already have read an Eclipse file.
EclipseGridInspector(Opm::DeckConstPtr deck);
/// Assuming that the pillars are vertical, compute the
/// volume of the cell given by logical coordinates (i, j, k).
double cellVolumeVerticalPillars(int i, int j, int k) const;
/// Assuming that the pillars are vertical, compute the
/// volume of the cell given by the cell index
double cellVolumeVerticalPillars(int cell_idx) const;
/// Compute the average dip in x- and y-direction of the
/// cell tops and bottoms relative to the xy-plane
std::pair<double,double> cellDips(int i, int j, int k) const;
std::pair<double,double> cellDips(int cell_idx) const;
// Convert global cell index to logical ijk-coordinates
std::array<int, 3> cellIdxToLogicalCoords(int cell_idx) const;
/// Returns a vector with the outer limits of grid (in the grid's unit).
/// The vector contains [xmin, xmax, ymin, ymax, zmin, zmax], as
/// read from COORDS and ZCORN
std::array<double, 6> getGridLimits() const;
/// Returns the extent of the logical cartesian grid
/// as number of cells in the (i, j, k) directions.
std::array<int, 3> gridSize() const;
/// Returns the eight z-values associated with a given cell.
/// The ordering is such that i runs fastest. That is, with
/// L = low and H = high:
/// {LLL, HLL, LHL, HHL, LLH, HLH, LHH, HHH }.
std::array<double, 8> cellZvals(int i, int j, int k) const;
private:
Opm::DeckConstPtr deck_;
int logical_gridsize_[3];
void init_();
void checkLogicalCoords(int i, int j, int k) const;
};
} // namespace Opm
#endif // OPM_ECLIPSEGRIDINSPECTOR_HEADER

View File

@ -1,34 +0,0 @@
#ifndef ECLIPSE_IO_UTIL_HPP
#define ECLIPSE_IO_UTIL_HPP
#include <vector>
#include <string>
#include <iostream>
namespace Opm
{
namespace EclipseIOUtil
{
template <typename T>
void addToStripedData(const std::vector<T>& data, std::vector<T>& result, size_t offset, size_t stride) {
int dataindex = 0;
for (size_t index = offset; index < result.size(); index += stride) {
result[index] = data[dataindex];
++dataindex;
}
}
template <typename T>
void extractFromStripedData(const std::vector<T>& data, std::vector<T>& result, size_t offset, size_t stride) {
for (size_t index = offset; index < data.size(); index += stride) {
result.push_back(data[index]);
}
}
} //namespace EclipseIOUtil
} //namespace Opm
#endif //ECLIPSE_IO_UTIL_HPP

View File

@ -1,157 +0,0 @@
/*
Copyright 2015 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 "EclipseReader.hpp"
#include <opm/core/simulator/WellState.hpp>
#include <opm/core/simulator/SimulatorState.hpp>
#include <opm/core/utility/Units.hpp>
#include <opm/core/grid/GridHelpers.hpp>
#include <opm/core/io/eclipse/EclipseIOUtil.hpp>
#include <algorithm>
#include <ert/ecl/ecl_file.h>
namespace Opm
{
void restoreOPM_XWELKeyword(const std::string& restart_filename, int reportstep, WellState& wellstate)
{
const char * keyword = "OPM_XWEL";
const char* filename = restart_filename.c_str();
ecl_file_type* file_type = ecl_file_open(filename, 0);
if (file_type != NULL) {
bool block_selected = ecl_file_select_rstblock_report_step(file_type , reportstep);
if (block_selected) {
ecl_kw_type* xwel = ecl_file_iget_named_kw(file_type , keyword, 0);
const double* xwel_data = ecl_kw_get_double_ptr(xwel);
std::copy_n(xwel_data + wellstate.getRestartTemperatureOffset(), wellstate.temperature().size(), wellstate.temperature().begin());
std::copy_n(xwel_data + wellstate.getRestartBhpOffset(), wellstate.bhp().size(), wellstate.bhp().begin());
std::copy_n(xwel_data + wellstate.getRestartPerfPressOffset(), wellstate.perfPress().size(), wellstate.perfPress().begin());
std::copy_n(xwel_data + wellstate.getRestartPerfRatesOffset(), wellstate.perfRates().size(), wellstate.perfRates().begin());
std::copy_n(xwel_data + wellstate.getRestartWellRatesOffset(), wellstate.wellRates().size(), wellstate.wellRates().begin());
}
ecl_file_close(file_type);
}
}
namespace {
void restoreTemperatureData(const ecl_file_type* file,
const EclipseState& eclipse_state,
const UnstructuredGrid& grid,
SimulatorState& simulator_state) {
const char* temperature_keyword = "TEMP";
if (ecl_file_has_kw(file , temperature_keyword)) {
ecl_kw_type* temperature_kw = ecl_file_iget_named_kw(file, temperature_keyword, 0);
if (ecl_kw_get_size(temperature_kw) != Opm::UgGridHelpers::numCells(grid)) {
throw std::runtime_error("Read of restart file: Could not restore temperature data, length of data from file not equal number of cells");
}
float* temperature_data = ecl_kw_get_float_ptr(temperature_kw);
// factor and offset from the temperature values given in the deck to Kelvin
double scaling = eclipse_state.getDeckUnitSystem()->parse("Temperature")->getSIScaling();
double offset = eclipse_state.getDeckUnitSystem()->parse("Temperature")->getSIOffset();
for (size_t index = 0; index < simulator_state.temperature().size(); ++index) {
simulator_state.temperature()[index] = unit::convert::from((double)temperature_data[index] - offset, scaling);
}
}
}
void restorePressureData(const ecl_file_type* file,
const EclipseState& eclipse_state,
const UnstructuredGrid& grid,
SimulatorState& simulator_state) {
const char* pressure_keyword = "PRESSURE";
if (ecl_file_has_kw(file , pressure_keyword)) {
ecl_kw_type* pressure_kw = ecl_file_iget_named_kw(file, pressure_keyword, 0);
if (ecl_kw_get_size(pressure_kw) != Opm::UgGridHelpers::numCells(grid)) {
throw std::runtime_error("Read of restart file: Could not restore pressure data, length of data from file not equal number of cells");
}
float* pressure_data = ecl_kw_get_float_ptr(pressure_kw);
const double deck_pressure_unit = (eclipse_state.getDeckUnitSystem()->getType() == UnitSystem::UNIT_TYPE_METRIC) ? Opm::unit::barsa : Opm::unit::psia;
for (size_t index = 0; index < simulator_state.pressure().size(); ++index) {
simulator_state.pressure()[index] = unit::convert::from((double)pressure_data[index], deck_pressure_unit);
}
}
}
}
void restoreSOLUTIONData(const std::string& restart_filename,
int reportstep,
const EclipseState& eclipseState,
const UnstructuredGrid& grid,
const PhaseUsage& phaseUsage,
SimulatorState& simulator_state)
{
const char* filename = restart_filename.c_str();
ecl_file_type* file_type = ecl_file_open(filename, 0);
if (file_type != NULL) {
bool block_selected = ecl_file_select_rstblock_report_step(file_type , reportstep);
if (block_selected) {
restorePressureData(file_type, eclipseState, grid, simulator_state);
restoreTemperatureData(file_type, eclipseState, grid, simulator_state);
int numcells = Opm::UgGridHelpers::numCells(grid);
float* sgas_data = NULL;
float* swat_data = NULL;
if (phaseUsage.phase_used[BlackoilPhases::Aqua]) {
ecl_kw_type* swat_kw = ecl_file_iget_named_kw(file_type , "SWAT", 0);
swat_data = ecl_kw_get_float_ptr(swat_kw);
std::vector<double> swat_datavec(&swat_data[0], &swat_data[numcells]);
EclipseIOUtil::addToStripedData(swat_datavec, simulator_state.saturation(), phaseUsage.phase_pos[BlackoilPhases::Aqua], phaseUsage.num_phases);
}
if (phaseUsage.phase_used[BlackoilPhases::Vapour]) {
ecl_kw_type* sgas_kw = ecl_file_iget_named_kw(file_type , "SGAS", 0);
sgas_data = ecl_kw_get_float_ptr(sgas_kw);
std::vector<double> sgas_datavec(&sgas_data[0], &sgas_data[numcells]);
EclipseIOUtil::addToStripedData(sgas_datavec, simulator_state.saturation(), phaseUsage.phase_pos[BlackoilPhases::Vapour], phaseUsage.num_phases);
}
} else {
std::cerr << "Warning: Could not load solution data for report step " << reportstep << ", data for reportstep not found on file " << filename << std::endl;
}
ecl_file_close(file_type);
}
}
} // namespace Opm

View File

@ -1,34 +0,0 @@
#ifndef ECLIPSEREADER_HPP
#define ECLIPSEREADER_HPP
#include <string>
#include <opm/core/simulator/WellState.hpp>
#include <opm/core/simulator/SimulatorState.hpp>
#include <opm/core/props/BlackoilPhases.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
namespace Opm
{
///
/// \brief restoreOPM_XWELKeyword
/// Reading from the restart file, information stored under the OPM_XWEL keyword is in this method filled into
/// an instance of a wellstate object.
/// \param restart_filename
/// The filename of the restart file.
/// \param reportstep
/// The report step to restart from.
/// \param wellstate
/// An instance of a WellState object, with correct size for each of the 5 contained std::vector<double> objects.
///
void restoreOPM_XWELKeyword(const std::string& restart_filename, int report_step, WellState& wellState);
void restoreSOLUTIONData(const std::string& restart_filename,
int report_step,
const EclipseState &eclipseState,
const UnstructuredGrid& grid,
const PhaseUsage& phaseUsage,
SimulatorState& simulator_state);
}
#endif // ECLIPSEREADER_HPP

View File

@ -1,63 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_ECLIPSEUNITS_HEADER_INCLUDED
#define OPM_ECLIPSEUNITS_HEADER_INCLUDED
namespace Opm
{
struct EclipseUnits
{
double length;
double time;
double density;
double polymer_density;
double pressure;
double compressibility;
double viscosity;
double permeability;
double liqvol_s;
double liqvol_r;
double gasvol_s;
double gasvol_r;
double transmissibility;
void setToOne()
{
length = 1.0;
time = 1.0;
density = 1.0;
polymer_density = 1.0;
pressure = 1.0;
compressibility = 1.0;
viscosity = 1.0;
permeability = 1.0;
liqvol_s = 1.0;
liqvol_r = 1.0;
gasvol_s = 1.0;
gasvol_r = 1.0;
transmissibility = 1.0;
}
};
} // namespace Opm
#endif // OPM_ECLIPSEUNITS_HEADER_INCLUDED

View File

@ -1,145 +0,0 @@
/*
Copyright 2015 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 <vector>
#include <opm/core/io/eclipse/EclipseWriteRFTHandler.hpp>
#include <opm/core/simulator/SimulatorState.hpp>
#include <opm/core/simulator/BlackoilState.hpp>
#include <opm/core/simulator/SimulatorTimer.hpp>
#include <opm/core/props/BlackoilPhases.hpp>
#include <opm/core/utility/Units.hpp>
#include <opm/core/utility/miscUtilities.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellSet.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <ert/ecl/ecl_rft_node.h>
#include <ert/ecl/ecl_rft_file.h>
namespace Opm {
namespace EclipseWriterDetails {
EclipseWriteRFTHandler::EclipseWriteRFTHandler(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize) {
initGlobalToActiveIndex(compressedToCartesianCellIdx, numCells, cartesianSize);
}
void EclipseWriteRFTHandler::writeTimeStep(const std::string& filename,
const ert_ecl_unit_enum ecl_unit,
const SimulatorTimerInterface& simulatorTimer,
std::vector<WellConstPtr>& wells,
EclipseGridConstPtr eclipseGrid,
std::vector<double>& pressure,
std::vector<double>& swat,
std::vector<double>& sgas) {
std::vector<ecl_rft_node_type *> rft_nodes;
for (std::vector<WellConstPtr>::const_iterator ci = wells.begin(); ci != wells.end(); ++ci) {
WellConstPtr well = *ci;
if ((well->getRFTActive(simulatorTimer.reportStepNum())) || (well->getPLTActive(simulatorTimer.reportStepNum()))) {
ecl_rft_node_type * ecl_node = createEclRFTNode(well,
simulatorTimer,
eclipseGrid,
pressure,
swat,
sgas);
// TODO: replace this silenced warning with an appropriate
// use of the OpmLog facilities.
// if (well->getPLTActive(simulatorTimer.reportStepNum())) {
// std::cerr << "PLT not supported, writing RFT data" << std::endl;
// }
rft_nodes.push_back(ecl_node);
}
}
if (rft_nodes.size() > 0) {
ecl_rft_file_update(filename.c_str(), rft_nodes.data(), rft_nodes.size(), ecl_unit);
}
//Cleanup: The ecl_rft_file_update method takes care of freeing the ecl_rft_nodes that it receives.
// Each ecl_rft_node is again responsible for freeing it's cells.
}
ecl_rft_node_type * EclipseWriteRFTHandler::createEclRFTNode(WellConstPtr well,
const SimulatorTimerInterface& simulatorTimer,
EclipseGridConstPtr eclipseGrid,
const std::vector<double>& pressure,
const std::vector<double>& swat,
const std::vector<double>& sgas) {
const std::string& well_name = well->name();
size_t timestep = (size_t)simulatorTimer.reportStepNum();
time_t recording_date = simulatorTimer.currentPosixTime();
double days = Opm::unit::convert::to(simulatorTimer.simulationTimeElapsed(), Opm::unit::day);
std::string type = "RFT";
ecl_rft_node_type * ecl_rft_node = ecl_rft_node_alloc_new(well_name.c_str(), type.c_str(), recording_date, days);
CompletionSetConstPtr completionsSet = well->getCompletions(timestep);
for (size_t index = 0; index < completionsSet->size(); ++index) {
CompletionConstPtr completion = completionsSet->get(index);
size_t i = (size_t)completion->getI();
size_t j = (size_t)completion->getJ();
size_t k = (size_t)completion->getK();
size_t global_index = eclipseGrid->getGlobalIndex(i,j,k);
int active_index = globalToActiveIndex_[global_index];
if (active_index > -1) {
double depth = eclipseGrid->getCellDepth(i,j,k);
double completion_pressure = pressure.size() > 0 ? pressure[active_index] : 0.0;
double saturation_water = swat.size() > 0 ? swat[active_index] : 0.0;
double saturation_gas = sgas.size() > 0 ? sgas[active_index] : 0.0;
ecl_rft_cell_type * ecl_rft_cell = ecl_rft_cell_alloc_RFT( i ,j, k , depth, completion_pressure, saturation_water, saturation_gas);
ecl_rft_node_append_cell( ecl_rft_node , ecl_rft_cell);
}
}
return ecl_rft_node;
}
void EclipseWriteRFTHandler::initGlobalToActiveIndex(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize) {
globalToActiveIndex_.resize(cartesianSize, -1);
for (size_t active_index = 0; active_index < numCells; ++active_index) {
//If compressedToCartesianCellIdx is NULL, assume no compressed to cartesian mapping, set global equal to active index
int global_index = (NULL != compressedToCartesianCellIdx) ? compressedToCartesianCellIdx[active_index] : active_index;
globalToActiveIndex_[global_index] = active_index;
}
}
}//namespace EclipseWriterDetails
}//namespace Opm

View File

@ -1,76 +0,0 @@
/*
Copyright 2015 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_ECLIPSE_WRITE_RFT_HANDLER_HPP
#define OPM_ECLIPSE_WRITE_RFT_HANDLER_HPP
#include <opm/core/simulator/SimulatorTimer.hpp>
#include <opm/core/simulator/BlackoilState.hpp>
#include <opm/core/simulator/SimulatorState.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <ert/ecl/ecl_rft_node.h>
#include <ert/ecl/ecl_util.h>
namespace Opm {
namespace EclipseWriterDetails {
class EclipseWriteRFTHandler {
public:
EclipseWriteRFTHandler(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize);
void writeTimeStep(const std::string& filename,
const ert_ecl_unit_enum ecl_unit,
const SimulatorTimerInterface& simulatorTimer,
std::vector<WellConstPtr>& wells,
EclipseGridConstPtr eclipseGrid,
std::vector<double>& pressure,
std::vector<double>& swat,
std::vector<double>& sgas);
private:
ecl_rft_node_type * createEclRFTNode(WellConstPtr well,
const SimulatorTimerInterface& simulatorTimer,
EclipseGridConstPtr eclipseGrid,
const std::vector<double>& pressure,
const std::vector<double>& swat,
const std::vector<double>& sgas);
void initGlobalToActiveIndex(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize);
std::vector<int> globalToActiveIndex_;
};
}//namespace EclipseWriterDetails
}//namespace Opm
#endif //OPM_ECLIPSE_WRITE_RFT_HANDLER_HPP

File diff suppressed because it is too large Load Diff

View File

@ -1,134 +0,0 @@
/*
Copyright (c) 2013 Andreas Lauser
Copyright (c) 2013 Uni Research AS
Copyright (c) 2014 IRIS AS
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_ECLIPSE_WRITER_HPP
#define OPM_ECLIPSE_WRITER_HPP
#include <opm/core/io/OutputWriter.hpp>
#include <opm/core/props/BlackoilPhases.hpp>
#include <opm/core/wells.h> // WellType
#include <opm/core/simulator/SimulatorTimerInterface.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <string>
#include <vector>
#include <array>
#include <memory>
struct UnstructuredGrid;
namespace Opm {
// forward declarations
namespace EclipseWriterDetails {
class Summary;
}
class SimulatorState;
class WellState;
namespace parameter { class ParameterGroup; }
/*!
* \brief A class to write the reservoir state and the well state of a
* blackoil simulation to disk using the Eclipse binary format.
*
* This class only writes files if the 'write_output' parameter is set
* to 1. It needs the ERT libraries to write to disk, so if the
* 'write_output' parameter is set but ERT is not available, all
* methods throw a std::runtime_error.
*/
class EclipseWriter : public OutputWriter
{
public:
/*!
* \brief Sets the common attributes required to write eclipse
* binary files using ERT.
*/
EclipseWriter(const parameter::ParameterGroup& params,
Opm::EclipseStateConstPtr eclipseState,
const Opm::PhaseUsage &phaseUsage,
int numCells,
const int* compressedToCartesianCellIdx);
/**
* We need a destructor in the compilation unit to avoid the
* EclipseSummary being a complete type here.
*/
virtual ~EclipseWriter ();
/**
* Write the static eclipse data (grid, PVT curves, etc) to disk.
*/
virtual void writeInit(const SimulatorTimerInterface &timer);
/*!
* \brief Write a reservoir state and summary information to disk.
*
*
* The reservoir state can be inspected with visualization tools like
* ResInsight.
*
* The summary information can then be visualized using tools from
* ERT or ECLIPSE. Note that calling this method is only
* meaningful after the first time step has been completed.
*
* \param[in] timer The timer providing time step and time information
* \param[in] reservoirState The thermodynamic state of the reservoir
* \param[in] wellState The production/injection data for all wells
*/
virtual void writeTimeStep(const SimulatorTimerInterface& timer,
const SimulatorState& reservoirState,
const WellState& wellState, bool isSubstep );
static int eclipseWellTypeMask(WellType wellType, WellInjector::TypeEnum injectorType);
static int eclipseWellStatusMask(WellCommon::StatusEnum wellStatus);
static ert_ecl_unit_enum convertUnitTypeErtEclUnitEnum(UnitSystem::UnitType unit);
private:
Opm::EclipseStateConstPtr eclipseState_;
int numCells_;
std::array<int, 3> cartesianSize_;
const int* compressedToCartesianCellIdx_;
std::vector< int > gridToEclipseIdx_;
double deckToSiPressure_;
double deckToSiTemperatureFactor_;
double deckToSiTemperatureOffset_;
bool enableOutput_;
int writeStepIdx_;
int reportStepIdx_;
std::string outputDir_;
std::string baseName_;
PhaseUsage phaseUsage_; // active phases in the input deck
std::shared_ptr<EclipseWriterDetails::Summary> summary_;
void init(const parameter::ParameterGroup& params);
};
typedef std::shared_ptr<EclipseWriter> EclipseWriterPtr;
typedef std::shared_ptr<const EclipseWriter> EclipseWriterConstPtr;
} // namespace Opm
#endif // OPM_ECLIPSE_WRITER_HPP

View File

@ -1,193 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
Copyright 2012 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/>.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <opm/core/grid.h>
#include <opm/core/io/eclipse/writeECLData.hpp>
#include <opm/core/utility/Units.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <vector>
#ifdef HAVE_ERT // This one goes almost to the bottom of the file
#include <ert/ecl/ecl_grid.h>
#include <ert/ecl/ecl_util.h>
#include <ert/ecl/ecl_rst_file.h>
namespace Opm
{
static ecl_kw_type * ecl_kw_wrapper( const UnstructuredGrid& grid,
const std::string& kw_name ,
const std::vector<double> * data ,
int offset ,
int stride ) {
if (stride <= 0)
OPM_THROW(std::runtime_error, "Vector strides must be positive. Got stride = " << stride);
if ((stride * std::vector<double>::size_type(grid.number_of_cells)) != data->size())
OPM_THROW(std::runtime_error, "Internal mismatch grid.number_of_cells: " << grid.number_of_cells << " data size: " << data->size() / stride);
{
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw_name.c_str() , grid.number_of_cells , ECL_FLOAT_TYPE );
for (int i=0; i < grid.number_of_cells; i++)
ecl_kw_iset_float( ecl_kw , i , (*data)[i*stride + offset]);
return ecl_kw;
}
}
/*
This function will write the data solution data in the DataMap
@data as an ECLIPSE restart file, in addition to the solution
fields the ECLIPSE restart file will have a minimum (hopefully
sufficient) amount of header information.
The ECLIPSE restart files come in two varietes; unified restart
files which have all the report steps lumped together in one large
chunk and non-unified restart files which are one file for each
report step. In addition the files can be either formatted
(i.e. ASCII) or unformatted (i.e. binary).
The writeECLData() function has two hardcoded settings:
'file_type' and 'fmt_file' which regulate which type of files the
should be created. The extension of the files follow a convention:
Unified, formatted : .FUNRST
Unified, unformatted : .UNRST
Multiple, formatted : .Fnnnn
Multiple, unformatted : .Xnnnn
For the multiple files the 'nnnn' part is the report number,
formatted with '%04d' format specifier. The writeECLData()
function will use the ecl_util_alloc_filename() function to create
an ECLIPSE filename according to this conventions.
*/
void writeECLData(const UnstructuredGrid& grid,
const DataMap& data,
const int current_step,
const double current_time,
const boost::posix_time::ptime& current_date_time,
const std::string& output_dir,
const std::string& base_name) {
ecl_file_enum file_type = ECL_UNIFIED_RESTART_FILE; // Alternatively ECL_RESTART_FILE for multiple restart files.
bool fmt_file = false;
char * filename = ecl_util_alloc_filename(output_dir.c_str() , base_name.c_str() , file_type , fmt_file , current_step );
int phases = ECL_OIL_PHASE + ECL_WATER_PHASE;
time_t date = 0;
int nx = grid.cartdims[0];
int ny = grid.cartdims[1];
int nz = grid.cartdims[2];
int nactive = grid.number_of_cells;
ecl_rst_file_type * rst_file;
{
using namespace boost::posix_time;
ptime t0( boost::gregorian::date(1970 , 1 ,1) );
time_duration::sec_type seconds = (current_date_time - t0).total_seconds();
date = time_t( seconds );
}
if (current_step > 0 && file_type == ECL_UNIFIED_RESTART_FILE)
rst_file = ecl_rst_file_open_append( filename );
else
rst_file = ecl_rst_file_open_write( filename );
{
ecl_rsthead_type rsthead_data = {};
const int num_wells = 0;
const int niwelz = 0;
const int nzwelz = 0;
const int niconz = 0;
const int ncwmax = 0;
rsthead_data.nx = nx;
rsthead_data.ny = ny;
rsthead_data.nz = nz;
rsthead_data.nwells = num_wells;
rsthead_data.niwelz = niwelz;
rsthead_data.nzwelz = nzwelz;
rsthead_data.niconz = niconz;
rsthead_data.ncwmax = ncwmax;
rsthead_data.nactive = nactive;
rsthead_data.phase_sum = phases;
rsthead_data.sim_time = date;
rsthead_data.sim_days = Opm::unit::convert::to(current_time, Opm::unit::day); //Data for doubhead
ecl_rst_file_fwrite_header( rst_file , current_step , &rsthead_data);
}
ecl_rst_file_start_solution( rst_file );
{
DataMap::const_iterator i = data.find("pressure");
if (i != data.end()) {
ecl_kw_type * pressure_kw = ecl_kw_wrapper( grid , "PRESSURE" , i->second , 0 , 1);
ecl_rst_file_add_kw( rst_file , pressure_kw );
ecl_kw_free( pressure_kw );
}
}
{
DataMap::const_iterator i = data.find("saturation");
if (i != data.end()) {
if (int(i->second->size()) != 2 * grid.number_of_cells) {
OPM_THROW(std::runtime_error, "writeECLData() requires saturation field to have two phases.");
}
ecl_kw_type * swat_kw = ecl_kw_wrapper( grid , "SWAT" , i->second , 0 , 2);
ecl_rst_file_add_kw( rst_file , swat_kw );
ecl_kw_free( swat_kw );
}
}
ecl_rst_file_end_solution( rst_file );
ecl_rst_file_close( rst_file );
free(filename);
}
}
#else // that is, we have not defined HAVE_ERT
namespace Opm
{
void writeECLData(const UnstructuredGrid&,
const DataMap&,
const int,
const double,
const boost::posix_time::ptime&,
const std::string&,
const std::string&)
{
OPM_THROW(std::runtime_error, "Cannot call writeECLData() without ERT library support. Reconfigure opm-core with ERT support and recompile.");
}
}
#endif

View File

@ -1,46 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
Copyright 2012 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_WRITEECLDATA_HEADER_INCLUDED
#define OPM_WRITEECLDATA_HEADER_INCLUDED
#include <opm/core/utility/DataMap.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <string>
struct UnstructuredGrid;
namespace Opm
{
// ECLIPSE output for general grids.
void writeECLData(const UnstructuredGrid& grid,
const DataMap& data,
const int current_step,
const double current_time,
const boost::posix_time::ptime& current_date_time,
const std::string& output_dir,
const std::string& base_name);
}
#endif

View File

@ -1,408 +0,0 @@
/*===========================================================================
//
// File: vag.cpp
//
// Created: 2012-06-08 15:45:53+0200
//
// Authors: Knut-Andreas Lie <Knut-Andreas.Lie@sintef.no>
// Halvor M. Nilsen <HalvorMoll.Nilsen@sintef.no>
// Atgeirr F. Rasmussen <atgeirr@sintef.no>
// Xavier Raynaud <Xavier.Raynaud@sintef.no>
// Bård Skaflestad <Bard.Skaflestad@sintef.no>
//
//==========================================================================*/
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
Copyright 2012 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 "config.h"
#include <opm/core/io/vag/vag.hpp>
#include <opm/core/grid/cornerpoint_grid.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <cmath>
#include <cassert>
#include <set>
#include <vector>
#include <map>
namespace Opm
{
void readPosStruct(std::istream& is,int n,PosStruct& pos_struct){
using namespace std;
//PosStruct pos_struct;
pos_struct.pos.resize(n+1);
pos_struct.pos[0]=0;
for(int i=0;i< n;++i){
int number;
is >> number ;
//cout <<number << endl;
pos_struct.pos[i+1]=pos_struct.pos[i]+number;
for(int j=0;j< number;++j){
int value;
is >> value;
// cout << value << " ";
pos_struct.value.push_back(value);
}
//cout << endl;
}
if(int(pos_struct.value.size()) != pos_struct.pos[n]){
cerr << "Failed to read pos structure" << endl;
cerr << "pos_struct.value.size()" << pos_struct.value.size() << endl;
cerr << "pos_struct.pos[n+1]" << pos_struct.pos[n] << endl;
}
}
void writePosStruct(std::ostream& os,PosStruct& pos_struct){
using namespace std;
//PosStruct pos_struct;
if(pos_struct.pos.size()==0){
return;
}
int n=pos_struct.pos.size()-1;
pos_struct.pos.resize(n+1);
pos_struct.pos[0]=0;
for(int i=0;i< n;++i){
int number=pos_struct.pos[i+1]-pos_struct.pos[i];
os << number << " ";
for(int j=0;j< number;++j){
os << pos_struct.value[pos_struct.pos[i]+j] << " ";
}
os << endl;
}
}
void readVagGrid(std::istream& is,Opm::VAG& vag_grid){
using namespace std;
using namespace Opm;
while (!is.eof()) {
string keyword;
is >> keyword;
//cout << keyword<< endl;
if(keyword == "Number"){
string stmp;
is >> stmp;
if(stmp == "of"){
string entity;
is >> entity;
getline(is,stmp);
int number;
is >> number;
if(entity=="vertices"){
vag_grid.number_of_vertices=number;
}else if((entity=="volumes") || (entity=="control")){
vag_grid.number_of_volumes=number;
}else if(entity=="faces"){
vag_grid.number_of_faces=number;
}else if(entity=="edges"){
vag_grid.number_of_edges=number;
}
cout << "Found Number of: " << entity <<" " << number << endl;
} else {
cerr << "Wrong format: Not of after Number" << endl;
return;
}
}else{
// read geometry defined by vertices
if(keyword=="Vertices"){
int number;
is >> number;
vag_grid.vertices.resize(3*number);// assume 3d data
readVector(is,vag_grid.vertices);
}
// here starts the reding of all pos structures
else if(keyword=="Volumes->Faces" || keyword=="Volumes->faces"){
//vag_grid.volumes_to_faces=
int number;
is >> number;
readPosStruct(is,number,vag_grid.volumes_to_faces);
cout << "Volumes->Faces: Number of " << number << endl;
}else if(keyword=="Faces->edges" || keyword=="Faces->Edges" || keyword=="Faces->Edgess"){
int number;
is >> number;
//vag_grid.volumes_to_faces=
readPosStruct(is,number,vag_grid.faces_to_edges);
cout << "Faces->edges: Number of " << number << endl;
}else if(keyword=="Faces->Vertices" || keyword=="Faces->vertices"){
int number;
is >> number;
//vag_grid.volumes_to_faces=
readPosStruct(is,number,vag_grid.faces_to_vertices);
cout << "Faces->Vertices: Number of " << number << endl;
}else if(keyword=="Volumes->Vertices" || keyword=="Volumes->Verticess"){
int number;
is >> number;
//vag_grid.volumes_to_faces=
readPosStruct(is,number,vag_grid.volumes_to_vertices);
cout << "Volumes->Vertices: Number of " << number << endl;
}
// read simple mappings
else if(keyword=="Edge" || keyword=="Edges"){
int number;
is >> number;
vag_grid.edges.resize(2*number);
readVector(is,vag_grid.edges);
cout << "Edges: Number of " << number << endl;
}else if(keyword=="Faces->Volumes" || keyword=="Faces->Control"){
int number;
if(keyword=="Faces->Control"){
string vol;
is >> vol;
}
is >> number;
vag_grid.faces_to_volumes.resize(2*number);
readVector(is,vag_grid.faces_to_volumes);
cout << "Faces->Volumes: Number of " << number << endl;
}
// read material
else if(keyword=="Material"){
string snum;
is >> snum;
int number;
is >> number;
cout << "Material number " << number << endl;
// we read all the rest into doubles
while(!is.eof()){
double value;
is >> value;
//cout << value << endl;
vag_grid.material.push_back(value);
}
}else{
//cout << "keyword;
}
//cout << "Found" << keyword << "Number of " << number << endl;
}
}
}
void vagToUnstructuredGrid(Opm::VAG& vag_grid,UnstructuredGrid& grid){
using namespace std;
using namespace Opm;
cout << "Converting grid" << endl;
cout << "Warning:: orignial grid may not be edge confomal" << endl;
cout << " inverse mappings from edges will be wrong" << endl;
grid.dimensions=3;
grid.number_of_cells=vag_grid.number_of_volumes;
grid.number_of_faces=vag_grid.number_of_faces;
grid.number_of_nodes=vag_grid.number_of_vertices;
// fill face_nodes
for(int i=0;i< int(vag_grid.faces_to_vertices.pos.size());++i){
grid.face_nodepos[i] = vag_grid.faces_to_vertices.pos[i];
}
for(int i=0;i< int(vag_grid.faces_to_vertices.value.size());++i){
grid.face_nodes[i] = vag_grid.faces_to_vertices.value[i]-1;
}
// fill cell_face
for(int i=0;i< int(vag_grid.volumes_to_faces.pos.size());++i){
grid.cell_facepos[i] = vag_grid.volumes_to_faces.pos[i];
}
for(int i=0;i< int(vag_grid.volumes_to_faces.value.size());++i){
grid.cell_faces[i] = vag_grid.volumes_to_faces.value[i]-1;
}
// fill face_cells
for(int i=0;i< int(vag_grid.faces_to_volumes.size());++i){
grid.face_cells[i] = vag_grid.faces_to_volumes[i]-1;
}
// fill node_cordinates. This is the only geometry given in the vag
for(int i=0;i< int(vag_grid.vertices.size());++i){
grid.node_coordinates[i] = vag_grid.vertices[i];
}
// informations in edges, faces_to_eges, faces_to_vertices, volume_to_vertices and materials
// is not used
cout << "Computing geometry" << endl;
compute_geometry(&grid);
}
void unstructuredGridToVag(UnstructuredGrid& grid,Opm::VAG& vag_grid){
using namespace std;
using namespace Opm;
cout << "Converting grid" << endl;
// grid.dimensions=3;
vag_grid.number_of_volumes=grid.number_of_cells;
vag_grid.number_of_faces=grid.number_of_faces;
vag_grid.number_of_vertices=grid.number_of_nodes;
// resizing vectors
vag_grid.vertices.resize(grid.number_of_nodes*3);
vag_grid.faces_to_vertices.pos.resize(grid.number_of_faces+1);
vag_grid.faces_to_vertices.value.resize(grid.face_nodepos[grid.number_of_faces]);
vag_grid.faces_to_volumes.resize(2*grid.number_of_faces);
vag_grid.volumes_to_faces.pos.resize(grid.number_of_cells+1);
vag_grid.volumes_to_faces.value.resize(grid.cell_facepos[grid.number_of_cells]);//not known
// fill face_nodes
for(int i=0;i< int(vag_grid.faces_to_vertices.pos.size());++i){
vag_grid.faces_to_vertices.pos[i] = grid.face_nodepos[i];
}
for(int i=0;i< int(vag_grid.faces_to_vertices.value.size());++i){
vag_grid.faces_to_vertices.value[i] = grid.face_nodes[i] +1;
}
// fill cell_face
for(int i=0;i< int(vag_grid.volumes_to_faces.pos.size());++i){
vag_grid.volumes_to_faces.pos[i] = grid.cell_facepos[i];
}
for(int i=0;i< int(vag_grid.volumes_to_faces.value.size());++i){
vag_grid.volumes_to_faces.value[i] = grid.cell_faces[i] +1;
}
// fill face_cells
for(int i=0;i< int(vag_grid.faces_to_volumes.size());++i){
vag_grid.faces_to_volumes[i] = grid.face_cells[i] +1;
}
// fill node_cordinates. This is the only geometry given in the vag
for(int i=0;i< int(vag_grid.vertices.size());++i){
vag_grid.vertices[i] = grid.node_coordinates[i];
}
// The missing field need to be constructed
// gennerate volume to vertice mapping
std::vector< std::set<int> > volumes_to_vertices(grid.number_of_cells);
for(int i=0;i < grid.number_of_cells; ++i){
int nlf=grid.cell_facepos[i+1]-grid.cell_facepos[i];
std::set<int> nodes;
for(int j=0; j < nlf; ++j){
int face = grid.cell_faces[grid.cell_facepos[i]+j];
int nlv = grid.face_nodepos[face+1]-grid.face_nodepos[face];
for(int k=0; k< nlv; ++k){
int node = grid.face_nodes[grid.face_nodepos[face]+k]+1;
nodes.insert(node);
}
}
volumes_to_vertices[i]=nodes;
}
// fill volume to vertice map
vag_grid.volumes_to_vertices.pos.resize(grid.number_of_cells+1);
vag_grid.volumes_to_vertices.value.resize(0);
vag_grid.volumes_to_vertices.pos[0]=0;
for(int i=0;i < grid.number_of_cells;++i){
int nv=volumes_to_vertices[i].size();
vag_grid.volumes_to_vertices.pos[i+1]=vag_grid.volumes_to_vertices.pos[i]+nv;
std::set<int>::iterator it;
for(it=volumes_to_vertices[i].begin();it!=volumes_to_vertices[i].end();++it){
vag_grid.volumes_to_vertices.value.push_back(*it);
}
}
std::set< std::set<int> > edges;
std::vector< std::vector< std::set<int> > > faces_spares;
int nfe=0;
faces_spares.resize(grid.number_of_faces);
for(int i=0;i < grid.number_of_faces;++i){
int ne=grid.face_nodepos[i+1]-grid.face_nodepos[i];
nfe=nfe+ne;
for(int j=0; j < ne-1;++j){
int node1=grid.face_nodes[grid.face_nodepos[i]+j]+1;
int node2=grid.face_nodes[grid.face_nodepos[i]+j+1]+1;
std::set<int> spair;
spair.insert(node1);
spair.insert(node2);
edges.insert(spair);
faces_spares[i].push_back(spair);
}
// add end segment
{
std::set<int> spair;
int node1=grid.face_nodes[grid.face_nodepos[i]+ne-1]+1;
int node2=grid.face_nodes[grid.face_nodepos[i]]+1;
spair.insert(node1);
spair.insert(node2);
edges.insert(spair);
faces_spares[i].push_back(spair);
}
}
// make edge numbering and fill edges
std::map<std::set<int>, int> edge_map;
std::set< std::set<int> >::iterator it;
vag_grid.edges.resize(0);
int k=0;
for(it=edges.begin(); it!=edges.end();++it){
edge_map.insert(std::pair< std::set<int> , int >(*it,k));
k=k+1;
std::set<int>::iterator sit;
for(sit=(*it).begin();sit!=(*it).end();++sit){
vag_grid.edges.push_back(*sit);
}
}
// fill face_to_egdes
vag_grid.number_of_edges=edges.size();
vag_grid.faces_to_edges.pos.resize(vag_grid.number_of_faces+1);
for(int i=0;i < grid.number_of_faces;++i){
int ne=grid.face_nodepos[i+1]-grid.face_nodepos[i];
vag_grid.faces_to_edges.pos[i+1]=vag_grid.faces_to_edges.pos[i]+ne;
for(int j=0;j<int(faces_spares[i].size());++j){
int edge_num=edge_map[faces_spares[i][j]];
vag_grid.faces_to_edges.value.push_back(edge_num+1);
}
}
// vag_grid.edges(0);//not known
// vag_grid.faces_to_edges// not known
// material // can not be extracted from the grid
}
void writeVagFormat(std::ostream& os,Opm::VAG& vag_grid){
using namespace std;
os << "File in the Vag grid format\n";
os << "Number of vertices " ;
os << vag_grid.number_of_vertices << endl;;
os <<"Number of control volume ";
os << vag_grid.number_of_volumes << endl;
os <<"Number of faces " ;
os << vag_grid.number_of_faces << endl;
os <<"Number of edges " ;
os << vag_grid.number_of_edges << endl;
os <<"Vertices " << vag_grid.vertices.size() << endl;
writeVector(os, vag_grid.vertices,3);
os << "Volumes->faces " << vag_grid.volumes_to_faces.pos.size()-1 << endl;
writePosStruct(os, vag_grid.volumes_to_faces);
os << "Volumes->Vertices " << vag_grid.volumes_to_vertices.pos.size()-1 << endl;
writePosStruct(os, vag_grid.volumes_to_vertices);
os << "Faces->edges " << vag_grid.faces_to_edges.pos.size()-1 << endl;
writePosStruct(os, vag_grid.faces_to_edges);
os << "Faces->vertices " << vag_grid.faces_to_vertices.pos.size()-1 << endl;
writePosStruct(os, vag_grid.faces_to_vertices);
os << "Faces->Control volumes " << floor(vag_grid.faces_to_volumes.size()/2) << endl;
writeVector(os,vag_grid.faces_to_volumes,2);
os << "Edges " << floor(vag_grid.edges.size()/2) << endl;
writeVector(os,vag_grid.edges,2);
/*
assert(vag_grid.material.size()%vag_grid.number_of_volumes==0);
int lines= floor(vag_grid.material.size()/vag_grid.number_of_volumes);
os << "Material number " << 1 << endl;
writeVector(os,vag_grid.material,lines);
*/
}
}

View File

@ -1,165 +0,0 @@
/*===========================================================================
//
// File: vag.hpp
//
// Created: 2012-06-08 15:46:23+0200
//
// Authors: Knut-Andreas Lie <Knut-Andreas.Lie@sintef.no>
// Halvor M. Nilsen <HalvorMoll.Nilsen@sintef.no>
// Atgeirr F. Rasmussen <atgeirr@sintef.no>
// Xavier Raynaud <Xavier.Raynaud@sintef.no>
// Bård Skaflestad <Bard.Skaflestad@sintef.no>
//
//==========================================================================*/
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
Copyright 2012 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_VAG_HPP_HEADER
#define OPM_VAG_HPP_HEADER
#include <opm/core/grid.h>
#include <istream>
#include <ostream>
#include <string>
#include <vector>
namespace Opm
{
/**
Struct to hold mapping from the natural numbers less than pos.size()-1 to
a set of integers. value(pos(i):pos(i+1)-1) hold the integers corresponding to i.
pos(end)-1==value.size();
*/
struct PosStruct{
std::vector<int> pos;
std::vector<int> value;
};
/**
Structure to represent the unstructured vag grid format. The format is only for
3D grids.
*/
struct VAG{
int number_of_vertices;
int number_of_volumes;
int number_of_faces;
int number_of_edges;
/** Vertices. The coordinates of vertice i is [vetices[3*i:3*i+2]*/
std::vector<double> vertices;
/** Mapping from volumes to faces */
PosStruct volumes_to_faces;
/** Mapping from volumes to vertices */
PosStruct volumes_to_vertices;
/** Mapping from faces to edges */
PosStruct faces_to_edges;
/** Mapping from faces to vertices */
PosStruct faces_to_vertices;
/** The edge i is given by the nodes edges[2*i:2*i+1] */
std::vector<int> edges;
/** The two neigbours of the face i is faces_to_volumes[2*i:2*i+1] */
std::vector<int> faces_to_volumes;
/** A vector containing information of each volume. The size is n*number_of_volumes.
For each i this is the information:
material[n*i] is the volume number and should be transformed to integer
material[n*i+1] is a tag and should be transformed to integer
material[n*i+2:n*(i+1)-1] represent propertices.
*/
std::vector<double> material;
};
/**
Function the vag grid format and make a vag_grid struct. This structure
is intended to be converted to a grid.
\param[in] is is is stream of the file.
\param[out] vag_grid is a reference to a vag_grid struct.
*/
void readVagGrid(std::istream& is,Opm::VAG& vag_grid);
/**
Function to write vag format.
\param[out] is is is stream of the file.
\param[in] vag_grid is a reference to a vag_grid struct.
*/
void writeVagFormat(std::ostream& os,Opm::VAG& vag_grid);
/**
Function to read a vector of some type from a stream.
\param[in] os is is stream of the file.
\param[out] vag_grid is a resized and filled vector containing the quantiy read.
*/
template <typename T>
void readVector(std::istream& is,std::vector<T>& vec){
using namespace std;
for(int i=0;i< int(vec.size());++i){
is >> vec[i];
}
}
/**
Function to write a vector of some type from a stream.
\param[in] os is is stream of the file.
\param[out] vag_grid is a resized and filled vector containing the quantiy read.
\param[in] n number of doubles on each line.
*/
template <typename T>
void writeVector(std::ostream& os,std::vector<T>& vec,int n){
typedef typename std::vector<T>::size_type sz_t;
const sz_t nn = n;
for (sz_t i = 0; i < vec.size(); ++i) {
os << vec[i] << (((i % nn) == 0) ? '\n' : ' ');
}
if ((vec.size() % nn) != 0) {
os << '\n';
}
}
/**
Read pos struct type mapping from a stream
\param[in] is is stream
\param[in] n number of lines to read
\param[out] pos_struct reference to PosStruct
*/
void readPosStruct(std::istream& is,int n,PosStruct& pos_struct);
/**
Read pos struct type mapping from a stream
\param[in] os is stream to write to
\param[in] pos_struct to write
*/
void writePosStruct(std::ostream& os,PosStruct& pos_struct);
/**
Fill a UnstructuredGrid from a vag_grid.
\param[out] vag_grid s is a valid vag_grid struct.
\param[in] grid is a grid with have allocated correct size to each pointer.
*/
void vagToUnstructuredGrid(Opm::VAG& vag_grid,UnstructuredGrid& grid);
/**
Fill a vag_grid from UnstructuredGrid
\param[out] vag_grid s is a valid vag_grid struct.
\param[in] grid is a grid with have allocated correct size to each pointer.
*/
void unstructuredGridToVag(UnstructuredGrid& grid, Opm::VAG& vag_grid);
}
#endif /* OPM_VAG_HPP_HEADER */

View File

@ -1,319 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <opm/core/io/vtk/writeVtkData.hpp>
#include <opm/core/utility/DataMap.hpp>
#include <opm/core/grid.h>
#include <opm/common/ErrorMacros.hpp>
#include <boost/lexical_cast.hpp>
#include <set>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
namespace Opm
{
void writeVtkData(const std::array<int, 3>& dims,
const std::array<double, 3>& cell_size,
const DataMap& data,
std::ostream& os)
{
// Dimension is hardcoded in the prototype and the next two lines,
// but the rest is flexible (allows dimension == 2 or 3).
int dimension = 3;
int num_cells = dims[0]*dims[1]*dims[2];
assert(dimension == 2 || dimension == 3);
assert(num_cells == dims[0]*dims[1]* (dimension == 2 ? 1 : dims[2]));
os << "# vtk DataFile Version 2.0\n";
os << "Structured Grid\n \n";
os << "ASCII \n";
os << "DATASET STRUCTURED_POINTS\n";
os << "DIMENSIONS "
<< dims[0] + 1 << " "
<< dims[1] + 1 << " ";
if (dimension == 3) {
os << dims[2] + 1;
} else {
os << 1;
}
os << "\n";
os << "ORIGIN " << 0.0 << " " << 0.0 << " " << 0.0 << "\n";
os << "SPACING " << cell_size[0] << " " << cell_size[1];
if (dimension == 3) {
os << " " << cell_size[2];
} else {
os << " " << 0.0;
}
os << "\n";
os << "\nCELL_DATA " << num_cells << '\n';
for (DataMap::const_iterator dit = data.begin(); dit != data.end(); ++dit) {
std::string name = dit->first;
os << "SCALARS " << name << " float" << '\n';
os << "LOOKUP_TABLE " << name << "_table " << '\n';
const std::vector<double>& field = *(dit->second);
// We always print only the first data item for every
// cell, using 'stride'.
// This is a hack to get water saturation nicely.
// \TODO: Extend to properly printing vector data.
const int stride = field.size()/num_cells;
const int num_per_line = 5;
for (int c = 0; c < num_cells; ++c) {
os << field[stride*c] << ' ';
if (c % num_per_line == num_per_line - 1
|| c == num_cells - 1) {
os << '\n';
}
}
}
}
typedef std::map<std::string, std::string> PMap;
struct Tag
{
Tag(const std::string& tag, const PMap& props, std::ostream& os)
: name_(tag), os_(os)
{
indent(os);
os << "<" << tag;
for (PMap::const_iterator it = props.begin(); it != props.end(); ++it) {
os << " " << it->first << "=\"" << it->second << "\"";
}
os << ">\n";
++indent_;
}
Tag(const std::string& tag, std::ostream& os)
: name_(tag), os_(os)
{
indent(os);
os << "<" << tag << ">\n";
++indent_;
}
~Tag()
{
--indent_;
indent(os_);
os_ << "</" << name_ << ">\n";
}
static void indent(std::ostream& os)
{
for (int i = 0; i < indent_; ++i) {
os << " ";
}
}
private:
static int indent_;
std::string name_;
std::ostream& os_;
};
int Tag::indent_ = 0;
void writeVtkData(const UnstructuredGrid& grid,
const DataMap& data,
std::ostream& os)
{
if (grid.dimensions != 3) {
OPM_THROW(std::runtime_error, "Vtk output for 3d grids only");
}
os.precision(12);
os << "<?xml version=\"1.0\"?>\n";
PMap pm;
pm["type"] = "UnstructuredGrid";
Tag vtkfiletag("VTKFile", pm, os);
Tag ugtag("UnstructuredGrid", os);
int num_pts = grid.number_of_nodes;
int num_cells = grid.number_of_cells;
pm.clear();
pm["NumberOfPoints"] = boost::lexical_cast<std::string>(num_pts);
pm["NumberOfCells"] = boost::lexical_cast<std::string>(num_cells);
Tag piecetag("Piece", pm, os);
{
Tag pointstag("Points", os);
pm.clear();
pm["type"] = "Float64";
pm["Name"] = "Coordinates";
pm["NumberOfComponents"] = "3";
pm["format"] = "ascii";
Tag datag("DataArray", pm, os);
for (int i = 0; i < num_pts; ++i) {
Tag::indent(os);
os << grid.node_coordinates[3*i + 0] << ' '
<< grid.node_coordinates[3*i + 1] << ' '
<< grid.node_coordinates[3*i + 2] << '\n';
}
}
{
Tag cellstag("Cells", os);
pm.clear();
pm["type"] = "Int32";
pm["NumberOfComponents"] = "1";
pm["format"] = "ascii";
std::vector<int> cell_numpts;
cell_numpts.reserve(num_cells);
{
pm["Name"] = "connectivity";
Tag t("DataArray", pm, os);
int hf = 0;
for (int c = 0; c < num_cells; ++c) {
std::set<int> cell_pts;
for (; hf < grid.cell_facepos[c+1]; ++hf) {
int f = grid.cell_faces[hf];
const int* fnbeg = grid.face_nodes + grid.face_nodepos[f];
const int* fnend = grid.face_nodes + grid.face_nodepos[f+1];
cell_pts.insert(fnbeg, fnend);
}
cell_numpts.push_back(cell_pts.size());
Tag::indent(os);
std::copy(cell_pts.begin(), cell_pts.end(),
std::ostream_iterator<int>(os, " "));
os << '\n';
}
}
{
pm["Name"] = "offsets";
Tag t("DataArray", pm, os);
int offset = 0;
const int num_per_line = 10;
for (int c = 0; c < num_cells; ++c) {
if (c % num_per_line == 0) {
Tag::indent(os);
}
offset += cell_numpts[c];
os << offset << ' ';
if (c % num_per_line == num_per_line - 1
|| c == num_cells - 1) {
os << '\n';
}
}
}
std::vector<int> cell_foffsets;
cell_foffsets.reserve(num_cells);
{
pm["Name"] = "faces";
Tag t("DataArray", pm, os);
const int* fp = grid.cell_facepos;
int offset = 0;
for (int c = 0; c < num_cells; ++c) {
Tag::indent(os);
os << fp[c+1] - fp[c] << '\n';
++offset;
for (int hf = fp[c]; hf < fp[c+1]; ++hf) {
int f = grid.cell_faces[hf];
const int* np = grid.face_nodepos;
int f_num_pts = np[f+1] - np[f];
Tag::indent(os);
os << f_num_pts << ' ';
++offset;
std::copy(grid.face_nodes + np[f],
grid.face_nodes + np[f+1],
std::ostream_iterator<int>(os, " "));
os << '\n';
offset += f_num_pts;
}
cell_foffsets.push_back(offset);
}
}
{
pm["Name"] = "faceoffsets";
Tag t("DataArray", pm, os);
const int num_per_line = 10;
for (int c = 0; c < num_cells; ++c) {
if (c % num_per_line == 0) {
Tag::indent(os);
}
os << cell_foffsets[c] << ' ';
if (c % num_per_line == num_per_line - 1
|| c == num_cells - 1) {
os << '\n';
}
}
}
{
pm["type"] = "UInt8";
pm["Name"] = "types";
Tag t("DataArray", pm, os);
const int num_per_line = 10;
for (int c = 0; c < num_cells; ++c) {
if (c % num_per_line == 0) {
Tag::indent(os);
}
os << "42 ";
if (c % num_per_line == num_per_line - 1
|| c == num_cells - 1) {
os << '\n';
}
}
}
}
{
pm.clear();
if (data.find("saturation") != data.end()) {
pm["Scalars"] = "saturation";
} else if (data.find("pressure") != data.end()) {
pm["Scalars"] = "pressure";
}
Tag celldatatag("CellData", pm, os);
pm.clear();
pm["NumberOfComponents"] = "1";
pm["format"] = "ascii";
pm["type"] = "Float64";
for (DataMap::const_iterator dit = data.begin(); dit != data.end(); ++dit) {
pm["Name"] = dit->first;
const std::vector<double>& field = *(dit->second);
const int num_comps = field.size()/grid.number_of_cells;
pm["NumberOfComponents"] = boost::lexical_cast<std::string>(num_comps);
Tag ptag("DataArray", pm, os);
const int num_per_line = num_comps == 1 ? 5 : num_comps;
for (int item = 0; item < num_cells*num_comps; ++item) {
if (item % num_per_line == 0) {
Tag::indent(os);
}
double value = field[item];
if (std::fabs(value) < std::numeric_limits<double>::min()) {
// Avoiding denormal numbers to work around
// bug in Paraview.
value = 0.0;
}
os << value << ' ';
if (item % num_per_line == num_per_line - 1
|| item == num_cells - 1) {
os << '\n';
}
}
}
}
}
} // namespace Opm

View File

@ -1,48 +0,0 @@
/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
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_WRITEVTKDATA_HEADER_INCLUDED
#define OPM_WRITEVTKDATA_HEADER_INCLUDED
#include <string>
#include <map>
#include <vector>
#include <array>
#include <iosfwd>
#include <opm/core/utility/DataMap.hpp>
struct UnstructuredGrid;
namespace Opm
{
/// Vtk output for cartesian grids.
void writeVtkData(const std::array<int, 3>& dims,
const std::array<double, 3>& cell_size,
const DataMap& data,
std::ostream& os);
/// Vtk output for general grids.
void writeVtkData(const UnstructuredGrid& grid,
const DataMap& data,
std::ostream& os);
} // namespace Opm
#endif // OPM_WRITEVTKDATA_HEADER_INCLUDED

View File

@ -17,7 +17,7 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#if HAVE_CONFIG_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@ -59,10 +59,21 @@ namespace Opm
LinearSolverFactory::LinearSolverFactory(const parameter::ParameterGroup& param)
LinearSolverFactory::LinearSolverFactory(const ParameterGroup& param)
{
#if HAVE_SUITESPARSE_UMFPACK_H
std::string default_solver = "umfpack";
#elif HAVE_DUNE_ISTL
std::string default_solver = "istl";
#elif HAVE_PETSC
std::string default_solver = "petsc";
#else
std::string default_solver = "no_solver_available";
OPM_THROW(std::runtime_error, "No linear solver available, you must have UMFPACK , dune-istl or Petsc installed to use LinearSolverFactory.");
#endif
const std::string ls =
param.getDefault<std::string>("linsolver", "umfpack");
param.getDefault("linsolver", default_solver);
if (ls == "umfpack") {
#if HAVE_SUITESPARSE_UMFPACK_H

View File

@ -27,7 +27,7 @@
namespace Opm
{
namespace parameter { class ParameterGroup; }
class ParameterGroup;
/// Concrete class encapsulating any available linear solver.
@ -55,7 +55,7 @@ namespace Opm
/// Any further parameters are passed on to the constructors
/// of the actual solver used, see LinearSolverUmfpack,
/// LinearSolverIstl and LinearSolverPetsc for details.
LinearSolverFactory(const parameter::ParameterGroup& param);
LinearSolverFactory(const ParameterGroup& param);
/// Destructor.
virtual ~LinearSolverFactory();

View File

@ -18,7 +18,7 @@
*/
#if HAVE_CONFIG_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@ -47,9 +47,7 @@
#include <dune/istl/paamg/kamg.hh>
#include <dune/istl/paamg/pinfo.hh>
#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 3)
#include <dune/istl/paamg/fastamg.hh>
#endif
#include <opm/common/utility/platform_dependent/reenable_warnings.h>
@ -77,7 +75,6 @@ namespace Opm
solveCG_AMG(O& A, Vector& x, Vector& b, S& sp, const C& comm, double tolerance, int maxit, int verbosity,
double prolongateFactor, int smoothsteps);
#if defined(HAS_DUNE_FAST_AMG) || DUNE_VERSION_NEWER(DUNE_ISTL, 2, 3)
template<class O, class S, class C>
LinearSolverInterface::LinearSolverReport
solveKAMG(O& A, Vector& x, Vector& b, S& sp, const C& comm, double tolerance, int maxit, int verbosity,
@ -87,7 +84,6 @@ namespace Opm
LinearSolverInterface::LinearSolverReport
solveFastAMG(O& A, Vector& x, Vector& b, S& sp, const C& comm, double tolerance, int maxit, int verbosity,
double prolongateFactor);
#endif
template<class O, class S, class C>
LinearSolverInterface::LinearSolverReport
@ -111,7 +107,7 @@ namespace Opm
LinearSolverIstl::LinearSolverIstl(const parameter::ParameterGroup& param)
LinearSolverIstl::LinearSolverIstl(const ParameterGroup& param)
: linsolver_residual_tolerance_(1e-8),
linsolver_verbosity_(0),
linsolver_type_(CG_AMG),
@ -223,16 +219,10 @@ namespace Opm
linsolver_prolongate_factor_, linsolver_smooth_steps_);
break;
case KAMG:
#if defined(HAS_DUNE_FAST_AMG) || DUNE_VERSION_NEWER(DUNE_ISTL, 2, 3)
res = solveKAMG(opA, x, b, sp, comm, linsolver_residual_tolerance_, maxit, linsolver_verbosity_,
linsolver_prolongate_factor_, linsolver_smooth_steps_);
#else
throw std::runtime_error("KAMG not supported with this version of DUNE");
#endif
break;
case FastAMG:
#if defined(HAS_DUNE_FAST_AMG) || DUNE_VERSION_NEWER(DUNE_ISTL, 2, 3)
#if HAVE_MPI
if(std::is_same<C,Dune::OwnerOverlapCopyCommunication<int,int> >::value)
{
@ -242,12 +232,6 @@ namespace Opm
res = solveFastAMG(opA, x, b, sp, comm, linsolver_residual_tolerance_, maxit, linsolver_verbosity_,
linsolver_prolongate_factor_);
#else
if(linsolver_verbosity_)
std::cerr<<"Fast AMG is not available; falling back to CG preconditioned with the normal one"<<std::endl;
res = solveCG_AMG(opA, x, b, sp, comm, linsolver_residual_tolerance_, maxit, linsolver_verbosity_,
linsolver_prolongate_factor_, linsolver_smooth_steps_);
#endif
break;
case BiCGStab_ILU0:
res = solveBiCGStab_ILU0(opA, x, b, sp, comm, linsolver_residual_tolerance_, maxit, linsolver_verbosity_);
@ -409,7 +393,6 @@ namespace Opm
}
#if defined(HAS_DUNE_FAST_AMG) || DUNE_VERSION_NEWER(DUNE_ISTL, 2, 3)
template<class O, class S, class C>
LinearSolverInterface::LinearSolverReport
solveKAMG(O& opA, Vector& x, Vector& b, S& /* sp */, const C& /* comm */, double tolerance, int maxit, int verbosity,
@ -466,8 +449,8 @@ namespace Opm
double linsolver_prolongate_factor)
{
// Solve with AMG solver.
typedef Dune::MatrixAdapter<typename O::matrix_type, Vector, Vector> Operator;
Operator sOpA(opA.getmat());
typedef Dune::MatrixAdapter<typename O::matrix_type, Vector, Vector> AMGOperator;
AMGOperator sOpA(opA.getmat());
#if FIRST_DIAGONAL
typedef Dune::Amg::FirstDiagonal CouplingMetric;
@ -482,7 +465,7 @@ namespace Opm
#endif
typedef Dune::Amg::CoarsenCriterion<CriterionBase> Criterion;
typedef Dune::Amg::FastAMG<Operator,Vector> Precond;
typedef Dune::Amg::FastAMG<AMGOperator, Vector> Precond;
// Construct preconditioner.
Criterion criterion;
@ -509,7 +492,6 @@ namespace Opm
res.residual_reduction = result.reduction;
return res;
}
#endif
template<class O, class S, class C>
LinearSolverInterface::LinearSolverReport

View File

@ -52,7 +52,7 @@ namespace Opm
/// Construct from parameters
/// Accepted parameters are, with defaults, listed in the
/// default constructor.
LinearSolverIstl(const parameter::ParameterGroup& param);
LinearSolverIstl(const ParameterGroup& param);
/// Destructor.
virtual ~LinearSolverIstl();

View File

@ -19,11 +19,16 @@
*/
#include "config.h"
#if HAVE_PETSC
#include <cstring>
#include <opm/core/linalg/LinearSolverPetsc.hpp>
#include <unordered_map>
#define PETSC_CLANGUAGE_CXX 1 //enable CHKERRXX macro.
#include <opm/common/utility/platform_dependent/disable_warnings.h>
#include <petsc.h>
#include <opm/common/utility/platform_dependent/reenable_warnings.h>
#include <opm/common/ErrorMacros.hpp>
namespace Opm
@ -148,7 +153,6 @@ namespace{
VecDestroy( &b );
MatDestroy( &A );
KSPDestroy( &ksp );
PCDestroy( &preconditioner );
}
};
@ -181,11 +185,11 @@ namespace{
VecRestoreArray( v, &vec );
}
Mat to_petsc_mat( const int size, const int nonzeros,
Mat to_petsc_mat( const int size, const int /* nonzeros */,
const int* ia, const int* ja, const double* sa ) {
Mat A;
auto err = MatCreateSeqAIJWithArrays( PETSC_COMM_WORLD, size, size, (int*)ia, (int*)ja, (double*)sa, &A );
auto err = MatCreateSeqAIJWithArrays( PETSC_COMM_WORLD, size, size, const_cast<int*>(ia), const_cast<int*>(ja), (double*)sa, &A );
CHKERRXX( err );
return A;
}
@ -197,7 +201,12 @@ namespace{
PetscReal residual;
KSPConvergedReason reason;
#if PETSC_VERSION_MAJOR <= 3 && PETSC_VERSION_MINOR < 5
KSPSetOperators( t.ksp, t.A, t.A, DIFFERENT_NONZERO_PATTERN );
#else
KSPSetOperators( t.ksp, t.A, t.A );
KSPSetReusePreconditioner(t.ksp, PETSC_FALSE);
#endif
KSPGetPC( t.ksp, &t.preconditioner );
auto err = KSPSetType( t.ksp, method );
CHKERRXX( err );
@ -216,13 +225,13 @@ namespace{
if( ksp_view )
KSPView( t.ksp, PETSC_VIEWER_STDOUT_WORLD );
err = PetscPrintf( PETSC_COMM_WORLD, "KSP Iterations %D, Final Residual %G\n", its, residual );
err = PetscPrintf( PETSC_COMM_WORLD, "KSP Iterations %D, Final Residual %g\n", its, (double)residual );
CHKERRXX( err );
}
} // anonymous namespace.
LinearSolverPetsc::LinearSolverPetsc(const parameter::ParameterGroup& param)
LinearSolverPetsc::LinearSolverPetsc(const ParameterGroup& param)
: ksp_type_( param.getDefault( std::string( "ksp_type" ), std::string( "gmres" ) ) )
, pc_type_( param.getDefault( std::string( "pc_type" ), std::string( "sor" ) ) )
, ksp_view_( param.getDefault( std::string( "ksp_view" ), int( false ) ) )
@ -281,3 +290,4 @@ namespace{
} // namespace Opm
#endif // HAVE_PETSC

View File

@ -20,6 +20,11 @@
#ifndef OPM_LINEARSOLVERPETSC_HEADER_INCLUDED
#define OPM_LINEARSOLVERPETSC_HEADER_INCLUDED
#if !HAVE_PETSC
#error "LinearSolverPetsc.hpp included, but the PETSc libraries are not available!"
#endif
#include <opm/core/linalg/LinearSolverInterface.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <string>
@ -42,7 +47,7 @@ namespace Opm
/// Construct from parameters
/// Accepted parameters are, with defaults, listed in the
/// default constructor.
LinearSolverPetsc(const parameter::ParameterGroup& param);
LinearSolverPetsc(const ParameterGroup& param);
/// Destructor.
virtual ~LinearSolverPetsc();

View File

@ -27,6 +27,12 @@
#include <boost/any.hpp>
#include <exception>
#include <algorithm>
#include <functional>
#include <limits>
#include <numeric>
#include <type_traits>
#if HAVE_MPI && HAVE_DUNE_ISTL
#include <opm/common/utility/platform_dependent/disable_warnings.h>
@ -37,12 +43,6 @@
#include <dune/common/enumset.hh>
#include <opm/common/utility/platform_dependent/reenable_warnings.h>
#include <algorithm>
#include <functional>
#include <limits>
#include <numeric>
#include <type_traits>
namespace Opm
{
namespace
@ -144,8 +144,9 @@ public:
void copyOwnerToAll (const T& source, T& dest) const
{
typedef Dune::Combine<Dune::EnumItem<Dune::OwnerOverlapCopyAttributeSet::AttributeSet,Dune::OwnerOverlapCopyAttributeSet::owner>,Dune::EnumItem<Dune::OwnerOverlapCopyAttributeSet::AttributeSet,Dune::OwnerOverlapCopyAttributeSet::overlap>,Dune::OwnerOverlapCopyAttributeSet::AttributeSet> OwnerOverlapSet;
typedef Dune::EnumItem<Dune::OwnerOverlapCopyAttributeSet::AttributeSet,Dune::OwnerOverlapCopyAttributeSet::owner> OwnerSet;
typedef Dune::Combine<OwnerOverlapSet, Dune::EnumItem<Dune::OwnerOverlapCopyAttributeSet::AttributeSet,Dune::OwnerOverlapCopyAttributeSet::copy>,Dune::OwnerOverlapCopyAttributeSet::AttributeSet> AllSet;
OwnerOverlapSet sourceFlags;
OwnerSet sourceFlags;
AllSet destFlags;
Dune::Interface interface(communicator_);
if( !remoteIndices_->isSynced() )
@ -159,7 +160,7 @@ public:
communicator.free();
}
template<class T>
void updateOwnerMask(const T& container) const
const std::vector<double>& updateOwnerMask(const T& container) const
{
if( ! indexSet_ )
{
@ -176,13 +177,26 @@ public:
}
}
}
return ownerMask_;
}
/// \brief Get the owner Mask.
///
/// \return A vector with entries 0, and 1. 0 marks an index that we cannot
/// compute correct results for. 1 marks an index that this process
/// is responsible for and computes correct results in parallel.
const std::vector<double>& getOwnerMask() const
{
return ownerMask_;
}
/// \brief Compute one or more global reductions.
///
/// This function can either be used with a container, an operator, and an initial value
/// to compute a reduction. Or with tuples of them to compute multiple reductions with only
/// one global communication.
/// The possible functors needed can be constructed with Opm::Reduction::makeGlobalMaxFunctor(),
/// Opm::Reduction::makeLInfinityNormFunctor(),
/// Opm::Reduction::makeGlobalMinFunctor(), and
/// Opm::Reduction::makeGlobalSumFunctor().
/// \tparam type of the container or the tuple of containers.
@ -572,6 +586,45 @@ private:
(std::pointer_to_binary_function<const T&,const T&,const T&>
((const T&(*)(const T&, const T&))std::max<T>));
}
namespace detail
{
/// \brief Computes the maximum of the absolute values of two values.
template<typename T, typename Enable = void>
struct MaxAbsFunctor
{
using result_type = T;
result_type operator()(const T& t1,
const T& t2)
{
return std::max(std::abs(t1), std::abs(t2));
}
};
// Specialization for unsigned integers. They need their own
// version since abs(x) is ambiguous (as well as somewhat
// meaningless).
template<typename T>
struct MaxAbsFunctor<T, typename std::enable_if<std::is_unsigned<T>::value>::type>
{
using result_type = T;
result_type operator()(const T& t1,
const T& t2)
{
return std::max(t1, t2);
}
};
}
/// \brief Create a functor for computing a global L infinity norm
///
/// To be used with ParallelISTLInformation::computeReduction.
template<class T>
MaskIDOperator<detail::MaxAbsFunctor<T> >
makeLInfinityNormFunctor()
{
return MaskIDOperator<detail::MaxAbsFunctor<T> >();
}
/// \brief Create a functor for computing a global minimum.
///
/// To be used with ParallelISTLInformation::computeReduction.
@ -610,6 +663,29 @@ inline void extractParallelGridInformationToISTL(boost::any& anyComm, const Unst
{
(void)anyComm; (void)grid;
}
/// \brief Accumulates entries masked with 1.
/// \param container The container whose values to accumulate.
/// \param maskContainer null pointer or a pointer to a container
/// with entries 0 and 1. Only values at indices with a 1 stored
/// will be accumulated. If null then all values will be accumulated
/// \return the summ of all entries that should be represented.
template<class T1>
auto
accumulateMaskedValues(const T1& container, const std::vector<double>* maskContainer)
-> decltype(container[0]*(*maskContainer)[0])
{
decltype(container[0]*(*maskContainer)[0]) initial = 0;
if( maskContainer )
{
return std::inner_product(container.begin(), container.end(), maskContainer->begin(),
initial);
}else
{
return std::accumulate(container.begin(), container.end(), initial);
}
}
} // end namespace Opm
#endif

View File

@ -1,148 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_BLAS_LAPACK_HEADER_INCLUDED
#define OPM_BLAS_LAPACK_HEADER_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MATLAB_MEX_FILE) && MATLAB_MEX_FILE
#include <mex.h>
#undef MAT_SIZE_T
#define MAT_SIZE_T mwSignedIndex
#endif
#ifndef MAT_SIZE_T
#define MAT_SIZE_T int
#endif
/* C <- a1*op(A)*op(B) + a2*C where op(X) in {X, X.'} */
void dgemm_(const char *transA , const char *transB ,
const MAT_SIZE_T* m, const MAT_SIZE_T* n , const MAT_SIZE_T* k ,
const double* a1, const double* A , const MAT_SIZE_T* ldA,
const double* B, const MAT_SIZE_T* ldB,
const double* a2, double* C , const MAT_SIZE_T* ldC);
/* C <- a1*A*A' + a2*C *or* C <- a1*A'*A + a2*C */
void dsyrk_(const char *uplo, const char *trans,
const MAT_SIZE_T *n , const MAT_SIZE_T *k ,
const double *a1 , const double *A , const MAT_SIZE_T *ldA,
const double *a2 , double *C , const MAT_SIZE_T *ldC);
void dgeqrf_(const MAT_SIZE_T *m , const MAT_SIZE_T *n ,
double *A , const MAT_SIZE_T *ld ,
double *tau , double *work,
const MAT_SIZE_T *lwork, MAT_SIZE_T *info);
void dorgqr_(const MAT_SIZE_T *m , const MAT_SIZE_T *n , const MAT_SIZE_T *k ,
double *A , const MAT_SIZE_T *ld , const double *tau,
double *work, const MAT_SIZE_T *lwork, MAT_SIZE_T *info);
/* A <- LU(A) */
void dgetrf_(const MAT_SIZE_T *m , const MAT_SIZE_T *n ,
double *A , const MAT_SIZE_T *ld,
MAT_SIZE_T *ipiv, MAT_SIZE_T *info);
/* B <- A \ B, when A is LU(A) from dgetrf() */
void dgetrs_(const char *trans, const MAT_SIZE_T *n,
const MAT_SIZE_T *nrhs ,
const double *A , const MAT_SIZE_T *lda,
const MAT_SIZE_T *ipiv , double *B,
const MAT_SIZE_T *ldb , MAT_SIZE_T *info);
/* B <- A \ B, tridiagonal A with bands DL, D, DU */
void dgtsv_(const MAT_SIZE_T *n ,
const MAT_SIZE_T *nrhs ,
double *DL ,
double *D ,
double *DU ,
double *B ,
const MAT_SIZE_T *ldb ,
MAT_SIZE_T *info);
/* B <- A \ B, band matrix A stored in AB with kl subdiagonals, ku superdiagonals */
void dgbsv_(const MAT_SIZE_T *n ,
const MAT_SIZE_T *kl ,
const MAT_SIZE_T *ku ,
const MAT_SIZE_T *nrhs ,
double *AB ,
const MAT_SIZE_T *ldab ,
MAT_SIZE_T *ipiv ,
double *B ,
const MAT_SIZE_T *ldb ,
MAT_SIZE_T *info);
/* B <- A \ B, general solver */
void dgesv_(const MAT_SIZE_T *n,
const MAT_SIZE_T *nrhs ,
double *A ,
const MAT_SIZE_T *lda ,
MAT_SIZE_T *piv ,
double *B ,
const MAT_SIZE_T *ldb ,
MAT_SIZE_T *info);
/* A <- chol(A) */
void dpotrf_(const char *uplo, const MAT_SIZE_T *n,
double *A , const MAT_SIZE_T *lda,
MAT_SIZE_T *info);
/* B <- (A \ (A' \ B)), when A=DPOTRF(A_orig) */
void dpotrs_(const char *uplo, const MAT_SIZE_T *n , const MAT_SIZE_T *nrhs,
double *A , const MAT_SIZE_T *lda,
double *B , const MAT_SIZE_T *ldb, MAT_SIZE_T *info);
/* A <- chol(A), packed format. */
void dpptrf_(const char *uplo, const MAT_SIZE_T *n,
double *Ap , MAT_SIZE_T *info);
/* A <- (A \ (A' \ eye(n)) when A=DPPTRF(A_orig) (packed format). */
void dpptri_(const char *uplo, const MAT_SIZE_T *n,
double *Ap , MAT_SIZE_T *info);
/* y <- a1*op(A)*x + a2*y */
void dgemv_(const char *trans,
const MAT_SIZE_T *m , const MAT_SIZE_T *n,
const double *a1 , const double *A, const MAT_SIZE_T *ldA ,
const double *x, const MAT_SIZE_T *incX,
const double *a2 , double *y, const MAT_SIZE_T *incY);
/* y <- a*x + y */
void daxpy_(const MAT_SIZE_T *n, const double *a,
const double *x, const MAT_SIZE_T *incx,
double *y, const MAT_SIZE_T *incy);
/* s <- x' * y */
double ddot_(const MAT_SIZE_T *n, const double *x, const MAT_SIZE_T *incx,
const double *y, const MAT_SIZE_T *incy);
#ifdef __cplusplus
}
#endif
#endif /* OPM_BLAS_LAPACK_HEADER_INCLUDED */

View File

@ -34,6 +34,8 @@
*/
#include "config.h"
#if HAVE_UMFPACK
#include <assert.h>
#include <stdlib.h>
@ -183,3 +185,15 @@ call_UMFPACK(struct CSRMatrix *A, const double *b, double *x)
csc_deallocate(csc);
}
#else
#include <stdlib.h>
#include <opm/core/linalg/call_umfpack.h>
void
call_UMFPACK(struct CSRMatrix *A, const double *b, double *x)
{
/* UMFPACK is not available */
abort();
}
#endif

View File

@ -18,8 +18,10 @@
*/
#include "config.h"
#include <opm/core/pressure/IncompTpfa.hpp>
#include <opm/common/data/SimulationDataContainer.hpp>
#include <opm/core/pressure/IncompTpfa.hpp>
#include <opm/core/props/IncompPropertiesInterface.hpp>
#include <opm/core/props/rock/RockCompressibility.hpp>
#include <opm/core/pressure/tpfa/ifs_tpfa.h>
@ -28,7 +30,6 @@
#include <opm/core/pressure/flow_bc.h>
#include <opm/core/linalg/LinearSolverInterface.hpp>
#include <opm/core/linalg/sparse_sys.h>
#include <opm/core/simulator/TwophaseState.hpp>
#include <opm/core/simulator/WellState.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/core/utility/miscUtilities.hpp>
@ -155,7 +156,7 @@ namespace Opm
/// May throw an exception if the number of iterations
/// exceed maxiter (set in constructor).
void IncompTpfa::solve(const double dt,
TwophaseState& state,
SimulationDataContainer& state,
WellState& well_state)
{
if (rock_comp_props_ != 0 && rock_comp_props_->isActive()) {
@ -169,7 +170,7 @@ namespace Opm
// Solve with no rock compressibility (linear eqn).
void IncompTpfa::solveIncomp(const double dt,
TwophaseState& state,
SimulationDataContainer& state,
WellState& well_state)
{
// Set up properties.
@ -207,7 +208,7 @@ namespace Opm
// Solve with rock compressibility (nonlinear eqn).
void IncompTpfa::solveRockComp(const double dt,
TwophaseState& state,
SimulationDataContainer& state,
WellState& well_state)
{
// This function is identical to CompressibleTpfa::solve().
@ -321,7 +322,7 @@ namespace Opm
/// Compute per-solve dynamic properties.
void IncompTpfa::computePerSolveDynamicData(const double /*dt*/,
const TwophaseState& state,
const SimulationDataContainer& state,
const WellState& /*well_state*/)
{
// Computed here:
@ -369,7 +370,7 @@ namespace Opm
/// Compute per-iteration dynamic properties.
void IncompTpfa::computePerIterationDynamicData(const double /*dt*/,
const TwophaseState& state,
const SimulationDataContainer& state,
const WellState& well_state)
{
// These are the variables that get computed by this function:
@ -396,7 +397,7 @@ namespace Opm
/// Compute the residual in h_->b and Jacobian in h_->A.
void IncompTpfa::assemble(const double dt,
const TwophaseState& state,
const SimulationDataContainer& state,
const WellState& /*well_state*/)
{
const double* pressures = wells_ ? &pressures_[0] : &state.pressure()[0];
@ -462,7 +463,7 @@ namespace Opm
/// Compute the output.
void IncompTpfa::computeResults(TwophaseState& state,
void IncompTpfa::computeResults(SimulationDataContainer& state,
WellState& well_state) const
{
// Make sure h_ contains the direct-solution matrix

View File

@ -20,7 +20,6 @@
#ifndef OPM_INCOMPTPFA_HEADER_INCLUDED
#define OPM_INCOMPTPFA_HEADER_INCLUDED
#include <opm/core/pressure/tpfa/ifs_tpfa.h>
#include <vector>
@ -34,8 +33,9 @@ namespace Opm
class IncompPropertiesInterface;
class RockCompressibility;
class LinearSolverInterface;
class TwophaseState;
class WellState;
class SimulationDataContainer;
/// Encapsulating a tpfa pressure solver for the incompressible-fluid case.
/// Supports gravity, wells controlled by bhp or reservoir rates,
@ -112,7 +112,7 @@ namespace Opm
/// May throw an exception if the number of iterations
/// exceed maxiter (set in constructor).
void solve(const double dt,
TwophaseState& state,
SimulationDataContainer& state,
WellState& well_state);
@ -122,28 +122,28 @@ namespace Opm
protected:
// Solve with no rock compressibility (linear eqn).
void solveIncomp(const double dt,
TwophaseState& state,
SimulationDataContainer& state,
WellState& well_state);
// Solve with rock compressibility (nonlinear eqn).
void solveRockComp(const double dt,
TwophaseState& state,
SimulationDataContainer& state,
WellState& well_state);
private:
// Helper functions.
void computeStaticData();
virtual void computePerSolveDynamicData(const double dt,
const TwophaseState& state,
const SimulationDataContainer& state,
const WellState& well_state);
void computePerIterationDynamicData(const double dt,
const TwophaseState& state,
const SimulationDataContainer& state,
const WellState& well_state);
void assemble(const double dt,
const TwophaseState& state,
const SimulationDataContainer& state,
const WellState& well_state);
void solveIncrement();
double residualNorm() const;
double incrementNorm() const;
void computeResults(TwophaseState& state,
void computeResults(SimulationDataContainer& state,
WellState& well_state) const;
protected:

View File

@ -1,210 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <opm/core/pressure/fsh.h>
#include <opm/core/pressure/fsh_common_impl.h>
#include <opm/core/pressure/mimetic/hybsys.h>
#include <opm/core/pressure/mimetic/hybsys_global.h>
/* ---------------------------------------------------------------------- */
static int
cfsh_assemble_grid(struct FlowBoundaryConditions *bc,
const double *Binv,
const double *gpress,
const double *src,
struct fsh_data *h)
/* ---------------------------------------------------------------------- */
{
int c, n, nc, p1, p2;
int npp;
int *pgconn, *gconn;
nc = h->pimpl->nc;
pgconn = h->pimpl->gdof_pos;
gconn = h->pimpl->gdof;
p1 = p2 = npp = 0;
for (c = 0; c < nc; c++) {
n = pgconn[c + 1] - pgconn[c];
hybsys_cellcontrib_unsymm(c, n, p1, p2, gpress, src, Binv,
h->pimpl->sys);
npp += fsh_impose_bc(n, gconn + p1, bc, h->pimpl);
hybsys_global_assemble_cell(n, gconn + p1,
h->pimpl->sys->S,
h->pimpl->sys->r, h->A, h->b);
p1 += n;
p2 += n * n;
}
return npp;
}
/* ======================================================================
* Public routines follow.
* ====================================================================== */
/* ---------------------------------------------------------------------- */
/* Allocate and define supporting structures for assembling the global
* system of linear equations to couple the grid (reservoir)
* connections represented by 'G' and, if present (i.e., non-NULL),
* the well connections represented by 'W'. */
/* ---------------------------------------------------------------------- */
struct fsh_data *
cfsh_construct(struct UnstructuredGrid *G, well_t *W)
/* ---------------------------------------------------------------------- */
{
int nc, ngconn_tot;
size_t idata_sz, ddata_sz, nnu;
struct fsh_data *new;
assert (G != NULL);
/* Allocate master structure, define system matrix sparsity */
new = malloc(1 * sizeof *new);
if (new != NULL) {
new->A = hybsys_define_globconn(G, W);
new->pimpl = NULL;
if (new->A == NULL) {
fsh_destroy(new);
new = NULL;
}
}
/* Allocate implementation structure */
if (new != NULL) {
fsh_count_grid_dof(G, &new->max_ngconn, &new->sum_ngconn2);
fsh_compute_table_sz(G, W, new->max_ngconn,
&nnu, &idata_sz, &ddata_sz);
new->pimpl = fsh_impl_allocate_basic(idata_sz, ddata_sz);
if (new->pimpl == NULL) {
fsh_destroy(new);
new = NULL;
}
}
/* Allocate Schur complement contributions. Unsymmetric system. */
if (new != NULL) {
nc = G->number_of_cells;
ngconn_tot = G->cell_facepos[nc];
fsh_define_linsys_arrays(new);
fsh_define_impl_arrays(nc, G->number_of_faces, nnu,
ngconn_tot, new->max_ngconn, W, new->pimpl);
new->pimpl->sys = hybsys_allocate_unsymm(new->max_ngconn,
nc, ngconn_tot);
if (W != NULL) {
fsh_define_cell_wells(nc, W, new->pimpl);
new->pimpl->wsys =
hybsys_well_allocate_unsymm(new->max_ngconn, nc,
new->pimpl->cwell_pos);
}
if ((new->pimpl->sys == NULL) ||
((W != NULL) && (new->pimpl->wsys == NULL))) {
/* Failed to allocate ->sys or ->wsys (if W != NULL) */
fsh_destroy(new);
new = NULL;
}
}
if (new != NULL) {
/* All allocations succeded. Fill metadata and return. */
new->pimpl->nc = nc;
new->pimpl->nf = G->number_of_faces;
new->pimpl->nw = (W != NULL) ? W->number_of_wells : 0;
memcpy(new->pimpl->gdof_pos,
G->cell_facepos ,
(nc + 1) * sizeof *new->pimpl->gdof_pos);
memcpy(new->pimpl->gdof ,
G->cell_faces ,
ngconn_tot * sizeof *new->pimpl->gdof);
hybsys_init(new->max_ngconn, new->pimpl->sys);
}
return new;
}
/* ---------------------------------------------------------------------- */
/* Assemble global system of linear equations
*
* fsh->A * fsh->x = fsh->b
*/
/* ---------------------------------------------------------------------- */
void
cfsh_assemble(struct FlowBoundaryConditions *bc,
const double *src,
const double *Binv,
const double *Biv,
const double *P,
const double *gpress,
well_control_t *wctrl,
const double *WI,
const double *BivW,
const double *wdp,
struct fsh_data *h)
/* ---------------------------------------------------------------------- */
{
int npp; /* Number of prescribed pressure values */
/* Suppress warnings about unused parameters. */
(void) wctrl; (void) WI; (void) BivW; (void) wdp;
hybsys_schur_comp_unsymm(h->pimpl->nc,
h->pimpl->gdof_pos,
Binv, Biv, P, h->pimpl->sys);
fsh_map_bdry_condition(bc, h->pimpl);
npp = cfsh_assemble_grid(bc, Binv, gpress, src, h);
if (npp == 0) {
h->A->sa[0] *= 2; /* Remove zero eigenvalue */
}
}

View File

@ -1,90 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <opm/core/pressure/fsh.h>
#include <opm/core/pressure/fsh_common_impl.h>
#include <opm/core/pressure/mimetic/hybsys.h>
#include <opm/core/pressure/mimetic/hybsys_global.h>
/* ---------------------------------------------------------------------- */
/* Compute cell pressures (cpress) and interface fluxes (fflux) from
* current solution of system of linear equations, h->x. Back
* substitution process, projected half-contact fluxes. */
/* ---------------------------------------------------------------------- */
void
fsh_press_flux(struct UnstructuredGrid *G,
const double *Binv, const double *gpress,
struct fsh_data *h,
double *cpress, double *fflux,
double *wpress, double *wflux)
/* ---------------------------------------------------------------------- */
{
int c, f, i;
double s;
hybsys_compute_press_flux(G->number_of_cells,
G->cell_facepos,
G->cell_faces,
gpress, Binv,
h->pimpl->sys,
h->x, cpress, h->pimpl->cflux,
h->pimpl->work);
if (h->pimpl->nw > 0) {
assert ((wpress != NULL) && (wflux != NULL));
hybsys_compute_press_flux_well(G->number_of_cells, G->cell_facepos,
G->number_of_faces, h->pimpl->nw,
h->pimpl->cwell_pos, h->pimpl->cwells,
Binv, h->pimpl->WI,
h->pimpl->wdp, h->pimpl->sys,
h->pimpl->wsys, h->x, cpress,
h->pimpl->cflux, wpress, wflux,
h->pimpl->work);
}
for (f = 0; f < G->number_of_faces; f++) { fflux[f] = 0.0; }
i = 0;
for (c = 0; c < G->number_of_cells; c++) {
for (; i < G->cell_facepos[c + 1]; i++) {
f = G->cell_faces[i];
s = 2.0*(G->face_cells[2*f + 0] == c) - 1.0;
fflux[f] += s * h->pimpl->cflux[i];
}
}
for (f = 0; f < G->number_of_faces; f++) {
i = (G->face_cells[2*f + 0] >= 0) +
(G->face_cells[2*f + 1] >= 0);
fflux[f] /= i;
}
}

View File

@ -1,243 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_FSH_HEADER_INCLUDED
#define OPM_FSH_HEADER_INCLUDED
/**
* \file
* Routines and data structures to support the construction and
* formation of hybridized pressure solvers based on Schur
* complement reductions.
*
* Pressure solvers based on this strategy will be structured
* according to the following scheme
* -# Construct @c FSH data object suitable for the particular
* problem using either of the functions cfsh_construct() or
* ifsh_construct() for compressible or incompressible flow,
* respectively
* -# Compute static discretisation quantities, for instance
* using functions mim_ip_simple_all() and mim_ip_compute_gpress()
* -# For each time step or non-linear iteration:
* -# Compute dynamic discretisation quantities incorporating
* effects of multiple phases and non-linear feedback.
* -# Assemble system of simultaneous linear equations using
* functions cfsh_assemble() or ifsh_assemble()
* -# Solve the resulting system of linear equations, available
* in the @c A and @c b objects of the @c FSH data object,
* using some linear solver software. The solution should
* be placed in the @c x object of the @c FSH object.
* -# Reconstruct derived quantities such as cell pressures and
* interface fluxes using function fsh_press_flux().
* Function fsh_press_flux() relies on the solution to the
* linear system being stored in the @c x object.
* -# Release resources using function fsh_destroy() at end of
* simulation.
*/
#include <opm/core/grid.h>
#include <opm/core/pressure/legacy_well.h>
#include <opm/core/pressure/flow_bc.h>
#ifdef __cplusplus
extern "C" {
#endif
struct CSRMatrix;
struct fsh_impl;
/**
* Main data structure of hybridized pressure solvers based on Schur
* complement reductions. Mainly intended to present a common view
* of a Schur complement system of simultaneous linear equations
* and to hold the solution of said system.
*/
struct fsh_data {
/**
* Maximum number of connections in any grid cell,
* \f[
* \mathit{max\_ngconn} = \max_c \{ n_c \}
* \f]
* in which \f$n_c\f$ denotes the number connections
* (i.e., faces) of cell \f$c\f$.
*/
int max_ngconn;
/**
* Sum of squared number of connections in all grid cells,
* \f[
* \mathit{sum\_ngconn2} = \sum_c n_c^2.
* \f]
*/
size_t sum_ngconn2;
/* Linear system */
struct CSRMatrix *A; /**< Coefficient matrix */
double *b; /**< System RHS */
double *x; /**< Solution */
/** Private implementational details. */
struct fsh_impl *pimpl;
};
/**
* Dispose of all memory associated to <CODE>FSH</CODE> object.
*
* @param[in,out] h <CODE>FSH</CODE> object. Following a call
* to function fsh_destroy(), the pointer is
* invalid.
*/
void
fsh_destroy(struct fsh_data *h);
/**
* Construct compressible hybrid flow-solver data object for a
* given grid and well pattern.
*
* @param[in] G Grid.
* @param[in] W Well topology. Ignored.
* @return Fully formed data object suitable for use in a
* compressible pressure solver. @c NULL in case of construction
* failure.
*/
struct fsh_data *
cfsh_construct(struct UnstructuredGrid *G, well_t *W);
/**
* Form Schur-complement system of simultaneous linear equations
* arising in compressible flow using a hybridized formulation.
*
* Upon returning from function cfsh_assemble(), the resulting
* system of simultaneous linear equations is stored in
* <CODE>h->A</CODE> and <CODE>h->b</CODE>.
*
* @param[in] bc Boundary conditions.
* @param[in] src Explicit source terms.
* @param[in] Binv Inverse of block-diagonal matrix \f$B\f$
* Typically computed using functions
* mim_ip_simple_all() and
* mim_ip_mobility_update().
* @param[in] Biv \f$B^{-1}v\f$.
* @param[in] P Compressible accumulation term.
* @param[in] gpress Gravity pressure.
* @param[in] wctrl Well controls. Ignored.
* @param[in] WI Well indices. Ignored.
* @param[in] BivW \f$B^{-1}v\f$ for wells. Ignored.
* @param[in] wdp Gravity pressure along well track. Ignored.
* @param[in,out] h Data object.
*/
void
cfsh_assemble(struct FlowBoundaryConditions *bc,
const double *src,
const double *Binv,
const double *Biv,
const double *P,
const double *gpress,
well_control_t *wctrl,
const double *WI,
const double *BivW,
const double *wdp,
struct fsh_data *h);
/**
* Construct incompressible hybrid flow-solver data object for a
* given grid and well pattern.
*
* @param G Grid.
* @param W Well topology.
* @return Fully formed data object suitable for use in an
* incompressible pressure solver. @c NULL in case of construction
* failure.
*/
struct fsh_data *
ifsh_construct(struct UnstructuredGrid *G, well_t *W);
/**
* Form Schur-complement system of simultaneous linear equations
* arising in compressible flow using a hybridized formulation.
*
* Upon returning from function cfsh_assemble(), the resulting
* system of simultaneous linear equations is stored in
* <CODE>h->A</CODE> and <CODE>h->b</CODE>.
*
* @param[in] bc Boundary conditions.
* @param[in] src Explicit source terms.
* @param[in] Binv Inverse of block-diagonal matrix \f$B\f$
* Typically computed using functions
* mim_ip_simple_all() and
* mim_ip_mobility_update().
* @param[in] gpress Gravity pressure.
* @param[in] wctrl Well controls.
* @param[in] WI Well indices.
* @param[in] wdp Gravity pressure along well track.
* @param[in,out] h Data object.
*/
void
ifsh_assemble(struct FlowBoundaryConditions *bc,
const double *src,
const double *Binv,
const double *gpress,
well_control_t *wctrl,
const double *WI,
const double *wdp,
struct fsh_data *h);
/**
* Compute cell pressures (cpress) and interface fluxes (fflux) from
* current solution of system of linear equations, <CODE>h->x</CODE>.
* Back substitution process, projected half-contact fluxes.
*
* @param[in] G Grid.
* @param[in] Binv Inverse of block-diagonal matrix \f$B\f$
* Must coincide with the matrix used to
* form the system of linear equations
* currently stored in the data object.
* @param[in] gpress Gravity pressure. Must coincide with
* the array used to form the system of
* linear equations.
* @param[in] h Data object.
* @param[out] cpress Cell pressure.
* @param[out] fflux Interface fluxes.
* @param[out] wpress Well pressure.
* @param[out] wflux Well perforation fluxes.
*/
void
fsh_press_flux(struct UnstructuredGrid *G,
const double *Binv, const double *gpress,
struct fsh_data *h,
double *cpress, double *fflux,
double *wpress, double *wflux);
#ifdef __cplusplus
}
#endif
#endif /* OPM_FSH_HEADER_INCLUDED */

View File

@ -1,317 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <opm/core/grid.h>
#include <opm/core/pressure/legacy_well.h>
#include <opm/core/pressure/flow_bc.h>
#include <opm/core/pressure/fsh.h>
#include <opm/core/pressure/fsh_common_impl.h>
#include <opm/core/pressure/mimetic/hybsys.h>
#include <opm/core/pressure/mimetic/hybsys_global.h>
#if defined MAX
#undef MAX
#endif
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
/* ---------------------------------------------------------------------- */
/* Release dynamic memory resources associated to internal data of a
* particular (incompressible) flow solver instance. */
/* ---------------------------------------------------------------------- */
static void
fsh_destroy_impl(struct fsh_impl *pimpl)
/* ---------------------------------------------------------------------- */
{
if (pimpl != NULL) {
hybsys_well_free(pimpl->wsys );
hybsys_free (pimpl->sys );
free (pimpl->ddata);
free (pimpl->idata);
}
free(pimpl);
}
/* ---------------------------------------------------------------------- */
/* Eliminate 'npp' prescribed (Dirichlet) conditions (locdof,dofval)
* from global system of linear equations. Move known values to RHS
* whilst zeroing coefficient matrix contributions. Local system of
* dimension 'n'. */
/* ---------------------------------------------------------------------- */
static void
fsh_explicit_elimination(int n, int npp,
int *locdof, double *dofval,
double *S, double *r)
/* ---------------------------------------------------------------------- */
{
int i, p;
for (i = 0; i < npp; i++) {
for (p = (locdof[i] + 1) % n; p != locdof[i]; p = (p + 1) % n) {
/* Subtract known values from RHS. */
r[p] -= S[p + locdof[i]*n] * dofval[i];
/* Eliminate DOF (zero row/col "locdof[i]"; leave diagonal). */
S[p + locdof[i]*n] = 0.0;
S[locdof[i] + p*n] = 0.0;
}
/* Produce trivial equation S(i,i)*x(i) = S(i,i)*x0(i). */
r[p] = S[p * (n + 1)] * dofval[i];
}
}
/* ---------------------------------------------------------------------- */
/* Release memory resources for ifsh data-handle 'h' */
/* ---------------------------------------------------------------------- */
void
fsh_destroy(struct fsh_data *h)
/* ---------------------------------------------------------------------- */
{
if (h != NULL) {
fsh_destroy_impl(h->pimpl);
csrmatrix_delete(h->A );
}
free(h);
}
/* ---------------------------------------------------------------------- */
struct fsh_impl *
fsh_impl_allocate_basic(size_t idata_sz, size_t ddata_sz)
/* ---------------------------------------------------------------------- */
{
struct fsh_impl *new;
new = malloc(1 * sizeof *new);
if (new != NULL) {
new->idata = malloc(idata_sz * sizeof *new->idata);
new->ddata = malloc(ddata_sz * sizeof *new->ddata);
new->sys = NULL;
new->wsys = NULL;
if ((new->idata == NULL) || (new->ddata == NULL)) {
fsh_destroy_impl(new);
new = NULL;
}
}
return new;
}
/* ---------------------------------------------------------------------- */
/* Determine nnz (=sum(diff(facePos)^2)) and max(diff(facePos) for grid */
/* ---------------------------------------------------------------------- */
void
fsh_count_grid_dof(struct UnstructuredGrid *G, int *max_ngdof, size_t *sum_ngdof2)
/* ---------------------------------------------------------------------- */
{
int c, n;
*max_ngdof = INT_MIN;
*sum_ngdof2 = 0;
for (c = 0; c < G->number_of_cells; c++) {
n = G->cell_facepos[c + 1] - G->cell_facepos[c];
*max_ngdof = MAX(*max_ngdof, n);
*sum_ngdof2 += n * n;
}
}
/* ---------------------------------------------------------------------- */
/* Impose boundary conditions on local contribution to global system. */
/* ---------------------------------------------------------------------- */
int
fsh_impose_bc(int nconn, int *conn, struct FlowBoundaryConditions *bc,
struct fsh_impl *pimpl)
/* ---------------------------------------------------------------------- */
{
int i, j, npp, f;
npp = 0;
for (i = 0; i < nconn; i++) {
f = conn[i];
j = pimpl->bdry_condition[ f ];
if (j != -1) {
if (bc->type[j] == BC_PRESSURE) {
pimpl->work [npp] = bc->value[j];
pimpl->iwork[npp] = i;
npp += 1;
} else if (bc->type[j] == BC_FLUX_TOTVOL) {
pimpl->sys->r[i] -= bc->value[j];
}
}
}
if (npp > 0) {
fsh_explicit_elimination(nconn, npp,
pimpl->iwork,
pimpl->work,
pimpl->sys->S,
pimpl->sys->r);
}
return npp;
}
/* ---------------------------------------------------------------------- */
void
fsh_map_bdry_condition(struct FlowBoundaryConditions *fbc ,
struct fsh_impl *pimpl)
/* ---------------------------------------------------------------------- */
{
int f, i;
size_t j;
for (i = 0; i < pimpl->nf; i++) { pimpl->bdry_condition[ i ] = -1; }
if (fbc != NULL) {
assert (fbc->cond_pos[0] == 0);
for (i = 0, j = 0; ((size_t) i) < fbc->nbc; i++) {
for (; j < fbc->cond_pos[i + 1]; j++) {
f = fbc->face[ j ];
assert ((0 <= f) && (f < pimpl->nf));
pimpl->bdry_condition[ f ] = i;
}
}
}
}
/* ---------------------------------------------------------------------- */
void
fsh_define_impl_arrays(size_t nc,
size_t nf,
size_t nnu,
size_t nhf,
size_t max_ncf,
well_t *W,
struct fsh_impl *pimpl)
/* ---------------------------------------------------------------------- */
{
pimpl->cflux = pimpl->ddata + 2 * nnu;
pimpl->work = pimpl->cflux + nhf;
pimpl->gdof_pos = pimpl->idata;
pimpl->gdof = pimpl->gdof_pos + (nc + 1);
pimpl->iwork = pimpl->gdof + nhf;
pimpl->bdry_condition = pimpl->iwork + max_ncf;
if (W != NULL) {
pimpl->cwell_pos = pimpl->bdry_condition + nf;
pimpl->cwells = pimpl->cwell_pos + nc + 1;
pimpl->WI = pimpl->work + max_ncf;
pimpl->wdp = pimpl->WI + W->well_connpos[ W->number_of_wells ];
}
}
/* ---------------------------------------------------------------------- */
void
fsh_define_cell_wells(size_t nc, well_t *W, struct fsh_impl *pimpl)
/* ---------------------------------------------------------------------- */
{
size_t i;
for (i = 0; i < nc + 1; i++) {
pimpl->cwell_pos[i] = 0;
}
derive_cell_wells(nc, W, pimpl->cwell_pos, pimpl->cwells);
}
/* ---------------------------------------------------------------------- */
void
fsh_define_linsys_arrays(struct fsh_data *h)
/* ---------------------------------------------------------------------- */
{
h->b = h->pimpl->ddata;
h->x = h->b + h->A->m;
}
/* ---------------------------------------------------------------------- */
void
fsh_compute_table_sz(struct UnstructuredGrid *G, well_t *W, int max_ngconn,
size_t *nnu, size_t *idata_sz, size_t *ddata_sz)
/* ---------------------------------------------------------------------- */
{
int nc, ngconn_tot;
*nnu = G->number_of_faces;
nc = G->number_of_cells;
ngconn_tot = G->cell_facepos[nc];
*idata_sz = nc + 1; /* gdof_pos */
*idata_sz += ngconn_tot; /* gdof */
*idata_sz += G->number_of_faces; /* bdry_condition */
*idata_sz += max_ngconn; /* iwork */
*ddata_sz = 2 * (*nnu); /* rhs + soln */
*ddata_sz += ngconn_tot; /* cflux */
*ddata_sz += max_ngconn; /* work */
if (W != NULL) {
*nnu += W->number_of_wells;
/* cwell_pos */
*idata_sz += nc + 1;
/* cwells */
*idata_sz += 2 * W->well_connpos[ W->number_of_wells ];
/* rhs + soln */
*ddata_sz += 2 * W->number_of_wells;
/* WI, wdp */
*ddata_sz += 2 * W->well_connpos[ W->number_of_wells ];
}
}

View File

@ -1,90 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_FSH_COMMON_IMPL_HEADER_INCLUDED
#define OPM_FSH_COMMON_IMPL_HEADER_INCLUDED
/* Internal header. Don't install. */
struct fsh_impl {
int nc, nf, nw; /* Number of cells, faces, wells */
/* Topology */
int *gdof_pos; /* Pointers, grid DOFs (== cell_facepos) */
int *gdof; /* Grid DOFs (== cell_faces) */
int *cwell_pos; /* Start pointers, well DOFs (c->w) */
int *cwells; /* Well DOFs (c->w) */
/* Discretisation data */
double *WI; /* Permuted well production indices */
double *wdp; /* Permuted well gravity pressures */
double *cflux; /* Cell (half-contact) fluxes */
struct hybsys *sys; /* Hybrid cell contribs */
struct hybsys_well *wsys; /* Hybrid cell contribs from wells */
double *work; /* Scratch array, floating point */
int *iwork; /* Scratch array, integers */
int *bdry_condition; /* Map face->boundary condition ID */
/* Linear storage goes here... */
int *idata; /* Actual storage array, integers */
double *ddata; /* Actual storage array, floating point */
};
struct fsh_impl *
fsh_impl_allocate_basic(size_t idata_sz, size_t ddata_sz);
void
fsh_count_grid_dof(struct UnstructuredGrid *G, int *max_ngdof, size_t *sum_ngdof2);
void
fsh_map_bdry_condition(struct FlowBoundaryConditions *fbc ,
struct fsh_impl *pimpl);
int
fsh_impose_bc(int ndof,
int *dof,
struct FlowBoundaryConditions *bc,
struct fsh_impl *pimpl);
void
fsh_define_impl_arrays(size_t nc,
size_t nf,
size_t nnu,
size_t nhf,
size_t max_ncf,
well_t *W,
struct fsh_impl *pimpl);
void
fsh_define_cell_wells(size_t nc, well_t *W, struct fsh_impl *pimpl);
void
fsh_define_linsys_arrays(struct fsh_data *h);
void
fsh_compute_table_sz(struct UnstructuredGrid *G, well_t *W, int max_ngconn,
size_t *nnu, size_t *idata_sz, size_t *ddata_sz);
#endif /* OPM_FSH_COMMON_IMPL_HEADER_INCLUDED */

View File

@ -1,390 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <opm/core/pressure/fsh.h>
#include <opm/core/pressure/fsh_common_impl.h>
#include <opm/core/pressure/mimetic/hybsys.h>
#include <opm/core/pressure/mimetic/hybsys_global.h>
/* ---------------------------------------------------------------------- */
static void
ifsh_set_effective_well_params(const double *WI,
const double *wdp,
struct fsh_data *ifsh)
/* ---------------------------------------------------------------------- */
{
int c, nc, i, perf;
int *cwpos, *cwells;
double *wsys_WI, *wsys_wdp;
nc = ifsh->pimpl->nc;
cwpos = ifsh->pimpl->cwell_pos;
cwells = ifsh->pimpl->cwells;
wsys_WI = ifsh->pimpl->WI;
wsys_wdp = ifsh->pimpl->wdp;
for (c = i = 0; c < nc; c++) {
for (; i < cwpos[c + 1]; i++) {
perf = cwells[2*i + 1];
wsys_WI [i] = WI [perf];
wsys_wdp[i] = wdp[perf];
}
}
}
/* ---------------------------------------------------------------------- */
static int
ifsh_assemble_grid(struct FlowBoundaryConditions *bc,
const double *Binv,
const double *gpress,
const double *src,
struct fsh_data *ifsh)
/* ---------------------------------------------------------------------- */
{
int c, n, nc, p1, p2;
int npp;
int *pgconn, *gconn;
nc = ifsh->pimpl->nc;
pgconn = ifsh->pimpl->gdof_pos;
gconn = ifsh->pimpl->gdof;
p1 = p2 = npp = 0;
for (c = 0; c < nc; c++) {
n = pgconn[c + 1] - pgconn[c];
hybsys_cellcontrib_symm(c, n, p1, p2, gpress, src, Binv,
ifsh->pimpl->sys);
npp += fsh_impose_bc(n, gconn + p1, bc, ifsh->pimpl);
hybsys_global_assemble_cell(n, gconn + p1,
ifsh->pimpl->sys->S,
ifsh->pimpl->sys->r,
ifsh->A, ifsh->b);
p1 += n;
p2 += n * n;
}
return npp;
}
/* ---------------------------------------------------------------------- */
static void
ifsh_impose_well_control(int c,
struct FlowBoundaryConditions *bc,
well_control_t *wctrl,
struct fsh_data *ifsh)
/* ---------------------------------------------------------------------- */
{
int ngconn, nwconn, i, j, w1, w2, wg, f;
int *pgconn, *gconn, *pwconn, *wconn;
double bhp;
double *r, *r2w, *w2w;
/* Enforce symmetric system */
assert (ifsh->pimpl->wsys->r2w == ifsh->pimpl->wsys->w2r);
pgconn = ifsh->pimpl->gdof_pos;
pwconn = ifsh->pimpl->cwell_pos;
gconn = ifsh->pimpl->gdof + pgconn[c];
wconn = ifsh->pimpl->cwells + 2*pwconn[c];
ngconn = pgconn[c + 1] - pgconn[c];
nwconn = pwconn[c + 1] - pwconn[c];
r2w = ifsh->pimpl->wsys->r2w;
w2w = ifsh->pimpl->wsys->w2w;
r = ifsh->pimpl->wsys->r ;
/* Adapt local system to prescribed boundary pressures (r->w) */
for (i = 0; i < ngconn; i++) {
f = gconn[i];
j = ifsh->pimpl->bdry_condition[ f ];
if (j != -1) {
for (w1 = 0; w1 < nwconn; w1++) {
/* Eliminate prescribed (boundary) pressure value */
r [ngconn + w1] -= r2w[i + w1*ngconn] * bc->value[j];
r2w[i + w1*ngconn] = 0.0;
}
r[i] = 0.0; /* RHS value handled in *reservoir* asm */
}
}
/* Adapt local system to prescribed well (bottom-hole) pressures;
* w->r and w->w. */
for (w1 = 0; w1 < nwconn; w1++) {
wg = wconn[2*w1 + 0];
if (wctrl->ctrl[wg] == BHP) {
bhp = wctrl->target[wg];
/* Well->reservoir */
for (i = 0; i < ngconn; i++) {
#ifndef NDEBUG
j = ifsh->pimpl->bdry_condition[ gconn[i] ];
assert ((j == -1) ||
(bc->type[j] != BC_PRESSURE) ||
!(fabs(r2w[i + w1*ngconn]) > 0.0));
#endif
r [i] -= r2w[i + w1*ngconn] * bhp;
r2w[i + w1*ngconn] = 0.0;
}
/* Well->well */
for (w2 = (w1 + 1) % nwconn; w2 != w1; w2 = (w2 + 1) % nwconn) {
r [ngconn + w2] -= w2w[w2 + w1*nwconn] * bhp;
w2w[w2 + w1*ngconn] = 0.0;
w2w[w1 + w2*ngconn] = 0.0;
}
/* Assemble final well equation of the form S*p_bh = S*p_bh^0 */
assert (fabs(w2w[w1 * (nwconn + 1)]) > 0.0);
r[ngconn + w1] = w2w[w1 * (nwconn + 1)] * bhp;
}
}
}
/* ---------------------------------------------------------------------- */
static int
ifsh_assemble_well(struct FlowBoundaryConditions *bc,
well_control_t *wctrl,
struct fsh_data *ifsh)
/* ---------------------------------------------------------------------- */
{
int npp;
int ngconn, nwconn, c, nc, w;
int *pgconn, *gconn, *pwconn, *wconn;
nc = ifsh->pimpl->nc;
pgconn = ifsh->pimpl->gdof_pos;
gconn = ifsh->pimpl->gdof;
pwconn = ifsh->pimpl->cwell_pos;
wconn = ifsh->pimpl->cwells;
for (c = 0; c < nc; c++) {
ngconn = pgconn[c + 1] - pgconn[c];
nwconn = pwconn[c + 1] - pwconn[c];
if (nwconn > 0) {
hybsys_well_cellcontrib_symm(c, ngconn, pgconn[c],
pwconn,
ifsh->pimpl->WI,
ifsh->pimpl->wdp,
ifsh->pimpl->sys,
ifsh->pimpl->wsys);
ifsh_impose_well_control(c, bc, wctrl, ifsh);
hybsys_global_assemble_well_sym(ifsh->pimpl->nf,
ngconn, gconn + pgconn[c],
nwconn, wconn + 2*pwconn[c] + 0,
ifsh->pimpl->wsys->r2w,
ifsh->pimpl->wsys->w2w,
ifsh->pimpl->wsys->r,
ifsh->A, ifsh->b);
}
}
npp = 0;
for (w = 0; w < ifsh->pimpl->nw; w++) {
if (wctrl->ctrl[w] == BHP) {
npp += 1;
} else if (wctrl->ctrl[w] == RATE) {
/* Impose total rate constraint.
*
* Note sign resulting from ->target[w] denoting
* *injection* flux. */
ifsh->b[ifsh->pimpl->nf + w] -= - wctrl->target[w];
}
}
return npp;
}
/* ======================================================================
* Public routines follow.
* ====================================================================== */
/* ---------------------------------------------------------------------- */
/* Allocate and define supporting structures for assembling the global
* system of linear equations to couple the grid (reservoir)
* connections represented by 'G' and, if present (i.e., non-NULL),
* the well connections represented by 'W'. */
/* ---------------------------------------------------------------------- */
struct fsh_data *
ifsh_construct(struct UnstructuredGrid *G, well_t *W)
/* ---------------------------------------------------------------------- */
{
int nc, ngconn_tot;
size_t idata_sz, ddata_sz, nnu;
struct fsh_data *new;
assert (G != NULL);
/* Allocate master structure, define system matrix sparsity */
new = malloc(1 * sizeof *new);
if (new != NULL) {
new->A = hybsys_define_globconn(G, W);
new->pimpl = NULL;
if (new->A == NULL) {
fsh_destroy(new);
new = NULL;
}
}
/* Allocate implementation structure */
if (new != NULL) {
fsh_count_grid_dof(G, &new->max_ngconn, &new->sum_ngconn2);
fsh_compute_table_sz(G, W, new->max_ngconn,
&nnu, &idata_sz, &ddata_sz);
new->pimpl = fsh_impl_allocate_basic(idata_sz, ddata_sz);
if (new->pimpl == NULL) {
fsh_destroy(new);
new = NULL;
}
}
/* Allocate Schur complement contributions. Symmetric system. */
if (new != NULL) {
nc = G->number_of_cells;
ngconn_tot = G->cell_facepos[nc];
fsh_define_linsys_arrays(new);
fsh_define_impl_arrays(nc, G->number_of_faces, nnu,
ngconn_tot, new->max_ngconn, W, new->pimpl);
new->pimpl->sys = hybsys_allocate_symm(new->max_ngconn,
nc, ngconn_tot);
if (W != NULL) {
fsh_define_cell_wells(nc, W, new->pimpl);
new->pimpl->wsys = hybsys_well_allocate_symm(new->max_ngconn, nc,
new->pimpl->cwell_pos);
}
if ((new->pimpl->sys == NULL) ||
((W != NULL) && (new->pimpl->wsys == NULL))) {
/* Failed to allocate ->sys or ->wsys (if W != NULL) */
fsh_destroy(new);
new = NULL;
}
}
if (new != NULL) {
/* All allocations succeded. Fill metadata and return. */
new->pimpl->nc = nc;
new->pimpl->nf = G->number_of_faces;
new->pimpl->nw = (W != NULL) ? W->number_of_wells : 0;
memcpy(new->pimpl->gdof_pos,
G->cell_facepos ,
(nc + 1) * sizeof *new->pimpl->gdof_pos);
memcpy(new->pimpl->gdof ,
G->cell_faces ,
ngconn_tot * sizeof *new->pimpl->gdof);
hybsys_init(new->max_ngconn, new->pimpl->sys);
}
return new;
}
/* ---------------------------------------------------------------------- */
/* Assemble global system of linear equations
*
* ifsh->A * ifsh->x = ifsh->b
*
* from effective local inner product matrices Binv, effective gravity
* pressure gpress, boundary conditions bc, and source terms src. */
/* ---------------------------------------------------------------------- */
void
ifsh_assemble(struct FlowBoundaryConditions *bc,
const double *src,
const double *Binv,
const double *gpress,
well_control_t *wctrl,
const double *WI,
const double *wdp,
struct fsh_data *ifsh)
/* ---------------------------------------------------------------------- */
{
int npp; /* Number of prescribed pressure values */
fsh_map_bdry_condition(bc, ifsh->pimpl);
hybsys_schur_comp_symm(ifsh->pimpl->nc,
ifsh->pimpl->gdof_pos,
Binv, ifsh->pimpl->sys);
if (ifsh->pimpl->nw > 0) {
ifsh_set_effective_well_params(WI, wdp, ifsh);
hybsys_well_schur_comp_symm(ifsh->pimpl->nc,
ifsh->pimpl->cwell_pos,
ifsh->pimpl->WI,
ifsh->pimpl->sys,
ifsh->pimpl->wsys);
}
npp = ifsh_assemble_grid(bc, Binv, gpress, src, ifsh);
if (ifsh->pimpl->nw > 0) {
npp += ifsh_assemble_well(bc, wctrl, ifsh);
}
if (npp == 0) {
ifsh->A->sa[0] *= 2; /* Remove zero eigenvalue */
}
}

View File

@ -1,102 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <stdlib.h>
#include <opm/core/pressure/legacy_well.h>
/* Release memory resources for cell->well mapping. */
/* ---------------------------------------------------------------------- */
void
deallocate_cell_wells(int *cwpos, int *cwells)
/* ---------------------------------------------------------------------- */
{
free(cwells);
free(cwpos);
}
/* Allocate memory resources for cell->well mapping.
*
* Returns 1 if successful and 0 if not. CSR array pair set to NULL
* unless allocation succeeds. */
/* ---------------------------------------------------------------------- */
int
allocate_cell_wells(int nc, well_t *W, int **cwpos, int **cwells)
/* ---------------------------------------------------------------------- */
{
int i, totwconn;
totwconn = W->well_connpos[W->number_of_wells];
*cwpos = malloc((nc + 1) * sizeof **cwpos );
*cwells = malloc(2 * totwconn * sizeof **cwells);
if ((*cwpos == NULL) || (*cwells == NULL)) {
deallocate_cell_wells(*cwpos, *cwells);
*cwpos = NULL;
*cwells = NULL;
totwconn = 0;
} else {
for (i = 0; i < nc + 1; i++) {
(*cwpos)[i] = 0;
}
}
return totwconn;
}
/* Derive cell->well mapping from well->cell (connection) mapping. */
/* ---------------------------------------------------------------------- */
void
derive_cell_wells(int nc, well_t *W, int *cwpos, int *cwells)
/* ---------------------------------------------------------------------- */
{
int i, w, *c, *connpos;
connpos = W->well_connpos;
c = W->well_cells;
for (w = 0; w < W->number_of_wells; w++) {
for (; c != W->well_cells + connpos[w + 1]; c++) {
cwpos[*c + 1] += 1;
}
}
for (i = 1; i <= nc; i++) {
cwpos[0] += cwpos[i];
cwpos[i] = cwpos[0] - cwpos[i];
}
cwpos[0] = 0;
c = W->well_cells;
for (w = 0; w < W->number_of_wells; w++) {
for (; c != W->well_cells + connpos[w + 1]; c++) {
cwells[ 2*cwpos[*c + 1] + 0 ] = w;
cwells[ 2*cwpos[*c + 1] + 1 ] = c - W->well_cells;
cwpos[*c + 1] += 1;
}
}
}

View File

@ -87,48 +87,6 @@ typedef struct LegacyWellCompletions well_t;
*/
typedef struct LegacyWellControls well_control_t;
/**
* Allocate cell-to-well mapping (as a sparse array).
*
* @param[in] nc Total number of cells.
* @param[in] W Well topology (well-to-cell mapping).
* @param[out] cwpos Indirection array. Points to array of size
* <CODE>nc + 1</CODE> if successful.
* @param[out] cwells Cell-to-well mapping. Points to array
* of size <CODE>W->well_connpos[
* W->number_of_wells]</CODE> if successful.
* @return Positive number (size of <CODE>*cwells</CODE>)
* if successful. Zero in case of allocation failure.
*/
int
allocate_cell_wells(int nc, well_t *W, int **cwpos, int **cwells);
/**
* Dispose of memory resources allocated using function
* allocate_cell_wells().
*
* Following a call to deallocate_cell_wells(), the input pointers
* are no longer valid.
*
* @param[in,out] cvpos Cell-to-well start pointers.
* @param[in,out] cwells Cell-to-well mapping.
*/
void
deallocate_cell_wells(int *cvpos, int *cwells);
/**
* Construct cell-to-well mapping (i.e., transpose the
* well-to-cell mapping represented by <CODE>W->well_cells</CODE>).
*
* @param[in] nc Total number of cells.
* @param[in] W Well topology (well-to-cell mapping).
* @param[out] cwpos Cell-to-well start pointers.
* @param[out] cwells Cell-to-well mapping.
*/
void
derive_cell_wells(int nc, well_t *W, int *cwpos, int *cwells);
#ifdef __cplusplus
}
#endif

View File

@ -1,694 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <opm/core/linalg/blas_lapack.h>
#include <opm/core/pressure/mimetic/hybsys.h>
#if defined(MAX)
#undef MAX
#endif
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
/* ---------------------------------------------------------------------- */
struct hybsys *
hybsys_allocate_symm(int max_nconn, int nc, int nconn_tot)
/* ---------------------------------------------------------------------- */
{
struct hybsys *new;
new = malloc(1 * sizeof *new);
if (new != NULL) {
new->one = malloc(max_nconn * sizeof *new->one);
new->r = malloc(max_nconn * sizeof *new->r );
new->S = malloc(max_nconn * max_nconn * sizeof *new->S );
new->L = malloc(nc * sizeof *new->L );
new->q = malloc(nc * sizeof *new->q );
new->F1 = malloc(nconn_tot * sizeof *new->F1 );
if ((new->one == NULL) || (new->r == NULL) || (new->S == NULL) ||
(new->L == NULL) || (new->q == NULL) || (new->F1 == NULL)) {
hybsys_free(new);
new = NULL;
} else {
new->F2 = new->F1;
}
}
return new;
}
/* ---------------------------------------------------------------------- */
struct hybsys *
hybsys_allocate_unsymm(int max_nconn, int nc, int nconn_tot)
/* ---------------------------------------------------------------------- */
{
struct hybsys *new;
new = hybsys_allocate_symm(max_nconn, nc, nconn_tot);
if (new != NULL) {
new->F2 = malloc(nconn_tot * sizeof *new->F2);
if (new->F2 == NULL) {
hybsys_free(new);
new = NULL;
}
}
return new;
}
/* ---------------------------------------------------------------------- */
static void
hybsys_well_count_conn(int nc, const int *cwpos,
int *max_nw, size_t *sum_nwc)
/* ---------------------------------------------------------------------- */
{
int c, nw;
*max_nw = 0;
*sum_nwc = 0;
for (c = 0; c < nc; c++) {
nw = cwpos[c + 1] - cwpos[c];
assert (nw >= 0);
*max_nw = MAX(*max_nw, nw);
*sum_nwc += nw;
}
}
/* ---------------------------------------------------------------------- */
struct hybsys_well *
hybsys_well_allocate_symm(int max_nconn, int nc, int *cwpos)
/* ---------------------------------------------------------------------- */
{
int max_nw;
size_t sum_nwc, alloc_sz;
struct hybsys_well *new;
assert (cwpos[nc] > cwpos[0]); /* Else no wells. */
new = malloc(1 * sizeof *new);
if (new != NULL) {
hybsys_well_count_conn(nc, cwpos, &max_nw, &sum_nwc);
alloc_sz = sum_nwc; /* F1 */
alloc_sz += max_nconn + max_nw; /* r */
alloc_sz += max_nw * max_nconn; /* w2r */
alloc_sz += max_nw * max_nw; /* w2w */
new->data = malloc(alloc_sz * sizeof *new->data);
if (new->data != NULL) {
new->F1 = new->data;
new->F2 = new->F1;
new->r = new->F2 + sum_nwc;
new->w2r = new->r + max_nconn + max_nw;
new->r2w = new->w2r;
new->w2w = new->r2w + (max_nw * max_nconn);
} else {
hybsys_well_free(new);
new = NULL;
}
}
return new;
}
/* ---------------------------------------------------------------------- */
struct hybsys_well *
hybsys_well_allocate_unsymm(int max_nconn, int nc, int *cwpos)
/* ---------------------------------------------------------------------- */
{
int max_nw;
size_t sum_nwc, alloc_sz;
struct hybsys_well *new;
assert (cwpos[nc] > cwpos[0]); /* Else no wells. */
new = malloc(1 * sizeof *new);
if (new != NULL) {
hybsys_well_count_conn(nc, cwpos, &max_nw, &sum_nwc);
alloc_sz = 2 * sum_nwc; /* F1, F2 */
alloc_sz += max_nconn + max_nw; /* r */
alloc_sz += 2 * max_nw * max_nconn; /* w2r, r2w */
alloc_sz += max_nw * max_nw; /* w2w */
new->data = malloc(alloc_sz * sizeof *new->data);
if (new->data != NULL) {
new->F1 = new->data;
new->F2 = new->F1 + sum_nwc;
new->r = new->F2 + sum_nwc;
new->w2r = new->r + max_nconn + max_nw;
new->r2w = new->w2r + (max_nw * max_nconn);
new->w2w = new->r2w + (max_nw * max_nconn);
} else {
hybsys_well_free(new);
new = NULL;
}
}
return new;
}
/* ---------------------------------------------------------------------- */
void
hybsys_free(struct hybsys *sys)
/* ---------------------------------------------------------------------- */
{
if (sys != NULL) {
if (sys->F2 != sys->F1) { free(sys->F2); } /* unsymmetric system */
free(sys->F1 );
free(sys->q );
free(sys->L );
free(sys->S );
free(sys->r );
free(sys->one);
}
free(sys);
}
/* ---------------------------------------------------------------------- */
void
hybsys_well_free(struct hybsys_well *wsys)
/* ---------------------------------------------------------------------- */
{
if (wsys != NULL) {
free(wsys->data);
}
free(wsys);
}
/* ---------------------------------------------------------------------- */
void
hybsys_init(int max_nconn, struct hybsys *sys)
/* ---------------------------------------------------------------------- */
{
int i;
for (i = 0; i < max_nconn; i++) {
sys->one[i] = 1.0;
}
}
/* ---------------------------------------------------------------------- */
void
hybsys_schur_comp_symm(int nc, const int *pconn,
const double *Binv, struct hybsys *sys)
/* ---------------------------------------------------------------------- */
{
int c, p1, p2, nconn;
double a1, a2;
MAT_SIZE_T incx, incy;
MAT_SIZE_T nrows, ncols, lda;
incx = incy = 1;
p1 = p2 = 0;
for (c = 0; c < nc; c++) {
p1 = pconn[c + 0];
nconn = pconn[c + 1] - pconn[c];
nrows = ncols = lda = nconn;
/* F <- C' * inv(B) == (inv(B) * ones(n,1))' in single cell */
a1 = 1.0; a2 = 0.0;
dgemv_("No Transpose" , &nrows, &ncols,
&a1, &Binv[p2] , &lda, sys->one, &incx,
&a2, &sys->F1[p1], &incy);
/* L <- C' * inv(B) * C == SUM(F) == ones(n,1)' * F */
sys->L[c] = ddot_(&nrows, sys->one, &incx, &sys->F1[p1], &incy);
p2 += nconn * nconn;
}
}
/* ---------------------------------------------------------------------- */
void
hybsys_schur_comp_unsymm(int nc, const int *pconn,
const double *Binv, const double *BIV,
const double *P, struct hybsys *sys)
/* ---------------------------------------------------------------------- */
{
int c, p1, p2, nconn;
double a1, a2;
MAT_SIZE_T incx, incy;
MAT_SIZE_T nrows, ncols, lda;
assert ((sys->F2 != sys->F1) &&
(sys->F2 != NULL));
incx = incy = 1;
p2 = 0;
for (c = 0; c < nc; c++) {
p1 = pconn[c + 0];
nconn = pconn[c + 1] - pconn[c];
nrows = ncols = lda = nconn;
/* F1 <- C' * inv(B) */
a1 = 1.0; a2 = 0.0;
dgemv_("No Transpose" , &nrows, &ncols,
&a1, &Binv[p2] , &lda, sys->one, &incx,
&a2, &sys->F1[p1], &incy);
/* F2 <- (C - V)' * inv(B) == F1 - V'*inv(B) */
a1 = -1.0;
memcpy(&sys->F2[p1], &sys->F1[p1], nconn * sizeof sys->F2[p1]);
daxpy_(&nrows, &a1, &BIV[p1], &incx, &sys->F2[p1], &incy);
/* L <- (C - V)' * inv(B) * C - P */
sys->L[c] = ddot_(&nrows, sys->one, &incx, &sys->F1[p1], &incy);
sys->L[c] -= ddot_(&nrows, sys->one, &incx, &BIV[p1] , &incy);
sys->L[c] -= P[c];
p2 += nconn * nconn;
}
}
/* ---------------------------------------------------------------------- */
void
hybsys_schur_comp_gen(int nc, const int *pconn,
const double *Binv, const double *C2,
const double *P, struct hybsys *sys)
/* ---------------------------------------------------------------------- */
{
int c, p1, p2, nconn;
double a1, a2;
MAT_SIZE_T incx, incy;
MAT_SIZE_T nrows, ncols, lda;
assert ((sys->F2 != sys->F1) &&
(sys->F2 != NULL));
incx = incy = 1;
p2 = 0;
for (c = 0; c < nc; c++) {
p1 = pconn[c + 0];
nconn = pconn[c + 1] - pconn[c];
nrows = ncols = lda = nconn;
/* F1 <- C' * inv(B) */
a1 = 1.0; a2 = 0.0;
dgemv_("No Transpose" , &nrows, &ncols,
&a1, &Binv[p2] , &lda, sys->one, &incx,
&a2, &sys->F1[p1], &incy);
/* F2 <- C2' * inv(B) */
dgemv_("No Transpose" , &nrows, &ncols,
&a1, &Binv[p2] , &lda, &C2[p1], &incx,
&a2, &sys->F2[p1], &incy);
/* L <- C2' * inv(B) * C - P == F2'*ones(n,1) - P */
sys->L[c] = ddot_(&nrows, sys->one, &incx, &sys->F2[p1], &incy);
sys->L[c] -= P[c];
p2 += nconn * nconn;
}
}
/* ---------------------------------------------------------------------- */
void
hybsys_well_schur_comp_symm(int nc, const int *cwpos,
double *WI,
struct hybsys *sys,
struct hybsys_well *wsys)
/* ---------------------------------------------------------------------- */
{
int c, i;
for (c = i = 0; c < nc; c++) {
for (; i < cwpos[c + 1]; i++) {
wsys->F1[i] = WI[i];
sys->L [c] += WI[i];
}
}
}
/* ---------------------------------------------------------------------- */
static void
hybsys_cellmat_symm_core(int nconn, const double *Binv, double L,
const double *F, double *S)
/* ---------------------------------------------------------------------- */
{
int i, j;
MAT_SIZE_T n, k, ldA, ldC;
double a1, a2;
/* S <- D' * inv(B) * D == inv(B) in single cell */
memcpy(S, Binv, nconn * nconn * sizeof *S);
/* S <- S - F'*inv(L)*F */
n = ldA = ldC = nconn;
k = 1;
a1 = -1.0 / L;
a2 = 1.0;
dsyrk_("Upper Triangular", "No Transpose", &n, &k,
&a1, F, &ldA, &a2, S, &ldC);
/* Account for DSYRK only updating the upper triangular part of S */
for (j = 0; j < nconn; j++) {
for (i = j + 1; i < nconn; i++) {
S[i + j*nconn] = S[j + i*nconn];
}
}
}
/* ---------------------------------------------------------------------- */
static void
hybsys_cellmat_unsymm_core(int nconn, const double *Binv, double L,
const double *F1, const double *F2,
double *S)
/* ---------------------------------------------------------------------- */
{
MAT_SIZE_T m, n, k, ldF1, ldF2, ldS;
double a1, a2;
/* S <- D' * inv(B) * D == inv(B) in single cell */
memcpy(S, Binv, nconn * nconn * sizeof *S);
/* S <- S - F1'*inv(L)*F2 */
a1 = -1.0 / L;
a2 = 1.0;
m = n = nconn;
k = 1;
ldF1 = ldF2 = 1;
ldS = nconn;
dgemm_("Transpose", "No Transpose", &m, &n, &k,
&a1, F1, &ldF1, F2, &ldF2, &a2, S, &ldS);
}
/* ---------------------------------------------------------------------- */
static double
hybsys_cellrhs_core(int nconn, const double *gpress, double src,
const double *Binv, double L, const double *F1,
const double *F2, double *R)
/* ---------------------------------------------------------------------- */
{
MAT_SIZE_T n, k, ldA, incx, incy;
double a1, a2;
/* r <- inv(B)*gpress + F1'*inv(L)*(src - F2*gpress)
* == inv(B)*gpress + F1'*inv(L)*(src - C2'*inv(B)*gpress) */
k = 1;
a1 = 1.0; a2 = 0.0;
incx = incy = 1;
n = k = ldA = nconn;
dgemv_("No Transpose", &n, &k,
&a1, Binv, &ldA, gpress, &incx,
&a2, R , &incy);
src -= ddot_(&n, F2, &incx, gpress, &incy);
a1 = src / L;
daxpy_(&n, &a1, F1, &incx, R, &incy);
return src;
}
/* ---------------------------------------------------------------------- */
void
hybsys_cellcontrib_symm(int c, int nconn, int p1, int p2,
const double *gpress, const double *src,
const double *Binv, struct hybsys *sys)
/* ---------------------------------------------------------------------- */
{
hybsys_cellmat_symm_core(nconn, &Binv[p2],
sys->L[c], &sys->F1[p1],
sys->S);
sys->q[c] = hybsys_cellrhs_core(nconn, &gpress[p1], src[c], &Binv[p2],
sys->L[c], &sys->F1[p1], &sys->F1[p1],
sys->r);
}
/* ---------------------------------------------------------------------- */
void
hybsys_cellcontrib_unsymm(int c, int nconn, int p1, int p2,
const double *gpress, const double *src,
const double *Binv, struct hybsys *sys)
/* ---------------------------------------------------------------------- */
{
assert ((sys->F2 != sys->F1) &&
(sys->F2 != NULL));
hybsys_cellmat_unsymm_core(nconn, &Binv[p2],
sys->L[c], &sys->F1[p1], &sys->F2[p1],
sys->S);
sys->q[c] = hybsys_cellrhs_core(nconn, &gpress[p1], src[c], &Binv[p2],
sys->L[c], &sys->F1[p1], &sys->F2[p1],
sys->r);
}
/* ---------------------------------------------------------------------- */
void
hybsys_well_cellcontrib_symm(int c, int ngconn, int p1,
const int *cwpos,
const double *WI, const double *wdp,
struct hybsys *sys, struct hybsys_well *wsys)
/* ---------------------------------------------------------------------- */
{
int i, w, nw, wp1;
MAT_SIZE_T mm, nn, kk, ld1, ld2, ld3, incx, incy;
double a1, a2, q;
nw = cwpos[c + 1] - cwpos[c];
wp1 = cwpos[c];
/* -------------------------------------------------------------- */
/* w2r = - F1(r)'*F2(w)/L, r2w = w2r' */
mm = ngconn; ld1 = 1;
nn = nw; ld2 = 1;
kk = 1; ld3 = ngconn;
a1 = -1.0 / sys->L[c];
a2 = 0.0;
dgemm_("Transpose", "No Transpose", &mm, &nn, &kk,
&a1, &sys->F1[p1], &ld1, &wsys->F2[wp1], &ld2,
&a2, wsys->w2r, &ld3);
/* -------------------------------------------------------------- */
/* w2w = BI - F1(w)'*F2(w)/L */
mm = nw; ld1 = 1;
nn = nw; ld2 = 1;
kk = 1; ld3 = nw;
a1 = -1.0 / sys->L[c];
a2 = 0.0;
dgemm_("Transpose", "No Transpose", &mm, &nn, &kk,
&a1, &wsys->F1[wp1], &ld1, &wsys->F2[wp1], &ld2,
&a2, wsys->w2w, &ld3);
for (w = 0; w < nw; w++) {
wsys->w2w[w * (nw + 1)] += WI[wp1 + w];
}
/* -------------------------------------------------------------- */
/* Global RHS contributions */
mm = nw;
incx = incy = 1;
q = ddot_(&mm, &wsys->F2[wp1], &incx, &wdp[wp1], &incy);
a1 = -q / sys->L[c];
for (i = 0; i < ngconn; i++) {
wsys->r[i] = a1 * sys->F1[p1 + i];
}
sys->q[c] -= q;
a1 = sys->q[c] / sys->L[c];
for (w = 0; w < nw; w++) {
wsys->r[ngconn + w] = a1*wsys->F1[wp1 + w] +
WI[wp1 + w] * wdp[wp1 + w];
}
}
/* ---------------------------------------------------------------------- */
void
hybsys_compute_press_flux(int nc, const int *pconn, const int *conn,
const double *gpress,
const double *Binv, const struct hybsys *sys,
const double *pi, double *press, double *flux,
double *work)
/* ---------------------------------------------------------------------- */
{
int c, i, nconn, p1, p2;
double a1, a2;
MAT_SIZE_T incx, incy, nrows, ncols, lda;
incx = incy = 1;
p2 = 0;
a1 = 1.0;
a2 = 0.0;
for (c = 0; c < nc; c++) {
p1 = pconn[c + 0];
nconn = pconn[c + 1] - p1;
/* Serialise interface pressures for cell */
for (i = 0; i < nconn; i++) {
/* work[i] = pi[conn[p1 + i]] - gpress[p1 + i]; */
work[i] = pi[conn[p1 + i]];
}
nrows = ncols = lda = nconn;
/* Solve Lp = g - F2*f + F2*pi (for cell pressure) */
press[c] = sys->q[c]; /* src[c]; */
press[c] += ddot_(&nrows, &sys->F2[p1], &incx, work, &incy);
press[c] /= sys->L[c];
/* Form rhs of system B*v = f + C*p - D*pi */
for (i = 0; i < nconn; i++) {
work[i] = gpress[p1 + i] + press[c] - work[i];
}
/* Solve resulting system (-> half face fluxes) */
dgemv_("No Transpose", &nrows, &ncols,
&a1, &Binv[p2], &lda, work, &incx,
&a2, &flux[p1], &incy);
p2 += nconn * nconn;
}
}
/* ---------------------------------------------------------------------- */
void
hybsys_compute_press_flux_well(int nc, const int *pgconn, int nf,
int nw, const int *pwconn, const int *wconn,
const double *Binv,
const double *WI,
const double *wdp,
const struct hybsys *sys,
const struct hybsys_well *wsys,
const double *pi,
double *cpress, double *cflux,
double *wpress, double *wflux,
double *work)
/* ---------------------------------------------------------------------- */
{
int c, w, wg, perf;
int ngconn, nwconn;
size_t gp1, gp2, wp1;
MAT_SIZE_T mm, nn, incx, incy, ld;
double dcp, one;
gp2 = 0;
for (c = 0; c < nc; c++) {
ngconn = pgconn[c + 1] - pgconn[c];
nwconn = pwconn[c + 1] - pwconn[c];
if (nwconn > 0) {
dcp = 0.0;
gp1 = pgconn[c];
wp1 = pwconn[c];
for (w = 0; w < nwconn; w++) {
wg = wconn[2*(wp1 + w) + 0];
work[w] = pi[nf + wg];
}
mm = nwconn; incx = incy = 1;
dcp = ddot_(&mm, &wsys->F2[wp1], &incx, work, &incy);
dcp /= sys->L[c];
cpress[c] += dcp;
mm = nn = ld = ngconn;
one = 1.0;
dgemv_("No Transpose", &mm, &nn,
&dcp, &Binv[gp2], &ld, sys->one , &incx,
&one, &cflux[gp1], &incy);
for (w = 0; w < nwconn; w++) {
perf = wconn[2*(wp1 + w) + 1];
wflux[perf] = wdp[wp1 + w] + cpress[c] - work[w];
wflux[perf] *= - WI [wp1 + w]; /* Sign => positive inj. */
}
}
gp2 += ngconn + ngconn;
}
/* Assign well BHP from linsolve output */
memcpy(wpress, pi + nf, nw * sizeof *wpress);
}

View File

@ -1,619 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_HYBSYS_HEADER_INCLUDED
#define OPM_HYBSYS_HEADER_INCLUDED
/**
* \file
* Routines and data structures to manage local contributions to a
* global system of simultaneous linear equations arising from a
* Schur complement reduction of an original block system.
*
* Specifically, these data structures and related routines compute
* and store the elemental (cell-based) contributions of the Schur
* complement reduction of the block system of simultaneous linear
* equations
* \f[
* \begin{pmatrix}
* B & C_1 & D \\
* C_2^\mathsf{T} & P & 0 \\
* D^\mathsf{T} & 0 & 0
* \end{pmatrix}
* \begin{pmatrix}
* v \\ -p \\ \pi
* \end{pmatrix} = \begin{pmatrix}
* G \\ g \\ h
* \end{pmatrix}
* \f]
* in which \f$G\f$ accounts for effects of gravity. The traditional
* Schurcomplement reduction (block Gaussian elimination) then produces
* the equivalent system of simultaneous linear equations
* \f[
* \begin{pmatrix}
* B & C_1 & D \\
* 0 & -L & -F_2 \\
* 0 & 0 & A
* \end{pmatrix}
* \begin{pmatrix}
* v \\ -p \\ \pi
* \end{pmatrix} = \begin{pmatrix}
* G \\ g - C_2^\mathsf{T}B^{-1}G \\ b
* \end{pmatrix}.
* \f]
* Here, the matrix \f$A\f$ and the right hand side vector \f$b\f$ are given
* by
* \f[
* \begin{aligned}
* A &= D^\mathsf{T}B^{-1}D - F_1^\mathsf{T}L^{-1}F_2 \\
* b &= D^\mathsf{T}B^{-1}G +
* F_1^\mathsf{T}L^{-1}(g - C_2^\mathsf{T}B^{-1}G) - h,
* \end{aligned}
* \f]
* and the component matrices \f$F_1\f$, \f$F_2\f$, and \f$L\f$ are given
* by
* \f[
* F_1 = C_1^\mathsf{T}B^{-1}D, \quad
* F_2 = C_2^\mathsf{T}B^{-1}D, \quad
* L = C_2^\mathsf{T}B^{-1}C_1 - P.
* \f]
* In the case of incompressible flow, the matrix \f$C_2\f$ is the same
* as \f$C_1\f$ and \f$P=0\f$ whence the coefficient matrix \f$A\f$ of
* the Schur complement system \f$A\pi=b\f$ is symmetric.
*
* A great deal of simplification arises from the simple characterisation
* of the \f$C_1\f$ and \f$D\f$ matrices. Specifically,
* \f[
* (C_1)_{ij} = \begin{cases}
* 1, &\quad i\in\{\mathit{pconn}_j, \dots, \mathit{pconn}_{j+1}-1\}, \\
* 0, &\quad \text{otherwise},
* \end{cases}
* \f]
* and
* \f[
* (D)_{ij} = \begin{cases}
* 1, &\quad \mathit{conn}_i = j, \\
* 0, &\quad \text{otherwise}.
* \end{cases}
* \f]
* When viewed in the context of a single cell, then the \f$D\f$ matrix
* is, effectively, the identity with the \f$\mathit{conn}\f$ array
* simply affecting a finite-element style redistribution (assembly)
* of the local contributions. This module leverages that property
* extensively.
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* Elemental contributions (from cells) to block system of simultaneous
* linear equations. Mixes quantities of single cells (@c r,
* @c S and @c one) with those that cater to all cells (@c L,
* @c q, @c F1, and--possibly--@c F2).
*/
struct hybsys {
double *L; /**< \f$C_2^\mathsf{T}B^{-1}C - P\f$, all cells */
double *q; /**< \f$g - F_2 G\f$, all cells */
double *F1; /**< \f$C_1^\mathsf{T}B^{-1}\f$, all cells */
double *F2; /**< \f$C_2^\mathsf{T}B^{-1}\f$, all cells*/
double *r; /**< Data buffer for system right-hand side, single cell */
double *S; /**< Data buffer system matrix, single cell */
double *one; /**< \f$(1,1,\dots,1)^\mathsf{T}\f$, single cell */
};
/**
* Elemental contributions (from wells) to block system of simultaneous
* linear equations. Mixes quantities of single cell connections (@c r,
* @c w2r, @c r2w, and @c w2w) and those that pertain to all well
* connections (perforations) in concert (@c F1 and @c F2).
*/
struct hybsys_well {
double *F1; /**< \f$C_1^\mathsf{T}B^{-1}\f$, all connections. */
double *F2; /**< \f$C_2^\mathsf{T}B^{-1}\f$, all connections. */
double *r; /**< Data buffer for system right-hand side, single cell. */
double *w2r; /**< Well-to-reservoir connection strength, single cell. */
double *r2w; /**< Reservoir-to-well connection strength, single cell. */
double *w2w; /**< Aggregate well-to-well connection strength. */
double *data; /**< Linear storage array. Structure undisclosed. */
};
/**
* Allocate a hybrid system management structure suitable for discretising
* a symmetric (i.e., incompressible) flow problem on a grid model of
* given size.
*
* @param[in] max_nconn Maximum number of single cell faces.
* @param[in] nc Total number of grid cells.
* @param[in] nconn_tot Aggregate number of cell faces for all cells.
* @return Fully formed hybrid system management structure if successful or
* @c NULL in case of allocation failure.
*/
struct hybsys *
hybsys_allocate_symm(int max_nconn, int nc, int nconn_tot);
/**
* Allocate a hybrid system management structure suitable for discretising
* an unsymmetric (i.e., compressible) flow problem on a grid model of
* given size.
*
* @param[in] max_nconn Maximum number of single cell faces.
* @param[in] nc Total number of grid cells.
* @param[in] nconn_tot Aggregate number of cell faces for all cells.
* @return Fully formed hybrid system management structure if successful or
* @c NULL in case of allocation failure.
*/
struct hybsys *
hybsys_allocate_unsymm(int max_nconn, int nc, int nconn_tot);
/**
* Allocate a hybrid system management structure suitable for discretising
* an incompressible (i.e., symmetric) well flow problem on a grid model
* of given size.
*
* @param[in] max_nconn Maximum number of single cell faces.
* @param[in] nc Total number of grid cells.
* @param[in] cwpos Indirection array that defines each cell's
* connecting wells. Values typically computed
* using function derive_cell_wells().
* @return Fully formed hybrid system management structure if successful or
* @c NULL in case of allocation failure.
*/
struct hybsys_well *
hybsys_well_allocate_symm(int max_nconn, int nc, int *cwpos);
/**
* Allocate a hybrid system management structure suitable for discretising
* a compressible (i.e., unsymmetric) well flow problem on a grid model
* of given size.
*
* @param[in] max_nconn Maximum number of single cell faces.
* @param[in] nc Total number of grid cells.
* @param[in] cwpos Indirection array that defines each cell's
* connecting wells. Values typically computed
* using function derive_cell_wells().
* @return Fully formed hybrid system management structure if successful
* or @c NULL in case of allocation failure.
*/
struct hybsys_well *
hybsys_well_allocate_unsymm(int max_nconn, int nc, int *cwpos);
/**
* Dispose of memory resources previously obtained through one of the
* allocation functions, hybsys_allocate_symm() or
* hybsys_allocate_unsymm().
*
* Following a call to hybsys_free(), the input pointer is no longer
* valid. <CODE>hybsys_free(NULL)</CODE> does nothing.
*
* @param[in,out] sys Previously allocated hybrid system management
* structure (or @c NULL).
*/
void
hybsys_free(struct hybsys *sys);
/**
* Dispose of memory resources previously obtained through one of the
* allocation functions, hybsys_well_allocate_symm() or
* hybsys_well_allocate_unsymm().
*
* Following a call to hybsys_well_free(), the input pointer is
* no longer valid. <CODE>hybsys_well_free(NULL)</CODE> does nothing.
*
* @param[in,out] wsys Previously allocated hybrid system management
* structure (or @c NULL).
*/
void
hybsys_well_free(struct hybsys_well *wsys);
/**
* Perform post-construction dynamic initialisation of system
* structure obtained from function hybsys_allocate_symm() or
* hybsys_allocate_unsymm().
*
* @param[in] max_nconn Maximum number of single cell faces.
* Must coincide with the equally named
* parameter of functions hybsys_allocate_symm()
* or hybsys_allocate_unsymm().
* @param[in,out] sys Previously allocated hybrid system management
* structure.
*/
void
hybsys_init(int max_nconn, struct hybsys *sys);
/**
* Compute elemental (per-cell) contributions to symmetric Schur
* system of simultaneous linear equations.
*
* This function assumes that the coefficient matrix of the hybrid
* system of linear equations is that of the introduction with the
* additional provision that \f$C_1=C_2=C\f$ and that \f$P=0\f$.
* In other words, this function assumes that the coefficient matrix
* is of the form
* \f[
* \begin{pmatrix}
* B & C & D \\
* C^\mathsf{T} & 0 & 0 \\
* D^\mathsf{T} & 0 & 0
* \end{pmatrix}.
* \f]
* This function fills the @c F1 and @c L fields of the management
* structure.
*
* @param[in] nc Total number of grid cells.
* @param[in] pconn Cell-to-face start pointers.
* @param[in] Binv Inverse inner product results, usually
* computed using mim_ip_simple_all() and
* mim_ip_mobility_update().
* @param[in,out] sys Hybrid system management structure allocated
* using hybsys_allocate_symm() and initialised
* using hybsys_init().
*/
void
hybsys_schur_comp_symm(int nc, const int *pconn,
const double *Binv, struct hybsys *sys);
/**
* Compute elemental (per-cell) contributions to unsymmetric Schur
* system of simultaneous linear equations.
*
* This function assumes that the coefficient matrix of the hybrid
* system of linear equations is that of the introduction with the
* additional provision that \f$C_2=C_1-V\f$. In other words, this
* function assumes that the coefficient matrix is of the form
* \f[
* \begin{pmatrix}
* B & C & D \\
* (C-V)^\mathsf{T} & P & 0 \\
* D^\mathsf{T} & 0 & 0
* \end{pmatrix}.
* \f]
* This matrix arises in the ``\f$v^2\f$'' phase compressibility
* formulation of the compressible black-oil model. This function
* fills the @c F1, @c F2 and @c L fields of the management structure.
*
* @param[in] nc Total number of grid cells.
* @param[in] pconn Cell-to-face start pointers.
* @param[in] Binv Inverse inner product results, usually
* computed using mim_ip_simple_all() and
* mim_ip_mobility_update().
* @param[in] BIV \f$B^{-1}v\f$ in which \f$v\f$ is the flux
* field of a previous time step or non-linear
* iteration.
* @param[in] P Per cell compressible accumulation term. One
* scalar per cell.
* @param[in,out] sys Hybrid system management structure allocated
* using hybsys_allocate_symm() and initialised
* using hybsys_init().
*/
void
hybsys_schur_comp_unsymm(int nc, const int *pconn,
const double *Binv, const double *BIV,
const double *P, struct hybsys *sys);
/**
* Compute elemental (per-cell) contributions to unsymmetric Schur
* system of simultaneous linear equations.
*
* This function assumes that the coefficient matrix of the hybrid
* system of linear equations is that of the introduction with no
* additional provisions. In other words, this
* function assumes that the coefficient matrix is of the form
* \f[
* \begin{pmatrix}
* B & C_1 & D \\
* C_2^\mathsf{T} & P & 0 \\
* D^\mathsf{T} & 0 & 0
* \end{pmatrix}.
* \f]
* This function fills the @c F1, @c F2 and @c L fields of
* the management structure.
*
* @param[in] nc Total number of grid cells.
* @param[in] pconn Cell-to-face start pointers.
* @param[in] Binv Inverse inner product results, usually
* computed using mim_ip_simple_all() and
* mim_ip_mobility_update().
* @param[in] C2 Explicit representation of the \f$C_2\f$
* matrix as a linear array. Assumed to only
* contain the (structurally) non-zero matrix
* elements (that correspond to the non-zero
* structure of \f$C_1\f$).
* @param[in] P Per cell compressible accumulation term. One
* scalar per cell.
* @param[in,out] sys Hybrid system management structure allocated
* using hybsys_allocate_symm() and initialised
* using hybsys_init().
*/
void
hybsys_schur_comp_gen(int nc, const int *pconn,
const double *Binv, const double *C2,
const double *P, struct hybsys *sys);
/**
* Compute elemental contributions to global, symmetric system of
* simultaneous linear equations from cell<->well connections.
*
* Specifically, for a well @c w intersecting a cell @c c, this function
* computes the elemental contributions
* \f[
* (F_1)_{wc} = C_{wc}^\mathsf{T} B_{wc}^{-1} D_{wc} = \mathit{WI}_{wc}
* \f]
* and
* \f[
* L_{wc} = C_{wc}^\mathsf{T} B_{wc}^{-1} C_{wc} = \mathit{WI}_{wc}
* \f]
* and incorporates the contributions into the global system quantities
* as appropriate.
*
* This function modifies <CODE>sys->L</CODE> and <CODE>wsys->F1</CODE>.
*
* @param[in] nc Total number of grid cells.
* @param[in] cwpos Indirection array that defines each cell's
* connecting wells. Values typically computed
* using function derive_cell_wells().
* @param[in] WI Peaceman well connection indices. Array of
* size <CODE>cwpos[nc]</CODE>. Must incorporate
* effects of multiple phases (i.e., total mobility)
* if applicable.
* @param[in,out] sys Hybrid system management structure allocated
* using hybsys_allocate_symm() and initialised
* using hybsys_init() and/or filled using function
* hybsys_schur_comp_symm().
* @param[in,out] wsys Hybrid well-system management structure obtained
* from function hybsys_well_allocate_symm().
*/
void
hybsys_well_schur_comp_symm(int nc, const int *cwpos,
double *WI,
struct hybsys *sys,
struct hybsys_well *wsys);
/**
* Compute final (symmetric) Schur complement contributions to
* global system of simultaneous linear equations.
*
* This function forms the coefficient matrix
* \f[
* S_c = D^\mathsf{T}B_c^{-1}D - F_c^\mathsf{T}L_c^{-1}F_c
* \f]
* and similar right-hand side \f$r_c\f$ elemental contributions.
* These values must be subsequently assembled into the global system
* using function hybsys_global_assemble_cell() after imposing any
* applicable boundary conditions.
*
* This function overwrites the fields @c S and @c r of the hybrid system
* structure.
*
* @param[in] c Cell for which to compute local contributions.
* @param[in] nconn Number of connections (faces) of cell @c c.
* @param[in] p1 Start address (into @c gpress) of the gravity
* contributions of cell @c c.
* @param[in] p2 Start address (into @c Binv) of the inverse
* inner product of cell @c c.
* @param[in] gpress Gravity contributions of all cells. Must
* include effects of multiple phases if applicable.
* @param[in] src Explicit source terms for all cells.
* @param[in] Binv Inverse inner products for all cells. Must
* include effects of multiple phases if applicable.
* @param[in,out] sys Hybrid system management structure allocated
* using hybsys_allocate_symm() and initialised
* using hybsys_init() and/or filled using function
* hybsys_schur_comp_symm() and
* hybsys_well_schur_comp_symm() if applicable.
*/
void
hybsys_cellcontrib_symm(int c, int nconn, int p1, int p2,
const double *gpress, const double *src,
const double *Binv, struct hybsys *sys);
/**
* Compute final (non-symmetric) Schur complement contributions to
* global system of simultaneous linear equations.
*
* This function forms the coefficient matrix
* \f[
* S_c = D^\mathsf{T}B_c^{-1}D - (F_1)_c^\mathsf{T}L_c^{-1}(F_2)_c
* \f]
* and similar right-hand side \f$r_c\f$ elemental contributions.
* These values must be subsequently assembled into the global system
* using function hybsys_global_assemble_cell() after imposing any
* applicable boundary conditions.
*
* This function overwrites the fields @c S and @c r of the hybrid system
* structure.
*
* @param[in] c Cell for which to compute local contributions.
* @param[in] nconn Number of connections (faces) of cell @c c.
* @param[in] p1 Start address (into @c gpress) of the gravity
* contributions of cell @c c.
* @param[in] p2 Start address (into @c Binv) of the inverse
* inner product of cell @c c.
* @param[in] gpress Gravity contributions of all cells. Must
* include effects of multiple phases if applicable.
* @param[in] src Explicit source terms for all cells.
* @param[in] Binv Inverse inner products for all cells. Must
* include effects of multiple phases if applicable.
* @param[in,out] sys Hybrid system management structure allocated
* using hybsys_allocate_symm() and initialised
* using hybsys_init() and/or filled using functions
* hybsys_schur_comp_unsymm() or hybsys_schur_comp_gen().
*/
void
hybsys_cellcontrib_unsymm(int c, int nconn, int p1, int p2,
const double *gpress, const double *src,
const double *Binv, struct hybsys *sys);
/**
* Form elemental direct contributions to global system of simultaneous linear
* equations from cell<->well interactions.
*
* Plays a role similar to function hybsys_cellcontrib_symm(), but for wells.
*
* @param[in] c Cell for which to compute cell<->well Schur complement
* @param[in] ngconn Number of inter-cell connections (faces) of cell @c c.
* @param[in] p1 Start index (into <CODE>sys->F1</CODE>) of cell @c c.
* @param[in] cwpos Indirection array that defines each cell's connecting
* wells. Must coincide with equally named parameter of
* function hybsys_well_schur_comp_symm().
* @param[in] WI Peaceman well connection indices. Array of
* size <CODE>pwconn[nc]</CODE>. Must coincide with
* equally named parameter of contribution function
* hybsys_well_schur_comp_symm().
* @param[in] wdp Well connection gravity pressure adjustments.
* One scalar for each well connection in an array of size
* <CODE>pwconn[nc]</CODE>.
* @param[in,out] sys Hybrid system management structure filled using
* functions hybsys_schur_comp_unsymm() or
* hybsys_schur_comp_gen().
* @param[in,out] wsys Hybrid well-system management structure filled using
* function hybsys_well_schur_comp_symm().
*/
void
hybsys_well_cellcontrib_symm(int c, int ngconn, int p1,
const int *cwpos,
const double *WI, const double *wdp,
struct hybsys *sys, struct hybsys_well *wsys);
/**
* Recover cell pressures and outward fluxes (with respect to cells--i.e., the
* ``half-face fluxes'') through back substitution after solving a symmetric
* (i.e., incompressible) Schur complement system of simultaneous linear
* equations.
*
* Specifically, given the solution \f$\pi\f$ to the global system of
* simultaneous linear equations, \f$A\pi=b\f$, that arises as a result of the
* Schur complement analysis, this function recovers the cell pressures \f$p\f$
* and outward fluxes \f$v\f$ defined by
* \f[
* \begin{aligned}
* Lp &= g - C_2^\mathsf{T}B^{-1}G + F_2\pi \\
* Bv &= G + C_1p - D\pi
* \end{aligned}.
* \f]
*
* @param[in] nc Total number of grid cells.
* @param[in] pconn Cell-to-face start pointers.
* @param[in] conn Cell-to-face mapping.
* @param[in] gpress Gravity contributions of all cells. Must coincide with
* equally named parameter in calls to cell contribution
* functions such as hybsys_cellcontrib_symm().
* @param[in] Binv Inverse inner products for all cells. Must coincide
* with equally named parameter in calls to contribution
* functions such as hybsys_cellcontrib_symm().
* @param[in] sys Hybrid system management structure coinciding with
* equally named parameter in contribution functions such
* as hybsys_cellcontrib_symm() or
* hybsys_cellcontrib_unsymm().
* @param[in] pi Solution (interface/contact pressure) obtained from
* solving the global system \f$A\pi = b\f$.
* @param[out] press Cell pressures, \f$p\f$. Array of size @c nc.
* @param[out] flux Outward interface fluxes, \f$v\f$. Array of size
* <CODE>pconn[nc]</CODE>.
* @param[in,out] work Scratch array for temporary results. Array of size at
* least \f$\max_c \{ \mathit{pconn}_{c + 1}
* - \mathit{pconn}_c \} \f$.
*/
void
hybsys_compute_press_flux(int nc, const int *pconn, const int *conn,
const double *gpress,
const double *Binv, const struct hybsys *sys,
const double *pi, double *press, double *flux,
double *work);
/**
* Recover well pressures (i.e., bottom-hole pressure values) and well
* connection (perforation) fluxes.
*
* Specifically, this function performs the same role (i.e., back-substitution)
* for wells as function hybsys_compute_press_flux() does for grid cells and
* grid contacts (interfaces).
*
* @param[in] nc Total number of grid cells.
* @param[in] pgconn Cell-to-face start pointers.
* @param[in] nf Total number of grid faces.
* @param[in] nw Total number of wells.
* @param[in] pwconn Cell-to-well start pointers. If <CODE>nw > 0</CODE>,
* then this parameter must coincide with the @c cwpos
* array used in call to hybsys_well_schur_comp_symm().
* @param[in] wconn Cell-to-well mapping.
* @param[in] Binv Inverse inner products for all cells. Must coincide
* with equally named parameter in calls to contribution
* functions such as hybsys_well_cellcontrib_symm().
* @param[in] WI Peaceman well connection indices. Array of
* size <CODE>pwconn[nc]</CODE>. Must coincide with
* equally named parameter of contribution function
* hybsys_well_cellcontrib_symm().
* @param[in] wdp Well connection gravity pressure adjustments.
* @param[in] sys Hybrid system management structure coinciding with
* equally named parameter in contribution functions such
* as hybsys_cellcontrib_symm() and
* hybsys_well_cellcontrib_symm().
* @param[in] wsys Hybrid well-system management structure. Must coincide
* with equally named paramter of contribution function
* hybsys_well_cellcontrib_symm().
* @param[in] pi Solution (interface/contact pressure and well BHPs)
* obtained from solving the global system \f$A\pi = b\f$.
* @param[in] cpress Cell pressures, \f$p\f$, obtained from a previous call
* to function hybsys_compute_press_flux().
* @param[in] cflux Outward fluxes, \f$v\f$, obtained from a previous call
* to function hybsys_compute_press_flux().
* @param[out] wpress Well (i.e., bottom-hole) pressures. Array of size
* @c nw.
* @param[out] wflux Well connection (perforation) fluxes. Array of size
* <CODE>pwconn[nw]</CODE>.
* @param[in,out] work Scratch array for storing intermediate results. Array
* of size at least \f$\max_w \{ \mathit{pwconn}_{w + 1}
* - \mathit{pwconn}_w\}\f$.
*/
void
hybsys_compute_press_flux_well(int nc, const int *pgconn, int nf,
int nw, const int *pwconn, const int *wconn,
const double *Binv,
const double *WI,
const double *wdp,
const struct hybsys *sys,
const struct hybsys_well *wsys,
const double *pi,
double *cpress, double *cflux,
double *wpress, double *wflux,
double *work);
#ifdef __cplusplus
}
#endif
#endif /* OPM_HYBSYS_HEADER_INCLUDED */

View File

@ -1,418 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
/* ---> Layering violation! */
#include <opm/core/pressure/msmfem/hash_set.h>
/* <--- Layering violation! */
#include <opm/core/pressure/mimetic/hybsys_global.h>
#if defined MAX
#undef MAX
#endif
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
/* Release memory resources for each individual well's DOF set (and
* the aggregate well DOF set structure). */
/* ---------------------------------------------------------------------- */
static void
deallocate_well_dofset(size_t nw, struct hash_set **wia)
/* ---------------------------------------------------------------------- */
{
size_t w;
if (wia != NULL) {
for (w = 0; w < nw; w++) {
hash_set_deallocate(wia[w]);
}
}
free(wia);
}
/* Allocate DOF set for each well.
*
* Returns fully created vector of W->number_of_wells DOF sets if
* successful and NULL otherwise. */
/* ---------------------------------------------------------------------- */
static struct hash_set **
allocate_well_dofset(struct UnstructuredGrid *G, well_t *W)
/* ---------------------------------------------------------------------- */
{
int w, i, c, ok;
int set_size;
struct hash_set **wia;
wia = malloc(W->number_of_wells * sizeof *wia);
if (wia != NULL) {
ok = 1;
for (w = 0; ok && (w < W->number_of_wells); w++) {
set_size = 1; /* Approximate expected set size */
for (i = W->well_connpos[w]; i < W->well_connpos[w + 1]; i++) {
c = W->well_cells[i];
set_size += G->cell_facepos[c + 1] - G->cell_facepos[c];
}
wia[w] = hash_set_allocate(set_size);
ok = wia[w] != NULL;
}
if (!ok) {
deallocate_well_dofset(w, wia);
wia = NULL;
}
}
return wia;
}
/* Count number of coefficient matrix connections (non-zeros) per row
* from grid contributions. Add self connections for all rows. Well
* connection counts will be overwritten in count_conn_per_row_well()
* if applicable. */
/* ---------------------------------------------------------------------- */
static void
count_conn_per_row_grid(struct UnstructuredGrid *G, struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
int c, nc, *ia, *ja;
size_t m;
nc = G->number_of_cells;
ia = G->cell_facepos;
ja = G->cell_faces;
A->ia[0] = 0;
for (m = 0; m < A->m; m++) {
A->ia[m + 1] = 1;
}
for (c = 0; c < nc; c++) {
for (; ja != G->cell_faces + ia[c + 1]; ja++) {
A->ia[ *ja + 1 ] += ia[c + 1] - ia[c] - 1;
}
}
}
/* Count number of coefficient matrix connections per row from well
* contributions. Increment connection count for other-to-well,
* define count for well-to-other.
*
* Fails if unable to insert a DOF into a DOF set.
*
* Returns 1 if successful, and zero otherwise. */
/* ---------------------------------------------------------------------- */
static int
count_conn_per_row_well(struct UnstructuredGrid *G, well_t *W,
int *cwpos,
int *cwells,
struct hash_set **wia,
struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
int c, w, nc, nf, nwdof, ok, i, dof, *ia, *ja, *wja;
size_t m;
nc = G->number_of_cells;
nf = G->number_of_faces;
ia = G->cell_facepos;
wja = cwells;
ok = 1;
for (c = 0; c < nc; c++) {
for (; ok && (wja != cwells + 2*cwpos[c + 1]); wja += 2) {
for ( ja = G->cell_faces + ia[c + 0];
ok && (ja != G->cell_faces + ia[c + 1]); ja++) {
dof = *ja;
ok = hash_set_insert(dof, wia[*wja]) == dof;
}
for (i = cwpos[c]; ok && (i < cwpos[c + 1]); i++) {
dof = nf + cwells[2*i + 0];
ok = hash_set_insert(dof, wia[*wja]) == dof;
}
}
}
if (ok) {
for (w = 0; w < W->number_of_wells; w++) {
nwdof = 0;
for (m = 0; m < wia[w]->m; m++) {
if ((dof = wia[w]->s[m]) >= 0) {
A->ia[ dof + 1 ] += 1; /* face to well */
nwdof += 1; /* well to face */
}
}
A->ia[ nf + w + 1 ] = nwdof;
}
}
return ok;
}
/* Fill self-connections (i.e., diagonal of coefficient matrix) for
* all DOFs. */
/* ---------------------------------------------------------------------- */
static void
fill_self_connections(struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
size_t r;
for (r = 0; r < A->m; r++) {
A->ja[ A->ia[r + 1] ++ ] = r;
}
}
/* Fill self-to-other DOF connections (i.e., define 'ja') for grid. */
/* ---------------------------------------------------------------------- */
static void
fill_grid_connections(struct UnstructuredGrid *G, struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
int c, i, j, n;
int dof1, dof2;
int *ia, *ja;
ia = G->cell_facepos;
ja = G->cell_faces;
for (c = 0; c < G->number_of_cells; c++) {
n = ia[c + 1] - ia[c];
for (i = 0; i < n; i++) {
dof1 = ja[ ia[c] + i ];
if (dof1 >= 0) {
for (j = (i + 1) % n; j != i; j = (j + 1) % n) {
dof2 = ja[ ia[c] + j ];
if (dof2 >= 0) {
A->ja[ A->ia[dof1 + 1] ++ ] = dof2;
}
}
}
}
}
}
/* Fill self-to-other and other-to-self DOF connections ('ja') for wells. */
/* ---------------------------------------------------------------------- */
static void
fill_well_connections(int nf, int nw,
struct hash_set **wia,
struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
int w, dof;
size_t i;
for (w = 0; w < nw; w++) {
for (i = 0; i < wia[w]->m; i++) {
dof = wia[w]->s[i];
if (dof >= 0) {
if (dof < nf) { /* Connect face to well */
A->ja[ A->ia[ dof + 1 ] ++ ] = nf + w;
}
if (dof != nf + w) {/* Connect well to dof (avoid self) */
A->ja[ A->ia[ nf + w + 1 ] ++ ] = dof;
}
}
}
}
}
/* Define pressure system coefficient matrix sparsity structure
* (A->ia, A->ja) from grid and well contributions. Allocate
* coefficient matrix elements (A->sa).
*
* Returns fully defined CSR matrix structure if successful or NULL
* otherwise. */
/* ---------------------------------------------------------------------- */
struct CSRMatrix *
hybsys_define_globconn(struct UnstructuredGrid *G, well_t *W)
/* ---------------------------------------------------------------------- */
{
int nw, ok;
int *cwell_pos = NULL, *cwells = NULL;
struct hash_set **wia;
struct CSRMatrix *A;
assert (G != NULL);
ok = 1;
nw = 0;
wia = NULL;
if (W != NULL) {
ok = allocate_cell_wells(G->number_of_cells, W, &cwell_pos, &cwells);
if (ok) {
derive_cell_wells(G->number_of_cells, W, cwell_pos, cwells);
}
nw = ok ? W->number_of_wells : 0;
if (nw > 0) {
wia = allocate_well_dofset(G, W);
if (wia == NULL) { nw = 0; }
}
}
A = csrmatrix_new_count_nnz(G->number_of_faces + nw);
if (A != NULL) {
count_conn_per_row_grid(G, A);
if (nw > 0) {
assert (nw == W->number_of_wells);
ok = count_conn_per_row_well(G, W, cwell_pos,
cwells, wia, A) > 0;
} else {
ok = 1;
}
ok = ok && (csrmatrix_new_elms_pushback(A) > 0);
if (ok) {
fill_self_connections(A);
fill_grid_connections(G, A);
fill_well_connections(G->number_of_faces, nw, wia, A);
csrmatrix_sortrows(A);
} else {
csrmatrix_delete(A);
A = NULL;
}
}
deallocate_well_dofset(nw, wia);
deallocate_cell_wells(cwell_pos, cwells);
return A;
}
/* Assemble (hybrid) cell contributions into global system coefficient
* matrix and right hand side. Traditional FEM assembly process.
* Boundary conditions assumed enforced outside.
*
* Local coefficient matrix contributions assumed organised in row
* major format (row index cycling the most rapidly--Fortran
* conventions). Convention immaterial if matrix is symmetric. */
/* ---------------------------------------------------------------------- */
void
hybsys_global_assemble_cell(int nconn, int *conn,
const double *S,
const double *r,
struct CSRMatrix *A,
double *b)
/* ---------------------------------------------------------------------- */
{
int il, jl; /* local */
size_t ig, jg; /* global */
for (il = 0; il < nconn; il++) {
assert ((0 <= conn[il]) && ((size_t) conn[il] < A->m));
ig = conn[il];
for (jl = 0; jl < nconn; jl++) {
jg = csrmatrix_elm_index(ig, conn[jl], A);
assert ((((size_t)(A->ia[ig])) <= jg) &&
(jg < ((size_t)(A->ia[ig + 1]))));
A->sa[jg] += S[il + jl*nconn]; /* Row major per cell */
}
b[ig] += r[il];
}
}
/* ---------------------------------------------------------------------- */
void
hybsys_global_assemble_well_sym(int ngconn_tot,
int ngconn, const int *gconn,
int nwconn, const int *wconn,
const double *r2w,
const double *w2w,
const double *r,
struct CSRMatrix *A,
double *b)
/* ---------------------------------------------------------------------- */
{
int il, wl1, wl2;
size_t ig, wg1, wg2, jg, jw;
/* Global matrix contributions for this cell's wells */
for (wl1 = 0; wl1 < nwconn; wl1++) {
wg1 = ngconn_tot + wconn[2*wl1 + 0];
for (il = 0; il < ngconn; il++) {
ig = gconn[il];
jw = csrmatrix_elm_index(ig, wg1, A);
jg = csrmatrix_elm_index(wg1, ig, A);
A->sa[jw] += r2w[il + wl1*ngconn]; /* Row major per cell */
A->sa[jg] += r2w[il + wl1*ngconn]; /* Symmetry */
}
for (wl2 = 0; wl2 < nwconn; wl2++) {
wg2 = ngconn_tot + wconn[2*wl2 + 0];
jw = csrmatrix_elm_index(wg1, wg2, A);
A->sa[jw] += w2w[wl1 + wl2*nwconn]; /* Row major per well */
}
}
/* Global right-hand side contributions */
for (il = 0; il < ngconn; il++) {
b[gconn[il]] += r[il];
}
for (wl1 = 0; wl1 < nwconn; wl1++) {
b[ngconn_tot + wconn[2*wl1 + 0]] += r[ngconn + wl1];
}
}

View File

@ -1,212 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_HYBSYS_GLOBAL_HEADER_INCLUDED
#define OPM_HYBSYS_GLOBAL_HEADER_INCLUDED
/**
* \file
* Routines to assist in the formation and assembly of a global
* system of simultaneous linear equations derived from a Schur
* complement reduction of an original hybrid block system.
*
* We assume that the original block system of linear equations
* is given by
* \f[
* \begin{pmatrix}
* B & C & D \\
* C^\mathsf{T} & 0 & 0 \\
* D^\mathsf{T} & 0 & 0
* \end{pmatrix}
* \begin{pmatrix}
* v \\ -p \\ \pi
* \end{pmatrix} = \begin{pmatrix}
* f \\ g \\ h
* \end{pmatrix}
* \f]
* in which the block matrices \f$C\f$ and \f$D\f$ are assumed to
* have a particularly simple structure and the matrix \f$B\f$ is
* block diagonal.
*
* The Schur complement reduction process (a block Gaussian elimination)
* then produces the following block system of simultaneous linear
* equations
* \f[
* \begin{pmatrix}
* B & C & D \\
* 0 & -L & -F \\
* 0 & 0 & A
* \end{pmatrix}
* \begin{pmatrix}
* v \\ -p \\ \pi
* \end{pmatrix} = \begin{pmatrix}
* f \\ g - C^\mathsf{T}B^{-1} f \\ b
* \end{pmatrix}
* \f]
* in which
* \f[
* \begin{aligned}
* A &= D^\mathsf{T}B^{-1}D - F^\mathsf{T}L^{-1}F \text{ and} \\
* b &= D^\mathsf{T}B^{-1}f + F^\mathsf{T}L^{-1} (g - C^\mathsf{T}B^{-1}f) - h.
* \end{aligned}
* \f] The component matrices \f$F\f$
* and \f$L\f$ are given by
* \f[
* \begin{aligned}
* L &= C^\mathsf{T} B^{-1} C \\
* F &= C^\mathsf{T} B^{-1} D.
* \end{aligned}
* \f]
* The primary degrees of freedom, \f$\pi\f$, may then be recovered
* by solving the Schur complement system
* \f[A\pi = b\f]
* from which the derived quantities \f$p\f$ and \f$v\f$ may be
* computed through a back-substitution process.
*
* The functions in this module assist in the creation of the sparsity
* pattern of matrix \f$A\f$ and in the global assembling of values
* into the matrix \f$A\f$ and the right-hand side vector \f$b\f$.
* Specifically, function hybsys_define_globconn() builds the
* sparsity pattern of \f$A\f$ while functions hybsys_global_assemble_cell()
* and hybsys_global_assemble_well_sym() perform the task of
* adding matrix and right-hand side values from local contributions.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <opm/core/grid.h>
#include <opm/core/pressure/legacy_well.h>
#include <opm/core/linalg/sparse_sys.h>
/**
* Construct sparse matrix capable of managing a (reduced) hybrid
* system of simultaneous linear equations with one degree of freedom
* for each grid interface and each well.
*
* The return value is suitable for use in pressure solvers based on
* Schur-complement reductions such as the mimetic finite-difference
* or multiscale mixed finite-element classes of discretisations. In
* typical applications, the matrix will be cleared using function
* csrmatrix_zero() and then filled using an assembly process similar
* to the traditional finite-element algorithm.
*
* Functions hybsys_global_assemble_cell() and
* hybsys_global_assemble_well_sys() may be used to assist such an
* assembly process.
*
* @param[in] G Grid.
* @param[in] W Well topology. @c NULL in a model without wells.
* @return Fully formed and structurally consistent sparse matrix
* whose number of rows (i.e., degrees-of-freedom) equals
* the number of grid faces (<CODE>G->number_of_faces</CODE>)
* plus the number of wells (<CODE>W->number_of_wells</CODE>).
*/
struct CSRMatrix *
hybsys_define_globconn(struct UnstructuredGrid *G, well_t *W);
/**
* Assemble local contributions into global system of simultaneous
* linear equations.
*
* The contributions will typically have been computed using
* function hybsys_schur_comp_symm() and function
* hybsys_cellcontrib_symm() or some of the related functions.
*
* @param[in] nconn Number of cell faces.
* @param[in] l2g Local-to-global mapping of cell's primary
* degrees of freedom (i.e., the faces).
* @param[in] S Single cell local contribution to global
* coefficient matrix. An
* \f$\mathit{nconn}\times\mathit{nconn}\f$
* dense matrix in column major (Fortran) order.
* @param[in] r Single cell local contribution to global
* system right-hand side. An
* \f$\mathit{nconn}\times 1\f$ dense vector.
* @param[in,out] A Global coefficient matrix (of Schur
* complement system).
* @param[in,out] b Global system right-hand side (of Schur
* complement system).
*/
void
hybsys_global_assemble_cell(int nconn, int *l2g,
const double *S,
const double *r,
struct CSRMatrix *A,
double *b);
/**
* Assemble local contributions from single cell's well connections
* (perforations) into global system of simultaneous linear equations.
*
* This function assumes that the connection strength from cell to well
* equals the connection strength from well to cell. In other words,
* that the numerical values of the well contributions are symmetric.
*
* The contributions are typically computed using functions
* hybsys_well_schur_comp_symm() and hybsys_well_cellcontrib_symm().
*
* @param[in] ngconn_tot Total number of grid connections.
* Expected to equal
* <CODE>G->number_of_faces</CODE>
* when @c G is the grid used to form the
* original matrix in
* hybsys_define_globconn().
* @param[in] ngconn Number of grid connections referenced by
* given cell.
* @param[in] gconn Actual grid connections (DOFs) referenced
* by given cell. Pointer to @c ngconn
* consecutive DOF indices.
* @param[in] nwconn Number of well connections intersecting
* given cell. Typically \f$\mathit{ngconn} = 1\f$.
* @param[in] wconn Actual well connections (DOFs) intersecting
* given cell. Pointer to @c nwconn consecutive
* DOF indices.
* @param[in] r2w Reservoir-to-well connection strengths.
* @param[in] w2w Well-to-well-connection strenghts.
* @param[in] r Single cell local contribution to global
* system right-hand side. An
* \f$(\mathit{ngconn} + \mathit{nwconn})
* \times 1\f$ dense vector.
* @param[in,out] A Global coefficient matrix (of Schur
* complement system).
* @param[in,out] b Global system right-hand side (of Schur
* complement system).
*/
void
hybsys_global_assemble_well_sym(int ngconn_tot,
int ngconn, const int *gconn,
int nwconn, const int *wconn,
const double *r2w,
const double *w2w,
const double *r,
struct CSRMatrix *A,
double *b);
#ifdef __cplusplus
}
#endif
#endif /* OPM_HYBSYS_GLOBAL_HEADER_INCLUDED */

View File

@ -1,626 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <assert.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <opm/core/pressure/msmfem/hash_set.h>
#include <opm/core/pressure/msmfem/coarse_conn.h>
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (-MAX(-(a), -(b)))
/* ======================================================================
* Data structures
* ====================================================================== */
/* Individual block connection. */
struct block_neighbour {
int b; /* Neighbouring block */
struct hash_set *fconns; /* Constituent connections */
};
/* Adjacency list of single block (directed graph) */
struct block_neighbours {
int nneigh; /* Number of neighbours. */
int cpty; /* Neighbour capacity. */
struct block_neighbour **neigh; /* Actual neighbours (sorted on neigh[i]->b) */
};
/* ======================================================================
* Operations
* ====================================================================== */
/* Relase dynamic memory resources for single block neighbour 'bn'. */
/* ---------------------------------------------------------------------- */
static void
block_neighbour_deallocate(struct block_neighbour *bn)
/* ---------------------------------------------------------------------- */
{
if (bn != NULL) {
hash_set_deallocate(bn->fconns);
}
free(bn);
}
/* Construct empty block neighbour connection capable of holding
* 'nconn' fine-scale connections (e.g., fine-scale interfaces).
* The fine-scale table is not allocated unless nconn > 0. */
/* ---------------------------------------------------------------------- */
static struct block_neighbour *
block_neighbour_allocate(int nconn)
/* ---------------------------------------------------------------------- */
{
struct block_neighbour *new;
new = malloc(1 * sizeof *new);
if (new != NULL) {
if (nconn > 0) {
new->fconns = hash_set_allocate(nconn);
if (new->fconns != NULL) {
new->b = INT_MIN;
} else {
block_neighbour_deallocate(new);
new = NULL;
}
} else {
new->b = INT_MIN;
new->fconns = NULL;
}
}
return new;
}
/* Insert fine-scale connection 'fconn' into block neighbour
* connection 'bn', but only if the bn->fconns table has been allocated. */
/* ---------------------------------------------------------------------- */
static int
block_neighbour_insert_fconn(int fconn, struct block_neighbour *bn)
/* ---------------------------------------------------------------------- */
{
int ret;
assert (bn != NULL);
ret = 0;
if (bn->fconns != NULL) {
ret = hash_set_insert(fconn, bn->fconns);
}
return ret;
}
/* Relase dynamic memory resources for single-block adjacency list 'bns'. */
/* ---------------------------------------------------------------------- */
static void
block_neighbours_deallocate(struct block_neighbours *bns)
/* ---------------------------------------------------------------------- */
{
int i;
if (bns != NULL) {
if (bns->neigh != NULL) {
for (i = bns->nneigh - 1; i >= 0; i--) {
block_neighbour_deallocate(bns->neigh[i]);
}
}
free(bns->neigh);
}
free(bns);
}
/* Allocate a single-block adjacency list capable of holding 'nneigh'
* connections. */
/* ---------------------------------------------------------------------- */
static struct block_neighbours *
block_neighbours_allocate(int nneigh)
/* ---------------------------------------------------------------------- */
{
int i;
struct block_neighbours *new;
new = malloc(1 * sizeof *new);
if (new != NULL) {
if (nneigh > 0) {
new->neigh = malloc(nneigh * sizeof *new->neigh);
if (new->neigh != NULL) {
for (i = 0; i < nneigh; i++) { new->neigh[i] = NULL; }
new->nneigh = 0;
new->cpty = nneigh;
} else {
block_neighbours_deallocate(new);
new = NULL;
}
} else {
new->nneigh = 0;
new->cpty = 0;
new->neigh = NULL;
}
}
return new;
}
/* Increase size of single-block adjacency list 'bns' to hold 'nneigh'
* coarse-scale connections. */
/* ---------------------------------------------------------------------- */
static int
block_neighbours_expand(int nneigh, struct block_neighbours *bns)
/* ---------------------------------------------------------------------- */
{
int ret;
struct block_neighbour **neigh;
assert (bns != NULL);
neigh = realloc(bns->neigh, nneigh * sizeof *neigh);
if (neigh != NULL) {
bns->neigh = neigh;
bns->cpty = nneigh;
for (ret = bns->nneigh; ret < bns->cpty; ret++) {
bns->neigh[ret] = NULL;
}
} else {
ret = -1;
}
return ret;
}
/* Insert fine-scale connection 'fconn' into single-block adjacency
* list 'bns' in slot corresponding to connection 'b'.
*
* New coarse-scale connections are assumed to hold 'expct_nconn'
* fine-scale connections.*/
/* ---------------------------------------------------------------------- */
static int
block_neighbours_insert_neighbour(int b, int fconn, int expct_nconn,
struct block_neighbours *bns)
/* ---------------------------------------------------------------------- */
{
int i, j, p, t, nmove, ret;
assert (bns != NULL);
ret = 1;
if ((bns->neigh == NULL) || (bns->cpty == 0)) {
ret = block_neighbours_expand(1, bns);
}
if (ret == 1) {
/* bns->neigh points to table containing at least one slot. */
i = 0;
j = bns->nneigh;
while (i < j) {
p = (i + j) / 2;
assert (bns->neigh[p] != NULL);
t = bns->neigh[p]->b;
if (t < b) { i = p + 1; }
else if (t > b) { j = p + 0; }
else { i = j = p; }
}
if ((i < bns->nneigh) &&
(bns->neigh[i] != NULL) && (bns->neigh[i]->b == b)) {
ret = block_neighbour_insert_fconn(fconn, bns->neigh[i]);
} else {
if (bns->nneigh == bns->cpty) {
assert (bns->cpty >= 1);
ret = block_neighbours_expand(2 * bns->cpty, bns);
}
if (ret >= 0) {
if (i < bns->nneigh) {
nmove = bns->nneigh - i;
memmove(bns->neigh + i + 1, bns->neigh + i + 0,
nmove * sizeof *bns->neigh);
}
bns->neigh[i] = block_neighbour_allocate(expct_nconn);
if (bns->neigh[i] != NULL) {
ret = block_neighbour_insert_fconn(fconn, bns->neigh[i]);
bns->neigh[i]->b = b;
bns->nneigh += 1;
} else {
ret = -1;
}
}
}
}
return ret;
}
/* Count number of (presumably) contiguously numbered blocks
* represented by partition vector 'p'. */
/* ---------------------------------------------------------------------- */
static int
count_blocks(int nc, const int *p)
/* ---------------------------------------------------------------------- */
{
int i, max_blk;
max_blk = -1;
for (i = 0; i < nc; i++) {
max_blk = MAX(max_blk, p[i]);
}
return max_blk + 1;
}
/* Derive coarse-scale block faces from fine-scale neighbour-ship
* definition 'neighbours' ('nfinef' connections) and partition vector
* 'p' (representing 'nblk' coarse blocks). Inter-block faces keyed
* off minimum block number if internal and valid block number if
* external.
*
* Fine-scale constituents of each coarse face are computed if
* 'expct_nconn' is positive, in which case 'expct_nconn' is
* interpreted as the expected number of constituents in each coarse
* face and used as an initial size of a hash_set.
*
* Return number of coarse faces if successful and -1 otherwise. */
/* ---------------------------------------------------------------------- */
static int
derive_block_faces(int nfinef, int nblk, int expct_nconn,
const int *p, const int *neighbours,
struct block_neighbours **bns)
/* ---------------------------------------------------------------------- */
{
int f, c1, b1, c2, b2, b_in, b_out;
int ret;
ret = 0;
for (f = 0; (f < nfinef) && (0 <= ret); f++) {
c1 = neighbours[2*f + 0]; b1 = (c1 >= 0) ? p[c1] : -1;
c2 = neighbours[2*f + 1]; b2 = (c2 >= 0) ? p[c2] : -1;
assert ((b1 >= 0) || (b2 >= 0));
if ((b1 >= 0) && (b2 >= 0)) {
b_in = MIN(b1, b2);
b_out = MAX(b1, b2);
} else if (b1 >= 0) { /* (b2 == -1) */
b_in = b1;
b_out = b2;
} else {/*(b2 >= 0) *//* (b1 == -1) */
b_in = b2;
b_out = b1;
}
if (b_in != b_out) {
/* Block boundary */
if (bns[b_in] == NULL) {
bns[b_in] = block_neighbours_allocate(1);
}
if (bns[b_in] != NULL) {
ret = block_neighbours_insert_neighbour(b_out, f,
expct_nconn,
bns[b_in]);
} else {
ret = -1;
}
}
}
if (ret >= 0) {
ret = 0;
for (b1 = 0; b1 < nblk; b1++) {
if (bns[b1] != NULL) {
ret += bns[b1]->nneigh;
}
}
}
return ret;
}
/* Create coarse-scale neighbour-ship definition from block-to-block
* connectivity information ('bns') keyed off block numbers. Set
* start pointers for CSR push-back build mode.
*
* Cannot fail. */
/* ---------------------------------------------------------------------- */
static void
coarse_topology_build_coarsef(int nblk, struct block_neighbours **bns,
int *neighbours, int *blkfacepos,
size_t *nblkf, size_t *nsubf)
/* ---------------------------------------------------------------------- */
{
int b, n, coarse_f;
coarse_f = 0;
*nsubf = 0;
for (b = 0; b < nblk; b++) {
if (bns[b] != NULL) {
for (n = 0; n < bns[b]->nneigh; n++) {
neighbours[2*coarse_f + 0] = b;
neighbours[2*coarse_f + 1] = bns[b]->neigh[n]->b;
coarse_f += 1;
blkfacepos[b + 1] += 1;
if (bns[b]->neigh[n]->b >= 0) {
blkfacepos[bns[b]->neigh[n]->b + 1] += 1;
}
if (bns[b]->neigh[n]->fconns != NULL) {
*nsubf += hash_set_count_elms(bns[b]->neigh[n]->fconns);
}
}
}
}
/* Derive start pointers */
for (b = 1; b <= nblk; b++) {
blkfacepos[0] += blkfacepos[b];
blkfacepos[b] = blkfacepos[0] - blkfacepos[b];
}
*nblkf = blkfacepos[0];
blkfacepos[0] = 0;
}
/* Create coarse-scale block-to-face mapping and, if requested,
* coarse-scale constituent faces for each coarse face.
*
* Constituent faces requested if subfacepos and subfaces non-NULL.
* In this case, all coarse faces must carry sub-face information.
*
* Returns 1 if successful (i.e., no sub-face information requested or
* sub-face information requested and available for all coarse faces)
* and zero otherwise. */
/* ---------------------------------------------------------------------- */
static int
coarse_topology_build_final(int ncoarse_f, int nblk,
const int *neighbours,
int *blkfacepos, int *blkfaces,
struct block_neighbours **bns,
int *subfacepos, int *subfaces)
/* ---------------------------------------------------------------------- */
{
int coarse_f, b1, b2, n, subpos, subface_valid = 1;
size_t i;
struct hash_set *set;
assert ((subfacepos == NULL) == (subfaces == NULL));
for (coarse_f = 0; coarse_f < ncoarse_f; coarse_f++) {
b1 = neighbours[2*coarse_f + 0];
b2 = neighbours[2*coarse_f + 1];
assert (b1 != b2);
if (b1 >= 0) { blkfaces[blkfacepos[b1 + 1] ++] = coarse_f; }
if (b2 >= 0) { blkfaces[blkfacepos[b2 + 1] ++] = coarse_f; }
}
if (subfacepos != NULL) {
coarse_f = 0;
subpos = 0;
for (b1 = 0; (b1 < nblk) && subface_valid; b1++) {
if (bns[b1] != NULL) {
for (n = 0; n < bns[b1]->nneigh; n++) {
set = bns[b1]->neigh[n]->fconns;
subface_valid = set != NULL;
if (subface_valid) {
for (i = 0; i < set->m; i++) {
if (set->s[i] != -1) {
subfaces[subpos ++] = set->s[i];
}
}
} else {
break;
}
subfacepos[++ coarse_f] = subpos;
}
}
}
}
return (subfacepos == NULL) || subface_valid;
}
/* Allocate and assemble coarse-grid structure from non-linear
* block-to-block connection information keyed off block numbers. The
* final coarse grid consists of 'ncoarse_f' coarse faces numbered
* 0..ncoarse_f-1 and 'nblk' coarse blocks numbered 0..nblk-1.
*
* Returns fully assembled coarse-grid structure if successful or NULL
* otherwise. */
/* ---------------------------------------------------------------------- */
static struct coarse_topology *
coarse_topology_build(int ncoarse_f, int nblk,
struct block_neighbours **bns)
/* ---------------------------------------------------------------------- */
{
int i;
int subface_valid;
size_t nblkf, nsubf;
struct coarse_topology *new;
new = malloc(1 * sizeof *new);
if (new != NULL) {
new->neighbours = malloc(2 * ncoarse_f * sizeof *new->neighbours);
new->blkfacepos = malloc((nblk + 1) * sizeof *new->blkfacepos);
new->blkfaces = NULL;
new->subfacepos = NULL;
new->subfaces = NULL;
if ((new->neighbours == NULL) ||
(new->blkfacepos == NULL)) {
coarse_topology_destroy(new);
new = NULL;
} else {
for (i = 0; i < 2 * ncoarse_f; i++) {
new->neighbours[i] = INT_MIN;
}
for (i = 0; i < nblk + 1; i++) {
new->blkfacepos[i] = 0;
}
coarse_topology_build_coarsef(nblk, bns, new->neighbours,
new->blkfacepos, &nblkf, &nsubf);
if (nsubf > 0) {
new->subfacepos = malloc((ncoarse_f + 1) * sizeof *new->subfacepos);
new->subfaces = malloc(nsubf * sizeof *new->subfaces);
if ((new->subfacepos == NULL) || (new->subfaces == NULL)) {
free(new->subfaces); new->subfaces = NULL;
free(new->subfacepos); new->subfacepos = NULL;
} else {
for (i = 0; i < ncoarse_f + 1; i++) {
new->subfacepos[i] = 0;
}
}
}
new->blkfaces = malloc(nblkf * sizeof *new->blkfaces);
if (new->blkfaces == NULL) {
coarse_topology_destroy(new);
new = NULL;
} else {
subface_valid = coarse_topology_build_final(ncoarse_f, nblk,
new->neighbours,
new->blkfacepos,
new->blkfaces,
bns,
new->subfacepos,
new->subfaces);
if (!subface_valid) {
free(new->subfaces); new->subfaces = NULL;
free(new->subfacepos); new->subfacepos = NULL;
} else {
new->nblocks = nblk;
new->nfaces = ncoarse_f;
}
}
}
}
return new;
}
/* Create coarse-grid topology structure from fine-scale
* neighbour-ship definition 'neighbours' and partition vector 'p'.
*
* Returns fully allocated and assembled coarse-grid structure if
* successful and NULL otherwise. */
/* ---------------------------------------------------------------------- */
struct coarse_topology *
coarse_topology_create(int nc, int nf, int expct_nconn,
const int *p, const int *neighbours)
/* ---------------------------------------------------------------------- */
{
int b, nblocks, ncoarse_f;
struct block_neighbours **bns;
struct coarse_topology *topo;
nblocks = count_blocks(nc, p);
bns = malloc(nblocks * sizeof *bns);
if (bns != NULL) {
for (b = 0; b < nblocks; b++) {
bns[b] = NULL;
}
ncoarse_f = derive_block_faces(nf, nblocks, expct_nconn,
p, neighbours, bns);
topo = coarse_topology_build(ncoarse_f, nblocks, bns);
for (b = 0; b < nblocks; b++) {
block_neighbours_deallocate(bns[b]);
}
free(bns);
} else {
topo = NULL;
}
return topo;
}
/* Release memory resources for dynamically allocated coarse-grid
* topology structure 't'. */
/* ---------------------------------------------------------------------- */
void
coarse_topology_destroy(struct coarse_topology *t)
/* ---------------------------------------------------------------------- */
{
if (t != NULL) {
free(t->subfaces);
free(t->subfacepos);
free(t->blkfaces);
free(t->blkfacepos);
free(t->neighbours);
}
free(t);
}

View File

@ -1,54 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_COARSE_CONN_HEADER_INCLUDED
#define OPM_COARSE_CONN_HEADER_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
struct coarse_topology {
int nblocks; /* Number of blocks */
int nfaces; /* Number of faces */
int *neighbours; /* Neighbourship definition */
int *blkfacepos; /* Index into blkfaces */
int *blkfaces; /* Faces per block */
int *subfacepos; /* Index into subfaces */
int *subfaces; /* FS faces per coarse face */
};
struct coarse_topology *
coarse_topology_create(int nc, int nf, int expct_nconn,
const int *p, const int *neighbours);
void
coarse_topology_destroy(struct coarse_topology *t);
#ifdef __cplusplus
}
#endif
#endif /* OPM_COARSE_CONN_HEADER_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_COARSE_SYS_HEADER_INCLUDED
#define OPM_COARSE_SYS_HEADER_INCLUDED
#include <opm/core/grid.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ---------------------------------------------------------------------- */
struct coarse_sys {
int *dof2conn; /* Map dof->connection (coarse interface) */
int *blkdof_pos; /* Start pointers to each block's dofs */
int *basis_pos; /* Start pointers to each block's bf's */
int *cell_ip_pos; /* Start pointers to each block's IP */
int *blkdof; /* Each block's dofs */
double *basis; /* All basis functions */
double *cell_ip; /* Fine-scale IP contributions */
double *Binv; /* Coarse-scale inverse IP per block */
};
/* ---------------------------------------------------------------------- */
struct coarse_topology;
struct CSRMatrix;
typedef void (*LocalSolver)(struct CSRMatrix *A,
double *b,
double *x);
struct coarse_sys *
coarse_sys_construct(struct UnstructuredGrid *g, const int *p,
struct coarse_topology *ct,
const double *perm,
const double *src,
const double *totmob,
LocalSolver linsolve);
void
coarse_sys_destroy(struct coarse_sys *sys);
void
coarse_sys_compute_cell_ip(int nc,
int max_nconn,
int nb,
const int *pconn,
const double *Binv,
const int *b2c_pos,
const int *b2c,
struct coarse_sys *sys);
void
coarse_sys_compute_Binv(int nb,
int max_bcells,
const double *totmob,
const int *b2c_pos,
const int *b2c,
struct coarse_sys *sys,
double *work);
void
coarse_sys_compute_fs_flux(struct UnstructuredGrid *g,
struct coarse_topology *ct,
struct coarse_sys *sys,
const int *b2c_pos,
const int *b2c,
const double *v_c,
double *flux,
double *work);
#ifdef __cplusplus
}
#endif
#endif /* OPM_COARSE_SYS_HEADER_INCLUDED */

View File

@ -1,241 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <opm/core/pressure/msmfem/hash_set.h>
/* ======================================================================
* Macros
* ====================================================================== */
#define GOLDEN_RAT (0.6180339887498949) /* (sqrt(5) - 1) / 2 */
#define IS_POW2(x) (((x) & ((x) - 1)) == 0)
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
/* Define a hash array size (1<<p) capable of holding a set of size 'm' */
/* ---------------------------------------------------------------------- */
static size_t
hash_set_size(size_t m)
/* ---------------------------------------------------------------------- */
{
size_t i;
if (m == 0) {
return 1;
}
if (IS_POW2(m)) {
return m;
}
/* General case. Use next power of two. */
/* Algorithm due to
*
* Warren Jr., Henry S. (2002). Hacker's Delight.
* Addison Wesley. pp. 48. ISBN 978-0201914658
*
* by way of Wikipedia. */
m -= 1;
for (i = 1; i < CHAR_BIT * sizeof m; i <<= 1) {
m = m | (m >> i);
}
return m + 1;
}
/* Hash element 'k' into table of size 'm' (multiplication method) */
/* ---------------------------------------------------------------------- */
static size_t
hash_set_idx(int k, size_t m)
/* ---------------------------------------------------------------------- */
{
double x = fmod(k * GOLDEN_RAT, 1.0);
double y = floor(m * x);
return y;
}
/* Insert element 'k' into set 's' of size 'm'
* (open addressing, double probing). */
/* ---------------------------------------------------------------------- */
static size_t
hash_set_insert_core(int k, size_t m, int *s)
/* ---------------------------------------------------------------------- */
{
size_t h1, h2, i, j;
assert ((0 < m) && (m < (size_t)(-1)));
assert (IS_POW2(m));
j = h1 = hash_set_idx(k, m);
assert (h1 < m);
if (s[j] == -1) { s[j] = k; }
if (s[j] == k) { return j; }
/* Double hash probing. h2 relatively prime to 'm' */
h2 = 2 * hash_set_idx(k, MAX(m >> 1, 1)) + 1;
for (i = 1; (s[j] != -1) && (s[j] != k) && (i < m); i++) {
j += h2;
j &= m - 1; /* Modulo m since IS_POW2(m). */
}
if ((s[j] == -1) || (s[j] == k)) {
s[j] = k; /* Possibly no-op. */
} else {
j = m + 1; /* Invalid. Caveat emptor. */
}
return j;
}
/* Increase size of hash set 't' to hold 'm' elements whilst copying
* existing elements. This is typically fairly expensive. */
/* ---------------------------------------------------------------------- */
static int
hash_set_expand(size_t m, struct hash_set *t)
/* ---------------------------------------------------------------------- */
{
int ret, *s, *p;
size_t i;
assert (m > t->m);
s = malloc(m * sizeof *s);
if (s != NULL) {
for (i = 0; i < m; i++) { s[i] = -1; }
for (i = 0; i < t->m; i++) {
ret = hash_set_insert_core(t->s[i], m, s);
assert ((size_t) ret < m);
}
p = t->s;
t->s = s;
t->m = m;
free(p);
ret = m;
} else {
ret = -1;
}
return ret;
}
/* Release dynamic memory resources for hash set 't'. */
/* ---------------------------------------------------------------------- */
void
hash_set_deallocate(struct hash_set *t)
/* ---------------------------------------------------------------------- */
{
if (t != NULL) {
free(t->s);
}
free(t);
}
/* Construct an emtpy hash set capable of holding 'm' elements */
/* ---------------------------------------------------------------------- */
struct hash_set *
hash_set_allocate(int m)
/* ---------------------------------------------------------------------- */
{
size_t i, sz;
struct hash_set *new;
new = malloc(1 * sizeof *new);
if (new != NULL) {
sz = hash_set_size(m);
new->s = malloc(sz * sizeof *new->s);
if (new->s == NULL) {
hash_set_deallocate(new);
new = NULL;
} else {
for (i = 0; i < sz; i++) { new->s[i] = -1; }
new->m = sz;
}
}
return new;
}
/* Insert element 'k' into hash set 't'. */
/* ---------------------------------------------------------------------- */
int
hash_set_insert(int k, struct hash_set *t)
/* ---------------------------------------------------------------------- */
{
int ret;
size_t i;
assert (k >= 0);
assert (t != NULL);
assert (IS_POW2(t->m));
i = hash_set_insert_core(k, t->m, t->s);
if (i == t->m + 1) {
/* Table full. Preferable an infrequent occurrence. Expand
* table and re-insert key (if possible). */
ret = hash_set_expand(t->m << 1, t);
if (ret > 0) {
i = hash_set_insert_core(k, t->m, t->s);
assert (i < t->m);
ret = k;
}
} else {
ret = k;
}
return ret;
}
/* ---------------------------------------------------------------------- */
size_t
hash_set_count_elms(const struct hash_set *set)
/* ---------------------------------------------------------------------- */
{
size_t i, n;
n = 0;
for (i = 0; i < set->m; i++) {
n += set->s[i] != -1;
}
return n;
}

View File

@ -1,70 +0,0 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_HASH_SET_HEADER_INCLUDED
#define OPM_HASH_SET_HEADER_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
/* ---------------------------------------------------------------------- */
/* Poor-man's unordered set (ind. key insert/all key extract only). */
/* ---------------------------------------------------------------------- */
struct hash_set {
size_t m; /* Table/set capacity (1<<p for some p) */
int *s; /* Set representation */
};
/* ---------------------------------------------------------------------- */
/* Release dynamic memory resources for hash set 's'. */
/* ---------------------------------------------------------------------- */
void
hash_set_deallocate(struct hash_set *s);
/* ---------------------------------------------------------------------- */
/* Construct an emtpy hash set capable of holding 'm' elements */
/* ---------------------------------------------------------------------- */
struct hash_set *
hash_set_allocate(int m);
/* ---------------------------------------------------------------------- */
/* Insert element 'k' into hash set 's'. */
/* ---------------------------------------------------------------------- */
int
hash_set_insert(int k, struct hash_set *s);
/* ---------------------------------------------------------------------- */
/* Count number of valid keys in a hash set. */
/* ---------------------------------------------------------------------- */
size_t
hash_set_count_elms(const struct hash_set *set);
#ifdef __cplusplus
}
#endif
#endif /* OPM_HASH_SET_HEADER_INCLUDED */

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