Merge pull request #26 from atgeirr/ert

Make ert branch up-to-date.

Merged as of commit 3e8b6a3 .  Thanks.
This commit is contained in:
Bård Skaflestad 2012-09-30 13:33:29 -07:00
commit 0b766e5ec2
126 changed files with 8379 additions and 3038 deletions

14
.gitignore vendored
View File

@ -1,4 +1,5 @@
*~ *~
.\#*
*.o *.o
*.lo *.lo
*.la *.la
@ -28,15 +29,28 @@ ltmain.sh
m4/libtool.m4 m4/libtool.m4
m4/lt*.m4 m4/lt*.m4
missing missing
ar-lib
tutorials/tutorial[1-4]
# Ignoring executables # Ignoring executables
*_test *_test
examples/scaneclipsedeck examples/scaneclipsedeck
examples/spu_2p examples/spu_2p
examples/reorder-qfs examples/reorder-qfs
examples/refine_wells
examples/sim_2p_incomp_reorder
examples/sim_2p_comp_reorder
examples/sim_wateroil
examples/wells_example
tests/test_cfs_tpfa tests/test_cfs_tpfa
tests/test_jacsys tests/test_jacsys
tests/test_readvector tests/test_readvector
tests/test_sf2p tests/test_sf2p
tests/bo_fluid_p_and_z_deps tests/bo_fluid_p_and_z_deps
tests/bo_fluid_pressuredeps tests/bo_fluid_pressuredeps
tests/test_cartgrid
tests/test_column_extract
tests/test_lapack
tests/test_read_vag
tests/test_readpolymer
tests/test_writeVtkData

View File

@ -2,8 +2,10 @@ cmake_minimum_required (VERSION 2.6)
project (opm-core) project (opm-core)
enable_language(Fortran) enable_language(Fortran)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
SET(CMAKE_BUILD_TYPE "debug")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG -pg -Wall -fopenmp -ggdb")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg -Wall -fopenmp -ggdb")
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON) set(Boost_USE_MULTITHREADED ON)
@ -16,94 +18,50 @@ include_directories(${PROJECT_SOURCE_DIR} ${Boost_INCLUDE_DIRS})
# The opmcore library # The opmcore library
add_library(opmcore FILE(GLOB_RECURSE C_FILES_CORE "opm/core/*.c")
opm/core/eclipse/EclipseGridInspector.cpp FILE(GLOB_RECURSE CPP_FILES_CORE "opm/core/*.cpp")
opm/core/eclipse/EclipseGridParser.cpp FILE(GLOB_RECURSE REMOVE_FILES "processgrid.c")
opm/core/fluid/blackoil/BlackoilPvtProperties.cpp FILE(GLOB_RECURSE REMOVE_FILESMX "mx*.c")
opm/core/fluid/blackoil/SinglePvtDead.cpp FILE(GLOB_RECURSE REMOVE_FILESAGMG "*AGMG.cpp" "*test*")
opm/core/fluid/blackoil/SinglePvtLiveGas.cpp list(REMOVE_ITEM C_FILES_CORE ${REMOVE_FILES} ${REMOVE_FILESMX} )
opm/core/fluid/blackoil/SinglePvtLiveOil.cpp list(REMOVE_ITEM CPP_FILES_CORE ${REMOVE_FILES} ${REMOVE_FILESAGMG})
opm/core/fluid/blackoil/SinglePvtInterface.cpp add_library(opmcore ${C_FILES_CORE} ${CPP_FILES_CORE} )
opm/core/fluid/BlackoilPropertiesBasic.cpp
opm/core/fluid/BlackoilPropertiesFromDeck.cpp
opm/core/fluid/IncompPropertiesBasic.cpp
opm/core/fluid/IncompPropertiesFromDeck.cpp
opm/core/fluid/PvtPropertiesBasic.cpp
opm/core/fluid/PvtPropertiesIncompFromDeck.cpp
opm/core/fluid/RockBasic.cpp
opm/core/fluid/RockFromDeck.cpp
opm/core/fluid/SaturationPropsBasic.cpp
opm/core/fluid/SaturationPropsFromDeck.cpp
opm/core/utility/MonotCubicInterpolator.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/cart_grid.c
opm/core/utility/cpgpreprocess/geometry.c
opm/core/utility/cpgpreprocess/preprocess.c
opm/core/utility/cpgpreprocess/readvector.cpp
opm/core/utility/cpgpreprocess/cgridinterface.c
opm/core/utility/cpgpreprocess/sparsetable.c
opm/core/utility/cpgpreprocess/facetopology.c
opm/core/utility/cpgpreprocess/uniquepoints.c
opm/core/utility/StopWatch.cpp
opm/core/utility/newwells.c
opm/core/utility/writeVtkData.cpp
opm/core/GridManager.cpp
opm/core/linalg/sparse_sys.c
opm/core/pressure/cfsh.c
opm/core/pressure/flow_bc.c
opm/core/pressure/well.c
opm/core/pressure/fsh_common_impl.c
opm/core/pressure/fsh.c
opm/core/pressure/tpfa/ifs_tpfa.c
opm/core/pressure/tpfa/compr_source.c
opm/core/pressure/tpfa/cfs_tpfa.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/cfs_tpfa_residual.c
opm/core/pressure/tpfa/trans_tpfa.c
opm/core/pressure/msmfem/coarse_conn.c
opm/core/pressure/msmfem/partition.c
opm/core/pressure/msmfem/hash_set.c
opm/core/pressure/msmfem/ifsh_ms.c
opm/core/pressure/msmfem/dfs.c
opm/core/pressure/msmfem/coarse_sys.c
opm/core/pressure/ifsh.c
opm/core/pressure/IncompTpfa.cpp
opm/core/pressure/mimetic/mimetic.c
opm/core/pressure/mimetic/hybsys_global.c
opm/core/pressure/mimetic/hybsys.c
opm/core/transport/spu_explicit.c
opm/core/transport/spu_implicit.c
opm/core/transport/transport_source.c
opm/core/transport/reorder/TransportModelInterface.cpp
opm/core/transport/reorder/TransportModelTwophase.cpp
opm/core/transport/reorder/reordersequence.cpp
opm/core/transport/reorder/nlsolvers.c
opm/core/transport/reorder/tarjan.c
opm/core/linalg/call_umfpack.c
opm/core/pressure/IncompTpfa.cpp
opm/core/linalg/LinearSolverInterface.cpp
opm/core/linalg/LinearSolverIstl.cpp
opm/core/linalg/LinearSolverUmfpack.cpp
)
target_link_libraries(opmcore target_link_libraries(opmcore
${UMFPACK_LIBRARIES} ${LAPACK_LINKER_FLAGS} ${LAPACK_LIBRARIES} ${Boost_LIBRARIES} ${UMFPACK_LIBRARIES} ${LAPACK_LINKER_FLAGS} ${LAPACK_LIBRARIES} ${Boost_LIBRARIES}
-lcholmod -lcamd -lccolamd -lmetis -ldunecommon -lcholmod -lcamd -lccolamd -lmetis -ldunecommon
) )
FILE(GLOB CPP_EXAMPLES "examples/*.cpp")
FILE(GLOB CPP_tests "tests/*.cpp")
add_executable(spu_2p examples/spu_2p.cpp) add_executable(spu_2p examples/spu_2p.cpp)
add_executable(sim_2p_incomp_reorder examples/sim_2p_incomp_reorder.cpp)
add_executable(sim_wateroil examples/sim_wateroil.cpp)
add_executable(pvt_test tests/pvt_test.cpp)
add_executable(relperm_test tests/relperm_test.cpp)
target_link_libraries(spu_2p target_link_libraries(spu_2p
opmcore opmcore
) )
target_link_libraries(sim_2p_incomp_reorder
opmcore
)
set_target_properties(opmcore spu_2p PROPERTIES COMPILE_FLAGS -m64 LINKER_LANGUAGE CXX LINK_FLAGS -m64) target_link_libraries(sim_wateroil
opmcore
)
target_link_libraries(pvt_test
opmcore
)
target_link_libraries(relperm_test
opmcore
)
#set_target_properties(opmcore spu_2p PROPERTIES COMPILE_FLAGS -m64 LINKER_LANGUAGE CXX LINK_FLAGS -m64)
#set_target_properties(opmcore sim_2p_incomp_reorder PROPERTIES COMPILE_FLAGS -m64 LINKER_LANGUAGE CXX LINK_FLAGS -m64)
#set_target_properties(opmcore sim_wateroil PROPERTIES COMPILE_FLAGS -m64 LINKER_LANGUAGE CXX LINK_FLAGS -m64)
#set_target_properties(opmcore pvt_test PROPERTIES COMPILE_FLAGS -m64 LINKER_LANGUAGE CXX LINK_FLAGS -m64)
set_target_properties(opmcore relperm_test PROPERTIES COMPILE_FLAGS -m64 LINKER_LANGUAGE CXX LINK_FLAGS -m64)

56
FindUmfPack.cmake Normal file
View File

@ -0,0 +1,56 @@
if (UMFPACK_INCLUDES AND UMFPACK_LIBRARIES)
set(UMFPACK_FIND_QUIETLY TRUE)
endif (UMFPACK_INCLUDES AND UMFPACK_LIBRARIES)
find_package(BLAS)
if(BLAS_FOUND)
find_path(UMFPACK_INCLUDES
NAMES
umfpack.h
PATHS
$ENV{UMFPACKDIR}
${INCLUDE_INSTALL_DIR}
PATH_SUFFIXES
suitesparse
)
find_library(UMFPACK_LIBRARIES umfpack PATHS $ENV{UMFPACKDIR} ${LIB_INSTALL_DIR})
if(UMFPACK_LIBRARIES)
get_filename_component(UMFPACK_LIBDIR ${UMFPACK_LIBRARIES} PATH)
find_library(AMD_LIBRARY amd PATHS ${UMFPACK_LIBDIR} $ENV{UMFPACKDIR} ${LIB_INSTALL_DIR})
if (AMD_LIBRARY)
set(UMFPACK_LIBRARIES ${UMFPACK_LIBRARIES} ${AMD_LIBRARY})
#else (AMD_LIBRARY)
# set(UMFPACK_LIBRARIES FALSE)
endif (AMD_LIBRARY)
endif(UMFPACK_LIBRARIES)
if(UMFPACK_LIBRARIES)
find_library(COLAMD_LIBRARY colamd PATHS ${UMFPACK_LIBDIR} $ENV{UMFPACKDIR} ${LIB_INSTALL_DIR})
if (COLAMD_LIBRARY)
set(UMFPACK_LIBRARIES ${UMFPACK_LIBRARIES} ${COLAMD_LIBRARY})
#else (COLAMD_LIBRARY)
# set(UMFPACK_LIBRARIES FALSE)
endif (COLAMD_LIBRARY)
endif(UMFPACK_LIBRARIES)
if(UMFPACK_LIBRARIES)
set(UMFPACK_LIBRARIES ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES})
endif(UMFPACK_LIBRARIES)
endif(BLAS_FOUND)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(UMFPACK DEFAULT_MSG
UMFPACK_INCLUDES UMFPACK_LIBRARIES)
mark_as_advanced(UMFPACK_INCLUDES UMFPACK_LIBRARIES AMD_LIBRARY COLAMD_LIBRARY)

View File

@ -6,50 +6,59 @@ SUBDIRS = . tests examples tutorials
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# Declare products (i.e., the library) # Declare products (i.e., the library)
lib_LTLIBRARIES = libopmcore.la lib_LTLIBRARIES = lib/libopmcore.la
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# Build-time flags needed to build libopmcore.la # Build-time flags needed to build libopmcore.la
AM_CPPFLAGS = \ AM_CPPFLAGS = \
$(ERT_CPPFLAGS) \ $(ERT_CPPFLAGS) \
$(BOOST_CPPFLAGS) $(OPM_BOOST_CPPFLAGS)
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# Link-time flags needed both to successfully link the library and to # Link-time flags needed both to successfully link the library and to
# (transitively) convey inter-library dependency information. # (transitively) convey inter-library dependency information.
libopmcore_la_LDFLAGS = \ lib_libopmcore_la_LDFLAGS = \
$(ERT_LDFLAGS) \ $(ERT_LDFLAGS) \
$(BOOST_LDFLAGS) \ $(OPM_BOOST_LDFLAGS) \
$(BOOST_FILESYSTEM_LIB) \ $(BOOST_FILESYSTEM_LIB) \
$(BOOST_SYSTEM_LIB) \ $(BOOST_SYSTEM_LIB) \
$(BOOST_DATE_TIME_LIB) \ $(BOOST_DATE_TIME_LIB) \
$(BOOST_UNIT_TEST_FRAMEWORK_LIB) \ $(BOOST_UNIT_TEST_FRAMEWORK_LIB) \
$(ERT_LIBS) $(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(ERT_LIBS) \
$(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS)
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# Library constituents. SOURCES followed by HEADERS. # Library constituents. SOURCES followed by HEADERS.
# #
# Please try to keep the list sorted. # Please try to keep the list sorted.
libopmcore_la_SOURCES = \ # List of sources that should be built but not distributed. See AGMG
opm/core/GridManager.cpp \ # support below for additional details.
opm/core/eclipse/EclipseGridInspector.cpp \ nodist_lib_libopmcore_la_SOURCES =
opm/core/eclipse/EclipseGridParser.cpp \
opm/core/fluid/BlackoilPropertiesBasic.cpp \ lib_libopmcore_la_SOURCES = \
opm/core/fluid/BlackoilPropertiesFromDeck.cpp \ opm/core/GridManager.cpp \
opm/core/fluid/IncompPropertiesBasic.cpp \ opm/core/eclipse/EclipseGridInspector.cpp \
opm/core/fluid/IncompPropertiesFromDeck.cpp \ opm/core/eclipse/EclipseGridParser.cpp \
opm/core/fluid/PvtPropertiesBasic.cpp \ opm/core/fluid/BlackoilPropertiesBasic.cpp \
opm/core/fluid/PvtPropertiesIncompFromDeck.cpp \ opm/core/fluid/BlackoilPropertiesFromDeck.cpp \
opm/core/fluid/RockBasic.cpp \ opm/core/fluid/IncompPropertiesBasic.cpp \
opm/core/fluid/RockCompressibility.cpp \ opm/core/fluid/IncompPropertiesFromDeck.cpp \
opm/core/fluid/RockFromDeck.cpp \ opm/core/fluid/PvtPropertiesBasic.cpp \
opm/core/fluid/SaturationPropsBasic.cpp \ opm/core/fluid/PvtPropertiesIncompFromDeck.cpp \
opm/core/fluid/SaturationPropsFromDeck.cpp \ opm/core/fluid/RockBasic.cpp \
opm/core/fluid/RockCompressibility.cpp \
opm/core/fluid/RockFromDeck.cpp \
opm/core/fluid/SaturationPropsBasic.cpp \
opm/core/fluid/SaturationPropsFromDeck.cpp \
opm/core/fluid/SatFuncGwseg.cpp \
opm/core/fluid/SatFuncStone2.cpp \
opm/core/fluid/SatFuncSimple.cpp \
opm/core/fluid/blackoil/BlackoilPvtProperties.cpp \ opm/core/fluid/blackoil/BlackoilPvtProperties.cpp \
opm/core/fluid/blackoil/SinglePvtDead.cpp \ opm/core/fluid/blackoil/SinglePvtDead.cpp \
opm/core/fluid/blackoil/SinglePvtDeadSpline.cpp \
opm/core/fluid/blackoil/SinglePvtInterface.cpp \ opm/core/fluid/blackoil/SinglePvtInterface.cpp \
opm/core/fluid/blackoil/SinglePvtLiveGas.cpp \ opm/core/fluid/blackoil/SinglePvtLiveGas.cpp \
opm/core/fluid/blackoil/SinglePvtLiveOil.cpp \ opm/core/fluid/blackoil/SinglePvtLiveOil.cpp \
@ -90,9 +99,10 @@ opm/core/pressure/tpfa/compr_source.c \
opm/core/pressure/tpfa/ifs_tpfa.c \ opm/core/pressure/tpfa/ifs_tpfa.c \
opm/core/pressure/tpfa/trans_tpfa.c \ opm/core/pressure/tpfa/trans_tpfa.c \
opm/core/pressure/well.c \ opm/core/pressure/well.c \
opm/core/simulator/SimulatorCompressibleTwophase.cpp \
opm/core/simulator/SimulatorIncompTwophase.cpp \
opm/core/simulator/SimulatorReport.cpp \ opm/core/simulator/SimulatorReport.cpp \
opm/core/simulator/SimulatorTimer.cpp \ opm/core/simulator/SimulatorTimer.cpp \
opm/core/simulator/SimulatorTwophase.cpp \
opm/core/transport/reorder/TransportModelCompressibleTwophase.cpp \ opm/core/transport/reorder/TransportModelCompressibleTwophase.cpp \
opm/core/transport/reorder/TransportModelInterface.cpp \ opm/core/transport/reorder/TransportModelInterface.cpp \
opm/core/transport/reorder/TransportModelTwophase.cpp \ opm/core/transport/reorder/TransportModelTwophase.cpp \
@ -122,33 +132,39 @@ opm/core/wells/WellCollection.cpp \
opm/core/wells/WellsGroup.cpp \ opm/core/wells/WellsGroup.cpp \
opm/core/wells/WellsManager.cpp opm/core/wells/WellsManager.cpp
nobase_include_HEADERS = \ nobase_include_HEADERS = \
opm/core/GridAdapter.hpp \ opm/core/GridAdapter.hpp \
opm/core/GridManager.hpp \ opm/core/GridManager.hpp \
opm/core/eclipse/CornerpointChopper.hpp \ opm/core/eclipse/CornerpointChopper.hpp \
opm/core/eclipse/EclipseGridInspector.hpp \ opm/core/eclipse/EclipseGridInspector.hpp \
opm/core/eclipse/EclipseGridParser.hpp \ opm/core/eclipse/EclipseGridParser.hpp \
opm/core/eclipse/EclipseGridParserHelpers.hpp \ opm/core/eclipse/EclipseGridParserHelpers.hpp \
opm/core/eclipse/EclipseUnits.hpp \ opm/core/eclipse/EclipseUnits.hpp \
opm/core/eclipse/SpecialEclipseFields.hpp \ opm/core/eclipse/SpecialEclipseFields.hpp \
opm/core/fluid/BlackoilPropertiesBasic.hpp \ opm/core/fluid/BlackoilPropertiesBasic.hpp \
opm/core/fluid/BlackoilPropertiesFromDeck.hpp \ opm/core/fluid/BlackoilPropertiesFromDeck.hpp \
opm/core/fluid/BlackoilPropertiesInterface.hpp \ opm/core/fluid/BlackoilPropertiesInterface.hpp \
opm/core/fluid/IncompPropertiesBasic.hpp \ opm/core/fluid/IncompPropertiesBasic.hpp \
opm/core/fluid/IncompPropertiesFromDeck.hpp \ opm/core/fluid/IncompPropertiesFromDeck.hpp \
opm/core/fluid/IncompPropertiesInterface.hpp \ opm/core/fluid/IncompPropertiesInterface.hpp \
opm/core/fluid/PvtPropertiesBasic.hpp \ opm/core/fluid/PvtPropertiesBasic.hpp \
opm/core/fluid/PvtPropertiesIncompFromDeck.hpp \ opm/core/fluid/PvtPropertiesIncompFromDeck.hpp \
opm/core/fluid/RockBasic.hpp \ opm/core/fluid/RockBasic.hpp \
opm/core/fluid/RockCompressibility.hpp \ opm/core/fluid/RockCompressibility.hpp \
opm/core/fluid/RockFromDeck.hpp \ opm/core/fluid/RockFromDeck.hpp \
opm/core/fluid/SatFuncGwseg.hpp \
opm/core/fluid/SatFuncStone2.hpp \
opm/core/fluid/SatFuncSimple.hpp \
opm/core/fluid/SaturationPropsBasic.hpp \ opm/core/fluid/SaturationPropsBasic.hpp \
opm/core/fluid/SaturationPropsFromDeck.hpp \ opm/core/fluid/SaturationPropsFromDeck.hpp \
opm/core/fluid/SaturationPropsFromDeck_impl.hpp \
opm/core/fluid/SaturationPropsInterface.hpp \
opm/core/fluid/SimpleFluid2p.hpp \ opm/core/fluid/SimpleFluid2p.hpp \
opm/core/fluid/blackoil/BlackoilPhases.hpp \ opm/core/fluid/blackoil/BlackoilPhases.hpp \
opm/core/fluid/blackoil/BlackoilPvtProperties.hpp \ opm/core/fluid/blackoil/BlackoilPvtProperties.hpp \
opm/core/fluid/blackoil/SinglePvtConstCompr.hpp \ opm/core/fluid/blackoil/SinglePvtConstCompr.hpp \
opm/core/fluid/blackoil/SinglePvtDead.hpp \ opm/core/fluid/blackoil/SinglePvtDead.hpp \
opm/core/fluid/blackoil/SinglePvtDeadSpline.hpp \
opm/core/fluid/blackoil/SinglePvtInterface.hpp \ opm/core/fluid/blackoil/SinglePvtInterface.hpp \
opm/core/fluid/blackoil/SinglePvtLiveGas.hpp \ opm/core/fluid/blackoil/SinglePvtLiveGas.hpp \
opm/core/fluid/blackoil/SinglePvtLiveOil.hpp \ opm/core/fluid/blackoil/SinglePvtLiveOil.hpp \
@ -193,9 +209,10 @@ opm/core/pressure/tpfa/compr_source.h \
opm/core/pressure/tpfa/ifs_tpfa.h \ opm/core/pressure/tpfa/ifs_tpfa.h \
opm/core/pressure/tpfa/trans_tpfa.h \ opm/core/pressure/tpfa/trans_tpfa.h \
opm/core/simulator/BlackoilState.hpp \ opm/core/simulator/BlackoilState.hpp \
opm/core/simulator/SimulatorCompressibleTwophase.hpp \
opm/core/simulator/SimulatorReport.hpp \ opm/core/simulator/SimulatorReport.hpp \
opm/core/simulator/SimulatorIncompTwophase.hpp \
opm/core/simulator/SimulatorTimer.hpp \ opm/core/simulator/SimulatorTimer.hpp \
opm/core/simulator/SimulatorTwophase.hpp \
opm/core/simulator/TwophaseState.hpp \ opm/core/simulator/TwophaseState.hpp \
opm/core/simulator/WellState.hpp \ opm/core/simulator/WellState.hpp \
opm/core/transport/CSRMatrixBlockAssembler.hpp \ opm/core/transport/CSRMatrixBlockAssembler.hpp \
@ -219,9 +236,11 @@ opm/core/transport/spu_implicit.h \
opm/core/transport/transport_source.h \ opm/core/transport/transport_source.h \
opm/core/utility/Average.hpp \ opm/core/utility/Average.hpp \
opm/core/utility/ColumnExtract.hpp \ opm/core/utility/ColumnExtract.hpp \
opm/core/utility/DataMap.hpp \
opm/core/utility/ErrorMacros.hpp \ opm/core/utility/ErrorMacros.hpp \
opm/core/utility/Factory.hpp \ opm/core/utility/Factory.hpp \
opm/core/utility/MonotCubicInterpolator.hpp \ opm/core/utility/MonotCubicInterpolator.hpp \
opm/core/utility/NonuniformTableLinear.hpp \
opm/core/utility/RootFinders.hpp \ opm/core/utility/RootFinders.hpp \
opm/core/utility/SparseTable.hpp \ opm/core/utility/SparseTable.hpp \
opm/core/utility/SparseVector.hpp \ opm/core/utility/SparseVector.hpp \
@ -246,7 +265,6 @@ opm/core/utility/parameters/ParameterXML.hpp \
opm/core/utility/parameters/tinyxml/tinystr.h \ opm/core/utility/parameters/tinyxml/tinystr.h \
opm/core/utility/parameters/tinyxml/tinyxml.h \ opm/core/utility/parameters/tinyxml/tinyxml.h \
opm/core/utility/writeVtkData.hpp \ opm/core/utility/writeVtkData.hpp \
opm/core/utility/DataMap.hpp \
opm/core/vag_format/vag.hpp \ opm/core/vag_format/vag.hpp \
opm/core/well.h \ opm/core/well.h \
opm/core/wells/InjectionSpecification.hpp \ opm/core/wells/InjectionSpecification.hpp \
@ -259,7 +277,7 @@ opm/core/wells/WellsManager.hpp
# Optional library constituents. # Optional library constituents.
if UMFPACK if UMFPACK
libopmcore_la_SOURCES += \ lib_libopmcore_la_SOURCES += \
opm/core/linalg/call_umfpack.c \ opm/core/linalg/call_umfpack.c \
opm/core/linalg/LinearSolverUmfpack.cpp opm/core/linalg/LinearSolverUmfpack.cpp
@ -269,16 +287,16 @@ opm/core/linalg/LinearSolverUmfpack.hpp
endif endif
if HAVE_ERT if HAVE_ERT
libopmcore_la_SOURCES += \ lib_libopmcore_la_SOURCES += \
opm/core/utility/writeECLData.cpp opm/core/utility/writeECLData.cpp
nobase_include_HEADERS += \ nobase_include_HEADERS += \
opm/core/utility/writeECLData.hpp opm/core/utility/writeECLData.hpp
endif endif
if DUNE_ISTL if DUNE_ISTL
libopmcore_la_SOURCES += \ lib_libopmcore_la_SOURCES += \
opm/core/linalg/LinearSolverIstl.cpp opm/core/linalg/LinearSolverIstl.cpp
nobase_include_HEADERS += \ nobase_include_HEADERS += \
@ -287,14 +305,19 @@ endif
if BUILD_AGMG if BUILD_AGMG
libopmcore_la_SOURCES += \ nodist_lib_libopmcore_la_SOURCES += \
$(AGMG_SRCDIR)/dagmg.f90 \ $(AGMG_SRCDIR)/dagmg.f90 \
$(AGMG_SRCDIR)/dagmg_mumps.f90 \ $(AGMG_SRCDIR)/dagmg_mumps.f90
lib_libopmcore_la_SOURCES += \
opm/core/linalg/LinearSolverAGMG.cpp opm/core/linalg/LinearSolverAGMG.cpp
nobase_include_HEADERS += \ nobase_include_HEADERS += \
opm/core/linalg/LinearSolverAGMG.hpp opm/core/linalg/LinearSolverAGMG.hpp
libopmcore_la_LDFLAGS += \ lib_libopmcore_la_LDFLAGS += \
$(FCLIBS) $(FCLIBS)
endif endif
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = lib/pkgconfig/opm-core.pc

103
README Normal file
View File

@ -0,0 +1,103 @@
Open Porous Media Core Library
==============================
These are release notes for opm-core.
CONTENT
-------
opm-core is the core library within OPM and contains the following
* 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)
LICENSE
-------
The library is distributed under the GNU General Public License,
version 3 or later (GPLv3+).
PLATFORMS
---------
The opm-core module is designed to run on Linux platforms. It is also
regularly run on Mac OS X. No efforts have been made to ensure that
the code will compile and run on windows platforms.
DEPENDENCIES FOR DEBIAN BASED DISTRIBUTIONS (Debian Squeeze/Ubuntu Precise)
---------------------------------------------------------------------------
# packages necessary for building
sudo apt-get install -y build-essential gfortran pkg-config libtool \
automake autoconf
# packages necessary for documentation
sudo apt-get install -y doxygen ghostscript texlive-latex-recommended pgf
# packages necessary for version control
sudo apt-get install -y git-core
# basic libraries necessary for both DUNE and OPM
sudo apt-get install -y libboost-all-dev libsuperlu3-dev libsuitesparse-dev
# add this repository for necessary backports (required for Ubuntu Precise)
sudo add-apt-repository -y ppa:opm/ppa
sudo apt-get update
# parts of DUNE needed
sudo apt-get install libdune-common-dev libdune-istl-dev
# libraries necessary for OPM
sudo apt-get install -y libxml0-dev
DEPENDENCIES FOR SUSE BASED DISTRIBUTIONS
-----------------------------------------
# libraries
sudo zypper in blas libblas3 lapack liblapack3 libboost libxml2 umfpack
# tools
sudo zypper in gcc automake autoconf git doxygen
# DUNE libraries
sudo zypper ar http://download.opensuse.org/repositories/science/openSUSE_12.2/science.repo
sudo zypper in dune-common dune-istl
DOWNLOADING
-----------
For a read-only download:
git clone git://github.com/OPM/opm-core.git
If you want to contribute, fork OPM/opm-core on github.
BUILDING
--------
cd opm-core
autoreconf -i
./configure
make
DOCUMENTATION
-------------
Efforts have been made to document the code with Doxygen.
In order to build the documentation, enter the command
$ doxygen
in the topmost directory.

View File

@ -2,12 +2,16 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ([2.59]) AC_PREREQ([2.59])
AC_INIT([OPM Core Library], [0.1], [atgeirr@sintef.no],dnl AC_INIT([OPM Core Library], [0.1], [atgeirr@sintef.no],
[opmcore], [https://public.ict.sintef.no/opm/hg/opmcore]) [opmcore], [https://public.ict.sintef.no/opm/hg/opmcore])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
# Needed for automake since version 1.12 because extra-portability
# warnings were then added to -Wall. Ifdef makes it backwards compatible.
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([opm/core/grid.h]) AC_CONFIG_SRCDIR([opm/core/grid.h])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
@ -16,8 +20,11 @@ AC_CONFIG_HEADERS([config.h])
AC_PROG_CC AC_PROG_CC
AM_PROG_CC_C_O AM_PROG_CC_C_O
dnl Initialize libtool; the funny indentation here is to
dnl satisfy libtoolize' check for the presence of this macro
m4_ifdef([LT_INIT], m4_ifdef([LT_INIT],
[LT_INIT[]dnl [
LT_INIT[]dnl
LT_LANG([C++])dnl LT_LANG([C++])dnl
LT_LANG([Fortran 77])dnl LT_LANG([Fortran 77])dnl
LT_LANG([Fortran])dnl LT_LANG([Fortran])dnl
@ -28,65 +35,29 @@ m4_ifdef([LT_INIT],
AC_PROG_FC[]dnl AC_PROG_FC[]dnl
])[]dnl ])[]dnl
# Checks for libraries. OPM_CORE_CHECKS
# Bring in numerics support (standard library component)
AC_SEARCH_LIBS([sqrt], [m])
OPM_LAPACK
AX_BOOST_BASE([1.37])
AX_BOOST_SYSTEM
AX_BOOST_DATE_TIME
AX_BOOST_FILESYSTEM
AX_BOOST_UNIT_TEST_FRAMEWORK
AX_DUNE_ISTL
OPM_AGMG
OPM_DYNLINK_BOOST_TEST OPM_DYNLINK_BOOST_TEST
# Checks for header files.
AC_CHECK_HEADERS([float.h limits.h stddef.h stdlib.h string.h])
AC_CHECK_HEADERS([suitesparse/umfpack.h],
[umfpack_header=yes],
[umfpack_header=no])
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_TYPE_SIZE_T
AC_CHECK_TYPES([ptrdiff_t])
# Checks for library functions.
AC_CHECK_FUNCS([floor memset memmove strchr strtol sqrt pow])
AC_FUNC_STRTOD
# Search for UMFPACK direct sparse solver.
AC_SEARCH_LIBS([amd_free], [amd])
AC_SEARCH_LIBS([camd_free], [camd])
AC_SEARCH_LIBS([colamd_set_defaults], [colamd])
AC_SEARCH_LIBS([ccolamd_set_defaults], [ccolamd])
AC_SEARCH_LIBS([cholmod_l_start], [cholmod])
AC_SEARCH_LIBS([umfpack_dl_solve], [umfpack],dnl
[umfpack_lib=yes], [umfpack_lib=no])
AM_CONDITIONAL([UMFPACK],
[test "x$umfpack_header" != "xno" -a "x$umfpack_lib" != "xno"])
m4_ifdef([AM_COND_IF],
[AM_COND_IF([UMFPACK], [],
[AC_MSG_NOTICE([Found no working installation of UMFPACK.
UMFPACK support is disabled.])])
])
ERT ERT
dnl Substitute Autoconf's abs_*dir variables into the Makefiles for the
dnl benefit of external code that uses these variables to derive
dnl locations (e.g., Dune's DUNE_CHECK_MODULES macro). Automakes prior
dnl to version 1.10 do not automatically substitute these variables into
dnl output files.
AC_SUBST([abs_srcdir])
AC_SUBST([abs_builddir])
AC_SUBST([abs_top_srcdir])
AC_SUBST([abs_top_builddir])
AC_CONFIG_FILES([ AC_CONFIG_FILES([
Makefile Makefile
tests/Makefile tests/Makefile
examples/Makefile examples/Makefile
tutorials/Makefile tutorials/Makefile
opm-core.pc
lib/pkgconfig/opm-core.pc
]) ])
AC_OUTPUT AC_OUTPUT

7
dune.module Normal file
View File

@ -0,0 +1,7 @@
#dune module information file#
##############################
#Name of the module
Module: opm-core
Version: 0.1
Maintainer: atgeirr@sintef.no

View File

@ -1,15 +1,15 @@
# Build-time flags needed to form example programs # Build-time flags needed to form example programs
ERT_INCLUDE_PATH = $(ERT_ROOT)/include ERT_INCLUDE_PATH = $(ERT_ROOT)/include
AM_CPPFLAGS = \ AM_CPPFLAGS = \
-I$(top_srcdir) \ -I$(top_srcdir) \
$(BOOST_CPPFLAGS) \ $(OPM_BOOST_CPPFLAGS) \
-I$(ERT_INCLUDE_PATH) -I$(ERT_INCLUDE_PATH)
# All targets link to the library # All targets link to the library
LDADD = \ LDADD = \
$(top_builddir)/libopmcore.la \ $(top_builddir)/lib/libopmcore.la \
$(BOOST_FILESYSTEM_LIB) \ $(BOOST_FILESYSTEM_LIB) \
$(BOOST_SYSTEM_LIB) $(BOOST_SYSTEM_LIB)
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
@ -17,11 +17,12 @@ $(BOOST_SYSTEM_LIB)
# #
# Please keep the list sorted. # Please keep the list sorted.
noinst_PROGRAMS = \ noinst_PROGRAMS = \
refine_wells \ refine_wells \
scaneclipsedeck \ scaneclipsedeck \
sim_2p_incomp_reorder \ sim_2p_comp_reorder \
sim_wateroil \ sim_2p_incomp_reorder \
sim_wateroil \
wells_example wells_example
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
@ -32,6 +33,7 @@ wells_example
# Please maintain sort order from "noinst_PROGRAMS". # Please maintain sort order from "noinst_PROGRAMS".
refine_wells_SOURCES = refine_wells.cpp refine_wells_SOURCES = refine_wells.cpp
sim_2p_comp_reorder_SOURCES = sim_2p_comp_reorder.cpp
sim_2p_incomp_reorder_SOURCES = sim_2p_incomp_reorder.cpp sim_2p_incomp_reorder_SOURCES = sim_2p_incomp_reorder.cpp
sim_wateroil_SOURCES = sim_wateroil.cpp sim_wateroil_SOURCES = sim_wateroil.cpp
wells_example_SOURCES = wells_example.cpp wells_example_SOURCES = wells_example.cpp
@ -43,7 +45,7 @@ if UMFPACK
noinst_PROGRAMS += spu_2p noinst_PROGRAMS += spu_2p
spu_2p_SOURCES = spu_2p.cpp spu_2p_SOURCES = spu_2p.cpp
spu_2p_LDADD = \ spu_2p_LDADD = \
$(LDADD) \ $(LDADD) \
$(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS)
endif endif

View File

@ -0,0 +1,284 @@
/*
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/GridManager.hpp>
#include <opm/core/newwells.h>
#include <opm/core/wells/WellsManager.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/utility/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/fluid/BlackoilPropertiesBasic.hpp>
#include <opm/core/fluid/BlackoilPropertiesFromDeck.hpp>
#include <opm/core/fluid/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 <boost/scoped_ptr.hpp>
#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)
{
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");
boost::scoped_ptr<EclipseGridParser> deck;
boost::scoped_ptr<GridManager> grid;
boost::scoped_ptr<BlackoilPropertiesInterface> props;
boost::scoped_ptr<RockCompressibility> rock_comp;
BlackoilState state;
// bool check_well_controls = false;
// int max_well_control_iterations = 0;
double gravity[3] = { 0.0 };
if (use_deck) {
std::string deck_filename = param.get<std::string>("deck_filename");
deck.reset(new EclipseGridParser(deck_filename));
// Grid init
grid.reset(new GridManager(*deck));
// Rock and fluid init
props.reset(new BlackoilPropertiesFromDeck(*deck, *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));
// Gravity.
gravity[2] = deck->hasField("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 (...) {
THROW("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"
<< " (number of epochs: "
<< (use_deck ? deck->numberOfEpochs() : 1) << ")\n\n" << std::flush;
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.
deck->setCurrentEpoch(deck->numberOfEpochs() - 1);
simtimer.init(*deck);
const double total_time = simtimer.totalTime();
for (int epoch = 0; epoch < deck->numberOfEpochs(); ++epoch) {
// Set epoch index.
deck->setCurrentEpoch(epoch);
// Update the timer.
if (deck->hasField("TSTEP")) {
simtimer.init(*deck);
} else {
if (epoch != 0) {
THROW("No TSTEP in deck for epoch " << epoch);
}
simtimer.init(param);
}
simtimer.setCurrentStepNum(step);
simtimer.setTotalTime(total_time);
// Report on start of epoch.
std::cout << "\n\n-------------- Starting epoch " << epoch << " --------------"
<< "\n (number of steps: "
<< simtimer.numSteps() - step << ")\n\n" << std::flush;
// Create new wells, well_state
WellsManager wells(*deck, *grid->c_grid(), props->permeability());
// @@@ HACK: we should really make a new well state and
// properly transfer old well state to it every epoch,
// since number of wells may change etc.
if (epoch == 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 (epoch == 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);
}
}

View File

@ -43,9 +43,10 @@
#include <opm/core/simulator/TwophaseState.hpp> #include <opm/core/simulator/TwophaseState.hpp>
#include <opm/core/simulator/WellState.hpp> #include <opm/core/simulator/WellState.hpp>
#include <opm/core/simulator/SimulatorTwophase.hpp> #include <opm/core/simulator/SimulatorIncompTwophase.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/filesystem.hpp>
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
@ -53,6 +54,18 @@
#include <numeric> #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 ----------------- // ----------------- Main program -----------------
@ -81,9 +94,7 @@ main(int argc, char** argv)
// Grid init // Grid init
grid.reset(new GridManager(*deck)); grid.reset(new GridManager(*deck));
// Rock and fluid init // Rock and fluid init
const int* gc = grid->c_grid()->global_cell; props.reset(new IncompPropertiesFromDeck(*deck, *grid->c_grid()));
std::vector<int> global_cell(gc, gc + grid->c_grid()->number_of_cells);
props.reset(new IncompPropertiesFromDeck(*deck, global_cell));
// check_well_controls = param.getDefault("check_well_controls", false); // check_well_controls = param.getDefault("check_well_controls", false);
// max_well_control_iterations = param.getDefault("max_well_control_iterations", 10); // max_well_control_iterations = param.getDefault("max_well_control_iterations", 10);
// Rock compressibility. // Rock compressibility.
@ -157,17 +168,28 @@ main(int argc, char** argv)
// Linear solver. // Linear solver.
LinearSolverFactory linsolver(param); LinearSolverFactory linsolver(param);
// Warn if any parameters are unused.
// if (param.anyUnused()) {
// std::cout << "-------------------- Unused parameters: --------------------\n";
// param.displayUsage();
// std::cout << "----------------------------------------------------------------" << std::endl;
// }
// Write parameters used for later reference. // Write parameters used for later reference.
// if (output) { bool output = param.getDefault("output", true);
// param.writeParam(output_dir + "/spu_2p.param"); 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 (...) {
THROW("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" std::cout << "\n\n================ Starting main simulation loop ===============\n"
@ -177,17 +199,19 @@ main(int argc, char** argv)
SimulatorReport rep; SimulatorReport rep;
if (!use_deck) { if (!use_deck) {
// Simple simulation without a deck. // Simple simulation without a deck.
SimulatorTwophase simulator(param, WellsManager wells; // no wells.
*grid->c_grid(), SimulatorIncompTwophase simulator(param,
*props, *grid->c_grid(),
rock_comp->isActive() ? rock_comp.get() : 0, *props,
0, // wells rock_comp->isActive() ? rock_comp.get() : 0,
src, wells,
bcs.c_bcs(), src,
linsolver, bcs.c_bcs(),
grav); linsolver,
grav);
SimulatorTimer simtimer; SimulatorTimer simtimer;
simtimer.init(param); simtimer.init(param);
warnIfUnusedParams(param);
WellState well_state; WellState well_state;
well_state.init(0, state); well_state.init(0, state);
rep = simulator.run(simtimer, state, well_state); rep = simulator.run(simtimer, state, well_state);
@ -221,7 +245,7 @@ main(int argc, char** argv)
<< "\n (number of steps: " << "\n (number of steps: "
<< simtimer.numSteps() - step << ")\n\n" << std::flush; << simtimer.numSteps() - step << ")\n\n" << std::flush;
// Create new wells, well_satate // Create new wells, well_state
WellsManager wells(*deck, *grid->c_grid(), props->permeability()); WellsManager wells(*deck, *grid->c_grid(), props->permeability());
// @@@ HACK: we should really make a new well state and // @@@ HACK: we should really make a new well state and
// properly transfer old well state to it every epoch, // properly transfer old well state to it every epoch,
@ -231,17 +255,22 @@ main(int argc, char** argv)
} }
// Create and run simulator. // Create and run simulator.
SimulatorTwophase simulator(param, SimulatorIncompTwophase simulator(param,
*grid->c_grid(), *grid->c_grid(),
*props, *props,
rock_comp->isActive() ? rock_comp.get() : 0, rock_comp->isActive() ? rock_comp.get() : 0,
wells.c_wells(), wells,
src, src,
bcs.c_bcs(), bcs.c_bcs(),
linsolver, linsolver,
grav); grav);
if (epoch == 0) {
warnIfUnusedParams(param);
}
SimulatorReport epoch_rep = simulator.run(simtimer, state, well_state); SimulatorReport epoch_rep = simulator.run(simtimer, state, well_state);
if (output) {
epoch_rep.reportParam(epoch_os);
}
// Update total timing report and remember step number. // Update total timing report and remember step number.
rep += epoch_rep; rep += epoch_rep;
step = simtimer.currentStepNum(); step = simtimer.currentStepNum();
@ -250,4 +279,11 @@ main(int argc, char** argv)
std::cout << "\n\n================ End of simulation ===============\n\n"; std::cout << "\n\n================ End of simulation ===============\n\n";
rep.report(std::cout); 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);
}
} }

View File

@ -68,8 +68,6 @@
#include <vector> #include <vector>
#include <numeric> #include <numeric>
#define TRANSPORT_SOLVER_FIXED 1
template <class State> template <class State>
static void outputState(const UnstructuredGrid& grid, static void outputState(const UnstructuredGrid& grid,
@ -143,7 +141,6 @@ main(int argc, char** argv)
std::cout << "--------------- Reading parameters ---------------" << std::endl; std::cout << "--------------- Reading parameters ---------------" << std::endl;
// Reading various control parameters. // Reading various control parameters.
const bool use_reorder = param.getDefault("use_reorder", true);
const bool output = param.getDefault("output", true); const bool output = param.getDefault("output", true);
std::string output_dir; std::string output_dir;
int output_interval = 1; int output_interval = 1;
@ -178,9 +175,7 @@ main(int argc, char** argv)
// Grid init // Grid init
grid.reset(new Opm::GridManager(deck)); grid.reset(new Opm::GridManager(deck));
// Rock and fluid init // Rock and fluid init
const int* gc = grid->c_grid()->global_cell; props.reset(new BlackoilPropertiesFromDeck(deck, *grid->c_grid(), param));
std::vector<int> global_cell(gc, gc + grid->c_grid()->number_of_cells);
props.reset(new Opm::BlackoilPropertiesFromDeck(deck, global_cell));
// Wells init. // Wells init.
wells.reset(new Opm::WellsManager(deck, *grid->c_grid(), props->permeability())); wells.reset(new Opm::WellsManager(deck, *grid->c_grid(), props->permeability()));
check_well_controls = param.getDefault("check_well_controls", false); check_well_controls = param.getDefault("check_well_controls", false);
@ -233,28 +228,8 @@ main(int argc, char** argv)
} }
} }
bool use_segregation_split = false; bool use_segregation_split = false;
bool use_column_solver = false; if (use_gravity) {
bool use_gauss_seidel_gravity = false;
if (use_gravity && use_reorder) {
use_segregation_split = param.getDefault("use_segregation_split", use_segregation_split); use_segregation_split = param.getDefault("use_segregation_split", use_segregation_split);
if (use_segregation_split) {
use_column_solver = param.getDefault("use_column_solver", use_column_solver);
if (use_column_solver) {
use_gauss_seidel_gravity = param.getDefault("use_gauss_seidel_gravity", use_gauss_seidel_gravity);
}
}
}
// Check that rock compressibility is not used with solvers that do not handle it.
// int nl_pressure_maxiter = 0;
// double nl_pressure_tolerance = 0.0;
if (rock_comp->isActive()) {
THROW("No rock compressibility in comp. pressure solver yet.");
if (!use_reorder) {
THROW("Cannot run implicit (non-reordering) transport solver with rock compressibility yet.");
}
// nl_pressure_maxiter = param.getDefault("nl_pressure_maxiter", 10);
// nl_pressure_tolerance = param.getDefault("nl_pressure_tolerance", 1.0); // in Pascal
} }
// Source-related variables init. // Source-related variables init.
@ -266,11 +241,11 @@ main(int argc, char** argv)
// Extra rock init. // Extra rock init.
std::vector<double> porevol; std::vector<double> porevol;
if (rock_comp->isActive()) { if (rock_comp->isActive()) {
THROW("CompressibleTpfa solver does not handle this.");
computePorevolume(*grid->c_grid(), props->porosity(), *rock_comp, state.pressure(), porevol); computePorevolume(*grid->c_grid(), props->porosity(), *rock_comp, state.pressure(), porevol);
} else { } else {
computePorevolume(*grid->c_grid(), props->porosity(), porevol); computePorevolume(*grid->c_grid(), props->porosity(), porevol);
} }
std::vector<double> initial_porevol = porevol;
double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0); double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
@ -297,21 +272,20 @@ main(int argc, char** argv)
const double nl_press_change_tol = param.getDefault("nl_press_change_tol", 10.0); const double nl_press_change_tol = param.getDefault("nl_press_change_tol", 10.0);
const int nl_press_maxiter = param.getDefault("nl_press_maxiter", 20); const int nl_press_maxiter = param.getDefault("nl_press_maxiter", 20);
const double *grav = use_gravity ? &gravity[0] : 0; const double *grav = use_gravity ? &gravity[0] : 0;
Opm::CompressibleTpfa psolver(*grid->c_grid(), *props, linsolver, Opm::CompressibleTpfa psolver(*grid->c_grid(), *props, rock_comp.get(), linsolver,
nl_press_res_tol, nl_press_change_tol, nl_press_maxiter, nl_press_res_tol, nl_press_change_tol, nl_press_maxiter,
grav, wells->c_wells()); grav, wells->c_wells());
// Reordering solver. // Reordering solver.
#if TRANSPORT_SOLVER_FIXED
const double nl_tolerance = param.getDefault("nl_tolerance", 1e-9); const double nl_tolerance = param.getDefault("nl_tolerance", 1e-9);
const int nl_maxiter = param.getDefault("nl_maxiter", 30); const int nl_maxiter = param.getDefault("nl_maxiter", 30);
Opm::TransportModelCompressibleTwophase reorder_model(*grid->c_grid(), *props, nl_tolerance, nl_maxiter); Opm::TransportModelCompressibleTwophase reorder_model(*grid->c_grid(), *props, nl_tolerance, nl_maxiter);
if (use_gauss_seidel_gravity) { if (use_segregation_split) {
reorder_model.initGravity(grav); reorder_model.initGravity(grav);
} }
#endif // TRANSPORT_SOLVER_FIXED
// Column-based gravity segregation solver. // Column-based gravity segregation solver.
std::vector<std::vector<int> > columns; std::vector<std::vector<int> > columns;
if (use_column_solver) { if (use_segregation_split) {
Opm::extractColumn(*grid->c_grid(), columns); Opm::extractColumn(*grid->c_grid(), columns);
} }
@ -414,24 +388,30 @@ main(int argc, char** argv)
Opm::computeTransportSource(*grid->c_grid(), src, state.faceflux(), 1.0, Opm::computeTransportSource(*grid->c_grid(), src, state.faceflux(), 1.0,
wells->c_wells(), well_state.perfRates(), reorder_src); wells->c_wells(), well_state.perfRates(), reorder_src);
// Compute new porevolumes after pressure solve, if necessary.
if (rock_comp->isActive()) {
initial_porevol = porevol;
computePorevolume(*grid->c_grid(), props->porosity(), *rock_comp, state.pressure(), porevol);
}
// Solve transport. // Solve transport.
transport_timer.start(); transport_timer.start();
#if TRANSPORT_SOLVER_FIXED
double stepsize = simtimer.currentStepLength(); double stepsize = simtimer.currentStepLength();
if (num_transport_substeps != 1) { if (num_transport_substeps != 1) {
stepsize /= double(num_transport_substeps); stepsize /= double(num_transport_substeps);
std::cout << "Making " << num_transport_substeps << " transport substeps." << std::endl; std::cout << "Making " << num_transport_substeps << " transport substeps." << std::endl;
} }
for (int tr_substep = 0; tr_substep < num_transport_substeps; ++tr_substep) { for (int tr_substep = 0; tr_substep < num_transport_substeps; ++tr_substep) {
reorder_model.solve(&state.faceflux()[0], &state.pressure()[0], &state.surfacevol()[0], // Note that for now we do not handle rock compressibility,
&porevol[0], &reorder_src[0], stepsize, state.saturation()); // although the transport solver should be able to.
reorder_model.solve(&state.faceflux()[0], &state.pressure()[0],
&porevol[0], &initial_porevol[0], &reorder_src[0], stepsize,
state.saturation(), state.surfacevol());
// Opm::computeInjectedProduced(*props, state.saturation(), reorder_src, stepsize, injected, produced); // Opm::computeInjectedProduced(*props, state.saturation(), reorder_src, stepsize, injected, produced);
if (use_segregation_split) { if (use_segregation_split) {
THROW("Segregation not implemented yet."); reorder_model.solveGravity(columns,
// reorder_model.solveGravity(columns, &porevol[0], stepsize, state.saturation()); stepsize, state.saturation(), state.surfacevol());
} }
} }
#endif // TRANSPORT_SOLVER_FIXED
transport_timer.stop(); transport_timer.stop();
double tt = transport_timer.secsSinceStart(); double tt = transport_timer.secsSinceStart();
std::cout << "Transport solver took: " << tt << " seconds." << std::endl; std::cout << "Transport solver took: " << tt << " seconds." << std::endl;

View File

@ -317,9 +317,7 @@ main(int argc, char** argv)
// Grid init // Grid init
grid.reset(new Opm::GridManager(deck)); grid.reset(new Opm::GridManager(deck));
// Rock and fluid init // Rock and fluid init
const int* gc = grid->c_grid()->global_cell; props.reset(new Opm::IncompPropertiesFromDeck(deck, *grid->c_grid()));
std::vector<int> global_cell(gc, gc + grid->c_grid()->number_of_cells);
props.reset(new Opm::IncompPropertiesFromDeck(deck, global_cell));
// Wells init. // Wells init.
wells.reset(new Opm::WellsManager(deck, *grid->c_grid(), props->permeability())); wells.reset(new Opm::WellsManager(deck, *grid->c_grid(), props->permeability()));
check_well_controls = param.getDefault("check_well_controls", false); check_well_controls = param.getDefault("check_well_controls", false);
@ -503,7 +501,7 @@ main(int argc, char** argv)
// Write parameters used for later reference. // Write parameters used for later reference.
if (output) { if (output) {
param.writeParam(output_dir + "/spu_2p.param"); param.writeParam(output_dir + "/simulation.param");
} }
// Main simulation loop. // Main simulation loop.

View File

@ -38,10 +38,8 @@ int main(int argc, char** argv)
// Finally handle the wells // Finally handle the wells
WellsManager wells(parser, *grid.c_grid(), NULL); WellsManager wells(parser, *grid.c_grid(), NULL);
std::vector<int> global_cells(grid.c_grid()->global_cell, grid.c_grid()->global_cell + grid.c_grid()->number_of_cells);
double gravity[3] = {0.0, 0.0, parameters.getDefault<double>("gravity", 0.0)}; double gravity[3] = {0.0, 0.0, parameters.getDefault<double>("gravity", 0.0)};
IncompPropertiesFromDeck incomp_properties(parser, global_cells); IncompPropertiesFromDeck incomp_properties(parser, *grid.c_grid());
RockCompressibility rock_comp(parser); RockCompressibility rock_comp(parser);

View File

@ -1,6 +1,24 @@
# This script generate the illustration pictures for the documentation.
#
# To run this script, you have to install paraview, see:
#
# http://www.paraview.org/paraview/resources/software.php
#
# Eventually, set up the paths (figure_path, tutorial_data_path, tutorial_path) according to your own installation.
# (The default values should be ok.)
#
# Make sure that pvpython is in your path of executables.
#
# Run the following command at the root of the directory where
# opm-core is installed (which also corresponds to the directory where
# generate_doc_figures is located):
#
# pvpython generate_doc_figures.py
#
from subprocess import call from subprocess import call
from paraview.simple import * from paraview.simple import *
# from paraview import servermanager
from os import remove, mkdir, curdir from os import remove, mkdir, curdir
from os.path import join, isdir from os.path import join, isdir
@ -13,7 +31,6 @@ collected_garbage_file = []
if not isdir(figure_path): if not isdir(figure_path):
mkdir(figure_path) mkdir(figure_path)
# connection = servermanager.Connect()
# tutorial 1 # tutorial 1
call(join(tutorial_path, "tutorial1")) call(join(tutorial_path, "tutorial1"))

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: @PACKAGE_NAME@
Description: @PACKAGE_STRING@
Version: @PACKAGE_VERSION@
URL: @PACKAGE_URL@
Libs: -L${libdir} -l@PACKAGE@
Cflags: -I${includedir}

View File

@ -11,10 +11,14 @@ AC_DEFUN([OPM_AGMG],dnl
[AS_IF([test -f "$with_agmg/dagmg.f90"],dnl [AS_IF([test -f "$with_agmg/dagmg.f90"],dnl
[AC_SUBST([AGMG_SRCDIR], [$with_agmg])[]dnl [AC_SUBST([AGMG_SRCDIR], [$with_agmg])[]dnl
AC_DEFINE([HAVE_AGMG], [1],dnl AC_DEFINE([HAVE_AGMG], [1],dnl
[Define to `1' if Notay's AGMG solver is included])[]dnl [Define to 1 if Notay's AGMG solver is included.])[]dnl
build_agmg="yes"],dnl build_agmg="yes"],dnl
[build_agmg="no"])],dnl [AC_DEFINE([HAVE_AGMG], [0],dnl
[build_agmg="no"])[]dnl [Define to 0 if Notay's AGMG solver is unavailable.])[]dnl
build_agmg="no"])],dnl
[AC_DEFINE([HAVE_AGMG], [0],dnl
[Define to 0 if Notay's AGMG solver is unwanted.])[]dnl
build_agmg="no"])[]dnl
AS_IF([test x"$build_agmg" = x"yes"],dnl AS_IF([test x"$build_agmg" = x"yes"],dnl
[AC_PROG_FC_C_O[]dnl [AC_PROG_FC_C_O[]dnl

View File

@ -55,11 +55,11 @@ AC_DEFUN([AX_BOOST_DATE_TIME],
if test "x$want_boost" = "xyes"; then if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_CC])
CPPFLAGS_SAVED="$CPPFLAGS" CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" CPPFLAGS="$CPPFLAGS $OPM_BOOST_CPPFLAGS"
export CPPFLAGS export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS" LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" LDFLAGS="$LDFLAGS $OPM_BOOST_LDFLAGS"
export LDFLAGS export LDFLAGS
AC_CACHE_CHECK(whether the Boost::Date_Time library is available, AC_CACHE_CHECK(whether the Boost::Date_Time library is available,
@ -74,7 +74,7 @@ AC_DEFUN([AX_BOOST_DATE_TIME],
]) ])
if test "x$ax_cv_boost_date_time" = "xyes"; then if test "x$ax_cv_boost_date_time" = "xyes"; then
AC_DEFINE(HAVE_BOOST_DATE_TIME,,[define if the Boost::Date_Time library is available]) AC_DEFINE(HAVE_BOOST_DATE_TIME,,[define if the Boost::Date_Time library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` BOOSTLIBDIR=`echo $OPM_BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
ax_lib="-lboost_date_time" ax_lib="-lboost_date_time"
if test "x$ax_boost_user_date_time_lib" = "x"; then if test "x$ax_boost_user_date_time_lib" = "x"; then

View File

@ -56,11 +56,11 @@ AC_DEFUN([AX_BOOST_FILESYSTEM],
if test "x$want_boost" = "xyes"; then if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_CC])
CPPFLAGS_SAVED="$CPPFLAGS" CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" CPPFLAGS="$CPPFLAGS $OPM_BOOST_CPPFLAGS"
export CPPFLAGS export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS" LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" LDFLAGS="$LDFLAGS $OPM_BOOST_LDFLAGS"
export LDFLAGS export LDFLAGS
LIBS_SAVED=$LIBS LIBS_SAVED=$LIBS
@ -79,7 +79,7 @@ AC_DEFUN([AX_BOOST_FILESYSTEM],
]) ])
if test "x$ax_cv_boost_filesystem" = "xyes"; then if test "x$ax_cv_boost_filesystem" = "xyes"; then
AC_DEFINE(HAVE_BOOST_FILESYSTEM,,[define if the Boost::Filesystem library is available]) AC_DEFINE(HAVE_BOOST_FILESYSTEM,,[define if the Boost::Filesystem library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` BOOSTLIBDIR=`echo $OPM_BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
ax_lib="-lboost_filesystem" ax_lib="-lboost_filesystem"
if test "x$ax_boost_user_filesystem_lib" = "x"; then if test "x$ax_boost_user_filesystem_lib" = "x"; then
for libextension in `ls $BOOSTLIBDIR/libboost_filesystem*.so* $BOOSTLIBDIR/libboost_filesystem*.dylib* $BOOSTLIBDIR/libboost_filesystem*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_filesystem.*\)\.so.*$;\1;' -e 's;^lib\(boost_filesystem.*\)\.a*$;\1;' -e 's;^lib\(boost_filesystem.*\)\.dylib$;\1;'` ; do for libextension in `ls $BOOSTLIBDIR/libboost_filesystem*.so* $BOOSTLIBDIR/libboost_filesystem*.dylib* $BOOSTLIBDIR/libboost_filesystem*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_filesystem.*\)\.so.*$;\1;' -e 's;^lib\(boost_filesystem.*\)\.a*$;\1;' -e 's;^lib\(boost_filesystem.*\)\.dylib$;\1;'` ; do

View File

@ -57,11 +57,11 @@ AC_DEFUN([AX_BOOST_SYSTEM],
AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_BUILD]) AC_REQUIRE([AC_CANONICAL_BUILD])
CPPFLAGS_SAVED="$CPPFLAGS" CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" CPPFLAGS="$CPPFLAGS $OPM_BOOST_CPPFLAGS"
export CPPFLAGS export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS" LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" LDFLAGS="$LDFLAGS $OPM_BOOST_LDFLAGS"
export LDFLAGS export LDFLAGS
AC_CACHE_CHECK(whether the Boost::System library is available, AC_CACHE_CHECK(whether the Boost::System library is available,
@ -76,10 +76,10 @@ AC_DEFUN([AX_BOOST_SYSTEM],
AC_LANG_POP([C++]) AC_LANG_POP([C++])
]) ])
if test "x$ax_cv_boost_system" = "xyes"; then if test "x$ax_cv_boost_system" = "xyes"; then
AC_SUBST(BOOST_CPPFLAGS) AC_SUBST(OPM_BOOST_CPPFLAGS)
AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available]) AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` BOOSTLIBDIR=`echo $OPM_BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
ax_lib="-lboost_system" ax_lib="-lboost_system"
LDFLAGS_SAVE=$LDFLAGS LDFLAGS_SAVE=$LDFLAGS

View File

@ -54,11 +54,11 @@ AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK],
if test "x$want_boost" = "xyes"; then if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_CC])
CPPFLAGS_SAVED="$CPPFLAGS" CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" CPPFLAGS="$CPPFLAGS $OPM_BOOST_CPPFLAGS"
export CPPFLAGS export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS" LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" LDFLAGS="$LDFLAGS $OPM_BOOST_LDFLAGS"
export LDFLAGS export LDFLAGS
AC_CACHE_CHECK(whether the Boost::Unit_Test_Framework library is available, AC_CACHE_CHECK(whether the Boost::Unit_Test_Framework library is available,
@ -72,7 +72,7 @@ AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK],
]) ])
if test "x$ax_cv_boost_unit_test_framework" = "xyes"; then if test "x$ax_cv_boost_unit_test_framework" = "xyes"; then
AC_DEFINE(HAVE_BOOST_UNIT_TEST_FRAMEWORK,,[define if the Boost::Unit_Test_Framework library is available]) AC_DEFINE(HAVE_BOOST_UNIT_TEST_FRAMEWORK,,[define if the Boost::Unit_Test_Framework library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` BOOSTLIBDIR=`echo $OPM_BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
ax_lib="-lboost_unit_test_framework" ax_lib="-lboost_unit_test_framework"
if test "x$ax_boost_user_unit_test_framework_lib" = "x"; then if test "x$ax_boost_user_unit_test_framework_lib" = "x"; then

View File

@ -31,7 +31,9 @@ AC_DEFUN([AX_DUNE_ISTL],
"x$ax_cv_dune_common_available" = "xyes"],dnl "x$ax_cv_dune_common_available" = "xyes"],dnl
[AC_DEFINE([HAVE_DUNE_ISTL], [1],dnl [AC_DEFINE([HAVE_DUNE_ISTL], [1],dnl
[Define to 1 if `dune-istl' is available]) [Define to 1 if `dune-istl' is available])
])[]dnl ],dnl
[AC_DEFINE([HAVE_DUNE_ISTL], [0],dnl
[Define to 0 if `dune-istl' is unavailable.])])[]dnl
AM_CONDITIONAL([DUNE_ISTL], AM_CONDITIONAL([DUNE_ISTL],
[test "x$ax_cv_dune_istl_available" = "xyes" -a \ [test "x$ax_cv_dune_istl_available" = "xyes" -a \

View File

@ -4,7 +4,7 @@
# #
# SYNOPSIS # SYNOPSIS
# #
# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # OPM_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# #
# DESCRIPTION # DESCRIPTION
# #
@ -17,11 +17,11 @@
# #
# This macro calls: # This macro calls:
# #
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) # AC_SUBST(OPM_BOOST_CPPFLAGS) / AC_SUBST(OPM_BOOST_LDFLAGS)
# #
# And sets: # And sets:
# #
# HAVE_BOOST # OPM_HAVE_BOOST
# #
# LICENSE # LICENSE
# #
@ -35,7 +35,7 @@
#serial 20 #serial 20
AC_DEFUN([AX_BOOST_BASE], AC_DEFUN([OPM_BOOST_BASE],
[ [
AC_ARG_WITH([boost], AC_ARG_WITH([boost],
[AS_HELP_STRING([--with-boost@<:@=ARG@:>@], [AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
@ -99,10 +99,10 @@ if test "x$want_boost" = "xyes"; then
dnl this location ist chosen if boost libraries are installed with the --layout=system option dnl this location ist chosen if boost libraries are installed with the --layout=system option
dnl or if you install boost with RPM dnl or if you install boost with RPM
if test "$ac_boost_path" != ""; then if test "$ac_boost_path" != ""; then
BOOST_CPPFLAGS="-I$ac_boost_path/include" OPM_BOOST_CPPFLAGS="-I$ac_boost_path/include"
for ac_boost_path_tmp in $libsubdirs; do for ac_boost_path_tmp in $libsubdirs; do
if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then
BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp" OPM_BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp"
break break
fi fi
done done
@ -112,8 +112,8 @@ if test "x$want_boost" = "xyes"; then
for libsubdir in $libsubdirs ; do for libsubdir in $libsubdirs ; do
if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done done
BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir" OPM_BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir"
BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" OPM_BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
break; break;
fi fi
done done
@ -122,15 +122,15 @@ if test "x$want_boost" = "xyes"; then
dnl overwrite ld flags if we have required special directory with dnl overwrite ld flags if we have required special directory with
dnl --with-boost-libdir parameter dnl --with-boost-libdir parameter
if test "$ac_boost_lib_path" != ""; then if test "$ac_boost_lib_path" != ""; then
BOOST_LDFLAGS="-L$ac_boost_lib_path" OPM_BOOST_LDFLAGS="-L$ac_boost_lib_path"
fi fi
CPPFLAGS_SAVED="$CPPFLAGS" CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" CPPFLAGS="$CPPFLAGS $OPM_BOOST_CPPFLAGS"
export CPPFLAGS export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS" LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" LDFLAGS="$LDFLAGS $OPM_BOOST_LDFLAGS"
export LDFLAGS export LDFLAGS
AC_REQUIRE([AC_PROG_CXX]) AC_REQUIRE([AC_PROG_CXX])
@ -166,7 +166,7 @@ if test "x$want_boost" = "xyes"; then
_version=$_version_tmp _version=$_version_tmp
fi fi
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" OPM_BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
done done
fi fi
else else
@ -185,12 +185,12 @@ if test "x$want_boost" = "xyes"; then
done done
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" OPM_BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
if test "$ac_boost_lib_path" = ""; then if test "$ac_boost_lib_path" = ""; then
for libsubdir in $libsubdirs ; do for libsubdir in $libsubdirs ; do
if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done done
BOOST_LDFLAGS="-L$best_path/$libsubdir" OPM_BOOST_LDFLAGS="-L$best_path/$libsubdir"
fi fi
fi fi
@ -205,16 +205,16 @@ if test "x$want_boost" = "xyes"; then
V_CHECK=`expr $stage_version_shorten \>\= $_version` V_CHECK=`expr $stage_version_shorten \>\= $_version`
if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
BOOST_CPPFLAGS="-I$BOOST_ROOT" OPM_BOOST_CPPFLAGS="-I$BOOST_ROOT"
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir" OPM_BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
fi fi
fi fi
fi fi
fi fi
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" CPPFLAGS="$CPPFLAGS $OPM_BOOST_CPPFLAGS"
export CPPFLAGS export CPPFLAGS
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" LDFLAGS="$LDFLAGS $OPM_BOOST_LDFLAGS"
export LDFLAGS export LDFLAGS
AC_LANG_PUSH(C++) AC_LANG_PUSH(C++)
@ -243,10 +243,12 @@ if test "x$want_boost" = "xyes"; then
fi fi
# execute ACTION-IF-NOT-FOUND (if present): # execute ACTION-IF-NOT-FOUND (if present):
ifelse([$3], , :, [$3]) ifelse([$3], , :, [$3])
AC_DEFINE([OPM_HAVE_BOOST], [0],dnl
[Define to `0' if the Boost library is not available])
else else
AC_SUBST(BOOST_CPPFLAGS) AC_SUBST([OPM_BOOST_CPPFLAGS])
AC_SUBST(BOOST_LDFLAGS) AC_SUBST([OPM_BOOST_LDFLAGS])
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) AC_DEFINE([OPM_HAVE_BOOST], [1], [define if the Boost library is available])
# execute ACTION-IF-FOUND (if present): # execute ACTION-IF-FOUND (if present):
ifelse([$2], , :, [$2]) ifelse([$2], , :, [$2])
fi fi

66
m4/opm_core.m4 Normal file
View File

@ -0,0 +1,66 @@
dnl -*- autoconf -*-
# Macros needed to find OPM-core and dependent libraries. They are called by
# the macros in ${top_src_dir}/dependencies.m4, which is generated by
# "dunecontrol autogen"
AC_DEFUN([OPM_CORE_CHECKS],
[
# Checks for libraries.
# Bring in numerics support (standard library component)
AC_SEARCH_LIBS([sqrt], [m])
OPM_LAPACK
OPM_BOOST_BASE([1.37])
AX_BOOST_SYSTEM
AX_BOOST_DATE_TIME
AX_BOOST_FILESYSTEM
AX_BOOST_UNIT_TEST_FRAMEWORK
AX_DUNE_ISTL
OPM_AGMG
# Checks for header files.
AC_CHECK_HEADERS([float.h limits.h stddef.h stdlib.h string.h])
AC_CHECK_HEADERS([suitesparse/umfpack.h],
[umfpack_header=yes],
[umfpack_header=no])
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_TYPE_SIZE_T
AC_CHECK_TYPES([ptrdiff_t])
# Checks for library functions.
AC_CHECK_FUNCS([floor memset memmove strchr strtol sqrt pow])
AC_FUNC_STRTOD
# Search for UMFPACK direct sparse solver.
AC_SEARCH_LIBS([amd_free], [amd])
AC_SEARCH_LIBS([camd_free], [camd])
AC_SEARCH_LIBS([colamd_set_defaults], [colamd])
AC_SEARCH_LIBS([ccolamd_set_defaults], [ccolamd])
AC_SEARCH_LIBS([cholmod_l_start], [cholmod])
AC_SEARCH_LIBS([umfpack_dl_solve], [umfpack],dnl
[umfpack_lib=yes], [umfpack_lib=no])
AM_CONDITIONAL([UMFPACK],
[test "x$umfpack_header" != "xno" -a "x$umfpack_lib" != "xno"])
m4_ifdef([AM_COND_IF],
[AM_COND_IF([UMFPACK], [],
[AC_MSG_NOTICE([Found no working installation of UMFPACK.
UMFPACK support is disabled.])])
])
])
# Additional checks needed to find eWoms
# This macro should be invoked by every module which depends on dumux, but
# not by dumux itself
AC_DEFUN([OPM_CORE_CHECK_MODULE],
[
OPM_CORE_CHECK_MODULES([opm-core],[opm/core/grid.h],[create_grid_empty()])
])

View File

@ -0,0 +1,281 @@
dnl -*- autoconf -*-
# OPM_CORE_CHECK_MODULES(NAME, HEADER, SYMBOL)
#
# THIS MACRO IS JUST A COPY OF DUNE_CHECK_MODULES WITH THE REQUIREMENT
# THAT ALL HEADERS MUST RESIDE IN $MODULE_ROOT/dune REMOVED. REMOVE
# THIS MACRO AS SOON AS DUNE DOES NOT ENFORCE THIS ANYMORE.
#
# Generic check for dune modules. This macro should not be used directly, but
# in the modules m4/{module}.m4 in the {MODULE}_CHECK_MODULE macro. The
# {MODULE}_CHECK_MODULE macro knows the parameters to call this
# DUNE_CHECK_MODULES macro with, and it does not take any parameters itself,
# so it may be used with AC_REQUIRE.
#
# NAME Name of the module, lowercase with dashes (like "dune-common"). The
# value must be known when autoconf runs, so shell variables in the
# value are not permissible.
#
# HEADER Header to check for. The check will really be for <dune/{HEADER}>,
# so the header must reside within a directory called "dune".
#
# SYMBOL Symbol to check for in the module's library. If this argument is
# empty or missing, it is assumed that the module does not provide a
# library. The value must be known when autoconf runs, so shell
# variables in the value are not permissible. This value is actually
# handed to AC_TRY_LINK unchanged as the FUNCTION-BODY argument, so it
# may contain more complex stuff than a simple symbol.
#
# The name of the library is assumed to be the same as the module name,
# with any occurance of "-" removed. The path of the library is
# obtained from pkgconfig for installed modules, or assumed to be the
# directory "lib" within the modules root for non-installed modules.
#
# In the following, {module} is {NAME} with any "-" replaced by "_" and
# {MODULE} is the uppercase version of {module}.
#
# configure options:
# --with-{NAME}
#
# configure/shell variables:
# {MODULE}_ROOT, {MODULE}_LIBDIR
# HAVE_{MODULE} (1 or 0)
# with_{module} ("yes" or "no")
# DUNE_CPPFLAGS, DUNE_LDFLAGS, DUNE_LIBS (adds the modules values here,
# substitution done by DUNE_CHECK_ALL)
# ALL_PKG_CPPFLAGS, ALL_PKG_LDFLAGS, ALL_PKG_LIBS (adds the modules values
# here, substitution done by DUNE_CHECK_ALL)
# {MODULE}_VERSION
# {MODULE}_VERSION_MAJOR
# {MODULE}_VERSION_MINOR
# {MODULE}_VERSION_REVISION
#
# configure substitutions/makefile variables:
# {MODULE}_CPPFLAGS, {MODULE}_LDFLAGS, {MODULE}_LIBS
# {MODULE}_ROOT
# {MODULE}_LIBDIR (only if modules provides a library)
#
# preprocessor defines:
# HAVE_{MODULE} (1 or undefined)
# {MODULE}_VERSION
# {MODULE}_VERSION_MAJOR
# {MODULE}_VERSION_MINOR
# {MODULE}_VERSION_REVISION
#
# automake conditionals:
# HAVE_{MODULE}
AC_DEFUN([OPM_CORE_CHECK_MODULES],[
AC_REQUIRE([AC_PROG_CXX])
AC_REQUIRE([AC_PROG_CXXCPP])
AC_REQUIRE([PKG_PROG_PKG_CONFIG])
AC_REQUIRE([DUNE_DISABLE_LIBCHECK])
AC_REQUIRE([LT_OUTPUT])
# ____DUNE_CHECK_MODULES_____ ($1)
m4_pushdef([_dune_name], [$1])
m4_pushdef([_dune_module], [m4_translit(_dune_name, [-], [_])])
m4_pushdef([_dune_header], [$2])
m4_pushdef([_dune_ldpath], [lib])
m4_pushdef([_dune_lib], [m4_translit(_dune_name, [-], [])])
m4_pushdef([_dune_symbol], [$3])
m4_pushdef([_DUNE_MODULE], [m4_toupper(_dune_module)])
# switch tests to c++
AC_LANG_PUSH([C++])
# the usual option...
AC_ARG_WITH(_dune_name,
AS_HELP_STRING([--with-_dune_name=PATH],[_dune_module directory]))
# backup of flags
ac_save_CPPFLAGS="$CPPFLAGS"
ac_save_LIBS="$LIBS"
ac_save_LDFLAGS="$LDFLAGS"
CPPFLAGS=""
LIBS=""
##
## Where is the module $1?
##
AC_MSG_CHECKING([for $1 installation or source tree])
# is a directory set?
AS_IF([test -z "$with_[]_dune_module"],[
#
# search module $1 via pkg-config
#
with_[]_dune_module="global installation"
AS_IF([test -z "$PKG_CONFIG"],[
AC_MSG_RESULT([failed])
AC_MSG_NOTICE([could not search for module _dune_name])
AC_MSG_ERROR([pkg-config is required for using installed modules])
])
AS_IF(AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]),[
_dune_cm_CPPFLAGS="`$PKG_CONFIG --cflags _dune_name`" 2>/dev/null
_DUNE_MODULE[]_ROOT="`$PKG_CONFIG --variable=prefix _dune_name`" 2>/dev/null
_DUNE_MODULE[]_VERSION="`$PKG_CONFIG --modversion _dune_name`" 2>/dev/null
_dune_cm_LDFLAGS=""
ifelse(_dune_symbol,,
[_DUNE_MODULE[]_LIBDIR=""
_dune_cm_LIBS=""],
[_DUNE_MODULE[]_LIBDIR=`$PKG_CONFIG --variable=libdir _dune_name 2>/dev/null`
_dune_cm_LIBS="-L$_DUNE_MODULE[]_LIBDIR -l[]_dune_lib"])
HAVE_[]_DUNE_MODULE=1
AC_MSG_RESULT([global installation in $_DUNE_MODULE[]_ROOT])
],[
HAVE_[]_DUNE_MODULE=0
AC_MSG_RESULT([not found])
])
],[
#
# path for module $1 is specified via command line
#
AS_IF([test -d "$with_[]_dune_module"],[
# expand tilde / other stuff
_DUNE_MODULE[]_ROOT=`cd $with_[]_dune_module && pwd`
# expand search path (otherwise empty CPPFLAGS)
AS_IF([test -d "$_DUNE_MODULE[]_ROOT/include/dune"],[
# Dune was installed into directory given by with-dunecommon
_dune_cm_CPPFLAGS="-I$_DUNE_MODULE[]_ROOT/include"
_DUNE_MODULE[]_BUILDDIR=_DUNE_MODULE[]_ROOT
_DUNE_MODULE[]_VERSION="`PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$_DUNE_MODULE[]_ROOT/lib/pkgconfig $PKG_CONFIG --modversion _dune_name`" 2>/dev/null
],[
_DUNE_MODULE[]_SRCDIR=$_DUNE_MODULE[]_ROOT
# extract src and build path from Makefile, if found
AS_IF([test -f $_DUNE_MODULE[]_ROOT/Makefile],[
_DUNE_MODULE[]_SRCDIR="`sed -ne '/^abs_top_srcdir = /{s/^abs_top_srcdir = //; p;}' $_DUNE_MODULE[]_ROOT/Makefile`"
])
_dune_cm_CPPFLAGS="-I$_DUNE_MODULE[]_SRCDIR"
_DUNE_MODULE[]_VERSION="`grep Version $_DUNE_MODULE[]_SRCDIR/dune.module | sed -e 's/^Version: *//'`" 2>/dev/null
])
_dune_cm_LDFLAGS=""
ifelse(_dune_symbol,,
[_DUNE_MODULE[]_LIBDIR=""
_dune_cm_LIBS=""],
[_DUNE_MODULE[]_LIBDIR="$_DUNE_MODULE[]_ROOT/lib"
_dune_cm_LIBS="-L$_DUNE_MODULE[]_LIBDIR -l[]_dune_lib"])
# set expanded module path
with_[]_dune_module="$_DUNE_MODULE[]_ROOT"
HAVE_[]_DUNE_MODULE=1
AC_MSG_RESULT([found in $_DUNE_MODULE[]_ROOT])
],[
HAVE_[]_DUNE_MODULE=0
AC_MSG_RESULT([not found])
AC_MSG_ERROR([_dune_name-directory $with_[]_dune_module does not exist])
])
])
CPPFLAGS="$ac_save_CPPFLAGS $DUNE_CPPFLAGS $_dune_cm_CPPFLAGS"
##
## check for an arbitrary header
##
AS_IF([test "$HAVE_[]_DUNE_MODULE" != "1"],[
AC_CHECK_HEADER([[]_dune_header],
[HAVE_[]_DUNE_MODULE=1], [HAVE_[]_DUNE_MODULE=0])
])
AS_IF([test "$HAVE_[]_DUNE_MODULE" != "1"],[
AC_MSG_WARN([$_DUNE_MODULE[]_ROOT does not seem to contain a valid _dune_name (dune/[]_dune_header not found)])
])
##
## check for lib (if lib name was provided)
##
ifelse(_dune_symbol,,
AC_MSG_NOTICE([_dune_name does not provide libs]),
AS_IF([test "x$enable_dunelibcheck" = "xno"],[
AC_MSG_WARN([library check for _dune_name is disabled. DANGEROUS!])
],[
AS_IF([test "x$HAVE_[]_DUNE_MODULE" = "x1"],[
# save current LDFLAGS
ac_save_CXX="$CXX"
HAVE_[]_DUNE_MODULE=0
# define LTCXXLINK like it will be defined in the Makefile
CXX="./libtool --tag=CXX --mode=link $ac_save_CXX"
# use module LDFLAGS
LDFLAGS="$ac_save_LDFLAGS $DUNE_LDFLAGS $_dune_cm_LDFLAGS"
LIBS="$_dune_cm_LIBS $DUNE_LIBS $LIBS"
AC_MSG_CHECKING([for lib[]_dune_lib])
AC_TRY_LINK(dnl
[#]include<_dune_header>,
_dune_symbol,
[
AC_MSG_RESULT([yes])
HAVE_[]_DUNE_MODULE=1
],[
AC_MSG_RESULT([no])
HAVE_[]_DUNE_MODULE=0
AS_IF([test -n "$_DUNE_MODULE[]_ROOT"],[
AC_MSG_WARN([$with_[]_dune_module does not seem to contain a valid _dune_name (failed to link with lib[]_dune_lib[].la)])
])
]
)
])
# reset variables
CXX="$ac_save_CXX"
])
)
# did we succeed?
AS_IF([test "x$HAVE_[]_DUNE_MODULE" = "x1"],[
# add the module's own flags and libs to the modules and the global
# variables
DUNE_ADD_MODULE_DEPS(m4_defn([_dune_name]), m4_defn([_dune_name]),
[$_dune_cm_CPPFLAGS], [$_dune_cm_LDFLAGS], [$_dune_cm_LIBS])
# set variables for our modules
AC_SUBST(_DUNE_MODULE[]_CPPFLAGS, "$_DUNE_MODULE[]_CPPFLAGS")
AC_SUBST(_DUNE_MODULE[]_LDFLAGS, "$_DUNE_MODULE[]_LDFLAGS")
AC_SUBST(_DUNE_MODULE[]_LIBS, "$_DUNE_MODULE[]_LIBS")
AC_SUBST(_DUNE_MODULE[]_ROOT, "$_DUNE_MODULE[]_ROOT")
ifelse(m4_defn([_dune_symbol]),,
[],
[AC_SUBST(_DUNE_MODULE[]_LIBDIR)
])
AC_DEFINE(HAVE_[]_DUNE_MODULE, 1, [Define to 1 if] _dune_name [was found])
DUNE_PARSE_MODULE_VERSION(_dune_name, $_DUNE_MODULE[]_VERSION)
# set DUNE_* variables
# This should actually be unneccesary, but I'm keeping it in here for now
# for backward compatibility
DUNE_LDFLAGS="$DUNE_LDFLAGS $_DUNE_MODULE[]_LDFLAGS"
DUNE_LIBS="$_DUNE_MODULE[]_LIBS $DUNE_LIBS"
with_[]_dune_module="yes"
],[
with_[]_dune_module="no"
])
AM_CONDITIONAL(HAVE_[]_DUNE_MODULE, test x$HAVE_[]_DUNE_MODULE = x1)
# reset previous flags
CPPFLAGS="$ac_save_CPPFLAGS"
LDFLAGS="$ac_save_LDFLAGS"
LIBS="$ac_save_LIBS"
# add this module to DUNE_SUMMARY
DUNE_MODULE_ADD_SUMMARY_ENTRY(_dune_name)
# remove local variables
m4_popdef([_dune_name])
m4_popdef([_dune_module])
m4_popdef([_dune_header])
m4_popdef([_dune_ldpath])
m4_popdef([_dune_lib])
m4_popdef([_dune_symbol])
m4_popdef([_DUNE_MODULE])
# restore previous language settings (leave C++)
AC_LANG_POP([C++])
])

View File

@ -38,14 +38,14 @@ dnl -------------------------------------------------------------------
# system uses dynamic linking of Boost.Test . # system uses dynamic linking of Boost.Test .
AC_DEFUN([OPM_DYNLINK_BOOST_TEST], AC_DEFUN([OPM_DYNLINK_BOOST_TEST],
[ [
AC_REQUIRE([AX_BOOST_BASE]) AC_REQUIRE([OPM_BOOST_BASE])
AC_REQUIRE([AX_BOOST_UNIT_TEST_FRAMEWORK]) AC_REQUIRE([AX_BOOST_UNIT_TEST_FRAMEWORK])
_opm_LIBS_SAVE="$LIBS" _opm_LIBS_SAVE="${LIBS}"
_opm_CPPFLAGS_SAVE="$CPPFLAGS" _opm_CPPFLAGS_SAVE="${CPPFLAGS}"
LIBS="${BOOST_LDFLAGS} ${BOOST_UNIT_TEST_FRAMEWORK_LIB} ${LIBS}" LIBS="${OPM_BOOST_LDFLAGS} ${BOOST_UNIT_TEST_FRAMEWORK_LIB} ${LIBS}"
CPPFLAGS="${BOOST_CPPFLAGS} ${CPPFLAGS}" CPPFLAGS="${OPM_BOOST_CPPFLAGS} ${CPPFLAGS}"
AC_LANG_PUSH([C++]) AC_LANG_PUSH([C++])
@ -66,12 +66,12 @@ AC_CACHE_CHECK([if the Boost.Test library can be linked dynamically],dnl
AC_LANG_POP([C++]) AC_LANG_POP([C++])
LIBS="$_opm_LIBS_SAVE" LIBS="${_opm_LIBS_SAVE}"
CPPFLAGS="$_opm_CPPFLAGS_SAVE" CPPFLAGS="${_opm_CPPFLAGS_SAVE}"
AS_IF([test x"$opm_cv_boost_link_static" = x"yes" -o \ AS_IF([test x"${opm_cv_boost_link_static}" = x"yes" -o \
x"$opm_cv_boost_link_dynamic" = x"yes"], x"${opm_cv_boost_link_dynamic}" = x"yes"],
[AS_IF([test x"$opm_cv_boost_link_dynamic" = x"yes"], [AS_IF([test x"${opm_cv_boost_link_dynamic}" = x"yes"],
[AC_DEFINE([HAVE_DYNAMIC_BOOST_TEST], [1], [AC_DEFINE([HAVE_DYNAMIC_BOOST_TEST], [1],
[Define to `1' if Boost.Test should use BOOST_TEST_DYN_LINK])] [Define to `1' if Boost.Test should use BOOST_TEST_DYN_LINK])]
[:])[]dnl [:])[]dnl

18
opm-core.pc.in Normal file
View File

@ -0,0 +1,18 @@
# This is the configuration for local builds. Use this by putting the
# compilation output path (the directory in which you ran ./configure)
# into the environment variable PKG_CONFIG_PATH. This will enable you
# to use pkg-config in your code while making changes to opm-core.
# This is NOT the file that is installed in the system directories when
# you do `make install`. That is the one in lib/pkgconfig. However, if
# you make changes here, you should consider that one as well.
libdir=@abs_top_builddir@/lib/.libs
includedir=@abs_top_srcdir@
Name: @PACKAGE_NAME@
Description: @PACKAGE_STRING@
Version: @PACKAGE_VERSION@
URL: @PACKAGE_URL@
Libs: -L${libdir} -l@PACKAGE@
Cflags: -I${includedir}

View File

@ -22,6 +22,8 @@
#include <opm/core/grid.h> #include <opm/core/grid.h>
#include <opm/core/grid/cart_grid.h> #include <opm/core/grid/cart_grid.h>
#include <opm/core/grid/cornerpoint_grid.h> #include <opm/core/grid/cornerpoint_grid.h>
#include <algorithm>
#include <numeric>
@ -33,14 +35,26 @@ namespace Opm
/// Construct a 3d corner-point grid from a deck. /// Construct a 3d corner-point grid from a deck.
GridManager::GridManager(const Opm::EclipseGridParser& deck) GridManager::GridManager(const Opm::EclipseGridParser& deck)
{ {
// Collect in input struct for preprocessing. // We accept two different ways to specify the grid.
struct grdecl grdecl = deck.get_grdecl(); // 1. Corner point format.
// Requires ZCORN, COORDS, DIMENS or SPECGRID, optionally
// ACTNUM, optionally MAPAXES.
// For this format, we will verify that DXV, DYV, DZV,
// DEPTHZ and TOPS are not present.
// 2. Tensor grid format.
// Requires DXV, DYV, DZV, optionally DEPTHZ or TOPS.
// For this format, we will verify that ZCORN, COORDS
// and ACTNUM are not present.
// Note that for TOPS, we only allow a uniform vector of values.
// Process grid. if (deck.hasField("ZCORN") && deck.hasField("COORD")) {
ug_ = create_grid_cornerpoint(&grdecl, 0.0); initFromDeckCornerpoint(deck);
if (!ug_) { } else if (deck.hasField("DXV") && deck.hasField("DYV") && deck.hasField("DZV")) {
THROW("Failed to construct grid."); initFromDeckTensorgrid(deck);
} } else {
THROW("Could not initialize grid from deck. "
"Need either ZCORN + COORD or DXV + DYV + DZV keywords.");
}
} }
@ -102,5 +116,94 @@ namespace Opm
// Construct corner-point grid from deck.
void GridManager::initFromDeckCornerpoint(const Opm::EclipseGridParser& deck)
{
// Extract data from deck.
// Collect in input struct for preprocessing.
struct grdecl grdecl = deck.get_grdecl();
// Process grid.
ug_ = create_grid_cornerpoint(&grdecl, 0.0);
if (!ug_) {
THROW("Failed to construct grid.");
}
}
namespace
{
std::vector<double> coordsFromDeltas(const std::vector<double>& deltas)
{
std::vector<double> coords(deltas.size() + 1);
coords[0] = 0.0;
std::partial_sum(deltas.begin(), deltas.end(), coords.begin() + 1);
return coords;
}
} // anonymous namespace
// Construct tensor grid from deck.
void GridManager::initFromDeckTensorgrid(const Opm::EclipseGridParser& deck)
{
// Extract logical cartesian size.
std::vector<int> dims;
if (deck.hasField("DIMENS")) {
dims = deck.getIntegerValue("DIMENS");
} else if (deck.hasField("SPECGRID")) {
dims = deck.getSPECGRID().dimensions;
} else {
THROW("Deck must have either DIMENS or SPECGRID.");
}
// Extract coordinates (or offsets from top, in case of z).
const std::vector<double>& dxv = deck.getFloatingPointValue("DXV");
const std::vector<double>& dyv = deck.getFloatingPointValue("DYV");
const std::vector<double>& dzv = deck.getFloatingPointValue("DZV");
std::vector<double> x = coordsFromDeltas(dxv);
std::vector<double> y = coordsFromDeltas(dyv);
std::vector<double> z = coordsFromDeltas(dzv);
// Check that number of cells given are consistent with DIMENS/SPECGRID.
if (dims[0] != int(dxv.size())) {
THROW("Number of DXV data points do not match DIMENS or SPECGRID.");
}
if (dims[1] != int(dyv.size())) {
THROW("Number of DYV data points do not match DIMENS or SPECGRID.");
}
if (dims[2] != int(dzv.size())) {
THROW("Number of DZV data points do not match DIMENS or SPECGRID.");
}
// Extract top corner depths, if available.
const double* top_depths = 0;
std::vector<double> top_depths_vec;
if (deck.hasField("DEPTHZ")) {
const std::vector<double>& depthz = deck.getFloatingPointValue("DEPTHZ");
if (depthz.size() != x.size()*y.size()) {
THROW("Incorrect size of DEPTHZ: " << depthz.size());
}
top_depths = &depthz[0];
} else if (deck.hasField("TOPS")) {
// We only support constant values for TOPS.
// It is not 100% clear how we best can deal with
// varying TOPS (stair-stepping grid, or not).
const std::vector<double>& tops = deck.getFloatingPointValue("TOPS");
if (std::count(tops.begin(), tops.end(), tops[0]) != int(tops.size())) {
THROW("We do not support nonuniform TOPS, please use ZCORN/COORDS instead.");
}
top_depths_vec.resize(x.size()*y.size(), tops[0]);
top_depths = &top_depths_vec[0];
}
// Construct grid.
ug_ = create_grid_tensor3d(dxv.size(), dyv.size(), dzv.size(),
&x[0], &y[0], &z[0], top_depths);
if (!ug_) {
THROW("Failed to construct grid.");
}
}
} // namespace Opm } // namespace Opm

View File

@ -33,39 +33,46 @@ namespace Opm
/// encapsulates creation and destruction of the grid. /// encapsulates creation and destruction of the grid.
/// The following grid types can be constructed: /// The following grid types can be constructed:
/// - 3d corner-point grids (from deck input) /// - 3d corner-point grids (from deck input)
/// - 3d tensor grids (from deck input)
/// - 2d cartesian grids /// - 2d cartesian grids
/// - 3d cartesian grids /// - 3d cartesian grids
/// The resulting UnstructuredGrid is available through the c_grid() method. /// The resulting UnstructuredGrid is available through the c_grid() method.
class GridManager class GridManager
{ {
public: public:
/// Construct a 3d corner-point grid from a deck. /// Construct a 3d corner-point grid or tensor grid from a deck.
GridManager(const Opm::EclipseGridParser& deck); GridManager(const Opm::EclipseGridParser& deck);
/// Construct a 2d cartesian grid with cells of unit size. /// Construct a 2d cartesian grid with cells of unit size.
GridManager(int nx, int ny); GridManager(int nx, int ny);
/// Construct a 3d cartesian grid with cells of unit size. /// Construct a 3d cartesian grid with cells of unit size.
GridManager(int nx, int ny, int nz); GridManager(int nx, int ny, int nz);
/// Construct a 3d cartesian grid with cells of size [dx, dy, dz]. /// Construct a 3d cartesian grid with cells of size [dx, dy, dz].
GridManager(int nx, int ny, int nz, GridManager(int nx, int ny, int nz,
double dx, double dy, double dz); double dx, double dy, double dz);
/// Destructor. /// Destructor.
~GridManager(); ~GridManager();
/// Access the managed UnstructuredGrid. /// Access the managed UnstructuredGrid.
/// The method is named similarly to c_str() in std::string, /// The method is named similarly to c_str() in std::string,
/// to make it clear that we are returning a C-compatible struct. /// to make it clear that we are returning a C-compatible struct.
const UnstructuredGrid* c_grid() const; const UnstructuredGrid* c_grid() const;
private: private:
// Disable copying and assignment. // Disable copying and assignment.
GridManager(const GridManager& other); GridManager(const GridManager& other);
GridManager& operator=(const GridManager& other); GridManager& operator=(const GridManager& other);
// The managed UnstructuredGrid.
UnstructuredGrid* ug_; // Construct corner-point grid from deck.
void initFromDeckCornerpoint(const Opm::EclipseGridParser& deck);
// Construct tensor grid from deck.
void initFromDeckTensorgrid(const Opm::EclipseGridParser& deck);
// The managed UnstructuredGrid.
UnstructuredGrid* ug_;
}; };
} // namespace Opm } // namespace Opm

View File

@ -96,7 +96,7 @@ namespace EclipseKeywords
string("MULTPV"), string("PRESSURE"), string("SGAS"), string("MULTPV"), string("PRESSURE"), string("SGAS"),
string("SWAT"), string("SOIL"), string("RS"), string("SWAT"), string("SOIL"), string("RS"),
string("DXV"), string("DYV"), string("DZV"), string("DXV"), string("DYV"), string("DZV"),
string("DEPTHZ"), string("MAPAXES") string("DEPTHZ"), string("TOPS"), string("MAPAXES")
}; };
const int num_floating_fields = sizeof(floating_fields) / sizeof(floating_fields[0]); const int num_floating_fields = sizeof(floating_fields) / sizeof(floating_fields[0]);
@ -201,21 +201,7 @@ namespace {
return us; return us;
} }
inline std::string readKeyword(std::istream& is) inline bool readKeyword(std::istream& is, std::string& keyword)
{
std::string keyword_candidate;
while (!is.eof()) {
is >> keyword_candidate;
if(keyword_candidate.find("--") == 0) {
is >> ignoreLine; // This line is a comment
} else {
return upcase(keyword_candidate);
}
}
return "CONTINUE"; // Last line in included file is a comment
}
inline bool readKeywordNew(std::istream& is, std::string& keyword)
{ {
char buf[9]; char buf[9];
int i, j; int i, j;
@ -387,7 +373,7 @@ void EclipseGridParser::readImpl(istream& is)
std::string keyword; std::string keyword;
while (is.good()) { while (is.good()) {
is >> ignoreWhitespace; is >> ignoreWhitespace;
bool ok = readKeywordNew(is, keyword); bool ok = readKeyword(is, keyword);
if (ok) { if (ok) {
//#ifdef VERBOSE //#ifdef VERBOSE
cout << "Keyword found: " << keyword << endl; cout << "Keyword found: " << keyword << endl;
@ -549,9 +535,9 @@ void EclipseGridParser::convertToSI()
// Find the right unit. // Find the right unit.
double unit = 1e100; double unit = 1e100;
bool do_convert = true; bool do_convert = true;
if (key == "COORD" || key == "ZCORN" || if (key == "COORD" || key == "ZCORN" ||
key == "DXV" || key == "DYV" || key == "DZV" || key == "DXV" || key == "DYV" || key == "DZV" ||
key == "DEPTHZ") { key == "DEPTHZ" || key == "TOPS") {
unit = units_.length; unit = units_.length;
} else if (key == "PERMX" || key == "PERMY" || key == "PERMZ" || } else if (key == "PERMX" || key == "PERMY" || key == "PERMZ" ||
key == "PERMXX" || key == "PERMYY" || key == "PERMZZ" || key == "PERMXX" || key == "PERMYY" || key == "PERMZZ" ||

View File

@ -136,47 +136,47 @@ public:
{ return dynamic_cast<const keyword&>(*getSpecialValue(#keyword)); } { return dynamic_cast<const keyword&>(*getSpecialValue(#keyword)); }
// Support for special fields. // Support for special fields.
SPECIAL_FIELD(SPECGRID); SPECIAL_FIELD(SPECGRID)
SPECIAL_FIELD(FAULTS); SPECIAL_FIELD(FAULTS)
SPECIAL_FIELD(MULTFLT); SPECIAL_FIELD(MULTFLT)
SPECIAL_FIELD(TITLE); SPECIAL_FIELD(TITLE)
SPECIAL_FIELD(START); SPECIAL_FIELD(START)
SPECIAL_FIELD(DATES); SPECIAL_FIELD(DATES)
SPECIAL_FIELD(DENSITY); SPECIAL_FIELD(DENSITY)
SPECIAL_FIELD(PVDG); SPECIAL_FIELD(PVDG)
SPECIAL_FIELD(PVDO); SPECIAL_FIELD(PVDO)
SPECIAL_FIELD(PVTG); SPECIAL_FIELD(PVTG)
SPECIAL_FIELD(PVTO); SPECIAL_FIELD(PVTO)
SPECIAL_FIELD(PVTW); SPECIAL_FIELD(PVTW)
SPECIAL_FIELD(SGOF); SPECIAL_FIELD(SGOF)
SPECIAL_FIELD(SWOF); SPECIAL_FIELD(SWOF)
SPECIAL_FIELD(ROCK); SPECIAL_FIELD(ROCK)
SPECIAL_FIELD(ROCKTAB); SPECIAL_FIELD(ROCKTAB)
SPECIAL_FIELD(WELSPECS); SPECIAL_FIELD(WELSPECS)
SPECIAL_FIELD(COMPDAT); SPECIAL_FIELD(COMPDAT)
SPECIAL_FIELD(WCONINJE); SPECIAL_FIELD(WCONINJE)
SPECIAL_FIELD(WCONPROD); SPECIAL_FIELD(WCONPROD)
SPECIAL_FIELD(WELTARG); SPECIAL_FIELD(WELTARG)
SPECIAL_FIELD(WELOPEN); SPECIAL_FIELD(WELOPEN)
SPECIAL_FIELD(EQUIL); SPECIAL_FIELD(EQUIL)
SPECIAL_FIELD(PVCDO); SPECIAL_FIELD(PVCDO)
SPECIAL_FIELD(TSTEP); SPECIAL_FIELD(TSTEP)
SPECIAL_FIELD(PLYVISC); SPECIAL_FIELD(PLYVISC)
SPECIAL_FIELD(PLYROCK); SPECIAL_FIELD(PLYROCK)
SPECIAL_FIELD(PLYADS); SPECIAL_FIELD(PLYADS)
SPECIAL_FIELD(PLYMAX); SPECIAL_FIELD(PLYMAX)
SPECIAL_FIELD(TLMIXPAR); SPECIAL_FIELD(TLMIXPAR)
SPECIAL_FIELD(WPOLYMER); SPECIAL_FIELD(WPOLYMER)
SPECIAL_FIELD(GRUPTREE); SPECIAL_FIELD(GRUPTREE)
SPECIAL_FIELD(GCONINJE); SPECIAL_FIELD(GCONINJE)
SPECIAL_FIELD(GCONPROD); SPECIAL_FIELD(GCONPROD)
SPECIAL_FIELD(WGRUPCON); SPECIAL_FIELD(WGRUPCON)
// The following fields only have a dummy implementation // The following fields only have a dummy implementation
// that allows us to ignore them. // that allows us to ignore them.
SPECIAL_FIELD(SWFN); SPECIAL_FIELD(SWFN)
SPECIAL_FIELD(SOF2); SPECIAL_FIELD(SOF2)
SPECIAL_FIELD(TUNING); SPECIAL_FIELD(TUNING)
#undef SPECIAL_FIELD #undef SPECIAL_FIELD

View File

@ -780,9 +780,11 @@ struct WelspecsLine
int fluids_in_place_reg_numb_; // Fluids in place region number int fluids_in_place_reg_numb_; // Fluids in place region number
WelspecsLine() : WelspecsLine() :
datum_depth_BHP_(-1.0), drain_rad_(0.0), spec_inflow_("STD"), name_(), group_(), I_(-1), J_(-1),
shut_in_("SHUT"), crossflow_("YES"), pressure_table_number_(0), datum_depth_BHP_(-1.0), pref_phase_(), drain_rad_(0.0),
density_calc_type_("SEG"), fluids_in_place_reg_numb_(0) spec_inflow_("STD"), shut_in_("SHUT"), crossflow_("YES"),
pressure_table_number_(0), density_calc_type_("SEG"),
fluids_in_place_reg_numb_(0)
{} {}
}; };
@ -1360,8 +1362,8 @@ struct WgrupconLine
bool available_for_group_control_; bool available_for_group_control_;
double guide_rate_; double guide_rate_;
std::string phase_; std::string phase_;
WgrupconLine() : WgrupconLine()
available_for_group_control_(true) : well_(), available_for_group_control_(true), guide_rate_(-1.0), phase_()
{ {
} }
}; };
@ -1580,6 +1582,7 @@ struct WeltargLine
double new_value_; // New value of this quantity double new_value_; // New value of this quantity
WeltargLine() WeltargLine()
: well_(), control_change_(), new_value_(-1.0)
{ {
} }
}; };
@ -1739,6 +1742,13 @@ struct EquilLine
// initial fluids in place calculation. // initial fluids in place calculation.
EquilLine() EquilLine()
{ {
datum_depth_ = datum_depth_pressure_ = 0.0;
water_oil_contact_depth_ = oil_water_cap_pressure_ = 0.0;
gas_oil_contact_depth_ = gas_oil_cap_pressure_ = 0.0;
live_oil_table_index_ = 0;
wet_gas_table_index_ = 0;
N_ = 0;
} }
}; };
@ -2129,6 +2139,7 @@ struct WpolymerLine
WpolymerLine() WpolymerLine()
{ {
well_ = polymer_group_ = salt_group_ = ""; well_ = polymer_group_ = salt_group_ = "";
polymer_concentration_ = salt_concentration_ = 0.0;
} }
}; };

View File

@ -26,20 +26,20 @@ namespace Opm
{ {
BlackoilPropertiesBasic::BlackoilPropertiesBasic(const parameter::ParameterGroup& param, BlackoilPropertiesBasic::BlackoilPropertiesBasic(const parameter::ParameterGroup& param,
const int dim, const int dim,
const int num_cells) const int num_cells)
{ {
double poro = param.getDefault("porosity", 1.0); double poro = param.getDefault("porosity", 1.0);
using namespace Opm::unit; using namespace Opm::unit;
using namespace Opm::prefix; using namespace Opm::prefix;
double perm = param.getDefault("permeability", 100.0)*milli*darcy; double perm = param.getDefault("permeability", 100.0)*milli*darcy;
rock_.init(dim, num_cells, poro, perm); rock_.init(dim, num_cells, poro, perm);
pvt_.init(param); pvt_.init(param);
satprops_.init(param); satprops_.init(param);
if (pvt_.numPhases() != satprops_.numPhases()) { if (pvt_.numPhases() != satprops_.numPhases()) {
THROW("BlackoilPropertiesBasic::BlackoilPropertiesBasic() - Inconsistent number of phases in pvt data (" THROW("BlackoilPropertiesBasic::BlackoilPropertiesBasic() - Inconsistent number of phases in pvt data ("
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ")."); << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
} }
} }
BlackoilPropertiesBasic::~BlackoilPropertiesBasic() BlackoilPropertiesBasic::~BlackoilPropertiesBasic()
@ -90,11 +90,11 @@ namespace Opm
/// \param[out] dmudp If non-null: array of nP viscosity derivative values, /// \param[out] dmudp If non-null: array of nP viscosity derivative values,
/// array must be valid before calling. /// array must be valid before calling.
void BlackoilPropertiesBasic::viscosity(const int n, void BlackoilPropertiesBasic::viscosity(const int n,
const double* p, const double* p,
const double* z, const double* z,
const int* /*cells*/, const int* /*cells*/,
double* mu, double* mu,
double* dmudp) const double* dmudp) const
{ {
if (dmudp) { if (dmudp) {
THROW("BlackoilPropertiesBasic::viscosity() -- derivatives of viscosity not yet implemented."); THROW("BlackoilPropertiesBasic::viscosity() -- derivatives of viscosity not yet implemented.");
@ -114,16 +114,16 @@ namespace Opm
/// array must be valid before calling. The matrices are output /// array must be valid before calling. The matrices are output
/// in Fortran order. /// in Fortran order.
void BlackoilPropertiesBasic::matrix(const int n, void BlackoilPropertiesBasic::matrix(const int n,
const double* /*p*/, const double* /*p*/,
const double* /*z*/, const double* /*z*/,
const int* /*cells*/, const int* /*cells*/,
double* A, double* A,
double* dAdp) const double* dAdp) const
{ {
const int np = numPhases(); const int np = numPhases();
ASSERT(np <= 2); ASSERT(np <= 2);
double B[2]; // Must be enough since component classes do not handle more than 2. double B[2]; // Must be enough since component classes do not handle more than 2.
pvt_.B(1, 0, 0, B); pvt_.B(1, 0, 0, B);
// Compute A matrix // Compute A matrix
// #pragma omp parallel for // #pragma omp parallel for
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
@ -152,8 +152,8 @@ namespace Opm
/// of a call to the method matrix(). /// of a call to the method matrix().
/// \param[out] rho Array of nP density values, array must be valid before calling. /// \param[out] rho Array of nP density values, array must be valid before calling.
void BlackoilPropertiesBasic::density(const int n, void BlackoilPropertiesBasic::density(const int n,
const double* A, const double* A,
double* rho) const double* rho) const
{ {
const int np = numPhases(); const int np = numPhases();
const double* sdens = pvt_.surfaceDensities(); const double* sdens = pvt_.surfaceDensities();
@ -186,10 +186,10 @@ namespace Opm
/// m_{ij} = \frac{dkr_i}{ds^j}, /// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...) /// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
void BlackoilPropertiesBasic::relperm(const int n, void BlackoilPropertiesBasic::relperm(const int n,
const double* s, const double* s,
const int* /*cells*/, const int* /*cells*/,
double* kr, double* kr,
double* dkrds) const double* dkrds) const
{ {
satprops_.relperm(n, s, kr, dkrds); satprops_.relperm(n, s, kr, dkrds);
} }
@ -205,10 +205,10 @@ namespace Opm
/// m_{ij} = \frac{dpc_i}{ds^j}, /// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...) /// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
void BlackoilPropertiesBasic::capPress(const int n, void BlackoilPropertiesBasic::capPress(const int n,
const double* s, const double* s,
const int* /*cells*/, const int* /*cells*/,
double* pc, double* pc,
double* dpcds) const double* dpcds) const
{ {
satprops_.capPress(n, s, pc, dpcds); satprops_.capPress(n, s, pc, dpcds);
} }
@ -226,7 +226,7 @@ namespace Opm
double* smin, double* smin,
double* smax) const double* smax) const
{ {
satprops_.satRange(n, smin, smax); satprops_.satRange(n, smin, smax);
} }

View File

@ -35,16 +35,16 @@ namespace Opm
{ {
public: public:
/// Construct from parameters. /// Construct from parameters.
/// The following parameters are accepted (defaults): /// The following parameters are accepted (defaults):
/// num_phases (2) Must be 1 or 2. /// num_phases (2) Must be 1 or 2.
/// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic". /// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic".
/// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3 /// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3
/// mu1 [mu2, mu3] (1.0) Viscosity in cP /// mu1 [mu2, mu3] (1.0) Viscosity in cP
/// porosity (1.0) Porosity /// porosity (1.0) Porosity
/// permeability (100.0) Permeability in mD /// permeability (100.0) Permeability in mD
BlackoilPropertiesBasic(const parameter::ParameterGroup& param, BlackoilPropertiesBasic(const parameter::ParameterGroup& param,
const int dim, const int dim,
const int num_cells); const int num_cells);
/// Destructor. /// Destructor.
virtual ~BlackoilPropertiesBasic(); virtual ~BlackoilPropertiesBasic();
@ -151,7 +151,7 @@ namespace Opm
double* dpcds) const; double* dpcds) const;
/// Obtain the range of allowable saturation values. /// Obtain the range of allowable saturation values.
/// In cell cells[i], saturation of phase p is allowed to be /// In cell cells[i], saturation of phase p is allowed to be
/// in the interval [smin[i*P + p], smax[i*P + p]]. /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points. /// \param[in] n Number of data points.

View File

@ -18,20 +18,82 @@
*/ */
#include <opm/core/fluid/BlackoilPropertiesFromDeck.hpp> #include <opm/core/fluid/BlackoilPropertiesFromDeck.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
namespace Opm namespace Opm
{ {
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(const EclipseGridParser& deck, BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
const std::vector<int>& global_cell) const UnstructuredGrid& grid)
{ {
rock_.init(deck, global_cell); rock_.init(deck, grid);
pvt_.init(deck); pvt_.init(deck, 200);
satprops_.init(deck, global_cell); SaturationPropsFromDeck<SatFuncSimpleUniform>* ptr
if (pvt_.numPhases() != satprops_.numPhases()) { = new SaturationPropsFromDeck<SatFuncSimpleUniform>();
THROW("BlackoilPropertiesBasic::BlackoilPropertiesBasic() - Inconsistent number of phases in pvt data (" satprops_.reset(ptr);
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ")."); ptr->init(deck, grid, 200);
}
if (pvt_.numPhases() != satprops_->numPhases()) {
THROW("BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
}
}
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
const UnstructuredGrid& grid,
const parameter::ParameterGroup& param)
{
rock_.init(deck, grid);
const int pvt_samples = param.getDefault("pvt_tab_size", 200);
pvt_.init(deck, pvt_samples);
// Unfortunate lack of pointer smartness here...
const int sat_samples = param.getDefault("sat_tab_size", 200);
std::string threephase_model = param.getDefault<std::string>("threephase_model", "simple");
if (sat_samples > 1) {
if (threephase_model == "stone2") {
SaturationPropsFromDeck<SatFuncStone2Uniform>* ptr
= new SaturationPropsFromDeck<SatFuncStone2Uniform>();
satprops_.reset(ptr);
ptr->init(deck, grid, sat_samples);
} else if (threephase_model == "simple") {
SaturationPropsFromDeck<SatFuncSimpleUniform>* ptr
= new SaturationPropsFromDeck<SatFuncSimpleUniform>();
satprops_.reset(ptr);
ptr->init(deck, grid, sat_samples);
} else if (threephase_model == "gwseg") {
SaturationPropsFromDeck<SatFuncGwsegUniform>* ptr
= new SaturationPropsFromDeck<SatFuncGwsegUniform>();
satprops_.reset(ptr);
ptr->init(deck, grid, sat_samples);
} else {
THROW("Unknown threephase_model: " << threephase_model);
}
} else {
if (threephase_model == "stone2") {
SaturationPropsFromDeck<SatFuncStone2Nonuniform>* ptr
= new SaturationPropsFromDeck<SatFuncStone2Nonuniform>();
satprops_.reset(ptr);
ptr->init(deck, grid, sat_samples);
} else if (threephase_model == "simple") {
SaturationPropsFromDeck<SatFuncSimpleNonuniform>* ptr
= new SaturationPropsFromDeck<SatFuncSimpleNonuniform>();
satprops_.reset(ptr);
ptr->init(deck, grid, sat_samples);
} else if (threephase_model == "gwseg") {
SaturationPropsFromDeck<SatFuncGwsegNonuniform>* ptr
= new SaturationPropsFromDeck<SatFuncGwsegNonuniform>();
satprops_.reset(ptr);
ptr->init(deck, grid, sat_samples);
} else {
THROW("Unknown threephase_model: " << threephase_model);
}
}
if (pvt_.numPhases() != satprops_->numPhases()) {
THROW("BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
}
} }
BlackoilPropertiesFromDeck::~BlackoilPropertiesFromDeck() BlackoilPropertiesFromDeck::~BlackoilPropertiesFromDeck()
@ -235,7 +297,7 @@ namespace Opm
double* kr, double* kr,
double* dkrds) const double* dkrds) const
{ {
satprops_.relperm(n, s, cells, kr, dkrds); satprops_->relperm(n, s, cells, kr, dkrds);
} }
@ -254,7 +316,7 @@ namespace Opm
double* pc, double* pc,
double* dpcds) const double* dpcds) const
{ {
satprops_.capPress(n, s, cells, pc, dpcds); satprops_->capPress(n, s, cells, pc, dpcds);
} }
@ -270,7 +332,7 @@ namespace Opm
double* smin, double* smin,
double* smax) const double* smax) const
{ {
satprops_.satRange(n, cells, smin, smax); satprops_->satRange(n, cells, smin, smax);
} }

View File

@ -26,6 +26,10 @@
#include <opm/core/fluid/blackoil/BlackoilPvtProperties.hpp> #include <opm/core/fluid/blackoil/BlackoilPvtProperties.hpp>
#include <opm/core/fluid/SaturationPropsFromDeck.hpp> #include <opm/core/fluid/SaturationPropsFromDeck.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp> #include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <boost/scoped_ptr.hpp>
struct UnstructuredGrid;
namespace Opm namespace Opm
{ {
@ -35,12 +39,28 @@ namespace Opm
class BlackoilPropertiesFromDeck : public BlackoilPropertiesInterface class BlackoilPropertiesFromDeck : public BlackoilPropertiesInterface
{ {
public: public:
/// Construct from deck and cell mapping. /// Initialize from deck and grid.
/// \param deck eclipse input parser /// \param[in] deck Deck input parser
/// \param global_cell mapping from cell indices (typically from a processed grid) /// \param[in] grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck. /// to logical cartesian indices consistent with the deck.
BlackoilPropertiesFromDeck(const EclipseGridParser& deck, BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
const std::vector<int>& global_cell); const UnstructuredGrid& grid);
/// Initialize from deck, grid and parameters.
/// \param[in] deck Deck input parser
/// \param[in] grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck.
/// \param[in] param Parameters. Accepted parameters include:
/// pvt_tab_size (200) number of uniform sample points for dead-oil pvt tables.
/// sat_tab_size (200) number of uniform sample points for saturation tables.
/// threephase_model("simple") three-phase relperm model (accepts "simple" and "stone2").
/// For both size parameters, a 0 or negative value indicates that no spline fitting is to
/// be done, and the input fluid data used directly for linear interpolation.
BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
const UnstructuredGrid& grid,
const parameter::ParameterGroup& param);
/// Destructor. /// Destructor.
virtual ~BlackoilPropertiesFromDeck(); virtual ~BlackoilPropertiesFromDeck();
@ -147,9 +167,9 @@ namespace Opm
double* dpcds) const; double* dpcds) const;
/// Obtain the range of allowable saturation values. /// Obtain the range of allowable saturation values.
/// In cell cells[i], saturation of phase p is allowed to be /// In cell cells[i], saturation of phase p is allowed to be
/// in the interval [smin[i*P + p], smax[i*P + p]]. /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points. /// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices. /// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.
@ -162,7 +182,7 @@ namespace Opm
private: private:
RockFromDeck rock_; RockFromDeck rock_;
BlackoilPvtProperties pvt_; BlackoilPvtProperties pvt_;
SaturationPropsFromDeck satprops_; boost::scoped_ptr<SaturationPropsInterface> satprops_;
mutable std::vector<double> B_; mutable std::vector<double> B_;
mutable std::vector<double> dB_; mutable std::vector<double> dB_;
mutable std::vector<double> R_; mutable std::vector<double> R_;

View File

@ -138,9 +138,9 @@ namespace Opm
double* dpcds) const = 0; double* dpcds) const = 0;
/// Obtain the range of allowable saturation values. /// Obtain the range of allowable saturation values.
/// In cell cells[i], saturation of phase p is allowed to be /// In cell cells[i], saturation of phase p is allowed to be
/// in the interval [smin[i*P + p], smax[i*P + p]]. /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points. /// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices. /// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.

View File

@ -28,22 +28,22 @@ namespace Opm
{ {
IncompPropertiesBasic::IncompPropertiesBasic(const parameter::ParameterGroup& param, IncompPropertiesBasic::IncompPropertiesBasic(const parameter::ParameterGroup& param,
const int dim, const int dim,
const int num_cells) const int num_cells)
{ {
double poro = param.getDefault("porosity", 1.0); double poro = param.getDefault("porosity", 1.0);
using namespace Opm::unit; using namespace Opm::unit;
using namespace Opm::prefix; using namespace Opm::prefix;
double perm = param.getDefault("permeability", 100.0)*milli*darcy; double perm = param.getDefault("permeability", 100.0)*milli*darcy;
rock_.init(dim, num_cells, poro, perm); rock_.init(dim, num_cells, poro, perm);
pvt_.init(param); pvt_.init(param);
satprops_.init(param); satprops_.init(param);
if (pvt_.numPhases() != satprops_.numPhases()) { if (pvt_.numPhases() != satprops_.numPhases()) {
THROW("IncompPropertiesBasic::IncompPropertiesBasic() - Inconsistent number of phases in pvt data (" THROW("IncompPropertiesBasic::IncompPropertiesBasic() - Inconsistent number of phases in pvt data ("
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ")."); << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
} }
viscosity_.resize(pvt_.numPhases()); viscosity_.resize(pvt_.numPhases());
pvt_.mu(1, 0, 0, &viscosity_[0]); pvt_.mu(1, 0, 0, &viscosity_[0]);
} }
IncompPropertiesBasic::IncompPropertiesBasic(const int num_phases, IncompPropertiesBasic::IncompPropertiesBasic(const int num_phases,
@ -56,14 +56,14 @@ namespace Opm
const int num_cells) const int num_cells)
{ {
rock_.init(dim, num_cells, por, perm); rock_.init(dim, num_cells, por, perm);
pvt_.init(num_phases, rho, mu); pvt_.init(num_phases, rho, mu);
satprops_.init(num_phases, relpermfunc); satprops_.init(num_phases, relpermfunc);
if (pvt_.numPhases() != satprops_.numPhases()) { if (pvt_.numPhases() != satprops_.numPhases()) {
THROW("IncompPropertiesBasic::IncompPropertiesBasic() - Inconsistent number of phases in pvt data (" THROW("IncompPropertiesBasic::IncompPropertiesBasic() - Inconsistent number of phases in pvt data ("
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ")."); << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
} }
viscosity_.resize(pvt_.numPhases()); viscosity_.resize(pvt_.numPhases());
pvt_.mu(1, 0, 0, &viscosity_[0]); pvt_.mu(1, 0, 0, &viscosity_[0]);
} }
IncompPropertiesBasic::~IncompPropertiesBasic() IncompPropertiesBasic::~IncompPropertiesBasic()
@ -109,7 +109,7 @@ namespace Opm
/// \return Array of P viscosity values. /// \return Array of P viscosity values.
const double* IncompPropertiesBasic::viscosity() const const double* IncompPropertiesBasic::viscosity() const
{ {
return &viscosity_[0]; return &viscosity_[0];
} }
/// \return Array of P density values. /// \return Array of P density values.
@ -117,7 +117,7 @@ namespace Opm
{ {
// No difference between reservoir and surface densities // No difference between reservoir and surface densities
// modelled by this class. // modelled by this class.
return pvt_.surfaceDensities(); return pvt_.surfaceDensities();
} }
/// \return Array of P density values. /// \return Array of P density values.
@ -125,7 +125,7 @@ namespace Opm
{ {
// No difference between reservoir and surface densities // No difference between reservoir and surface densities
// modelled by this class. // modelled by this class.
return pvt_.surfaceDensities(); return pvt_.surfaceDensities();
} }
/// \param[in] n Number of data points. /// \param[in] n Number of data points.
@ -138,10 +138,10 @@ namespace Opm
/// m_{ij} = \frac{dkr_i}{ds^j}, /// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m_01 ...) /// and is output in Fortran order (m_00 m_10 m_20 m_01 ...)
void IncompPropertiesBasic::relperm(const int n, void IncompPropertiesBasic::relperm(const int n,
const double* s, const double* s,
const int* /*cells*/, const int* /*cells*/,
double* kr, double* kr,
double* dkrds) const double* dkrds) const
{ {
satprops_.relperm(n, s, kr, dkrds); satprops_.relperm(n, s, kr, dkrds);
} }
@ -157,10 +157,10 @@ namespace Opm
/// m_{ij} = \frac{dpc_i}{ds^j}, /// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m_01 ...) /// and is output in Fortran order (m_00 m_10 m_20 m_01 ...)
void IncompPropertiesBasic::capPress(const int n, void IncompPropertiesBasic::capPress(const int n,
const double* s, const double* s,
const int* /*cells*/, const int* /*cells*/,
double* pc, double* pc,
double* dpcds) const double* dpcds) const
{ {
satprops_.capPress(n, s, pc, dpcds); satprops_.capPress(n, s, pc, dpcds);
} }
@ -174,11 +174,11 @@ namespace Opm
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling. /// \param[out] smax Array of nP maximum s values, array must be valid before calling.
void IncompPropertiesBasic::satRange(const int n, void IncompPropertiesBasic::satRange(const int n,
const int* /*cells*/, const int* /*cells*/,
double* smin, double* smin,
double* smax) const double* smax) const
{ {
satprops_.satRange(n, smin, smax); satprops_.satRange(n, smin, smax);
} }
} // namespace Opm } // namespace Opm

View File

@ -42,29 +42,29 @@ namespace Opm
{ {
public: public:
/// Construct from parameters. /// Construct from parameters.
/// The following parameters are accepted (defaults): /// The following parameters are accepted (defaults):
/// num_phases (2) Must be 1 or 2. /// num_phases (2) Must be 1 or 2.
/// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic". /// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic".
/// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3 /// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3
/// mu1 [mu2, mu3] (1.0) Viscosity in cP /// mu1 [mu2, mu3] (1.0) Viscosity in cP
/// porosity (1.0) Porosity /// porosity (1.0) Porosity
/// permeability (100.0) Permeability in mD /// permeability (100.0) Permeability in mD
IncompPropertiesBasic(const parameter::ParameterGroup& param, IncompPropertiesBasic(const parameter::ParameterGroup& param,
const int dim, const int dim,
const int num_cells); const int num_cells);
/// Construct from arguments a basic two phase fluid. /// Construct from arguments a basic two phase fluid.
IncompPropertiesBasic(const int num_phases, IncompPropertiesBasic(const int num_phases,
const SaturationPropsBasic::RelPermFunc& relpermfunc, const SaturationPropsBasic::RelPermFunc& relpermfunc,
const std::vector<double>& rho, const std::vector<double>& rho,
const std::vector<double>& mu, const std::vector<double>& mu,
const double porosity, const double porosity,
const double permeability, const double permeability,
const int dim, const int dim,
const int num_cells); const int num_cells);
/// Destructor. /// Destructor.
virtual ~IncompPropertiesBasic(); virtual ~IncompPropertiesBasic();
// ---- Rock interface ---- // ---- Rock interface ----
@ -132,9 +132,9 @@ namespace Opm
double* dpcds) const; double* dpcds) const;
/// Obtain the range of allowable saturation values. /// Obtain the range of allowable saturation values.
/// In cell cells[i], saturation of phase p is allowed to be /// In cell cells[i], saturation of phase p is allowed to be
/// in the interval [smin[i*P + p], smax[i*P + p]]. /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points. /// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices. /// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.
@ -145,9 +145,9 @@ namespace Opm
double* smax) const; double* smax) const;
private: private:
RockBasic rock_; RockBasic rock_;
PvtPropertiesBasic pvt_; PvtPropertiesBasic pvt_;
SaturationPropsBasic satprops_; SaturationPropsBasic satprops_;
std::vector<double> viscosity_; std::vector<double> viscosity_;
}; };

View File

@ -27,15 +27,15 @@ namespace Opm
{ {
IncompPropertiesFromDeck::IncompPropertiesFromDeck(const EclipseGridParser& deck, IncompPropertiesFromDeck::IncompPropertiesFromDeck(const EclipseGridParser& deck,
const std::vector<int>& global_cell) const UnstructuredGrid& grid)
{ {
rock_.init(deck, global_cell); rock_.init(deck, grid);
pvt_.init(deck); pvt_.init(deck);
satprops_.init(deck, global_cell); satprops_.init(deck, grid, 200);
if (pvt_.numPhases() != satprops_.numPhases()) { if (pvt_.numPhases() != satprops_.numPhases()) {
THROW("IncompPropertiesFromDeck::IncompPropertiesFromDeck() - Inconsistent number of phases in pvt data (" THROW("IncompPropertiesFromDeck::IncompPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ")."); << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
} }
} }
IncompPropertiesFromDeck::~IncompPropertiesFromDeck() IncompPropertiesFromDeck::~IncompPropertiesFromDeck()
@ -81,19 +81,19 @@ namespace Opm
/// \return Array of P viscosity values. /// \return Array of P viscosity values.
const double* IncompPropertiesFromDeck::viscosity() const const double* IncompPropertiesFromDeck::viscosity() const
{ {
return pvt_.viscosity(); return pvt_.viscosity();
} }
/// \return Array of P density values. /// \return Array of P density values.
const double* IncompPropertiesFromDeck::density() const const double* IncompPropertiesFromDeck::density() const
{ {
return pvt_.reservoirDensities(); return pvt_.reservoirDensities();
} }
/// \return Array of P density values. /// \return Array of P density values.
const double* IncompPropertiesFromDeck::surfaceDensity() const const double* IncompPropertiesFromDeck::surfaceDensity() const
{ {
return pvt_.surfaceDensities(); return pvt_.surfaceDensities();
} }
/// \param[in] n Number of data points. /// \param[in] n Number of data points.
@ -106,10 +106,10 @@ namespace Opm
/// m_{ij} = \frac{dkr_i}{ds^j}, /// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m_01 ...) /// and is output in Fortran order (m_00 m_10 m_20 m_01 ...)
void IncompPropertiesFromDeck::relperm(const int n, void IncompPropertiesFromDeck::relperm(const int n,
const double* s, const double* s,
const int* cells, const int* cells,
double* kr, double* kr,
double* dkrds) const double* dkrds) const
{ {
satprops_.relperm(n, s, cells, kr, dkrds); satprops_.relperm(n, s, cells, kr, dkrds);
} }
@ -125,10 +125,10 @@ namespace Opm
/// m_{ij} = \frac{dpc_i}{ds^j}, /// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m_01 ...) /// and is output in Fortran order (m_00 m_10 m_20 m_01 ...)
void IncompPropertiesFromDeck::capPress(const int n, void IncompPropertiesFromDeck::capPress(const int n,
const double* s, const double* s,
const int* cells, const int* cells,
double* pc, double* pc,
double* dpcds) const double* dpcds) const
{ {
satprops_.capPress(n, s, cells, pc, dpcds); satprops_.capPress(n, s, cells, pc, dpcds);
} }
@ -142,11 +142,11 @@ namespace Opm
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling. /// \param[out] smax Array of nP maximum s values, array must be valid before calling.
void IncompPropertiesFromDeck::satRange(const int n, void IncompPropertiesFromDeck::satRange(const int n,
const int* cells, const int* cells,
double* smin, double* smin,
double* smax) const double* smax) const
{ {
satprops_.satRange(n, cells, smin, smax); satprops_.satRange(n, cells, smin, smax);
} }
} // namespace Opm } // namespace Opm

View File

@ -26,6 +26,8 @@
#include <opm/core/fluid/SaturationPropsFromDeck.hpp> #include <opm/core/fluid/SaturationPropsFromDeck.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp> #include <opm/core/eclipse/EclipseGridParser.hpp>
struct UnstructuredGrid;
namespace Opm namespace Opm
{ {
@ -43,14 +45,15 @@ namespace Opm
class IncompPropertiesFromDeck : public IncompPropertiesInterface class IncompPropertiesFromDeck : public IncompPropertiesInterface
{ {
public: public:
/// Construct from deck and cell mapping. /// Initialize from deck and grid.
/// \param deck eclipse input parser /// \param deck Deck input parser
/// \param global_cell mapping from cell indices (typically from a processed grid) /// \param grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck. /// to logical cartesian indices consistent with the deck.
IncompPropertiesFromDeck(const EclipseGridParser& deck, IncompPropertiesFromDeck(const EclipseGridParser& deck,
const std::vector<int>& global_cell); const UnstructuredGrid& grid);
/// Destructor. /// Destructor.
virtual ~IncompPropertiesFromDeck(); virtual ~IncompPropertiesFromDeck();
// ---- Rock interface ---- // ---- Rock interface ----
@ -118,9 +121,9 @@ namespace Opm
double* dpcds) const; double* dpcds) const;
/// Obtain the range of allowable saturation values. /// Obtain the range of allowable saturation values.
/// In cell cells[i], saturation of phase p is allowed to be /// In cell cells[i], saturation of phase p is allowed to be
/// in the interval [smin[i*P + p], smax[i*P + p]]. /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points. /// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices. /// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.
@ -131,8 +134,8 @@ namespace Opm
double* smax) const; double* smax) const;
private: private:
RockFromDeck rock_; RockFromDeck rock_;
PvtPropertiesIncompFromDeck pvt_; PvtPropertiesIncompFromDeck pvt_;
SaturationPropsFromDeck satprops_; SaturationPropsFromDeck<SatFuncStone2Uniform> satprops_;
}; };

View File

@ -109,9 +109,9 @@ namespace Opm
double* pc, double* pc,
double* dpcds) const = 0; double* dpcds) const = 0;
/// Obtain the range of allowable saturation values. /// Obtain the range of allowable saturation values.
/// In cell cells[i], saturation of phase p is allowed to be /// In cell cells[i], saturation of phase p is allowed to be
/// in the interval [smin[i*P + p], smax[i*P + p]]. /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points. /// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices. /// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.

View File

@ -34,41 +34,41 @@ namespace Opm
void PvtPropertiesBasic::init(const parameter::ParameterGroup& param) void PvtPropertiesBasic::init(const parameter::ParameterGroup& param)
{ {
int num_phases = param.getDefault("num_phases", 2); int num_phases = param.getDefault("num_phases", 2);
if (num_phases > 3 || num_phases < 1) { if (num_phases > 3 || num_phases < 1) {
THROW("PvtPropertiesBasic::init() illegal num_phases: " << num_phases); THROW("PvtPropertiesBasic::init() illegal num_phases: " << num_phases);
} }
density_.resize(num_phases); density_.resize(num_phases);
viscosity_.resize(num_phases); viscosity_.resize(num_phases);
// We currently do not allow the user to set B. // We currently do not allow the user to set B.
formation_volume_factor_.clear(); formation_volume_factor_.clear();
formation_volume_factor_.resize(num_phases, 1.0); formation_volume_factor_.resize(num_phases, 1.0);
// Setting mu and rho from parameters // Setting mu and rho from parameters
using namespace Opm::prefix; using namespace Opm::prefix;
using namespace Opm::unit; using namespace Opm::unit;
const double kgpm3 = kilogram/cubic(meter); const double kgpm3 = kilogram/cubic(meter);
const double cP = centi*Poise; const double cP = centi*Poise;
std::string rname[3] = { "rho1", "rho2", "rho3" }; std::string rname[3] = { "rho1", "rho2", "rho3" };
double rdefault[3] = { 1.0e3, 1.0e3, 1.0e3 }; double rdefault[3] = { 1.0e3, 1.0e3, 1.0e3 };
std::string vname[3] = { "mu1", "mu2", "mu3" }; std::string vname[3] = { "mu1", "mu2", "mu3" };
double vdefault[3] = { 1.0, 1.0, 1.0 }; double vdefault[3] = { 1.0, 1.0, 1.0 };
for (int phase = 0; phase < num_phases; ++phase) { for (int phase = 0; phase < num_phases; ++phase) {
density_[phase] = kgpm3*param.getDefault(rname[phase], rdefault[phase]); density_[phase] = kgpm3*param.getDefault(rname[phase], rdefault[phase]);
viscosity_[phase] = cP*param.getDefault(vname[phase], vdefault[phase]); viscosity_[phase] = cP*param.getDefault(vname[phase], vdefault[phase]);
} }
} }
void PvtPropertiesBasic::init(const int num_phases, void PvtPropertiesBasic::init(const int num_phases,
const std::vector<double>& rho, const std::vector<double>& rho,
const std::vector<double>& visc) const std::vector<double>& visc)
{ {
if (num_phases > 3 || num_phases < 1) { if (num_phases > 3 || num_phases < 1) {
THROW("PvtPropertiesBasic::init() illegal num_phases: " << num_phases); THROW("PvtPropertiesBasic::init() illegal num_phases: " << num_phases);
} }
// We currently do not allow the user to set B. // We currently do not allow the user to set B.
formation_volume_factor_.clear(); formation_volume_factor_.clear();
formation_volume_factor_.resize(num_phases, 1.0); formation_volume_factor_.resize(num_phases, 1.0);
density_ = rho; density_ = rho;
viscosity_ = visc; viscosity_ = visc;
} }
@ -87,69 +87,69 @@ namespace Opm
void PvtPropertiesBasic::mu(const int n, void PvtPropertiesBasic::mu(const int n,
const double* /*p*/, const double* /*p*/,
const double* /*z*/, const double* /*z*/,
double* output_mu) const double* output_mu) const
{ {
const int np = numPhases(); const int np = numPhases();
for (int phase = 0; phase < np; ++phase) { for (int phase = 0; phase < np; ++phase) {
// #pragma omp parallel for // #pragma omp parallel for
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
output_mu[np*i + phase] = viscosity_[phase]; output_mu[np*i + phase] = viscosity_[phase];
} }
} }
} }
void PvtPropertiesBasic::B(const int n, void PvtPropertiesBasic::B(const int n,
const double* /*p*/, const double* /*p*/,
const double* /*z*/, const double* /*z*/,
double* output_B) const double* output_B) const
{ {
const int np = numPhases(); const int np = numPhases();
for (int phase = 0; phase < np; ++phase) { for (int phase = 0; phase < np; ++phase) {
// #pragma omp parallel for // #pragma omp parallel for
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
output_B[np*i + phase] = formation_volume_factor_[phase]; output_B[np*i + phase] = formation_volume_factor_[phase];
} }
} }
} }
void PvtPropertiesBasic::dBdp(const int n, void PvtPropertiesBasic::dBdp(const int n,
const double* /*p*/, const double* /*p*/,
const double* /*z*/, const double* /*z*/,
double* output_B, double* output_B,
double* output_dBdp) const double* output_dBdp) const
{ {
const int np = numPhases(); const int np = numPhases();
for (int phase = 0; phase < np; ++phase) { for (int phase = 0; phase < np; ++phase) {
// #pragma omp parallel for // #pragma omp parallel for
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
output_B[np*i + phase] = formation_volume_factor_[phase]; output_B[np*i + phase] = formation_volume_factor_[phase];
output_dBdp[np*i + phase] = 0.0; output_dBdp[np*i + phase] = 0.0;
} }
} }
} }
void PvtPropertiesBasic::R(const int n, void PvtPropertiesBasic::R(const int n,
const double* /*p*/, const double* /*p*/,
const double* /*z*/, const double* /*z*/,
double* output_R) const double* output_R) const
{ {
const int np = numPhases(); const int np = numPhases();
std::fill(output_R, output_R + n*np, 0.0); std::fill(output_R, output_R + n*np, 0.0);
} }
void PvtPropertiesBasic::dRdp(const int n, void PvtPropertiesBasic::dRdp(const int n,
const double* /*p*/, const double* /*p*/,
const double* /*z*/, const double* /*z*/,
double* output_R, double* output_R,
double* output_dRdp) const double* output_dRdp) const
{ {
const int np = numPhases(); const int np = numPhases();
std::fill(output_R, output_R + n*np, 0.0); std::fill(output_R, output_R + n*np, 0.0);
std::fill(output_dRdp, output_dRdp + n*np, 0.0); std::fill(output_dRdp, output_dRdp + n*np, 0.0);
} }
} // namespace Opm } // namespace Opm

View File

@ -38,11 +38,11 @@ namespace Opm
PvtPropertiesBasic(); PvtPropertiesBasic();
/// Initialize from parameters. /// Initialize from parameters.
/// The following parameters are accepted (defaults): /// The following parameters are accepted (defaults):
/// num_phases (2) Must be 1, 2 or 3. /// num_phases (2) Must be 1, 2 or 3.
/// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3 /// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3
/// mu1 [mu2, mu3] (1.0) Viscosity in cP /// mu1 [mu2, mu3] (1.0) Viscosity in cP
void init(const parameter::ParameterGroup& param); void init(const parameter::ParameterGroup& param);
/// Initialize from arguments. /// Initialize from arguments.
/// Basic multi phase fluid pvt properties. /// Basic multi phase fluid pvt properties.
@ -55,7 +55,7 @@ namespace Opm
/// Densities of stock components at surface conditions. /// Densities of stock components at surface conditions.
/// \return Array of size numPhases(). /// \return Array of size numPhases().
const double* surfaceDensities() const; const double* surfaceDensities() const;
/// Viscosity as a function of p and z. /// Viscosity as a function of p and z.
void mu(const int n, void mu(const int n,
@ -90,9 +90,9 @@ namespace Opm
double* output_dRdp) const; double* output_dRdp) const;
private: private:
std::vector<double> density_; std::vector<double> density_;
std::vector<double> viscosity_; std::vector<double> viscosity_;
std::vector<double> formation_volume_factor_; std::vector<double> formation_volume_factor_;
}; };
} }

View File

@ -38,54 +38,54 @@ namespace Opm
{ {
typedef std::vector<std::vector<std::vector<double> > > table_t; typedef std::vector<std::vector<std::vector<double> > > table_t;
// If we need multiple regions, this class and the SinglePvt* classes must change. // If we need multiple regions, this class and the SinglePvt* classes must change.
int region_number = 0; int region_number = 0;
PhaseUsage phase_usage = phaseUsageFromDeck(deck); PhaseUsage phase_usage = phaseUsageFromDeck(deck);
if (phase_usage.phase_used[PhaseUsage::Vapour] || if (phase_usage.phase_used[PhaseUsage::Vapour] ||
!phase_usage.phase_used[PhaseUsage::Aqua] || !phase_usage.phase_used[PhaseUsage::Aqua] ||
!phase_usage.phase_used[PhaseUsage::Liquid]) { !phase_usage.phase_used[PhaseUsage::Liquid]) {
THROW("PvtPropertiesIncompFromDeck::init() -- must have gas and oil phases (only) in deck input.\n"); THROW("PvtPropertiesIncompFromDeck::init() -- must have gas and oil phases (only) in deck input.\n");
} }
// Surface densities. Accounting for different orders in eclipse and our code. // Surface densities. Accounting for different orders in eclipse and our code.
if (deck.hasField("DENSITY")) { if (deck.hasField("DENSITY")) {
const std::vector<double>& d = deck.getDENSITY().densities_[region_number]; const std::vector<double>& d = deck.getDENSITY().densities_[region_number];
enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 }; enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 };
surface_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] = d[ECL_water]; surface_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] = d[ECL_water];
surface_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] = d[ECL_oil]; surface_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] = d[ECL_oil];
} else { } else {
THROW("Input is missing DENSITY\n"); THROW("Input is missing DENSITY\n");
} }
// Make reservoir densities the same as surface densities initially. // Make reservoir densities the same as surface densities initially.
// We will modify them with formation volume factors if found. // We will modify them with formation volume factors if found.
reservoir_density_ = surface_density_; reservoir_density_ = surface_density_;
// Water viscosity. // Water viscosity.
if (deck.hasField("PVTW")) { if (deck.hasField("PVTW")) {
const std::vector<double>& pvtw = deck.getPVTW().pvtw_[region_number]; const std::vector<double>& pvtw = deck.getPVTW().pvtw_[region_number];
if (pvtw[2] != 0.0 || pvtw[4] != 0.0) { if (pvtw[2] != 0.0 || pvtw[4] != 0.0) {
MESSAGE("Compressibility effects in PVTW are ignored."); MESSAGE("Compressibility effects in PVTW are ignored.");
} }
reservoir_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] /= pvtw[1]; reservoir_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] /= pvtw[1];
viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = pvtw[3]; viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = pvtw[3];
} else { } else {
// Eclipse 100 default. // Eclipse 100 default.
// viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = 0.5*Opm::prefix::centi*Opm::unit::Poise; // viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = 0.5*Opm::prefix::centi*Opm::unit::Poise;
THROW("Input is missing PVTW\n"); THROW("Input is missing PVTW\n");
} }
// Oil viscosity. // Oil viscosity.
if (deck.hasField("PVCDO")) { if (deck.hasField("PVCDO")) {
const std::vector<double>& pvcdo = deck.getPVCDO().pvcdo_[region_number]; const std::vector<double>& pvcdo = deck.getPVCDO().pvcdo_[region_number];
if (pvcdo[2] != 0.0 || pvcdo[4] != 0.0) { if (pvcdo[2] != 0.0 || pvcdo[4] != 0.0) {
MESSAGE("Compressibility effects in PVCDO are ignored."); MESSAGE("Compressibility effects in PVCDO are ignored.");
} }
reservoir_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] /= pvcdo[1]; reservoir_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] /= pvcdo[1];
viscosity_[phase_usage.phase_pos[PhaseUsage::Liquid]] = pvcdo[3]; viscosity_[phase_usage.phase_pos[PhaseUsage::Liquid]] = pvcdo[3];
} else { } else {
THROW("Input is missing PVCDO\n"); THROW("Input is missing PVCDO\n");
} }
} }
const double* PvtPropertiesIncompFromDeck::surfaceDensities() const const double* PvtPropertiesIncompFromDeck::surfaceDensities() const

View File

@ -39,14 +39,14 @@ namespace Opm
PvtPropertiesIncompFromDeck(); PvtPropertiesIncompFromDeck();
/// Initialize from deck. /// Initialize from deck.
void init(const EclipseGridParser& deck); void init(const EclipseGridParser& deck);
/// Number of active phases. /// Number of active phases.
int numPhases() const; int numPhases() const;
/// Densities of stock components at surface conditions. /// Densities of stock components at surface conditions.
/// \return Array of size numPhases(). /// \return Array of size numPhases().
const double* surfaceDensities() const; const double* surfaceDensities() const;
/// Densities of stock components at reservoir conditions. /// Densities of stock components at reservoir conditions.
/// Note: a reasonable question to ask is why there can be /// Note: a reasonable question to ask is why there can be
@ -58,15 +58,15 @@ namespace Opm
/// reporting and using data given in terms of surface values, /// reporting and using data given in terms of surface values,
/// we need to handle this difference. /// we need to handle this difference.
/// \return Array of size numPhases(). /// \return Array of size numPhases().
const double* reservoirDensities() const; const double* reservoirDensities() const;
/// Viscosities. /// Viscosities.
const double* viscosity() const; const double* viscosity() const;
private: private:
std::tr1::array<double, 2> surface_density_; std::tr1::array<double, 2> surface_density_;
std::tr1::array<double, 2> reservoir_density_; std::tr1::array<double, 2> reservoir_density_;
std::tr1::array<double, 2> viscosity_; std::tr1::array<double, 2> viscosity_;
}; };
} }

View File

@ -25,29 +25,29 @@ namespace Opm
/// Default constructor. /// Default constructor.
RockBasic::RockBasic() RockBasic::RockBasic()
: dimensions_(-1) : dimensions_(-1)
{ {
} }
/// Initialize with homogenous porosity and permeability. /// Initialize with homogenous porosity and permeability.
void RockBasic::init(const int dimensions, void RockBasic::init(const int dimensions,
const int num_cells, const int num_cells,
const double poro, const double poro,
const double perm) const double perm)
{ {
dimensions_ = dimensions; dimensions_ = dimensions;
porosity_.clear(); porosity_.clear();
porosity_.resize(num_cells, poro); porosity_.resize(num_cells, poro);
permeability_.clear(); permeability_.clear();
const int dsq = dimensions*dimensions; const int dsq = dimensions*dimensions;
permeability_.resize(num_cells*dsq, 0.0); permeability_.resize(num_cells*dsq, 0.0);
// #pragma omp parallel for // #pragma omp parallel for
for (int i = 0; i < num_cells; ++i) { for (int i = 0; i < num_cells; ++i) {
for (int d = 0; d < dimensions; ++d) { for (int d = 0; d < dimensions; ++d) {
permeability_[dsq*i + dimensions*d + d] = perm; permeability_[dsq*i + dimensions*d + d] = perm;
} }
} }
} }

View File

@ -35,9 +35,9 @@ namespace Opm
/// Initialize with homogenous porosity and permeability. /// Initialize with homogenous porosity and permeability.
void init(const int dimensions, void init(const int dimensions,
const int num_cells, const int num_cells,
const double poro, const double poro,
const double perm); const double perm);
/// \return D, the number of spatial dimensions. /// \return D, the number of spatial dimensions.
int numDimensions() const int numDimensions() const
@ -66,7 +66,7 @@ namespace Opm
} }
private: private:
int dimensions_; int dimensions_;
std::vector<double> porosity_; std::vector<double> porosity_;
std::vector<double> permeability_; std::vector<double> permeability_;
}; };

View File

@ -69,7 +69,8 @@ namespace Opm
const double cpnorm = rock_comp_*(pressure - pref_); const double cpnorm = rock_comp_*(pressure - pref_);
return (1.0 + cpnorm + 0.5*cpnorm*cpnorm); return (1.0 + cpnorm + 0.5*cpnorm*cpnorm);
} else { } else {
return Opm::linearInterpolation(p_, poromult_, pressure); // return Opm::linearInterpolation(p_, poromult_, pressure);
return Opm::linearInterpolationExtrap(p_, poromult_, pressure);
} }
} }
@ -78,8 +79,11 @@ namespace Opm
if (p_.empty()) { if (p_.empty()) {
return rock_comp_; return rock_comp_;
} else { } else {
const double poromult = Opm::linearInterpolation(p_, poromult_, pressure); //const double poromult = Opm::linearInterpolation(p_, poromult_, pressure);
const double dporomultdp = Opm::linearInterpolationDerivative(p_, poromult_, pressure); //const double dporomultdp = Opm::linearInterpolationDerivative(p_, poromult_, pressure);
const double poromult = Opm::linearInterpolationExtrap(p_, poromult_, pressure);
const double dporomultdp = Opm::linearInterpolationDerivativeExtrap(p_, poromult_, pressure);
return dporomultdp/poromult; return dporomultdp/poromult;
} }
} }

View File

@ -19,7 +19,7 @@
#include <opm/core/fluid/RockFromDeck.hpp> #include <opm/core/fluid/RockFromDeck.hpp>
#include <opm/core/grid.h>
#include <tr1/array> #include <tr1/array>
namespace Opm namespace Opm
@ -36,8 +36,6 @@ namespace Opm
PermeabilityKind fillTensor(const EclipseGridParser& parser, PermeabilityKind fillTensor(const EclipseGridParser& parser,
std::vector<const std::vector<double>*>& tensor, std::vector<const std::vector<double>*>& tensor,
std::tr1::array<int,9>& kmap); std::tr1::array<int,9>& kmap);
int numGlobalCells(const EclipseGridParser& parser);
} // anonymous namespace } // anonymous namespace
@ -53,28 +51,29 @@ namespace Opm
/// Initialize from deck and cell mapping. /// Initialize from deck and cell mapping.
/// \param deck Deck input parser /// \param deck Deck input parser
/// \param global_cell mapping from cell indices (typically from a processed grid) /// \param grid grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck. /// to logical cartesian indices consistent with the deck.
void RockFromDeck::init(const EclipseGridParser& deck, void RockFromDeck::init(const EclipseGridParser& deck,
const std::vector<int>& global_cell) const UnstructuredGrid& grid)
{ {
assignPorosity(deck, global_cell); assignPorosity(deck, grid);
permfield_valid_.assign(global_cell.size(), false); permfield_valid_.assign(grid.number_of_cells, false);
const double perm_threshold = 0.0; // Maybe turn into parameter? const double perm_threshold = 0.0; // Maybe turn into parameter?
assignPermeability(deck, global_cell, perm_threshold); assignPermeability(deck, grid, perm_threshold);
} }
void RockFromDeck::assignPorosity(const EclipseGridParser& parser, void RockFromDeck::assignPorosity(const EclipseGridParser& parser,
const std::vector<int>& global_cell) const UnstructuredGrid& grid)
{ {
porosity_.assign(global_cell.size(), 1.0); porosity_.assign(grid.number_of_cells, 1.0);
const int* gc = grid.global_cell;
if (parser.hasField("PORO")) { if (parser.hasField("PORO")) {
const std::vector<double>& poro = parser.getFloatingPointValue("PORO"); const std::vector<double>& poro = parser.getFloatingPointValue("PORO");
for (int c = 0; c < int(porosity_.size()); ++c) { for (int c = 0; c < int(porosity_.size()); ++c) {
porosity_[c] = poro[global_cell[c]]; const int deck_pos = (gc == NULL) ? c : gc[c];
porosity_[c] = poro[deck_pos];
} }
} }
} }
@ -82,14 +81,16 @@ namespace Opm
void RockFromDeck::assignPermeability(const EclipseGridParser& parser, void RockFromDeck::assignPermeability(const EclipseGridParser& parser,
const std::vector<int>& global_cell, const UnstructuredGrid& grid,
double perm_threshold) double perm_threshold)
{ {
const int dim = 3; const int dim = 3;
const int num_global_cells = numGlobalCells(parser); const int num_global_cells = grid.cartdims[0]*grid.cartdims[1]*grid.cartdims[2];
const int nc = grid.number_of_cells;
ASSERT (num_global_cells > 0); ASSERT (num_global_cells > 0);
permeability_.assign(dim * dim * global_cell.size(), 0.0); permeability_.assign(dim * dim * nc, 0.0);
std::vector<const std::vector<double>*> tensor; std::vector<const std::vector<double>*> tensor;
tensor.reserve(10); tensor.reserve(10);
@ -111,13 +112,13 @@ namespace Opm
// chosen) default value... // chosen) default value...
// //
if (tensor.size() > 1) { if (tensor.size() > 1) {
const int nc = global_cell.size(); const int* gc = grid.global_cell;
int off = 0; int off = 0;
for (int c = 0; c < nc; ++c, off += dim*dim) { for (int c = 0; c < nc; ++c, off += dim*dim) {
// SharedPermTensor K(dim, dim, &permeability_[off]); // SharedPermTensor K(dim, dim, &permeability_[off]);
int kix = 0; int kix = 0;
const int glob = global_cell[c]; const int glob = (gc == NULL) ? c : gc[c];
for (int i = 0; i < dim; ++i) { for (int i = 0; i < dim; ++i) {
for (int j = 0; j < dim; ++j, ++kix) { for (int j = 0; j < dim; ++j, ++kix) {
@ -331,26 +332,6 @@ namespace Opm
return kind; return kind;
} }
int numGlobalCells(const EclipseGridParser& parser)
{
int ngc = -1;
if (parser.hasField("DIMENS")) {
const std::vector<int>&
dims = parser.getIntegerValue("DIMENS");
ngc = dims[0] * dims[1] * dims[2];
}
else if (parser.hasField("SPECGRID")) {
const SPECGRID& sgr = parser.getSPECGRID();
ngc = sgr.dimensions[ 0 ];
ngc *= sgr.dimensions[ 1 ];
ngc *= sgr.dimensions[ 2 ];
}
return ngc;
}
} // anonymous namespace } // anonymous namespace
} // namespace Opm } // namespace Opm

View File

@ -24,6 +24,7 @@
#include <opm/core/eclipse/EclipseGridParser.hpp> #include <opm/core/eclipse/EclipseGridParser.hpp>
#include <vector> #include <vector>
struct UnstructuredGrid;
namespace Opm namespace Opm
{ {
@ -34,12 +35,13 @@ namespace Opm
/// Default constructor. /// Default constructor.
RockFromDeck(); RockFromDeck();
/// Initialize from deck and cell mapping. /// Initialize from deck and grid.
/// \param deck Deck input parser /// \param deck Deck input parser
/// \param global_cell mapping from cell indices (typically from a processed grid) /// \param grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck. /// to logical cartesian indices consistent with the deck.
void init(const EclipseGridParser& deck, void init(const EclipseGridParser& deck,
const std::vector<int>& global_cell); const UnstructuredGrid& grid);
/// \return D, the number of spatial dimensions. Always 3 for deck input. /// \return D, the number of spatial dimensions. Always 3 for deck input.
int numDimensions() const int numDimensions() const
@ -69,9 +71,9 @@ namespace Opm
private: private:
void assignPorosity(const EclipseGridParser& parser, void assignPorosity(const EclipseGridParser& parser,
const std::vector<int>& global_cell); const UnstructuredGrid& grid);
void assignPermeability(const EclipseGridParser& parser, void assignPermeability(const EclipseGridParser& parser,
const std::vector<int>& global_cell, const UnstructuredGrid& grid,
const double perm_threshold); const double perm_threshold);
std::vector<double> porosity_; std::vector<double> porosity_;

View File

@ -0,0 +1,440 @@
/*
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 <opm/core/fluid/SatFuncGwseg.hpp>
#include <opm/core/fluid/blackoil/BlackoilPhases.hpp>
#include <opm/core/fluid/SaturationPropsFromDeck.hpp>
#include <opm/core/grid.h>
#include <opm/core/fluid/blackoil/phaseUsageFromDeck.hpp>
#include <opm/core/utility/buildUniformMonotoneTable.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <iostream>
namespace Opm
{
void SatFuncGwsegUniform::init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples)
{
phase_usage = phase_usg;
double swco = 0.0;
double swmax = 1.0;
if (phase_usage.phase_used[Aqua]) {
const SWOF::table_t& swof_table = deck.getSWOF().swof_;
const std::vector<double>& sw = swof_table[table_num][0];
const std::vector<double>& krw = swof_table[table_num][1];
const std::vector<double>& krow = swof_table[table_num][2];
const std::vector<double>& pcow = swof_table[table_num][3];
buildUniformMonotoneTable(sw, krw, samples, krw_);
buildUniformMonotoneTable(sw, krow, samples, krow_);
buildUniformMonotoneTable(sw, pcow, samples, pcow_);
krocw_ = krow[0]; // At connate water -> ecl. SWOF
swco = sw[0];
smin_[phase_usage.phase_pos[Aqua]] = sw[0];
swmax = sw.back();
smax_[phase_usage.phase_pos[Aqua]] = sw.back();
}
if (phase_usage.phase_used[Vapour]) {
const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
const std::vector<double>& sg = sgof_table[table_num][0];
const std::vector<double>& krg = sgof_table[table_num][1];
const std::vector<double>& krog = sgof_table[table_num][2];
const std::vector<double>& pcog = sgof_table[table_num][3];
buildUniformMonotoneTable(sg, krg, samples, krg_);
buildUniformMonotoneTable(sg, krog, samples, krog_);
buildUniformMonotoneTable(sg, pcog, samples, pcog_);
smin_[phase_usage.phase_pos[Vapour]] = sg[0];
if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
", should equal (1.0 - connate water sat) = " << (1.0 - swco));
}
smax_[phase_usage.phase_pos[Vapour]] = sg.back();
}
// These only consider water min/max sats. Consider gas sats?
smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
}
void SatFuncGwsegUniform::evalKr(const double* s, double* kr) const
{
if (phase_usage.num_phases == 3) {
// Relative permeability model based on segregation of water
// and gas, with oil present in both water and gas zones.
const double swco = smin_[phase_usage.phase_pos[Aqua]];
const double sw = std::max(s[Aqua], swco);
const double sg = s[Vapour];
// xw and xg are the fractions occupied by water and gas zones.
const double eps = 1e-6;
const double xw = (sw - swco) / std::max(sg + sw - swco, eps);
const double xg = 1 - xw;
const double ssw = sg + sw;
const double ssg = sw - swco + sg;
const double krw = krw_(ssw);
const double krg = krg_(ssg);
const double krow = krow_(ssw);
const double krog = krog_(ssg);
kr[Aqua] = xw*krw;
kr[Vapour] = xg*krg;
kr[Liquid] = xw*krow + xg*krog;
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double krow = krow_(sw);
kr[wpos] = krw;
kr[opos] = krow;
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double krog = krog_(sg);
kr[gpos] = krg;
kr[opos] = krog;
}
}
void SatFuncGwsegUniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
{
const int np = phase_usage.num_phases;
std::fill(dkrds, dkrds + np*np, 0.0);
if (np == 3) {
// Relative permeability model based on segregation of water
// and gas, with oil present in both water and gas zones.
const double swco = smin_[phase_usage.phase_pos[Aqua]];
const double sw = std::max(s[Aqua], swco);
const double sg = s[Vapour];
// xw and xg are the fractions occupied by water and gas zones.
const double eps = 1e-6;
const double xw = (sw - swco) / std::max(sg + sw - swco, eps);
const double xg = 1 - xw;
const double ssw = sg + sw;
const double ssg = sw - swco + sg;
const double krw = krw_(ssw);
const double krg = krg_(ssg);
const double krow = krow_(ssw);
const double krog = krog_(ssg);
kr[Aqua] = xw*krw;
kr[Vapour] = xg*krg;
kr[Liquid] = xw*krow + xg*krog;
// Derivatives.
const double dkrww = krw_.derivative(ssw);
const double dkrgg = krg_.derivative(ssg);
const double dkrow = krow_.derivative(ssw);
const double dkrog = krog_.derivative(ssg);
const double d = ssg; // = sw - swco + sg (using 'd' for consistency with mrst docs).
dkrds[Aqua + Aqua*np] = (xg/d)*krw + xw*dkrww;
dkrds[Aqua + Vapour*np] = -(xw/d)*krw + xw*dkrww;
dkrds[Liquid + Aqua*np] = (xg/d)*krow + xw*dkrow - (xg/d)*krog + xg*dkrog;
dkrds[Liquid + Vapour*np] = -(xw/d)*krow + xw*dkrow + (xw/d)*krog + xg*dkrog;
dkrds[Vapour + Aqua*np] = -(xg/d)*krg + xg*dkrgg;
dkrds[Vapour + Vapour*np] = (xw/d)*krg + xg*dkrgg;
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krow = krow_(sw);
double dkrow = krow_.derivative(sw);
kr[wpos] = krw;
kr[opos] = krow;
dkrds[wpos + wpos*np] = dkrww;
dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
kr[gpos] = krg;
kr[opos] = krog;
dkrds[gpos + gpos*np] = dkrgg;
dkrds[opos + gpos*np] = dkrog;
}
}
void SatFuncGwsegUniform::evalPc(const double* s, double* pc) const
{
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
}
}
void SatFuncGwsegUniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
{
// The problem of determining three-phase capillary pressures
// is very hard experimentally, usually one extends two-phase
// data (as for relative permeability).
// In our approach the derivative matrix is quite sparse, only
// the diagonal elements corresponding to non-oil phases are
// (potentially) nonzero.
const int np = phase_usage.num_phases;
std::fill(dpcds, dpcds + np*np, 0.0);
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
}
}
// ====== Methods for SatFuncGwsegNonuniform ======
void SatFuncGwsegNonuniform::init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int /*samples*/)
{
phase_usage = phase_usg;
double swco = 0.0;
double swmax = 1.0;
if (phase_usage.phase_used[Aqua]) {
const SWOF::table_t& swof_table = deck.getSWOF().swof_;
const std::vector<double>& sw = swof_table[table_num][0];
const std::vector<double>& krw = swof_table[table_num][1];
const std::vector<double>& krow = swof_table[table_num][2];
const std::vector<double>& pcow = swof_table[table_num][3];
krw_ = NonuniformTableLinear<double>(sw, krw);
krow_ = NonuniformTableLinear<double>(sw, krow);
pcow_ = NonuniformTableLinear<double>(sw, pcow);
krocw_ = krow[0]; // At connate water -> ecl. SWOF
swco = sw[0];
smin_[phase_usage.phase_pos[Aqua]] = sw[0];
swmax = sw.back();
smax_[phase_usage.phase_pos[Aqua]] = sw.back();
}
if (phase_usage.phase_used[Vapour]) {
const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
const std::vector<double>& sg = sgof_table[table_num][0];
const std::vector<double>& krg = sgof_table[table_num][1];
const std::vector<double>& krog = sgof_table[table_num][2];
const std::vector<double>& pcog = sgof_table[table_num][3];
krg_ = NonuniformTableLinear<double>(sg, krg);
krog_ = NonuniformTableLinear<double>(sg, krog);
pcog_ = NonuniformTableLinear<double>(sg, pcog);
smin_[phase_usage.phase_pos[Vapour]] = sg[0];
if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
", should equal (1.0 - connate water sat) = " << (1.0 - swco));
}
smax_[phase_usage.phase_pos[Vapour]] = sg.back();
}
// These only consider water min/max sats. Consider gas sats?
smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
}
void SatFuncGwsegNonuniform::evalKr(const double* s, double* kr) const
{
if (phase_usage.num_phases == 3) {
// Relative permeability model based on segregation of water
// and gas, with oil present in both water and gas zones.
const double swco = smin_[phase_usage.phase_pos[Aqua]];
const double sw = std::max(s[Aqua], swco);
const double sg = s[Vapour];
// xw and xg are the fractions occupied by water and gas zones.
const double eps = 1e-6;
const double xw = (sw - swco) / std::max(sg + sw - swco, eps);
const double xg = 1 - xw;
const double ssw = sg + sw;
const double ssg = sw - swco + sg;
const double krw = krw_(ssw);
const double krg = krg_(ssg);
const double krow = krow_(ssw);
const double krog = krog_(ssg);
kr[Aqua] = xw*krw;
kr[Vapour] = xg*krg;
kr[Liquid] = xw*krow + xg*krog;
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double krow = krow_(sw);
kr[wpos] = krw;
kr[opos] = krow;
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double krog = krog_(sg);
kr[gpos] = krg;
kr[opos] = krog;
}
}
void SatFuncGwsegNonuniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
{
const int np = phase_usage.num_phases;
std::fill(dkrds, dkrds + np*np, 0.0);
if (np == 3) {
// Relative permeability model based on segregation of water
// and gas, with oil present in both water and gas zones.
const double swco = smin_[phase_usage.phase_pos[Aqua]];
const double sw = std::max(s[Aqua], swco);
const double sg = s[Vapour];
// xw and xg are the fractions occupied by water and gas zones.
const double eps = 1e-6;
const double xw = (sw - swco) / std::max(sg + sw - swco, eps);
const double xg = 1 - xw;
const double ssw = sg + sw;
const double ssg = sw - swco + sg;
const double krw = krw_(ssw);
const double krg = krg_(ssg);
const double krow = krow_(ssw);
const double krog = krog_(ssg);
kr[Aqua] = xw*krw;
kr[Vapour] = xg*krg;
kr[Liquid] = xw*krow + xg*krog;
// Derivatives.
const double dkrww = krw_.derivative(ssw);
const double dkrgg = krg_.derivative(ssg);
const double dkrow = krow_.derivative(ssw);
const double dkrog = krog_.derivative(ssg);
const double d = ssg; // = sw - swco + sg (using 'd' for consistency with mrst docs).
dkrds[Aqua + Aqua*np] = (xg/d)*krw + xw*dkrww;
dkrds[Aqua + Vapour*np] = -(xw/d)*krw + xw*dkrww;
dkrds[Liquid + Aqua*np] = (xg/d)*krow + xw*dkrow - (xg/d)*krog + xg*dkrog;
dkrds[Liquid + Vapour*np] = -(xw/d)*krow + xw*dkrow + (xw/d)*krog + xg*dkrog;
dkrds[Vapour + Aqua*np] = -(xg/d)*krg + xg*dkrgg;
dkrds[Vapour + Vapour*np] = (xw/d)*krg + xg*dkrgg;
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krow = krow_(sw);
double dkrow = krow_.derivative(sw);
kr[wpos] = krw;
kr[opos] = krow;
dkrds[wpos + wpos*np] = dkrww;
dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
kr[gpos] = krg;
kr[opos] = krog;
dkrds[gpos + gpos*np] = dkrgg;
dkrds[opos + gpos*np] = dkrog;
}
}
void SatFuncGwsegNonuniform::evalPc(const double* s, double* pc) const
{
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
}
}
void SatFuncGwsegNonuniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
{
// The problem of determining three-phase capillary pressures
// is very hard experimentally, usually one extends two-phase
// data (as for relative permeability).
// In our approach the derivative matrix is quite sparse, only
// the diagonal elements corresponding to non-oil phases are
// (potentially) nonzero.
const int np = phase_usage.num_phases;
std::fill(dpcds, dpcds + np*np, 0.0);
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
}
}
} // namespace Opm

View File

@ -0,0 +1,80 @@
/*
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 SATFUNCGWSEG_HPP
#define SATFUNCGWSEG_HPP
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/utility/UniformTableLinear.hpp>
#include <opm/core/utility/NonuniformTableLinear.hpp>
#include <opm/core/fluid/blackoil/BlackoilPhases.hpp>
#include <vector>
namespace Opm
{
class SatFuncGwsegUniform : public BlackoilPhases
{
public:
void init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
void evalPc(const double* s, double* pc) const;
void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
double smin_[PhaseUsage::MaxNumPhases];
double smax_[PhaseUsage::MaxNumPhases];
private:
PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
UniformTableLinear<double> krw_;
UniformTableLinear<double> krow_;
UniformTableLinear<double> pcow_;
UniformTableLinear<double> krg_;
UniformTableLinear<double> krog_;
UniformTableLinear<double> pcog_;
double krocw_; // = krow_(s_wc)
};
class SatFuncGwsegNonuniform : public BlackoilPhases
{
public:
void init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
void evalPc(const double* s, double* pc) const;
void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
double smin_[PhaseUsage::MaxNumPhases];
double smax_[PhaseUsage::MaxNumPhases];
private:
PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
NonuniformTableLinear<double> krw_;
NonuniformTableLinear<double> krow_;
NonuniformTableLinear<double> pcow_;
NonuniformTableLinear<double> krg_;
NonuniformTableLinear<double> krog_;
NonuniformTableLinear<double> pcog_;
double krocw_; // = krow_(s_wc)
};
} // namespace Opm
#endif // SATFUNCGWSEG_HPP

View File

@ -0,0 +1,425 @@
/*
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 <opm/core/fluid/SatFuncSimple.hpp>
#include <opm/core/fluid/blackoil/BlackoilPhases.hpp>
#include <opm/core/fluid/SaturationPropsFromDeck.hpp>
#include <opm/core/grid.h>
#include <opm/core/fluid/blackoil/phaseUsageFromDeck.hpp>
#include <opm/core/utility/buildUniformMonotoneTable.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <iostream>
namespace Opm
{
void SatFuncSimpleUniform::init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples)
{
phase_usage = phase_usg;
double swco = 0.0;
double swmax = 1.0;
if (phase_usage.phase_used[Aqua]) {
const SWOF::table_t& swof_table = deck.getSWOF().swof_;
const std::vector<double>& sw = swof_table[table_num][0];
const std::vector<double>& krw = swof_table[table_num][1];
const std::vector<double>& krow = swof_table[table_num][2];
const std::vector<double>& pcow = swof_table[table_num][3];
buildUniformMonotoneTable(sw, krw, samples, krw_);
buildUniformMonotoneTable(sw, krow, samples, krow_);
buildUniformMonotoneTable(sw, pcow, samples, pcow_);
krocw_ = krow[0]; // At connate water -> ecl. SWOF
swco = sw[0];
smin_[phase_usage.phase_pos[Aqua]] = sw[0];
swmax = sw.back();
smax_[phase_usage.phase_pos[Aqua]] = sw.back();
}
if (phase_usage.phase_used[Vapour]) {
const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
const std::vector<double>& sg = sgof_table[table_num][0];
const std::vector<double>& krg = sgof_table[table_num][1];
const std::vector<double>& krog = sgof_table[table_num][2];
const std::vector<double>& pcog = sgof_table[table_num][3];
buildUniformMonotoneTable(sg, krg, samples, krg_);
buildUniformMonotoneTable(sg, krog, samples, krog_);
buildUniformMonotoneTable(sg, pcog, samples, pcog_);
smin_[phase_usage.phase_pos[Vapour]] = sg[0];
if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
", should equal (1.0 - connate water sat) = " << (1.0 - swco));
}
smax_[phase_usage.phase_pos[Vapour]] = sg.back();
}
// These only consider water min/max sats. Consider gas sats?
smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
}
void SatFuncSimpleUniform::evalKr(const double* s, double* kr) const
{
if (phase_usage.num_phases == 3) {
// A simplified relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double krg = krg_(sg);
double krow = krow_(sw + sg); // = 1 - so
// double krog = krog_(sg); // = 1 - so - sw
// double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krow;
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double krow = krow_(sw);
kr[wpos] = krw;
kr[opos] = krow;
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double krog = krog_(sg);
kr[gpos] = krg;
kr[opos] = krog;
}
}
void SatFuncSimpleUniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
{
const int np = phase_usage.num_phases;
std::fill(dkrds, dkrds + np*np, 0.0);
if (np == 3) {
// A simplified relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krow = krow_(sw + sg);
double dkrow = krow_.derivative(sw + sg);
// double krog = krog_(sg);
// double dkrog = krog_.derivative(sg);
// double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krow;
//krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
dkrds[Aqua + Aqua*np] = dkrww;
dkrds[Vapour + Vapour*np] = dkrgg;
//dkrds[Liquid + Aqua*np] = dkrow;
dkrds[Liquid + Liquid*np] = -dkrow;
//krocw*((dkrow/krocw + dkrww)*(krog/krocw + krg) - dkrww);
dkrds[Liquid + Vapour*np] = 0.0;
//krocw*((krow/krocw + krw)*(dkrog/krocw + dkrgg) - dkrgg)
//+ krocw*((dkrow/krocw + krw)*(krog/krocw + krg) - dkrgg);
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krow = krow_(sw);
double dkrow = krow_.derivative(sw);
kr[wpos] = krw;
kr[opos] = krow;
dkrds[wpos + wpos*np] = dkrww;
dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
kr[gpos] = krg;
kr[opos] = krog;
dkrds[gpos + gpos*np] = dkrgg;
dkrds[opos + gpos*np] = dkrog;
}
}
void SatFuncSimpleUniform::evalPc(const double* s, double* pc) const
{
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
}
}
void SatFuncSimpleUniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
{
// The problem of determining three-phase capillary pressures
// is very hard experimentally, usually one extends two-phase
// data (as for relative permeability).
// In our approach the derivative matrix is quite sparse, only
// the diagonal elements corresponding to non-oil phases are
// (potentially) nonzero.
const int np = phase_usage.num_phases;
std::fill(dpcds, dpcds + np*np, 0.0);
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
}
}
// ====== Methods for SatFuncSimpleNonuniform ======
void SatFuncSimpleNonuniform::init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int /*samples*/)
{
phase_usage = phase_usg;
double swco = 0.0;
double swmax = 1.0;
if (phase_usage.phase_used[Aqua]) {
const SWOF::table_t& swof_table = deck.getSWOF().swof_;
const std::vector<double>& sw = swof_table[table_num][0];
const std::vector<double>& krw = swof_table[table_num][1];
const std::vector<double>& krow = swof_table[table_num][2];
const std::vector<double>& pcow = swof_table[table_num][3];
krw_ = NonuniformTableLinear<double>(sw, krw);
krow_ = NonuniformTableLinear<double>(sw, krow);
pcow_ = NonuniformTableLinear<double>(sw, pcow);
krocw_ = krow[0]; // At connate water -> ecl. SWOF
swco = sw[0];
smin_[phase_usage.phase_pos[Aqua]] = sw[0];
swmax = sw.back();
smax_[phase_usage.phase_pos[Aqua]] = sw.back();
}
if (phase_usage.phase_used[Vapour]) {
const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
const std::vector<double>& sg = sgof_table[table_num][0];
const std::vector<double>& krg = sgof_table[table_num][1];
const std::vector<double>& krog = sgof_table[table_num][2];
const std::vector<double>& pcog = sgof_table[table_num][3];
krg_ = NonuniformTableLinear<double>(sg, krg);
krog_ = NonuniformTableLinear<double>(sg, krog);
pcog_ = NonuniformTableLinear<double>(sg, pcog);
smin_[phase_usage.phase_pos[Vapour]] = sg[0];
if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
", should equal (1.0 - connate water sat) = " << (1.0 - swco));
}
smax_[phase_usage.phase_pos[Vapour]] = sg.back();
}
// These only consider water min/max sats. Consider gas sats?
smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
}
void SatFuncSimpleNonuniform::evalKr(const double* s, double* kr) const
{
if (phase_usage.num_phases == 3) {
// A simplified relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double krg = krg_(sg);
double krow = krow_(sw + sg); // = 1 - so
// double krog = krog_(sg); // = 1 - so - sw
// double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krow;
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double krow = krow_(sw);
kr[wpos] = krw;
kr[opos] = krow;
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double krog = krog_(sg);
kr[gpos] = krg;
kr[opos] = krog;
}
}
void SatFuncSimpleNonuniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
{
const int np = phase_usage.num_phases;
std::fill(dkrds, dkrds + np*np, 0.0);
if (np == 3) {
// A simplified relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krow = krow_(sw + sg);
double dkrow = krow_.derivative(sw + sg);
// double krog = krog_(sg);
// double dkrog = krog_.derivative(sg);
// double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krow;
//krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
dkrds[Aqua + Aqua*np] = dkrww;
dkrds[Vapour + Vapour*np] = dkrgg;
//dkrds[Liquid + Aqua*np] = dkrow;
dkrds[Liquid + Liquid*np] = -dkrow;
//krocw*((dkrow/krocw + dkrww)*(krog/krocw + krg) - dkrww);
dkrds[Liquid + Vapour*np] = 0.0;
//krocw*((krow/krocw + krw)*(dkrog/krocw + dkrgg) - dkrgg)
//+ krocw*((dkrow/krocw + krw)*(krog/krocw + krg) - dkrgg);
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krow = krow_(sw);
double dkrow = krow_.derivative(sw);
kr[wpos] = krw;
kr[opos] = krow;
dkrds[wpos + wpos*np] = dkrww;
dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
kr[gpos] = krg;
kr[opos] = krog;
dkrds[gpos + gpos*np] = dkrgg;
dkrds[opos + gpos*np] = dkrog;
}
}
void SatFuncSimpleNonuniform::evalPc(const double* s, double* pc) const
{
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
}
}
void SatFuncSimpleNonuniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
{
// The problem of determining three-phase capillary pressures
// is very hard experimentally, usually one extends two-phase
// data (as for relative permeability).
// In our approach the derivative matrix is quite sparse, only
// the diagonal elements corresponding to non-oil phases are
// (potentially) nonzero.
const int np = phase_usage.num_phases;
std::fill(dpcds, dpcds + np*np, 0.0);
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
}
}
} // namespace Opm

View File

@ -0,0 +1,80 @@
/*
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 SATFUNCSIMPLE_HPP
#define SATFUNCSIMPLE_HPP
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/utility/UniformTableLinear.hpp>
#include <opm/core/utility/NonuniformTableLinear.hpp>
#include <opm/core/fluid/blackoil/BlackoilPhases.hpp>
#include <vector>
namespace Opm
{
class SatFuncSimpleUniform : public BlackoilPhases
{
public:
void init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
void evalPc(const double* s, double* pc) const;
void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
double smin_[PhaseUsage::MaxNumPhases];
double smax_[PhaseUsage::MaxNumPhases];
private:
PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
UniformTableLinear<double> krw_;
UniformTableLinear<double> krow_;
UniformTableLinear<double> pcow_;
UniformTableLinear<double> krg_;
UniformTableLinear<double> krog_;
UniformTableLinear<double> pcog_;
double krocw_; // = krow_(s_wc)
};
class SatFuncSimpleNonuniform : public BlackoilPhases
{
public:
void init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
void evalPc(const double* s, double* pc) const;
void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
double smin_[PhaseUsage::MaxNumPhases];
double smax_[PhaseUsage::MaxNumPhases];
private:
PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
NonuniformTableLinear<double> krw_;
NonuniformTableLinear<double> krow_;
NonuniformTableLinear<double> pcow_;
NonuniformTableLinear<double> krg_;
NonuniformTableLinear<double> krog_;
NonuniformTableLinear<double> pcog_;
double krocw_; // = krow_(s_wc)
};
} // namespace Opm
#endif // SATFUNCSIMPLE_HPP

View File

@ -0,0 +1,417 @@
/*
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 <opm/core/fluid/SatFuncStone2.hpp>
#include <opm/core/fluid/blackoil/BlackoilPhases.hpp>
#include <opm/core/fluid/SaturationPropsFromDeck.hpp>
#include <opm/core/grid.h>
#include <opm/core/fluid/blackoil/phaseUsageFromDeck.hpp>
#include <opm/core/utility/buildUniformMonotoneTable.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <iostream>
namespace Opm
{
void SatFuncStone2Uniform::init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples)
{
phase_usage = phase_usg;
double swco = 0.0;
double swmax = 1.0;
if (phase_usage.phase_used[Aqua]) {
const SWOF::table_t& swof_table = deck.getSWOF().swof_;
const std::vector<double>& sw = swof_table[table_num][0];
const std::vector<double>& krw = swof_table[table_num][1];
const std::vector<double>& krow = swof_table[table_num][2];
const std::vector<double>& pcow = swof_table[table_num][3];
buildUniformMonotoneTable(sw, krw, samples, krw_);
buildUniformMonotoneTable(sw, krow, samples, krow_);
buildUniformMonotoneTable(sw, pcow, samples, pcow_);
krocw_ = krow[0]; // At connate water -> ecl. SWOF
swco = sw[0];
smin_[phase_usage.phase_pos[Aqua]] = sw[0];
swmax = sw.back();
smax_[phase_usage.phase_pos[Aqua]] = sw.back();
}
if (phase_usage.phase_used[Vapour]) {
const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
const std::vector<double>& sg = sgof_table[table_num][0];
const std::vector<double>& krg = sgof_table[table_num][1];
const std::vector<double>& krog = sgof_table[table_num][2];
const std::vector<double>& pcog = sgof_table[table_num][3];
buildUniformMonotoneTable(sg, krg, samples, krg_);
buildUniformMonotoneTable(sg, krog, samples, krog_);
buildUniformMonotoneTable(sg, pcog, samples, pcog_);
smin_[phase_usage.phase_pos[Vapour]] = sg[0];
if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
", should equal (1.0 - connate water sat) = " << (1.0 - swco));
}
smax_[phase_usage.phase_pos[Vapour]] = sg.back();
}
// These only consider water min/max sats. Consider gas sats?
smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
}
void SatFuncStone2Uniform::evalKr(const double* s, double* kr) const
{
if (phase_usage.num_phases == 3) {
// Stone-II relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double krg = krg_(sg);
double krow = krow_(sw + sg); // = 1 - so
double krog = krog_(sg); // = 1 - so - sw
double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double krow = krow_(sw);
kr[wpos] = krw;
kr[opos] = krow;
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double krog = krog_(sg);
kr[gpos] = krg;
kr[opos] = krog;
}
}
void SatFuncStone2Uniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
{
const int np = phase_usage.num_phases;
std::fill(dkrds, dkrds + np*np, 0.0);
if (np == 3) {
// Stone-II relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krow = krow_(sw + sg);
double dkrow = krow_.derivative(sw + sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
dkrds[Aqua + Aqua*np] = dkrww;
dkrds[Vapour + Vapour*np] = dkrgg;
dkrds[Liquid + Aqua*np] = krocw*((dkrow/krocw + dkrww)*(krog/krocw + krg) - dkrww);
dkrds[Liquid + Vapour*np] = krocw*((krow/krocw + krw)*(dkrog/krocw + dkrgg) - dkrgg)
+ krocw*((dkrow/krocw + krw)*(krog/krocw + krg) - dkrgg);
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krow = krow_(sw);
double dkrow = krow_.derivative(sw);
kr[wpos] = krw;
kr[opos] = krow;
dkrds[wpos + wpos*np] = dkrww;
dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
kr[gpos] = krg;
kr[opos] = krog;
dkrds[gpos + gpos*np] = dkrgg;
dkrds[opos + gpos*np] = dkrog;
}
}
void SatFuncStone2Uniform::evalPc(const double* s, double* pc) const
{
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
}
}
void SatFuncStone2Uniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
{
// The problem of determining three-phase capillary pressures
// is very hard experimentally, usually one extends two-phase
// data (as for relative permeability).
// In our approach the derivative matrix is quite sparse, only
// the diagonal elements corresponding to non-oil phases are
// (potentially) nonzero.
const int np = phase_usage.num_phases;
std::fill(dpcds, dpcds + np*np, 0.0);
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
}
}
// ====== Methods for SatFuncStone2Nonuniform ======
void SatFuncStone2Nonuniform::init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int /*samples*/)
{
phase_usage = phase_usg;
double swco = 0.0;
double swmax = 1.0;
if (phase_usage.phase_used[Aqua]) {
const SWOF::table_t& swof_table = deck.getSWOF().swof_;
const std::vector<double>& sw = swof_table[table_num][0];
const std::vector<double>& krw = swof_table[table_num][1];
const std::vector<double>& krow = swof_table[table_num][2];
const std::vector<double>& pcow = swof_table[table_num][3];
krw_ = NonuniformTableLinear<double>(sw, krw);
krow_ = NonuniformTableLinear<double>(sw, krow);
pcow_ = NonuniformTableLinear<double>(sw, pcow);
krocw_ = krow[0]; // At connate water -> ecl. SWOF
swco = sw[0];
smin_[phase_usage.phase_pos[Aqua]] = sw[0];
swmax = sw.back();
smax_[phase_usage.phase_pos[Aqua]] = sw.back();
}
if (phase_usage.phase_used[Vapour]) {
const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
const std::vector<double>& sg = sgof_table[table_num][0];
const std::vector<double>& krg = sgof_table[table_num][1];
const std::vector<double>& krog = sgof_table[table_num][2];
const std::vector<double>& pcog = sgof_table[table_num][3];
krg_ = NonuniformTableLinear<double>(sg, krg);
krog_ = NonuniformTableLinear<double>(sg, krog);
pcog_ = NonuniformTableLinear<double>(sg, pcog);
smin_[phase_usage.phase_pos[Vapour]] = sg[0];
if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
", should equal (1.0 - connate water sat) = " << (1.0 - swco));
}
smax_[phase_usage.phase_pos[Vapour]] = sg.back();
}
// These only consider water min/max sats. Consider gas sats?
smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
}
void SatFuncStone2Nonuniform::evalKr(const double* s, double* kr) const
{
if (phase_usage.num_phases == 3) {
// Stone-II relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double krg = krg_(sg);
double krow = krow_(sw + sg); // = 1 - so
double krog = krog_(sg); // = 1 - so - sw
double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double krow = krow_(sw);
kr[wpos] = krw;
kr[opos] = krow;
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double krog = krog_(sg);
kr[gpos] = krg;
kr[opos] = krog;
}
}
void SatFuncStone2Nonuniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
{
const int np = phase_usage.num_phases;
std::fill(dkrds, dkrds + np*np, 0.0);
if (np == 3) {
// Stone-II relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krow = krow_(sw + sg);
double dkrow = krow_.derivative(sw + sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
dkrds[Aqua + Aqua*np] = dkrww;
dkrds[Vapour + Vapour*np] = dkrgg;
dkrds[Liquid + Aqua*np] = krocw*((dkrow/krocw + dkrww)*(krog/krocw + krg) - dkrww);
dkrds[Liquid + Vapour*np] = krocw*((krow/krocw + krw)*(dkrog/krocw + dkrgg) - dkrgg)
+ krocw*((dkrow/krocw + krw)*(krog/krocw + krg) - dkrgg);
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krow = krow_(sw);
double dkrow = krow_.derivative(sw);
kr[wpos] = krw;
kr[opos] = krow;
dkrds[wpos + wpos*np] = dkrww;
dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
kr[gpos] = krg;
kr[opos] = krog;
dkrds[gpos + gpos*np] = dkrgg;
dkrds[opos + gpos*np] = dkrog;
}
}
void SatFuncStone2Nonuniform::evalPc(const double* s, double* pc) const
{
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
}
}
void SatFuncStone2Nonuniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
{
// The problem of determining three-phase capillary pressures
// is very hard experimentally, usually one extends two-phase
// data (as for relative permeability).
// In our approach the derivative matrix is quite sparse, only
// the diagonal elements corresponding to non-oil phases are
// (potentially) nonzero.
const int np = phase_usage.num_phases;
std::fill(dpcds, dpcds + np*np, 0.0);
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
}
}
} // namespace Opm

View File

@ -0,0 +1,80 @@
/*
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 SATFUNCSTONE2_HPP
#define SATFUNCSTONE2_HPP
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/utility/UniformTableLinear.hpp>
#include <opm/core/utility/NonuniformTableLinear.hpp>
#include <opm/core/fluid/blackoil/BlackoilPhases.hpp>
#include <vector>
namespace Opm
{
class SatFuncStone2Uniform : public BlackoilPhases
{
public:
void init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
void evalPc(const double* s, double* pc) const;
void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
double smin_[PhaseUsage::MaxNumPhases];
double smax_[PhaseUsage::MaxNumPhases];
private:
PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
UniformTableLinear<double> krw_;
UniformTableLinear<double> krow_;
UniformTableLinear<double> pcow_;
UniformTableLinear<double> krg_;
UniformTableLinear<double> krog_;
UniformTableLinear<double> pcog_;
double krocw_; // = krow_(s_wc)
};
class SatFuncStone2Nonuniform : public BlackoilPhases
{
public:
void init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
void evalPc(const double* s, double* pc) const;
void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
double smin_[PhaseUsage::MaxNumPhases];
double smax_[PhaseUsage::MaxNumPhases];
private:
PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
NonuniformTableLinear<double> krw_;
NonuniformTableLinear<double> krow_;
NonuniformTableLinear<double> pcow_;
NonuniformTableLinear<double> krg_;
NonuniformTableLinear<double> krog_;
NonuniformTableLinear<double> pcog_;
double krocw_; // = krow_(s_wc)
};
} // namespace Opm
#endif // SATFUNCSTONE2_HPP

View File

@ -29,64 +29,64 @@ namespace Opm
namespace { namespace {
struct KrFunConstant struct KrFunConstant
{ {
double kr(double) double kr(double)
{ {
return 1.0; return 1.0;
} }
double dkrds(double) double dkrds(double)
{ {
return 0.0; return 0.0;
} }
}; };
struct KrFunLinear struct KrFunLinear
{ {
double kr(double s) double kr(double s)
{ {
return s; return s;
} }
double dkrds(double) double dkrds(double)
{ {
return 1.0; return 1.0;
} }
}; };
struct KrFunQuadratic struct KrFunQuadratic
{ {
double kr(double s) double kr(double s)
{ {
return s*s; return s*s;
} }
double dkrds(double s) double dkrds(double s)
{ {
return 2.0*s; return 2.0*s;
} }
}; };
template <class Fun> template <class Fun>
static inline void evalAllKrDeriv(const int n, const int np, static inline void evalAllKrDeriv(const int n, const int np,
const double* s, double* kr, double* dkrds, Fun fun) const double* s, double* kr, double* dkrds, Fun fun)
{ {
if (dkrds == 0) { if (dkrds == 0) {
// #pragma omp parallel for // #pragma omp parallel for
for (int i = 0; i < n*np; ++i) { for (int i = 0; i < n*np; ++i) {
kr[i] = fun.kr(s[i]); kr[i] = fun.kr(s[i]);
} }
return; return;
} }
// #pragma omp parallel for // #pragma omp parallel for
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
std::fill(dkrds + i*np*np, dkrds + (i+1)*np*np, 0.0); std::fill(dkrds + i*np*np, dkrds + (i+1)*np*np, 0.0);
for (int phase = 0; phase < np; ++phase) { for (int phase = 0; phase < np; ++phase) {
kr[i*np + phase] = fun.kr(s[i*np + phase]); kr[i*np + phase] = fun.kr(s[i*np + phase]);
// Only diagonal elements in derivative. // Only diagonal elements in derivative.
dkrds[i*np*np + phase*np + phase] = fun.dkrds(s[i*np + phase]); dkrds[i*np*np + phase*np + phase] = fun.dkrds(s[i*np + phase]);
} }
} }
} }
} // anon namespace } // anon namespace
@ -99,6 +99,7 @@ namespace Opm
/// Default constructor. /// Default constructor.
SaturationPropsBasic::SaturationPropsBasic() SaturationPropsBasic::SaturationPropsBasic()
: num_phases_(0), relperm_func_(Constant)
{ {
} }
@ -108,24 +109,25 @@ namespace Opm
/// Initialize from parameters. /// Initialize from parameters.
void SaturationPropsBasic::init(const parameter::ParameterGroup& param) void SaturationPropsBasic::init(const parameter::ParameterGroup& param)
{ {
int num_phases = param.getDefault("num_phases", 2); int num_phases = param.getDefault("num_phases", 2);
if (num_phases > 2 || num_phases < 1) { if (num_phases > 2 || num_phases < 1) {
THROW("SaturationPropsBasic::init() illegal num_phases: " << num_phases); THROW("SaturationPropsBasic::init() illegal num_phases: " << num_phases);
} }
num_phases_ = num_phases; num_phases_ = num_phases;
std::string rpf = param.getDefault("relperm_func", std::string("Unset")); //std::string rpf = param.getDefault("relperm_func", std::string("Unset"));
if (rpf == "Constant") { std::string rpf = param.getDefault("relperm_func", std::string("Linear"));
relperm_func_ = Constant; if (rpf == "Constant") {
if(num_phases!=1){ relperm_func_ = Constant;
THROW("Constant relperm with more than one phase???"); if(num_phases!=1){
} THROW("Constant relperm with more than one phase???");
} else if (rpf == "Linear") { }
relperm_func_ = Linear; } else if (rpf == "Linear") {
} else if (rpf == "Quadratic") { relperm_func_ = Linear;
relperm_func_ = Quadratic; } else if (rpf == "Quadratic") {
} else { relperm_func_ = Quadratic;
THROW("SaturationPropsBasic::init() illegal relperm_func: " << rpf); } else {
} THROW("SaturationPropsBasic::init() illegal relperm_func: " << rpf);
}
} }
@ -134,7 +136,7 @@ namespace Opm
/// \return P, the number of phases. /// \return P, the number of phases.
int SaturationPropsBasic::numPhases() const int SaturationPropsBasic::numPhases() const
{ {
return num_phases_; return num_phases_;
} }
@ -150,29 +152,29 @@ namespace Opm
/// m_{ij} = \frac{dkr_i}{ds^j}, /// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...) /// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
void SaturationPropsBasic::relperm(const int n, void SaturationPropsBasic::relperm(const int n,
const double* s, const double* s,
double* kr, double* kr,
double* dkrds) const double* dkrds) const
{ {
switch (relperm_func_) { switch (relperm_func_) {
case Constant: case Constant:
{ {
evalAllKrDeriv(n, num_phases_, s, kr, dkrds, KrFunConstant()); evalAllKrDeriv(n, num_phases_, s, kr, dkrds, KrFunConstant());
break; break;
} }
case Linear: case Linear:
{ {
evalAllKrDeriv(n, num_phases_, s, kr, dkrds, KrFunLinear()); evalAllKrDeriv(n, num_phases_, s, kr, dkrds, KrFunLinear());
break; break;
} }
case Quadratic: case Quadratic:
{ {
evalAllKrDeriv(n, num_phases_, s, kr, dkrds, KrFunQuadratic()); evalAllKrDeriv(n, num_phases_, s, kr, dkrds, KrFunQuadratic());
break; break;
} }
default: default:
THROW("SaturationPropsBasic::relperm() unhandled relperm func type: " << relperm_func_); THROW("SaturationPropsBasic::relperm() unhandled relperm func type: " << relperm_func_);
} }
} }
@ -188,13 +190,13 @@ namespace Opm
/// m_{ij} = \frac{dpc_i}{ds^j}, /// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...) /// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
void SaturationPropsBasic::capPress(const int n, void SaturationPropsBasic::capPress(const int n,
const double* /*s*/, const double* /*s*/,
double* pc, double* pc,
double* dpcds) const double* dpcds) const
{ {
std::fill(pc, pc + num_phases_*n, 0.0); std::fill(pc, pc + num_phases_*n, 0.0);
if (dpcds) { if (dpcds) {
std::fill(dpcds, dpcds + num_phases_*num_phases_*n, 0.0); std::fill(dpcds, dpcds + num_phases_*num_phases_*n, 0.0);
} }
} }
@ -205,11 +207,11 @@ namespace Opm
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling. /// \param[out] smax Array of nP maximum s values, array must be valid before calling.
void SaturationPropsBasic::satRange(const int n, void SaturationPropsBasic::satRange(const int n,
double* smin, double* smin,
double* smax) const double* smax) const
{ {
std::fill(smin, smin + num_phases_*n, 0.0); std::fill(smin, smin + num_phases_*n, 0.0);
std::fill(smax, smax + num_phases_*n, 1.0); std::fill(smax, smax + num_phases_*n, 1.0);
} }

View File

@ -40,12 +40,12 @@ namespace Opm
SaturationPropsBasic(); SaturationPropsBasic();
/// Initialize from parameters. /// Initialize from parameters.
/// The following parameters are accepted (defaults): /// The following parameters are accepted (defaults):
/// num_phases (2) Must be 1 or 2. /// num_phases (2) Must be 1 or 2.
/// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic". /// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic".
void init(const parameter::ParameterGroup& param); void init(const parameter::ParameterGroup& param);
enum RelPermFunc { Constant, Linear, Quadratic }; enum RelPermFunc { Constant, Linear, Quadratic };
/// Initialize from arguments a basic Saturation property. /// Initialize from arguments a basic Saturation property.
void init(const int num_phases, void init(const int num_phases,
@ -86,18 +86,18 @@ namespace Opm
double* pc, double* pc,
double* dpcds) const; double* dpcds) const;
/// Obtain the range of allowable saturation values. /// Obtain the range of allowable saturation values.
/// \param[in] n Number of data points. /// \param[in] n Number of data points.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling. /// \param[out] smax Array of nP maximum s values, array must be valid before calling.
void satRange(const int n, void satRange(const int n,
double* smin, double* smin,
double* smax) const; double* smax) const;
private: private:
int num_phases_; int num_phases_;
RelPermFunc relperm_func_; RelPermFunc relperm_func_;
}; };

View File

@ -18,7 +18,7 @@
*/ */
#include <opm/core/fluid/SaturationPropsFromDeck.hpp> #include <opm/core/fluid/SaturationPropsFromDeck.hpp>
#include <opm/core/fluid/blackoil/phaseUsageFromDeck.hpp> #include <opm/core/grid.h>
#include <opm/core/utility/buildUniformMonotoneTable.hpp> #include <opm/core/utility/buildUniformMonotoneTable.hpp>
#include <opm/core/utility/ErrorMacros.hpp> #include <opm/core/utility/ErrorMacros.hpp>
#include <iostream> #include <iostream>
@ -26,368 +26,8 @@
namespace Opm namespace Opm
{ {
/// Default constructor. // This file should be removed in the future.
SaturationPropsFromDeck::SaturationPropsFromDeck() // Holding off until refactoring of SaturationPropsFromDeck class is done.
{
}
/// Initialize from deck.
void SaturationPropsFromDeck::init(const EclipseGridParser& deck,
const std::vector<int>& global_cell)
{
phase_usage_ = phaseUsageFromDeck(deck);
// Extract input data.
// Oil phase should be active.
if (!phase_usage_.phase_used[Liquid]) {
THROW("SaturationPropsFromDeck::init() -- oil phase must be active.");
}
// Obtain SATNUM, if it exists, and create cell_to_func_.
// Otherwise, let the cell_to_func_ mapping be just empty.
int satfuncs_expected = 1;
if (deck.hasField("SATNUM")) {
const std::vector<int>& satnum = deck.getIntegerValue("SATNUM");
satfuncs_expected = *std::max_element(satnum.begin(), satnum.end());
int num_cells = global_cell.size();
cell_to_func_.resize(num_cells);
for (int cell = 0; cell < num_cells; ++cell) {
cell_to_func_[cell] = satnum[global_cell[cell]] - 1;
}
}
// Find number of tables, check for consistency.
enum { Uninitialized = -1 };
int num_tables = Uninitialized;
if (phase_usage_.phase_used[Aqua]) {
const SWOF::table_t& swof_table = deck.getSWOF().swof_;
num_tables = swof_table.size();
if (num_tables < satfuncs_expected) {
THROW("Found " << num_tables << " SWOF tables, SATNUM specifies at least " << satfuncs_expected);
}
}
if (phase_usage_.phase_used[Vapour]) {
const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
int num_sgof_tables = sgof_table.size();
if (num_sgof_tables < satfuncs_expected) {
THROW("Found " << num_tables << " SGOF tables, SATNUM specifies at least " << satfuncs_expected);
}
if (num_tables == Uninitialized) {
num_tables = num_sgof_tables;
} else if (num_tables != num_sgof_tables) {
THROW("Inconsistent number of tables in SWOF and SGOF.");
}
}
// Initialize tables.
satfuncset_.resize(num_tables);
for (int table = 0; table < num_tables; ++table) {
satfuncset_[table].init(deck, table, phase_usage_);
}
}
/// \return P, the number of phases.
int SaturationPropsFromDeck::numPhases() const
{
return phase_usage_.num_phases;
}
/// Relative permeability.
/// \param[in] n Number of data points.
/// \param[in] s Array of nP saturation values.
/// \param[in] cells Array of n cell indices to be associated with the s values.
/// \param[out] kr Array of nP relperm values, array must be valid before calling.
/// \param[out] dkrds If non-null: array of nP^2 relperm derivative values,
/// array must be valid before calling.
/// The P^2 derivative matrix is
/// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
void SaturationPropsFromDeck::relperm(const int n,
const double* s,
const int* cells,
double* kr,
double* dkrds) const
{
ASSERT (cells != 0);
const int np = phase_usage_.num_phases;
if (dkrds) {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
funcForCell(cells[i]).evalKrDeriv(s + np*i, kr + np*i, dkrds + np*np*i);
}
} else {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
funcForCell(cells[i]).evalKr(s + np*i, kr + np*i);
}
}
}
/// Capillary pressure.
/// \param[in] n Number of data points.
/// \param[in] s Array of nP saturation values.
/// \param[in] cells Array of n cell indices to be associated with the s values.
/// \param[out] pc Array of nP capillary pressure values, array must be valid before calling.
/// \param[out] dpcds If non-null: array of nP^2 derivative values,
/// array must be valid before calling.
/// The P^2 derivative matrix is
/// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
void SaturationPropsFromDeck::capPress(const int n,
const double* s,
const int* cells,
double* pc,
double* dpcds) const
{
ASSERT (cells != 0);
const int np = phase_usage_.num_phases;
if (dpcds) {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
funcForCell(cells[i]).evalPcDeriv(s + np*i, pc + np*i, dpcds + np*np*i);
}
} else {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
funcForCell(cells[i]).evalPc(s + np*i, pc + np*i);
}
}
}
/// Obtain the range of allowable saturation values.
/// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling.
void SaturationPropsFromDeck::satRange(const int n,
const int* cells,
double* smin,
double* smax) const
{
ASSERT (cells != 0);
const int np = phase_usage_.num_phases;
for (int i = 0; i < n; ++i) {
for (int p = 0; p < np; ++p) {
smin[np*i + p] = funcForCell(cells[i]).smin_[p];
smax[np*i + p] = funcForCell(cells[i]).smax_[p];
}
}
}
// Map the cell number to the correct function set.
const SaturationPropsFromDeck::SatFuncSet&
SaturationPropsFromDeck::funcForCell(const int cell) const
{
return cell_to_func_.empty() ? satfuncset_[0] : satfuncset_[cell_to_func_[cell]];
}
// ----------- Methods of SatFuncSet below -----------
void SaturationPropsFromDeck::SatFuncSet::init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg)
{
phase_usage = phase_usg;
const int samples = 200;
double swco = 0.0;
double swmax = 1.0;
if (phase_usage.phase_used[Aqua]) {
const SWOF::table_t& swof_table = deck.getSWOF().swof_;
const std::vector<double>& sw = swof_table[table_num][0];
const std::vector<double>& krw = swof_table[table_num][1];
const std::vector<double>& krow = swof_table[table_num][2];
const std::vector<double>& pcow = swof_table[table_num][3];
buildUniformMonotoneTable(sw, krw, samples, krw_);
buildUniformMonotoneTable(sw, krow, samples, krow_);
buildUniformMonotoneTable(sw, pcow, samples, pcow_);
krocw_ = krow[0]; // At connate water -> ecl. SWOF
swco = sw[0];
smin_[phase_usage.phase_pos[Aqua]] = sw[0];
swmax = sw.back();
smax_[phase_usage.phase_pos[Aqua]] = sw.back();
}
if (phase_usage.phase_used[Vapour]) {
const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
const std::vector<double>& sg = sgof_table[table_num][0];
const std::vector<double>& krg = sgof_table[table_num][1];
const std::vector<double>& krog = sgof_table[table_num][2];
const std::vector<double>& pcog = sgof_table[table_num][3];
buildUniformMonotoneTable(sg, krg, samples, krg_);
buildUniformMonotoneTable(sg, krog, samples, krog_);
buildUniformMonotoneTable(sg, pcog, samples, pcog_);
smin_[phase_usage.phase_pos[Vapour]] = sg[0];
if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
", should equal (1.0 - connate water sat) = " << (1.0 - swco));
}
smax_[phase_usage.phase_pos[Vapour]] = sg.back();
}
// These only consider water min/max sats. Consider gas sats?
smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
}
void SaturationPropsFromDeck::SatFuncSet::evalKr(const double* s, double* kr) const
{
if (phase_usage.num_phases == 3) {
// Stone-II relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double krg = krg_(sg);
double krow = krow_(sw + sg); // = 1 - so
double krog = krog_(sg); // = 1 - so - sw
double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double krow = krow_(sw);
kr[wpos] = krw;
kr[opos] = krow;
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double krog = krog_(sg);
kr[gpos] = krg;
kr[opos] = krog;
}
}
void SaturationPropsFromDeck::SatFuncSet::evalKrDeriv(const double* s, double* kr, double* dkrds) const
{
const int np = phase_usage.num_phases;
std::fill(dkrds, dkrds + np*np, 0.0);
if (np == 3) {
// Stone-II relative permeability model.
double sw = s[Aqua];
double sg = s[Vapour];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krow = krow_(sw + sg);
double dkrow = krow_.derivative(sw + sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
double krocw = krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
dkrds[Aqua + Aqua*np] = dkrww;
dkrds[Vapour + Vapour*np] = dkrgg;
dkrds[Liquid + Aqua*np] = krocw*((dkrow/krocw + dkrww)*(krog/krocw + krg) - dkrww);
dkrds[Liquid + Vapour*np] = krocw*((krow/krocw + krw)*(dkrog/krocw + dkrgg) - dkrgg)
+ krocw*((dkrow/krocw + krw)*(krog/krocw + krg) - dkrgg);
return;
}
// We have a two-phase situation. We know that oil is active.
if (phase_usage.phase_used[Aqua]) {
int wpos = phase_usage.phase_pos[Aqua];
int opos = phase_usage.phase_pos[Liquid];
double sw = s[wpos];
double krw = krw_(sw);
double dkrww = krw_.derivative(sw);
double krow = krow_(sw);
double dkrow = krow_.derivative(sw);
kr[wpos] = krw;
kr[opos] = krow;
dkrds[wpos + wpos*np] = dkrww;
dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
} else {
ASSERT(phase_usage.phase_used[Vapour]);
int gpos = phase_usage.phase_pos[Vapour];
int opos = phase_usage.phase_pos[Liquid];
double sg = s[gpos];
double krg = krg_(sg);
double dkrgg = krg_.derivative(sg);
double krog = krog_(sg);
double dkrog = krog_.derivative(sg);
kr[gpos] = krg;
kr[opos] = krog;
dkrds[gpos + gpos*np] = dkrgg;
dkrds[opos + gpos*np] = dkrog;
}
}
void SaturationPropsFromDeck::SatFuncSet::evalPc(const double* s, double* pc) const
{
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
}
}
void SaturationPropsFromDeck::SatFuncSet::evalPcDeriv(const double* s, double* pc, double* dpcds) const
{
// The problem of determining three-phase capillary pressures
// is very hard experimentally, usually one extends two-phase
// data (as for relative permeability).
// In our approach the derivative matrix is quite sparse, only
// the diagonal elements corresponding to non-oil phases are
// (potentially) nonzero.
const int np = phase_usage.num_phases;
std::fill(dpcds, dpcds + np*np, 0.0);
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
int pos = phase_usage.phase_pos[Aqua];
pc[pos] = pcow_(s[pos]);
dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
}
if (phase_usage.phase_used[Vapour]) {
int pos = phase_usage.phase_pos[Vapour];
pc[pos] = pcog_(s[pos]);
dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
}
}
} // namespace Opm } // namespace Opm

View File

@ -20,24 +20,45 @@
#ifndef OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED #ifndef OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED
#define OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED #define OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED
#include <opm/core/fluid/SaturationPropsInterface.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp> #include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/utility/UniformTableLinear.hpp>
#include <opm/core/fluid/blackoil/BlackoilPhases.hpp> #include <opm/core/fluid/blackoil/BlackoilPhases.hpp>
#include <opm/core/fluid/SatFuncStone2.hpp>
#include <opm/core/fluid/SatFuncSimple.hpp>
#include <opm/core/fluid/SatFuncGwseg.hpp>
#include <vector> #include <vector>
struct UnstructuredGrid;
namespace Opm namespace Opm
{ {
class SaturationPropsFromDeck : public BlackoilPhases
/// Interface to saturation functions from deck.
/// Possible values for template argument (for now):
/// SatFuncSetStone2Nonuniform,
/// SatFuncSetStone2Uniform.
/// SatFuncSetSimpleNonuniform,
/// SatFuncSetSimpleUniform.
template <class SatFuncSet>
class SaturationPropsFromDeck : public SaturationPropsInterface
{ {
public: public:
/// Default constructor. /// Default constructor.
SaturationPropsFromDeck(); SaturationPropsFromDeck();
/// Initialize from deck. /// Initialize from deck and grid.
/// global_cell maps from grid cells to their original logical Cartesian indices. /// \param[in] deck Deck input parser
/// \param[in] grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck.
/// \param[in] samples Number of uniform sample points for saturation tables.
/// NOTE: samples will only be used with the SatFuncSetUniform template argument.
void init(const EclipseGridParser& deck, void init(const EclipseGridParser& deck,
const std::vector<int>& global_cell); const UnstructuredGrid& grid,
const int samples);
/// \return P, the number of phases. /// \return P, the number of phases.
int numPhases() const; int numPhases() const;
@ -72,41 +93,23 @@ namespace Opm
double* pc, double* pc,
double* dpcds) const; double* dpcds) const;
/// Obtain the range of allowable saturation values. /// Obtain the range of allowable saturation values.
/// \param[in] n Number of data points. /// \param[in] n Number of data points.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling. /// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling. /// \param[out] smax Array of nP maximum s values, array must be valid before calling.
void satRange(const int n, void satRange(const int n,
const int* cells, const int* cells,
double* smin, double* smin,
double* smax) const; double* smax) const;
private: private:
PhaseUsage phase_usage_; PhaseUsage phase_usage_;
class SatFuncSet
{
public:
void init(const EclipseGridParser& deck, const int table_num, PhaseUsage phase_usg);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
void evalPc(const double* s, double* pc) const;
void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
double smin_[PhaseUsage::MaxNumPhases];
double smax_[PhaseUsage::MaxNumPhases];
private:
PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
UniformTableLinear<double> krw_;
UniformTableLinear<double> krow_;
UniformTableLinear<double> pcow_;
UniformTableLinear<double> krg_;
UniformTableLinear<double> krog_;
UniformTableLinear<double> pcog_;
double krocw_; // = krow_(s_wc)
};
std::vector<SatFuncSet> satfuncset_; std::vector<SatFuncSet> satfuncset_;
std::vector<int> cell_to_func_; // = SATNUM - 1 std::vector<int> cell_to_func_; // = SATNUM - 1
const SatFuncSet& funcForCell(const int cell) const; typedef SatFuncSet Funcs;
const Funcs& funcForCell(const int cell) const;
}; };
@ -114,6 +117,7 @@ namespace Opm
} // namespace Opm } // namespace Opm
#include <opm/core/fluid/SaturationPropsFromDeck_impl.hpp>
#endif // OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED #endif // OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED

View File

@ -0,0 +1,221 @@
/*
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_SATURATIONPROPSFROMDECK_IMPL_HEADER_INCLUDED
#define OPM_SATURATIONPROPSFROMDECK_IMPL_HEADER_INCLUDED
#include <opm/core/utility/UniformTableLinear.hpp>
#include <opm/core/utility/NonuniformTableLinear.hpp>
#include <opm/core/fluid/blackoil/phaseUsageFromDeck.hpp>
#include <opm/core/grid.h>
namespace Opm
{
// ----------- Methods of SaturationPropsFromDeck ---------
/// Default constructor.
template <class SatFuncSet>
SaturationPropsFromDeck<SatFuncSet>::SaturationPropsFromDeck()
{
}
/// Initialize from deck.
template <class SatFuncSet>
void SaturationPropsFromDeck<SatFuncSet>::init(const EclipseGridParser& deck,
const UnstructuredGrid& grid,
const int samples)
{
phase_usage_ = phaseUsageFromDeck(deck);
// Extract input data.
// Oil phase should be active.
if (!phase_usage_.phase_used[Liquid]) {
THROW("SaturationPropsFromDeck::init() -- oil phase must be active.");
}
// Obtain SATNUM, if it exists, and create cell_to_func_.
// Otherwise, let the cell_to_func_ mapping be just empty.
int satfuncs_expected = 1;
if (deck.hasField("SATNUM")) {
const std::vector<int>& satnum = deck.getIntegerValue("SATNUM");
satfuncs_expected = *std::max_element(satnum.begin(), satnum.end());
const int num_cells = grid.number_of_cells;
cell_to_func_.resize(num_cells);
const int* gc = grid.global_cell;
for (int cell = 0; cell < num_cells; ++cell) {
const int deck_pos = (gc == NULL) ? cell : gc[cell];
cell_to_func_[cell] = satnum[deck_pos] - 1;
}
}
// Find number of tables, check for consistency.
enum { Uninitialized = -1 };
int num_tables = Uninitialized;
if (phase_usage_.phase_used[Aqua]) {
const SWOF::table_t& swof_table = deck.getSWOF().swof_;
num_tables = swof_table.size();
if (num_tables < satfuncs_expected) {
THROW("Found " << num_tables << " SWOF tables, SATNUM specifies at least " << satfuncs_expected);
}
}
if (phase_usage_.phase_used[Vapour]) {
const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
int num_sgof_tables = sgof_table.size();
if (num_sgof_tables < satfuncs_expected) {
THROW("Found " << num_tables << " SGOF tables, SATNUM specifies at least " << satfuncs_expected);
}
if (num_tables == Uninitialized) {
num_tables = num_sgof_tables;
} else if (num_tables != num_sgof_tables) {
THROW("Inconsistent number of tables in SWOF and SGOF.");
}
}
// Initialize tables.
satfuncset_.resize(num_tables);
for (int table = 0; table < num_tables; ++table) {
satfuncset_[table].init(deck, table, phase_usage_, samples);
}
}
/// \return P, the number of phases.
template <class SatFuncSet>
int SaturationPropsFromDeck<SatFuncSet>::numPhases() const
{
return phase_usage_.num_phases;
}
/// Relative permeability.
/// \param[in] n Number of data points.
/// \param[in] s Array of nP saturation values.
/// \param[in] cells Array of n cell indices to be associated with the s values.
/// \param[out] kr Array of nP relperm values, array must be valid before calling.
/// \param[out] dkrds If non-null: array of nP^2 relperm derivative values,
/// array must be valid before calling.
/// The P^2 derivative matrix is
/// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
template <class SatFuncSet>
void SaturationPropsFromDeck<SatFuncSet>::relperm(const int n,
const double* s,
const int* cells,
double* kr,
double* dkrds) const
{
ASSERT (cells != 0);
const int np = phase_usage_.num_phases;
if (dkrds) {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
funcForCell(cells[i]).evalKrDeriv(s + np*i, kr + np*i, dkrds + np*np*i);
}
} else {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
funcForCell(cells[i]).evalKr(s + np*i, kr + np*i);
}
}
}
/// Capillary pressure.
/// \param[in] n Number of data points.
/// \param[in] s Array of nP saturation values.
/// \param[in] cells Array of n cell indices to be associated with the s values.
/// \param[out] pc Array of nP capillary pressure values, array must be valid before calling.
/// \param[out] dpcds If non-null: array of nP^2 derivative values,
/// array must be valid before calling.
/// The P^2 derivative matrix is
/// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
template <class SatFuncSet>
void SaturationPropsFromDeck<SatFuncSet>::capPress(const int n,
const double* s,
const int* cells,
double* pc,
double* dpcds) const
{
ASSERT (cells != 0);
const int np = phase_usage_.num_phases;
if (dpcds) {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
funcForCell(cells[i]).evalPcDeriv(s + np*i, pc + np*i, dpcds + np*np*i);
}
} else {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
funcForCell(cells[i]).evalPc(s + np*i, pc + np*i);
}
}
}
/// Obtain the range of allowable saturation values.
/// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling.
template <class SatFuncSet>
void SaturationPropsFromDeck<SatFuncSet>::satRange(const int n,
const int* cells,
double* smin,
double* smax) const
{
ASSERT (cells != 0);
const int np = phase_usage_.num_phases;
for (int i = 0; i < n; ++i) {
for (int p = 0; p < np; ++p) {
smin[np*i + p] = funcForCell(cells[i]).smin_[p];
smax[np*i + p] = funcForCell(cells[i]).smax_[p];
}
}
}
// Map the cell number to the correct function set.
template <class SatFuncSet>
const typename SaturationPropsFromDeck<SatFuncSet>::Funcs&
SaturationPropsFromDeck<SatFuncSet>::funcForCell(const int cell) const
{
return cell_to_func_.empty() ? satfuncset_[0] : satfuncset_[cell_to_func_[cell]];
}
} // namespace Opm
#endif // OPM_SATURATIONPROPSFROMDECK_IMPL_HEADER_INCLUDED

View File

@ -0,0 +1,85 @@
/*
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_SATURATIONPROPSINTERFACE_HEADER_INCLUDED
#define OPM_SATURATIONPROPSINTERFACE_HEADER_INCLUDED
#include <opm/core/fluid/blackoil/BlackoilPhases.hpp>
namespace Opm
{
class SaturationPropsInterface : public BlackoilPhases
{
public:
/// Virtual destructor.
virtual ~SaturationPropsInterface() {};
/// \return P, the number of phases.
virtual int numPhases() const = 0;
/// Relative permeability.
/// \param[in] n Number of data points.
/// \param[in] s Array of nP saturation values.
/// \param[out] kr Array of nP relperm values, array must be valid before calling.
/// \param[out] dkrds If non-null: array of nP^2 relperm derivative values,
/// array must be valid before calling.
/// The P^2 derivative matrix is
/// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
virtual void relperm(const int n,
const double* s,
const int* cells,
double* kr,
double* dkrds) const = 0;
/// Capillary pressure.
/// \param[in] n Number of data points.
/// \param[in] s Array of nP saturation values.
/// \param[out] pc Array of nP capillary pressure values, array must be valid before calling.
/// \param[out] dpcds If non-null: array of nP^2 derivative values,
/// array must be valid before calling.
/// The P^2 derivative matrix is
/// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
virtual void capPress(const int n,
const double* s,
const int* cells,
double* pc,
double* dpcds) const = 0;
/// Obtain the range of allowable saturation values.
/// \param[in] n Number of data points.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling.
virtual void satRange(const int n,
const int* cells,
double* smin,
double* smax) const = 0;
};
} // namespace Opm
#endif // OPM_SATURATIONPROPSINTERFACE_HEADER_INCLUDED

View File

@ -21,6 +21,7 @@
#include <opm/core/fluid/blackoil/BlackoilPvtProperties.hpp> #include <opm/core/fluid/blackoil/BlackoilPvtProperties.hpp>
#include <opm/core/fluid/blackoil/SinglePvtDead.hpp> #include <opm/core/fluid/blackoil/SinglePvtDead.hpp>
#include <opm/core/fluid/blackoil/SinglePvtDeadSpline.hpp>
#include <opm/core/fluid/blackoil/SinglePvtLiveOil.hpp> #include <opm/core/fluid/blackoil/SinglePvtLiveOil.hpp>
#include <opm/core/fluid/blackoil/SinglePvtLiveGas.hpp> #include <opm/core/fluid/blackoil/SinglePvtLiveGas.hpp>
#include <opm/core/fluid/blackoil/SinglePvtConstCompr.hpp> #include <opm/core/fluid/blackoil/SinglePvtConstCompr.hpp>
@ -39,18 +40,18 @@ namespace Opm
} }
void BlackoilPvtProperties::init(const EclipseGridParser& deck) void BlackoilPvtProperties::init(const EclipseGridParser& deck, const int samples)
{ {
typedef std::vector<std::vector<std::vector<double> > > table_t; typedef std::vector<std::vector<std::vector<double> > > table_t;
// If we need multiple regions, this class and the SinglePvt* classes must change. // If we need multiple regions, this class and the SinglePvt* classes must change.
region_number_ = 0; region_number_ = 0;
phase_usage_ = phaseUsageFromDeck(deck); phase_usage_ = phaseUsageFromDeck(deck);
// Surface densities. Accounting for different orders in eclipse and our code. // Surface densities. Accounting for different orders in eclipse and our code.
if (deck.hasField("DENSITY")) { if (deck.hasField("DENSITY")) {
const std::vector<double>& d = deck.getDENSITY().densities_[region_number_]; const std::vector<double>& d = deck.getDENSITY().densities_[region_number_];
enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 }; enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 };
if (phase_usage_.phase_used[Aqua]) { if (phase_usage_.phase_used[Aqua]) {
densities_[phase_usage_.phase_pos[Aqua]] = d[ECL_water]; densities_[phase_usage_.phase_pos[Aqua]] = d[ECL_water];
} }
@ -60,9 +61,9 @@ namespace Opm
if (phase_usage_.phase_used[Liquid]) { if (phase_usage_.phase_used[Liquid]) {
densities_[phase_usage_.phase_pos[Liquid]] = d[ECL_oil]; densities_[phase_usage_.phase_pos[Liquid]] = d[ECL_oil];
} }
} else { } else {
THROW("Input is missing DENSITY\n"); THROW("Input is missing DENSITY\n");
} }
// Set the properties. // Set the properties.
props_.resize(phase_usage_.num_phases); props_.resize(phase_usage_.num_phases);
@ -78,7 +79,11 @@ namespace Opm
// Oil PVT // Oil PVT
if (phase_usage_.phase_used[Liquid]) { if (phase_usage_.phase_used[Liquid]) {
if (deck.hasField("PVDO")) { if (deck.hasField("PVDO")) {
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDead(deck.getPVDO().pvdo_)); if (samples > 0) {
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDeadSpline(deck.getPVDO().pvdo_, samples));
} else {
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDead(deck.getPVDO().pvdo_));
}
} else if (deck.hasField("PVTO")) { } else if (deck.hasField("PVTO")) {
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtLiveOil(deck.getPVTO().pvto_)); props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtLiveOil(deck.getPVTO().pvto_));
} else if (deck.hasField("PVCDO")) { } else if (deck.hasField("PVCDO")) {
@ -87,10 +92,14 @@ namespace Opm
THROW("Input is missing PVDO or PVTO\n"); THROW("Input is missing PVDO or PVTO\n");
} }
} }
// Gas PVT // Gas PVT
if (phase_usage_.phase_used[Vapour]) { if (phase_usage_.phase_used[Vapour]) {
if (deck.hasField("PVDG")) { if (deck.hasField("PVDG")) {
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDead(deck.getPVDG().pvdg_)); if (samples > 0) {
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDeadSpline(deck.getPVDG().pvdg_, samples));
} else {
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDead(deck.getPVDG().pvdg_));
}
} else if (deck.hasField("PVTG")) { } else if (deck.hasField("PVTG")) {
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtLiveGas(deck.getPVTG().pvtg_)); props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtLiveGas(deck.getPVTG().pvtg_));
} else { } else {

View File

@ -47,7 +47,13 @@ namespace Opm
BlackoilPvtProperties(); BlackoilPvtProperties();
/// Initialize from deck. /// Initialize from deck.
void init(const EclipseGridParser& deck); /// \param deck An input deck.
/// \param samples If greater than zero, indicates the number of
/// uniform samples to be taken from monotone spline
/// curves interpolating the fluid data.
/// Otherwise, interpolate linearly in the original
/// data without fitting a spline.
void init(const EclipseGridParser& deck, const int samples);
/// Number of active phases. /// Number of active phases.
int numPhases() const; int numPhases() const;
@ -64,7 +70,7 @@ namespace Opm
/// Densities of stock components at surface conditions. /// Densities of stock components at surface conditions.
/// \return Array of size numPhases(). /// \return Array of size numPhases().
const double* surfaceDensities() const; const double* surfaceDensities() const;
/// Viscosity as a function of p and z. /// Viscosity as a function of p and z.
void mu(const int n, void mu(const int n,
@ -105,11 +111,11 @@ namespace Opm
PhaseUsage phase_usage_; PhaseUsage phase_usage_;
int region_number_; int region_number_;
std::vector<std::tr1::shared_ptr<SinglePvtInterface> > props_; std::vector<std::tr1::shared_ptr<SinglePvtInterface> > props_;
double densities_[MaxNumPhases]; double densities_[MaxNumPhases];
mutable std::vector<double> data1_; mutable std::vector<double> data1_;
mutable std::vector<double> data2_; mutable std::vector<double> data2_;
}; };

View File

@ -40,12 +40,12 @@ namespace Opm
public: public:
typedef std::vector<std::vector<double> > table_t; typedef std::vector<std::vector<double> > table_t;
SinglePvtConstCompr(const table_t& pvtw) SinglePvtConstCompr(const table_t& pvtw)
{ {
const int region_number = 0; const int region_number = 0;
if (pvtw.size() != 1) { if (pvtw.size() != 1) {
THROW("More than one PVD-region"); THROW("More than one PVD-region");
} }
ref_press_ = pvtw[region_number][0]; ref_press_ = pvtw[region_number][0];
ref_B_ = pvtw[region_number][1]; ref_B_ = pvtw[region_number][1];
comp_ = pvtw[region_number][2]; comp_ = pvtw[region_number][2];
@ -53,7 +53,7 @@ namespace Opm
visc_comp_ = pvtw[region_number][4]; visc_comp_ = pvtw[region_number][4];
} }
SinglePvtConstCompr(double visc) SinglePvtConstCompr(double visc)
: ref_press_(0.0), : ref_press_(0.0),
ref_B_(1.0), ref_B_(1.0),
comp_(0.0), comp_(0.0),
@ -62,7 +62,7 @@ namespace Opm
{ {
} }
virtual ~SinglePvtConstCompr() virtual ~SinglePvtConstCompr()
{ {
} }
@ -106,13 +106,16 @@ namespace Opm
double* output_B, double* output_B,
double* output_dBdp) const double* output_dBdp) const
{ {
B(n, p, 0, output_B);
if (comp_) { if (comp_) {
// #pragma omp parallel for // #pragma omp parallel for
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
output_dBdp[i] = -comp_*output_B[i]; double x = comp_*(p[i] - ref_press_);
double d = (1.0 + x + 0.5*x*x);
output_B[i] = ref_B_/d;
output_dBdp[i] = (-ref_B_/(d*d))*(1 + x) * comp_;
} }
} else { } else {
std::fill(output_B, output_B + n, ref_B_);
std::fill(output_dBdp, output_dBdp + n, 0.0); std::fill(output_dBdp, output_dBdp + n, 0.0);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2010, 2011, 2012 SINTEF ICT, Applied Mathematics. Copyright 2012 SINTEF ICT, Applied Mathematics.
This file is part of the Open Porous Media project (OPM). This file is part of the Open Porous Media project (OPM).
@ -17,8 +17,8 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <opm/core/fluid/blackoil/SinglePvtDead.hpp> #include <opm/core/fluid/blackoil/SinglePvtDead.hpp>
#include <opm/core/utility/buildUniformMonotoneTable.hpp>
#include <algorithm> #include <algorithm>
// Extra includes for debug dumping of tables. // Extra includes for debug dumping of tables.
@ -32,28 +32,26 @@ namespace Opm
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// Member functions // Member functions
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
/// Constructor /// Constructor
SinglePvtDead::SinglePvtDead(const table_t& pvd_table) SinglePvtDead::SinglePvtDead(const table_t& pvd_table)
{ {
const int region_number = 0; const int region_number = 0;
if (pvd_table.size() != 1) { if (pvd_table.size() != 1) {
THROW("More than one PVT-region"); THROW("More than one PVT-region");
} }
// Copy data // Copy data
const int sz = pvd_table[region_number][0].size(); const int sz = pvd_table[region_number][0].size();
std::vector<double> press(sz); std::vector<double> press(sz);
std::vector<double> B_inv(sz); std::vector<double> B_inv(sz);
std::vector<double> visc(sz); std::vector<double> visc(sz);
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
press[i] = pvd_table[region_number][0][i]; press[i] = pvd_table[region_number][0][i];
B_inv[i] = 1.0 / pvd_table[region_number][1][i]; B_inv[i] = 1.0 / pvd_table[region_number][1][i];
visc[i] = pvd_table[region_number][2][i]; visc[i] = pvd_table[region_number][2][i];
} }
int samples = 1025; one_over_B_ = NonuniformTableLinear<double>(press, B_inv);
buildUniformMonotoneTable(press, B_inv, samples, one_over_B_); viscosity_ = NonuniformTableLinear<double>(press, visc);
buildUniformMonotoneTable(press, visc, samples, viscosity_);
// Dumping the created tables. // Dumping the created tables.
// static int count = 0; // static int count = 0;

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2010, 2011, 2012 SINTEF ICT, Applied Mathematics. Copyright 2012 SINTEF ICT, Applied Mathematics.
This file is part of the Open Porous Media project (OPM). This file is part of the Open Porous Media project (OPM).
@ -22,7 +22,7 @@
#include <opm/core/fluid/blackoil/SinglePvtInterface.hpp> #include <opm/core/fluid/blackoil/SinglePvtInterface.hpp>
#include <opm/core/utility/UniformTableLinear.hpp> #include <opm/core/utility/NonuniformTableLinear.hpp>
#include <vector> #include <vector>
namespace Opm namespace Opm
@ -36,10 +36,9 @@ namespace Opm
class SinglePvtDead : public SinglePvtInterface class SinglePvtDead : public SinglePvtInterface
{ {
public: public:
typedef std::vector<std::vector<std::vector<double> > > table_t; typedef std::vector<std::vector<std::vector<double> > > table_t;
SinglePvtDead(const table_t& pvd_table);
SinglePvtDead(const table_t& pvd_table); virtual ~SinglePvtDead();
virtual ~SinglePvtDead();
/// Viscosity as a function of p and z. /// Viscosity as a function of p and z.
virtual void mu(const int n, virtual void mu(const int n,
@ -73,12 +72,12 @@ namespace Opm
double* output_R, double* output_R,
double* output_dRdp) const; double* output_dRdp) const;
private: private:
// PVT properties of dry gas or dead oil // PVT properties of dry gas or dead oil
UniformTableLinear<double> one_over_B_; NonuniformTableLinear<double> one_over_B_;
UniformTableLinear<double> viscosity_; NonuniformTableLinear<double> viscosity_;
}; };
} }
#endif // OPM_SINGLEPVTDEAD_HEADER_INCLUDED
#endif // OPM_SINGLEPVTDEAD_HEADER_INCLUDED

View File

@ -0,0 +1,127 @@
/*
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/>.
*/
#include <opm/core/fluid/blackoil/SinglePvtDeadSpline.hpp>
#include <opm/core/utility/buildUniformMonotoneTable.hpp>
#include <algorithm>
// Extra includes for debug dumping of tables.
// #include <boost/lexical_cast.hpp>
// #include <string>
// #include <fstream>
namespace Opm
{
//------------------------------------------------------------------------
// Member functions
//-------------------------------------------------------------------------
/// Constructor
SinglePvtDeadSpline::SinglePvtDeadSpline(const table_t& pvd_table, const int samples)
{
const int region_number = 0;
if (pvd_table.size() != 1) {
THROW("More than one PVT-region");
}
// Copy data
const int sz = pvd_table[region_number][0].size();
std::vector<double> press(sz);
std::vector<double> B_inv(sz);
std::vector<double> visc(sz);
for (int i = 0; i < sz; ++i) {
press[i] = pvd_table[region_number][0][i];
B_inv[i] = 1.0 / pvd_table[region_number][1][i];
visc[i] = pvd_table[region_number][2][i];
}
buildUniformMonotoneTable(press, B_inv, samples, one_over_B_);
buildUniformMonotoneTable(press, visc, samples, viscosity_);
// Dumping the created tables.
// static int count = 0;
// std::ofstream os((std::string("dump-") + boost::lexical_cast<std::string>(count++)).c_str());
// os.precision(15);
// os << "1/B\n\n" << one_over_B_
// << "\n\nvisc\n\n" << viscosity_ << std::endl;
}
// Destructor
SinglePvtDeadSpline::~SinglePvtDeadSpline()
{
}
void SinglePvtDeadSpline::mu(const int n,
const double* p,
const double* /*z*/,
double* output_mu) const
{
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
output_mu[i] = viscosity_(p[i]);
}
}
void SinglePvtDeadSpline::B(const int n,
const double* p,
const double* /*z*/,
double* output_B) const
{
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
output_B[i] = 1.0/one_over_B_(p[i]);
}
}
void SinglePvtDeadSpline::dBdp(const int n,
const double* p,
const double* /*z*/,
double* output_B,
double* output_dBdp) const
{
B(n, p, 0, output_B);
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
double Bg = output_B[i];
output_dBdp[i] = -Bg*Bg*one_over_B_.derivative(p[i]);
}
}
void SinglePvtDeadSpline::R(const int n,
const double* /*p*/,
const double* /*z*/,
double* output_R) const
{
std::fill(output_R, output_R + n, 0.0);
}
void SinglePvtDeadSpline::dRdp(const int n,
const double* /*p*/,
const double* /*z*/,
double* output_R,
double* output_dRdp) const
{
std::fill(output_R, output_R + n, 0.0);
std::fill(output_dRdp, output_dRdp + n, 0.0);
}
}

View File

@ -0,0 +1,84 @@
/*
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_SINGLEPVTDEADSPLINE_HEADER_INCLUDED
#define OPM_SINGLEPVTDEADSPLINE_HEADER_INCLUDED
#include <opm/core/fluid/blackoil/SinglePvtInterface.hpp>
#include <opm/core/utility/UniformTableLinear.hpp>
#include <vector>
namespace Opm
{
/// Class for immiscible dead oil and dry gas.
/// For all the virtual methods, the following apply: p and z
/// are expected to be of size n and n*num_phases, respectively.
/// Output arrays shall be of size n, and must be valid before
/// calling the method.
class SinglePvtDeadSpline : public SinglePvtInterface
{
public:
typedef std::vector<std::vector<std::vector<double> > > table_t;
SinglePvtDeadSpline(const table_t& pvd_table, const int samples);
virtual ~SinglePvtDeadSpline();
/// Viscosity as a function of p and z.
virtual void mu(const int n,
const double* p,
const double* z,
double* output_mu) const;
/// Formation volume factor as a function of p and z.
virtual void B(const int n,
const double* p,
const double* z,
double* output_B) const;
/// Formation volume factor and p-derivative as functions of p and z.
virtual void dBdp(const int n,
const double* p,
const double* z,
double* output_B,
double* output_dBdp) const;
/// Solution factor as a function of p and z.
virtual void R(const int n,
const double* p,
const double* z,
double* output_R) const;
/// Solution factor and p-derivative as functions of p and z.
virtual void dRdp(const int n,
const double* p,
const double* z,
double* output_R,
double* output_dRdp) const;
private:
// PVT properties of dry gas or dead oil
UniformTableLinear<double> one_over_B_;
UniformTableLinear<double> viscosity_;
};
}
#endif // OPM_SINGLEPVTDEADSPLINE_HEADER_INCLUDED

View File

@ -32,7 +32,7 @@ namespace Opm
public: public:
SinglePvtInterface(); SinglePvtInterface();
virtual ~SinglePvtInterface(); virtual ~SinglePvtInterface();
/// \param[in] num_phases The number of active phases. /// \param[in] num_phases The number of active phases.
/// \param[in] phase_pos Array of BlackpoilPhases::MaxNumPhases /// \param[in] phase_pos Array of BlackpoilPhases::MaxNumPhases

View File

@ -47,37 +47,37 @@ namespace Opm
/// Constructor /// Constructor
SinglePvtLiveGas::SinglePvtLiveGas(const table_t& pvtg) SinglePvtLiveGas::SinglePvtLiveGas(const table_t& pvtg)
{ {
// GAS, PVTG // GAS, PVTG
const int region_number = 0; const int region_number = 0;
if (pvtg.size() != 1) { if (pvtg.size() != 1) {
THROW("More than one PVD-region"); THROW("More than one PVD-region");
} }
saturated_gas_table_.resize(4); saturated_gas_table_.resize(4);
const int sz = pvtg[region_number].size(); const int sz = pvtg[region_number].size();
for (int k=0; k<4; ++k) { for (int k=0; k<4; ++k) {
saturated_gas_table_[k].resize(sz); saturated_gas_table_[k].resize(sz);
} }
for (int i=0; i<sz; ++i) { for (int i=0; i<sz; ++i) {
saturated_gas_table_[0][i] = pvtg[region_number][i][0]; // p saturated_gas_table_[0][i] = pvtg[region_number][i][0]; // p
saturated_gas_table_[1][i] = pvtg[region_number][i][2]; // Bg saturated_gas_table_[1][i] = pvtg[region_number][i][2]; // Bg
saturated_gas_table_[2][i] = pvtg[region_number][i][3]; // mu_g saturated_gas_table_[2][i] = pvtg[region_number][i][3]; // mu_g
saturated_gas_table_[3][i] = pvtg[region_number][i][1]; // Rv saturated_gas_table_[3][i] = pvtg[region_number][i][1]; // Rv
} }
undersat_gas_tables_.resize(sz); undersat_gas_tables_.resize(sz);
for (int i=0; i<sz; ++i) { for (int i=0; i<sz; ++i) {
undersat_gas_tables_[i].resize(3); undersat_gas_tables_[i].resize(3);
int tsize = (pvtg[region_number][i].size() - 1)/3; int tsize = (pvtg[region_number][i].size() - 1)/3;
undersat_gas_tables_[i][0].resize(tsize); undersat_gas_tables_[i][0].resize(tsize);
undersat_gas_tables_[i][1].resize(tsize); undersat_gas_tables_[i][1].resize(tsize);
undersat_gas_tables_[i][2].resize(tsize); undersat_gas_tables_[i][2].resize(tsize);
for (int j=0, k=0; j<tsize; ++j) { for (int j=0, k=0; j<tsize; ++j) {
undersat_gas_tables_[i][0][j] = pvtg[region_number][i][++k]; // Rv undersat_gas_tables_[i][0][j] = pvtg[region_number][i][++k]; // Rv
undersat_gas_tables_[i][1][j] = pvtg[region_number][i][++k]; // Bg undersat_gas_tables_[i][1][j] = pvtg[region_number][i][++k]; // Bg
undersat_gas_tables_[i][2][j] = pvtg[region_number][i][++k]; // mu_g undersat_gas_tables_[i][2][j] = pvtg[region_number][i][++k]; // mu_g
} }
} }
} }
// Destructor // Destructor
@ -184,16 +184,16 @@ namespace Opm
// To handle no-gas case. // To handle no-gas case.
return 0.0; return 0.0;
} }
double satR = linearInterpolationExtrap(saturated_gas_table_[0], double satR = linearInterpolationExtrap(saturated_gas_table_[0],
saturated_gas_table_[3], press); saturated_gas_table_[3], press);
double maxR = surfvol[phase_pos_[Liquid]]/surfvol[phase_pos_[Vapour]]; double maxR = surfvol[phase_pos_[Liquid]]/surfvol[phase_pos_[Vapour]];
if (satR < maxR ) { if (satR < maxR ) {
// Saturated case // Saturated case
return satR; return satR;
} else { } else {
// Undersaturated case // Undersaturated case
return maxR; return maxR;
} }
} }
void SinglePvtLiveGas::evalRDeriv(const double press, const double* surfvol, void SinglePvtLiveGas::evalRDeriv(const double press, const double* surfvol,
@ -205,20 +205,20 @@ namespace Opm
dRdpval = 0.0; dRdpval = 0.0;
return; return;
} }
double satR = linearInterpolationExtrap(saturated_gas_table_[0], double satR = linearInterpolationExtrap(saturated_gas_table_[0],
saturated_gas_table_[3], press); saturated_gas_table_[3], press);
double maxR = surfvol[phase_pos_[Liquid]]/surfvol[phase_pos_[Vapour]]; double maxR = surfvol[phase_pos_[Liquid]]/surfvol[phase_pos_[Vapour]];
if (satR < maxR ) { if (satR < maxR ) {
// Saturated case // Saturated case
Rval = satR; Rval = satR;
dRdpval = linearInterpolDerivative(saturated_gas_table_[0], dRdpval = linearInterpolDerivative(saturated_gas_table_[0],
saturated_gas_table_[3], saturated_gas_table_[3],
press); press);
} else { } else {
// Undersaturated case // Undersaturated case
Rval = maxR; Rval = maxR;
dRdpval = 0.0; dRdpval = 0.0;
} }
} }
double SinglePvtLiveGas::miscible_gas(const double press, double SinglePvtLiveGas::miscible_gas(const double press,
@ -226,81 +226,81 @@ namespace Opm
const int item, const int item,
const bool deriv) const const bool deriv) const
{ {
int section; int section;
double Rval = linearInterpolationExtrap(saturated_gas_table_[0], double Rval = linearInterpolationExtrap(saturated_gas_table_[0],
saturated_gas_table_[3], press, saturated_gas_table_[3], press,
section); section);
double maxR = surfvol[phase_pos_[Liquid]]/surfvol[phase_pos_[Vapour]]; double maxR = surfvol[phase_pos_[Liquid]]/surfvol[phase_pos_[Vapour]];
if (deriv) { if (deriv) {
if (Rval < maxR ) { // Saturated case if (Rval < maxR ) { // Saturated case
return linearInterpolDerivative(saturated_gas_table_[0], return linearInterpolDerivative(saturated_gas_table_[0],
saturated_gas_table_[item], saturated_gas_table_[item],
press); press);
} else { // Undersaturated case } else { // Undersaturated case
int is = section; int is = section;
if (undersat_gas_tables_[is][0].size() < 2) { if (undersat_gas_tables_[is][0].size() < 2) {
double val = (saturated_gas_table_[item][is+1] double val = (saturated_gas_table_[item][is+1]
- saturated_gas_table_[item][is]) / - saturated_gas_table_[item][is]) /
(saturated_gas_table_[0][is+1] - (saturated_gas_table_[0][is+1] -
saturated_gas_table_[0][is]); saturated_gas_table_[0][is]);
return val; return val;
} }
double val1 = double val1 =
linearInterpolationExtrap(undersat_gas_tables_[is][0], linearInterpolationExtrap(undersat_gas_tables_[is][0],
undersat_gas_tables_[is][item], undersat_gas_tables_[is][item],
maxR); maxR);
double val2 = double val2 =
linearInterpolationExtrap(undersat_gas_tables_[is+1][0], linearInterpolationExtrap(undersat_gas_tables_[is+1][0],
undersat_gas_tables_[is+1][item], undersat_gas_tables_[is+1][item],
maxR); maxR);
double val = (val2 - val1)/ double val = (val2 - val1)/
(saturated_gas_table_[0][is+1] - saturated_gas_table_[0][is]); (saturated_gas_table_[0][is+1] - saturated_gas_table_[0][is]);
return val; return val;
} }
} else { } else {
if (Rval < maxR ) { // Saturated case if (Rval < maxR ) { // Saturated case
return linearInterpolationExtrap(saturated_gas_table_[0], return linearInterpolationExtrap(saturated_gas_table_[0],
saturated_gas_table_[item], saturated_gas_table_[item],
press); press);
} else { // Undersaturated case } else { // Undersaturated case
int is = section; int is = section;
// Extrapolate from first table section // Extrapolate from first table section
if (is == 0 && press < saturated_gas_table_[0][0]) { if (is == 0 && press < saturated_gas_table_[0][0]) {
return linearInterpolationExtrap(undersat_gas_tables_[0][0], return linearInterpolationExtrap(undersat_gas_tables_[0][0],
undersat_gas_tables_[0][item], undersat_gas_tables_[0][item],
maxR); maxR);
} }
// Extrapolate from last table section // Extrapolate from last table section
int ltp = saturated_gas_table_[0].size() - 1; int ltp = saturated_gas_table_[0].size() - 1;
if (is+1 == ltp && press > saturated_gas_table_[0][ltp]) { if (is+1 == ltp && press > saturated_gas_table_[0][ltp]) {
return linearInterpolationExtrap(undersat_gas_tables_[ltp][0], return linearInterpolationExtrap(undersat_gas_tables_[ltp][0],
undersat_gas_tables_[ltp][item], undersat_gas_tables_[ltp][item],
maxR); maxR);
} }
// Interpolate between table sections // Interpolate between table sections
double w = (press - saturated_gas_table_[0][is]) / double w = (press - saturated_gas_table_[0][is]) /
(saturated_gas_table_[0][is+1] - (saturated_gas_table_[0][is+1] -
saturated_gas_table_[0][is]); saturated_gas_table_[0][is]);
if (undersat_gas_tables_[is][0].size() < 2) { if (undersat_gas_tables_[is][0].size() < 2) {
double val = saturated_gas_table_[item][is] + double val = saturated_gas_table_[item][is] +
w*(saturated_gas_table_[item][is+1] - w*(saturated_gas_table_[item][is+1] -
saturated_gas_table_[item][is]); saturated_gas_table_[item][is]);
return val; return val;
} }
double val1 = double val1 =
linearInterpolationExtrap(undersat_gas_tables_[is][0], linearInterpolationExtrap(undersat_gas_tables_[is][0],
undersat_gas_tables_[is][item], undersat_gas_tables_[is][item],
maxR); maxR);
double val2 = double val2 =
linearInterpolationExtrap(undersat_gas_tables_[is+1][0], linearInterpolationExtrap(undersat_gas_tables_[is+1][0],
undersat_gas_tables_[is+1][item], undersat_gas_tables_[is+1][item],
maxR); maxR);
double val = val1 + w*(val2 - val1); double val = val1 + w*(val2 - val1);
return val; return val;
} }
} }
} }

View File

@ -33,10 +33,10 @@ namespace Opm
class SinglePvtLiveGas : public SinglePvtInterface class SinglePvtLiveGas : public SinglePvtInterface
{ {
public: public:
typedef std::vector<std::vector<std::vector<double> > > table_t; typedef std::vector<std::vector<std::vector<double> > > table_t;
SinglePvtLiveGas(const table_t& pvto); SinglePvtLiveGas(const table_t& pvto);
virtual ~SinglePvtLiveGas(); virtual ~SinglePvtLiveGas();
/// Viscosity as a function of p and z. /// Viscosity as a function of p and z.
virtual void mu(const int n, virtual void mu(const int n,
@ -76,14 +76,14 @@ namespace Opm
double evalR(double press, const double* surfvol) const; double evalR(double press, const double* surfvol) const;
void evalRDeriv(double press, const double* surfvol, double& R, double& dRdp) const; void evalRDeriv(double press, const double* surfvol, double& R, double& dRdp) const;
// item: 1=>B 2=>mu; // item: 1=>B 2=>mu;
double miscible_gas(const double press, double miscible_gas(const double press,
const double* surfvol, const double* surfvol,
const int item, const int item,
const bool deriv = false) const; const bool deriv = false) const;
// PVT properties of wet gas (with vaporised oil) // PVT properties of wet gas (with vaporised oil)
std::vector<std::vector<double> > saturated_gas_table_; std::vector<std::vector<double> > saturated_gas_table_;
std::vector<std::vector<std::vector<double> > > undersat_gas_tables_; std::vector<std::vector<std::vector<double> > > undersat_gas_tables_;
}; };

View File

@ -38,122 +38,122 @@ namespace Opm
/// Constructor /// Constructor
SinglePvtLiveOil::SinglePvtLiveOil(const table_t& pvto) SinglePvtLiveOil::SinglePvtLiveOil(const table_t& pvto)
{ {
// OIL, PVTO // OIL, PVTO
const int region_number = 0; const int region_number = 0;
if (pvto.size() != 1) { if (pvto.size() != 1) {
THROW("More than one PVD-region"); THROW("More than one PVD-region");
} }
saturated_oil_table_.resize(4); saturated_oil_table_.resize(4);
const int sz = pvto[region_number].size(); const int sz = pvto[region_number].size();
for (int k=0; k<4; ++k) { for (int k=0; k<4; ++k) {
saturated_oil_table_[k].resize(sz); saturated_oil_table_[k].resize(sz);
} }
for (int i=0; i<sz; ++i) { for (int i=0; i<sz; ++i) {
saturated_oil_table_[0][i] = pvto[region_number][i][1]; // p saturated_oil_table_[0][i] = pvto[region_number][i][1]; // p
saturated_oil_table_[1][i] = 1.0/pvto[region_number][i][2]; // 1/Bo saturated_oil_table_[1][i] = 1.0/pvto[region_number][i][2]; // 1/Bo
saturated_oil_table_[2][i] = pvto[region_number][i][3]; // mu_o saturated_oil_table_[2][i] = pvto[region_number][i][3]; // mu_o
saturated_oil_table_[3][i] = pvto[region_number][i][0]; // Rs saturated_oil_table_[3][i] = pvto[region_number][i][0]; // Rs
} }
undersat_oil_tables_.resize(sz); undersat_oil_tables_.resize(sz);
for (int i=0; i<sz; ++i) { for (int i=0; i<sz; ++i) {
undersat_oil_tables_[i].resize(3); undersat_oil_tables_[i].resize(3);
int tsize = (pvto[region_number][i].size() - 1)/3; int tsize = (pvto[region_number][i].size() - 1)/3;
undersat_oil_tables_[i][0].resize(tsize); undersat_oil_tables_[i][0].resize(tsize);
undersat_oil_tables_[i][1].resize(tsize); undersat_oil_tables_[i][1].resize(tsize);
undersat_oil_tables_[i][2].resize(tsize); undersat_oil_tables_[i][2].resize(tsize);
for (int j=0, k=0; j<tsize; ++j) { for (int j=0, k=0; j<tsize; ++j) {
undersat_oil_tables_[i][0][j] = pvto[region_number][i][++k]; // p undersat_oil_tables_[i][0][j] = pvto[region_number][i][++k]; // p
undersat_oil_tables_[i][1][j] = 1.0/pvto[region_number][i][++k]; // 1/Bo undersat_oil_tables_[i][1][j] = 1.0/pvto[region_number][i][++k]; // 1/Bo
undersat_oil_tables_[i][2][j] = pvto[region_number][i][++k]; // mu_o undersat_oil_tables_[i][2][j] = pvto[region_number][i][++k]; // mu_o
} }
} }
// Fill in additional entries in undersaturated tables by interpolating/extrapolating 1/Bo and mu_o ... // Fill in additional entries in undersaturated tables by interpolating/extrapolating 1/Bo and mu_o ...
int iPrev = -1; int iPrev = -1;
int iNext = 1; int iNext = 1;
while (undersat_oil_tables_[iNext][0].size() < 2) { while (undersat_oil_tables_[iNext][0].size() < 2) {
++iNext; ++iNext;
} }
ASSERT(iNext < sz); ASSERT(iNext < sz);
for (int i=0; i<sz; ++i) { for (int i=0; i<sz; ++i) {
if (undersat_oil_tables_[i][0].size() > 1) { if (undersat_oil_tables_[i][0].size() > 1) {
iPrev = i; iPrev = i;
continue; continue;
} }
bool flagPrev = (iPrev >= 0); bool flagPrev = (iPrev >= 0);
bool flagNext = true; bool flagNext = true;
if (iNext < i) { if (iNext < i) {
iPrev = iNext; iPrev = iNext;
flagPrev = true; flagPrev = true;
iNext = i+1; iNext = i+1;
while (undersat_oil_tables_[iNext][0].size() < 2) { while (undersat_oil_tables_[iNext][0].size() < 2) {
++iNext; ++iNext;
} }
} }
double slopePrevBinv = 0.0; double slopePrevBinv = 0.0;
double slopePrevVisc = 0.0; double slopePrevVisc = 0.0;
double slopeNextBinv = 0.0; double slopeNextBinv = 0.0;
double slopeNextVisc = 0.0; double slopeNextVisc = 0.0;
while (flagPrev || flagNext) { while (flagPrev || flagNext) {
double pressure0 = undersat_oil_tables_[i][0].back(); double pressure0 = undersat_oil_tables_[i][0].back();
double pressure = 1.0e47; double pressure = 1.0e47;
if (flagPrev) { if (flagPrev) {
std::vector<double>::iterator itPrev = upper_bound(undersat_oil_tables_[iPrev][0].begin(), std::vector<double>::iterator itPrev = upper_bound(undersat_oil_tables_[iPrev][0].begin(),
undersat_oil_tables_[iPrev][0].end(),pressure0+1.); undersat_oil_tables_[iPrev][0].end(),pressure0+1.);
if (itPrev == undersat_oil_tables_[iPrev][0].end()) { if (itPrev == undersat_oil_tables_[iPrev][0].end()) {
--itPrev; // Extrapolation ... --itPrev; // Extrapolation ...
} else if (itPrev == undersat_oil_tables_[iPrev][0].begin()) { } else if (itPrev == undersat_oil_tables_[iPrev][0].begin()) {
++itPrev; ++itPrev;
} }
if (itPrev == undersat_oil_tables_[iPrev][0].end()-1) { if (itPrev == undersat_oil_tables_[iPrev][0].end()-1) {
flagPrev = false; // Last data set for "prev" ... flagPrev = false; // Last data set for "prev" ...
} }
double dPPrev = *itPrev - *(itPrev-1); double dPPrev = *itPrev - *(itPrev-1);
pressure = *itPrev; pressure = *itPrev;
int index = int(itPrev - undersat_oil_tables_[iPrev][0].begin()); int index = int(itPrev - undersat_oil_tables_[iPrev][0].begin());
slopePrevBinv = (undersat_oil_tables_[iPrev][1][index] - undersat_oil_tables_[iPrev][1][index-1])/dPPrev; slopePrevBinv = (undersat_oil_tables_[iPrev][1][index] - undersat_oil_tables_[iPrev][1][index-1])/dPPrev;
slopePrevVisc = (undersat_oil_tables_[iPrev][2][index] - undersat_oil_tables_[iPrev][2][index-1])/dPPrev; slopePrevVisc = (undersat_oil_tables_[iPrev][2][index] - undersat_oil_tables_[iPrev][2][index-1])/dPPrev;
} }
if (flagNext) { if (flagNext) {
std::vector<double>::iterator itNext = upper_bound(undersat_oil_tables_[iNext][0].begin(), std::vector<double>::iterator itNext = upper_bound(undersat_oil_tables_[iNext][0].begin(),
undersat_oil_tables_[iNext][0].end(),pressure0+1.); undersat_oil_tables_[iNext][0].end(),pressure0+1.);
if (itNext == undersat_oil_tables_[iNext][0].end()) { if (itNext == undersat_oil_tables_[iNext][0].end()) {
--itNext; // Extrapolation ... --itNext; // Extrapolation ...
} else if (itNext == undersat_oil_tables_[iNext][0].begin()) { } else if (itNext == undersat_oil_tables_[iNext][0].begin()) {
++itNext; ++itNext;
} }
if (itNext == undersat_oil_tables_[iNext][0].end()-1) { if (itNext == undersat_oil_tables_[iNext][0].end()-1) {
flagNext = false; // Last data set for "next" ... flagNext = false; // Last data set for "next" ...
} }
double dPNext = *itNext - *(itNext-1); double dPNext = *itNext - *(itNext-1);
if (flagPrev) { if (flagPrev) {
pressure = std::min(pressure,*itNext); pressure = std::min(pressure,*itNext);
} else { } else {
pressure = *itNext; pressure = *itNext;
} }
int index = int(itNext - undersat_oil_tables_[iNext][0].begin()); int index = int(itNext - undersat_oil_tables_[iNext][0].begin());
slopeNextBinv = (undersat_oil_tables_[iNext][1][index] - undersat_oil_tables_[iNext][1][index-1])/dPNext; slopeNextBinv = (undersat_oil_tables_[iNext][1][index] - undersat_oil_tables_[iNext][1][index-1])/dPNext;
slopeNextVisc = (undersat_oil_tables_[iNext][2][index] - undersat_oil_tables_[iNext][2][index-1])/dPNext; slopeNextVisc = (undersat_oil_tables_[iNext][2][index] - undersat_oil_tables_[iNext][2][index-1])/dPNext;
} }
double dP = pressure - pressure0; double dP = pressure - pressure0;
if (iPrev >= 0) { if (iPrev >= 0) {
double w = (saturated_oil_table_[3][i] - saturated_oil_table_[3][iPrev]) / double w = (saturated_oil_table_[3][i] - saturated_oil_table_[3][iPrev]) /
(saturated_oil_table_[3][iNext] - saturated_oil_table_[3][iPrev]); (saturated_oil_table_[3][iNext] - saturated_oil_table_[3][iPrev]);
undersat_oil_tables_[i][0].push_back(pressure0+dP); undersat_oil_tables_[i][0].push_back(pressure0+dP);
undersat_oil_tables_[i][1].push_back(undersat_oil_tables_[i][1].back() + undersat_oil_tables_[i][1].push_back(undersat_oil_tables_[i][1].back() +
dP*(slopePrevBinv+w*(slopeNextBinv-slopePrevBinv))); dP*(slopePrevBinv+w*(slopeNextBinv-slopePrevBinv)));
undersat_oil_tables_[i][2].push_back(undersat_oil_tables_[i][2].back() + undersat_oil_tables_[i][2].push_back(undersat_oil_tables_[i][2].back() +
dP*(slopePrevVisc+w*(slopeNextVisc-slopePrevVisc))); dP*(slopePrevVisc+w*(slopeNextVisc-slopePrevVisc)));
} else { } else {
undersat_oil_tables_[i][0].push_back(pressure0+dP); undersat_oil_tables_[i][0].push_back(pressure0+dP);
undersat_oil_tables_[i][1].push_back(undersat_oil_tables_[i][1].back()+dP*slopeNextBinv); undersat_oil_tables_[i][1].push_back(undersat_oil_tables_[i][1].back()+dP*slopeNextBinv);
undersat_oil_tables_[i][2].push_back(undersat_oil_tables_[i][2].back()+dP*slopeNextVisc); undersat_oil_tables_[i][2].push_back(undersat_oil_tables_[i][2].back()+dP*slopeNextVisc);
} }
} }
} }
} }
/// Destructor. /// Destructor.
@ -238,15 +238,15 @@ namespace Opm
double SinglePvtLiveOil::evalB(double press, const double* surfvol) const double SinglePvtLiveOil::evalB(double press, const double* surfvol) const
{ {
// if (surfvol[phase_pos_[Liquid]] == 0.0) return 1.0; // To handle no-oil case. // if (surfvol[phase_pos_[Liquid]] == 0.0) return 1.0; // To handle no-oil case.
return 1.0/miscible_oil(press, surfvol, 1, false); return 1.0/miscible_oil(press, surfvol, 1, false);
} }
void SinglePvtLiveOil::evalBDeriv(const double press, const double* surfvol, void SinglePvtLiveOil::evalBDeriv(const double press, const double* surfvol,
double& Bval, double& dBdpval) const double& Bval, double& dBdpval) const
{ {
Bval = evalB(press, surfvol); Bval = evalB(press, surfvol);
dBdpval = -Bval*Bval*miscible_oil(press, surfvol, 1, true); dBdpval = -Bval*Bval*miscible_oil(press, surfvol, 1, true);
} }
double SinglePvtLiveOil::evalR(double press, const double* surfvol) const double SinglePvtLiveOil::evalR(double press, const double* surfvol) const
@ -254,14 +254,14 @@ namespace Opm
if (surfvol[phase_pos_[Vapour]] == 0.0) { if (surfvol[phase_pos_[Vapour]] == 0.0) {
return 0.0; return 0.0;
} }
double Rval = linearInterpolationExtrap(saturated_oil_table_[0], double Rval = linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[3], press); saturated_oil_table_[3], press);
double maxR = surfvol[phase_pos_[Vapour]]/surfvol[phase_pos_[Liquid]]; double maxR = surfvol[phase_pos_[Vapour]]/surfvol[phase_pos_[Liquid]];
if (Rval < maxR ) { // Saturated case if (Rval < maxR ) { // Saturated case
return Rval; return Rval;
} else { } else {
return maxR; // Undersaturated case return maxR; // Undersaturated case
} }
} }
void SinglePvtLiveOil::evalRDeriv(const double press, const double* surfvol, void SinglePvtLiveOil::evalRDeriv(const double press, const double* surfvol,
@ -272,19 +272,19 @@ namespace Opm
dRdpval = 0.0; dRdpval = 0.0;
return; return;
} }
Rval = linearInterpolationExtrap(saturated_oil_table_[0], Rval = linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[3], press); saturated_oil_table_[3], press);
double maxR = surfvol[phase_pos_[Vapour]]/surfvol[phase_pos_[Liquid]]; double maxR = surfvol[phase_pos_[Vapour]]/surfvol[phase_pos_[Liquid]];
if (Rval < maxR ) { if (Rval < maxR ) {
// Saturated case // Saturated case
dRdpval = linearInterpolDerivative(saturated_oil_table_[0], dRdpval = linearInterpolDerivative(saturated_oil_table_[0],
saturated_oil_table_[3], saturated_oil_table_[3],
press); press);
} else { } else {
// Undersaturated case // Undersaturated case
Rval = maxR; Rval = maxR;
dRdpval = 0.0; dRdpval = 0.0;
} }
} }
@ -293,57 +293,57 @@ namespace Opm
const int item, const int item,
const bool deriv) const const bool deriv) const
{ {
int section; int section;
double Rval = linearInterpolationExtrap(saturated_oil_table_[0], double Rval = linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[3], saturated_oil_table_[3],
press, section); press, section);
double maxR = (surfvol[phase_pos_[Liquid]] == 0.0) ? 0.0 : surfvol[phase_pos_[Vapour]]/surfvol[phase_pos_[Liquid]]; double maxR = (surfvol[phase_pos_[Liquid]] == 0.0) ? 0.0 : surfvol[phase_pos_[Vapour]]/surfvol[phase_pos_[Liquid]];
if (deriv) { if (deriv) {
if (Rval < maxR ) { // Saturated case if (Rval < maxR ) { // Saturated case
return linearInterpolDerivative(saturated_oil_table_[0], return linearInterpolDerivative(saturated_oil_table_[0],
saturated_oil_table_[item], saturated_oil_table_[item],
press); press);
} else { // Undersaturated case } else { // Undersaturated case
int is = tableIndex(saturated_oil_table_[3], maxR);
double w = (maxR - saturated_oil_table_[3][is]) /
(saturated_oil_table_[3][is+1] - saturated_oil_table_[3][is]);
ASSERT(undersat_oil_tables_[is][0].size() >= 2);
ASSERT(undersat_oil_tables_[is+1][0].size() >= 2);
double val1 =
linearInterpolDerivative(undersat_oil_tables_[is][0],
undersat_oil_tables_[is][item],
press);
double val2 =
linearInterpolDerivative(undersat_oil_tables_[is+1][0],
undersat_oil_tables_[is+1][item],
press);
double val = val1 + w*(val2 - val1);
return val;
}
} else {
if (Rval < maxR ) { // Saturated case
return linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[item],
press);
} else { // Undersaturated case
// Interpolate between table sections
int is = tableIndex(saturated_oil_table_[3], maxR); int is = tableIndex(saturated_oil_table_[3], maxR);
double w = (maxR - saturated_oil_table_[3][is]) / double w = (maxR - saturated_oil_table_[3][is]) /
(saturated_oil_table_[3][is+1] - saturated_oil_table_[3][is]); (saturated_oil_table_[3][is+1] - saturated_oil_table_[3][is]);
ASSERT(undersat_oil_tables_[is][0].size() >= 2); ASSERT(undersat_oil_tables_[is][0].size() >= 2);
ASSERT(undersat_oil_tables_[is+1][0].size() >= 2); ASSERT(undersat_oil_tables_[is+1][0].size() >= 2);
double val1 = double val1 =
linearInterpolationExtrap(undersat_oil_tables_[is][0], linearInterpolDerivative(undersat_oil_tables_[is][0],
undersat_oil_tables_[is][item], undersat_oil_tables_[is][item],
press); press);
double val2 = double val2 =
linearInterpolationExtrap(undersat_oil_tables_[is+1][0], linearInterpolDerivative(undersat_oil_tables_[is+1][0],
undersat_oil_tables_[is+1][item], undersat_oil_tables_[is+1][item],
press); press);
double val = val1 + w*(val2 - val1); double val = val1 + w*(val2 - val1);
return val; return val;
} }
} } else {
if (Rval < maxR ) { // Saturated case
return linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[item],
press);
} else { // Undersaturated case
// Interpolate between table sections
int is = tableIndex(saturated_oil_table_[3], maxR);
double w = (maxR - saturated_oil_table_[3][is]) /
(saturated_oil_table_[3][is+1] - saturated_oil_table_[3][is]);
ASSERT(undersat_oil_tables_[is][0].size() >= 2);
ASSERT(undersat_oil_tables_[is+1][0].size() >= 2);
double val1 =
linearInterpolationExtrap(undersat_oil_tables_[is][0],
undersat_oil_tables_[is][item],
press);
double val2 =
linearInterpolationExtrap(undersat_oil_tables_[is+1][0],
undersat_oil_tables_[is+1][item],
press);
double val = val1 + w*(val2 - val1);
return val;
}
}
} }
} // namespace Opm } // namespace Opm

View File

@ -34,10 +34,10 @@ namespace Opm
class SinglePvtLiveOil : public SinglePvtInterface class SinglePvtLiveOil : public SinglePvtInterface
{ {
public: public:
typedef std::vector<std::vector<std::vector<double> > > table_t; typedef std::vector<std::vector<std::vector<double> > > table_t;
SinglePvtLiveOil(const table_t& pvto); SinglePvtLiveOil(const table_t& pvto);
virtual ~SinglePvtLiveOil(); virtual ~SinglePvtLiveOil();
/// Viscosity as a function of p and z. /// Viscosity as a function of p and z.
virtual void mu(const int n, virtual void mu(const int n,
@ -77,15 +77,15 @@ namespace Opm
double evalR(double press, const double* surfvol) const; double evalR(double press, const double* surfvol) const;
void evalRDeriv(double press, const double* surfvol, double& R, double& dRdp) const; void evalRDeriv(double press, const double* surfvol, double& R, double& dRdp) const;
// item: 1=>1/B 2=>mu; // item: 1=>1/B 2=>mu;
double miscible_oil(const double press, double miscible_oil(const double press,
const double* surfvol, const double* surfvol,
const int item, const int item,
const bool deriv = false) const; const bool deriv = false) const;
// PVT properties of live oil (with dissolved gas) // PVT properties of live oil (with dissolved gas)
std::vector<std::vector<double> > saturated_oil_table_; std::vector<std::vector<double> > saturated_oil_table_;
std::vector<std::vector<std::vector<double> > > undersat_oil_tables_; std::vector<std::vector<std::vector<double> > > undersat_oil_tables_;
}; };
} }

View File

@ -104,6 +104,8 @@ allocate_grid(size_t ndims ,
nel = ncellfaces; nel = ncellfaces;
G->cell_faces = malloc(nel * sizeof *G->cell_faces); G->cell_faces = malloc(nel * sizeof *G->cell_faces);
G->cell_facetag = malloc(nel * sizeof *G->cell_facetag);
nel = ncells + 1; nel = ncells + 1;
G->cell_facepos = malloc(nel * sizeof *G->cell_facepos); G->cell_facepos = malloc(nel * sizeof *G->cell_facepos);
@ -121,6 +123,7 @@ allocate_grid(size_t ndims ,
(G->face_normals == NULL) || (G->face_normals == NULL) ||
(G->face_areas == NULL) || (G->face_areas == NULL) ||
(G->cell_faces == NULL) || (G->cell_faces == NULL) ||
(G->cell_facetag == NULL) ||
(G->cell_facepos == NULL) || (G->cell_facepos == NULL) ||
(G->cell_centroids == NULL) || (G->cell_centroids == NULL) ||
(G->cell_volumes == NULL) ) (G->cell_volumes == NULL) )

View File

@ -118,7 +118,7 @@ create_grid_cart2d(int nx, int ny)
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
struct UnstructuredGrid * struct UnstructuredGrid *
create_grid_tensor2d(int nx, int ny, double x[], double y[]) create_grid_tensor2d(int nx, int ny, const double *x, const double *y)
{ {
struct UnstructuredGrid *G; struct UnstructuredGrid *G;
@ -136,9 +136,13 @@ create_grid_tensor2d(int nx, int ny, double x[], double y[])
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
struct UnstructuredGrid * struct UnstructuredGrid *
create_grid_tensor3d(int nx, int ny , int nz , create_grid_tensor3d(int nx ,
double x[], double y[], double z[], int ny ,
const double depthz[]) int nz ,
const double *x ,
const double *y ,
const double *z ,
const double *depthz)
{ {
struct UnstructuredGrid *G; struct UnstructuredGrid *G;
@ -259,6 +263,11 @@ fill_cart_topology_3d(struct UnstructuredGrid *G)
} }
} }
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; fnodes = G->face_nodes;
fnodepos = G->face_nodepos; fnodepos = G->face_nodepos;
@ -561,6 +570,12 @@ fill_cart_topology_2d(struct UnstructuredGrid *G)
} }
} }
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; fnodes = G->face_nodes;

View File

@ -30,25 +30,140 @@
#ifndef OPM_CART_GRID_H_HEADER #ifndef OPM_CART_GRID_H_HEADER
#define 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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
struct UnstructuredGrid; struct UnstructuredGrid;
struct UnstructuredGrid *create_grid_cart2d(int nx, int ny); /**
struct UnstructuredGrid *create_grid_cart3d(int nx, int ny, int nz); * Form geometrically Cartesian grid in two space dimensions with unit-sized
struct UnstructuredGrid *create_grid_hexa3d(int nx, int ny, int nz, * cells.
double dx, double dy, double dz); *
* @param[in] nx Number of cells in @c x direction.
struct UnstructuredGrid *create_grid_tensor2d(int nx, int ny, * @param[in] ny Number of cells in @c y direction.
double x[], double y[]); *
* @return Fully formed grid structure containing valid geometric primitives.
* Must be destroyed using function destroy_grid().
*/
struct UnstructuredGrid * struct UnstructuredGrid *
create_grid_tensor3d(int nx, int ny, int nz, create_grid_cart2d(int nx, int ny);
double x[], double y[], double z[],
const double depthz[]);
/**
* 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -34,6 +34,12 @@
#ifndef OPM_CORNERPOINT_GRID_HEADER_INCLUDED #ifndef OPM_CORNERPOINT_GRID_HEADER_INCLUDED
#define 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.h>
#include <opm/core/grid/cpgpreprocess/preprocess.h> #include <opm/core/grid/cpgpreprocess/preprocess.h>
@ -41,9 +47,53 @@
extern "C" { extern "C" {
#endif #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 * struct UnstructuredGrid *
create_grid_cornerpoint(const struct grdecl *in, double tol); 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); void compute_geometry(struct UnstructuredGrid *g);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -587,8 +587,8 @@ get_zcorn_sign(int nx, int ny, int nz, const int *actnum,
z1 = sign*zcorn[i+2*nx*(j+2*ny*(k))]; z1 = sign*zcorn[i+2*nx*(j+2*ny*(k))];
z2 = sign*zcorn[i+2*nx*(j+2*ny*(k+1))]; z2 = sign*zcorn[i+2*nx*(j+2*ny*(k+1))];
c1 = i/2 + nx*(j/2 + ny*k/2); c1 = i/2 + nx*(j/2 + ny*(k/2));
c2 = i/2 + nx*(j/2 + ny*(k+1)/2); c2 = i/2 + nx*(j/2 + ny*((k+1)/2));
if (((actnum == NULL) || if (((actnum == NULL) ||
(actnum[c1] && actnum[c2])) (actnum[c1] && actnum[c2]))
@ -872,7 +872,7 @@ void process_grdecl(const struct grdecl *in,
/* -----------------------------------------------------------------*/ /* -----------------------------------------------------------------*/
/* (re)allocate space for and compute coordinates of nodes that /* (re)allocate space for and compute coordinates of nodes that
* arise from intesecting cells (faults) */ * arise from intersecting cells (faults) */
compute_intersection_coordinates(intersections, out); compute_intersection_coordinates(intersections, out);
free (intersections); free (intersections);

View File

@ -35,48 +35,112 @@
#ifndef OPENRS_PREPROCESS_HEADER #ifndef OPENRS_PREPROCESS_HEADER
#define OPENRS_PREPROCESS_HEADER #define OPENRS_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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Input structure holding raw cornerpoint spec. */ /**
struct grdecl{ * Raw corner-point specification of a particular geological model.
int dims[3]; */
const double *coord; struct grdecl {
const double *zcorn; int dims[3]; /**< Cartesian box dimensions. */
const int *actnum; const double *coord; /**< Pillar end-points. */
const double *mapaxes; /* 6 Element rotation vector - can be NULL. */ const double *zcorn; /**< Explicit "active" map. May be NULL.*/
const int *actnum; /**< Corner-point depths. */
const double *mapaxes; /**< 6 Element rotation vector - can be NULL. */
}; };
/* Constant: I J K */ /**
enum face_tag { LEFT, BACK, TOP }; * Connection taxonomy.
*/
/* Output structure holding grid topology */ enum face_tag {
struct processed_grid{ LEFT, /**< Connection topologically parallel to J-K plane. */
int m; /** Upper bound on "number_of_faces" */ BACK, /**< Connection topologically parallel to I-K plane. */
int n; /** Upper bound on "number_of_nodes" */ TOP /**< Connection topologically parallel to I-J plane. */
int dimensions[3]; /* Cartesian dimension */
int number_of_faces;
int *face_nodes; /* Nodes numbers of each face sequentially. */
int *face_ptr; /* Start position for each face in face_nodes. */
int *face_neighbors; /* Global cell numbers. 2 ints per face sequentially */
enum face_tag *face_tag;
int number_of_nodes;
int number_of_nodes_on_pillars; /** Total number of unique cell vertices that lie on pillars. */
double *node_coordinates; /* 3 doubles per node, sequentially */
int number_of_cells; /* number of active cells */
int *local_cell_index; /* Global to local map */
}; };
void process_grdecl (const struct grdecl *g, /**
double tol, * Result structure representing minimal derived topology and geometry of
struct processed_grid *out); * 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); void free_processed_grid(struct processed_grid *g);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -65,9 +65,16 @@ namespace Opm
rtol_ (rtol) , rtol_ (rtol) ,
is_spd_(is_spd) is_spd_(is_spd)
{ {
#if !HAVE_AGMG }
THROW("AGMG support is not enabled in this library");
#endif // HAVE_AGMG LinearSolverAGMG::LinearSolverAGMG(const parameter::ParameterGroup& param)
: max_it_(100) ,
rtol_ (1.0e-6),
is_spd_(false)
{
max_it_ = param.getDefault("max_it", max_it_);
rtol_ = param.getDefault("rtol" , rtol_ );
is_spd_ = param.getDefault("is_spd", is_spd_);
} }
LinearSolverAGMG::~LinearSolverAGMG() {} LinearSolverAGMG::~LinearSolverAGMG() {}

View File

@ -43,6 +43,7 @@
*/ */
#include <opm/core/linalg/LinearSolverInterface.hpp> #include <opm/core/linalg/LinearSolverInterface.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
namespace Opm namespace Opm
{ {
@ -62,20 +63,29 @@ namespace Opm
const double rtol = 1.0e-6, const double rtol = 1.0e-6,
const bool is_spd = false); const bool is_spd = false);
/// Destructor. /**
* Constructor.
* \param[in] param ParameterGroup object containing the fields
* max_it,rtol,is_spd as used in the constructor.
*/
LinearSolverAGMG(const parameter::ParameterGroup& param);
/**
* Destructor.
*/
virtual ~LinearSolverAGMG(); virtual ~LinearSolverAGMG();
using LinearSolverInterface::solve; using LinearSolverInterface::solve;
/// Solve a linear system, with a matrix given in compressed /// Solve a linear system, with a matrix given in compressed
/// sparse row format. /// sparse row format.
/// \param[in] size Number of rows (and colums). /// \param[in] size Number of rows (and columns).
/// \param[in] nonzeros Number of (structural) non-zeros. /// \param[in] nonzeros Number of (structural) non-zeros.
/// \param[in] ia Row pointers. /// \param[in] ia Row pointers.
/// \param[in] ja Column indices. /// \param[in] ja Column indices.
/// \param[in] sa (structurally) non-zero elements. /// \param[in] sa (structurally) non-zero elements.
/// \param[in] rhs System right-hand side. /// \param[in] rhs System right-hand side.
/// \param[inout] solution System solution. /// \param[in,out] solution System solution.
/// \return Solver meta-data concerning most recent system solve. /// \return Solver meta-data concerning most recent system solve.
virtual LinearSolverInterface::LinearSolverReport virtual LinearSolverInterface::LinearSolverReport
solve(const int size, const int nonzeros, solve(const int size, const int nonzeros,

View File

@ -31,6 +31,11 @@
#include <opm/core/linalg/LinearSolverIstl.hpp> #include <opm/core/linalg/LinearSolverIstl.hpp>
#endif #endif
#if HAVE_AGMG
#include <opm/core/linalg/LinearSolverAGMG.hpp>
#endif
#include <opm/core/utility/parameters/ParameterGroup.hpp> #include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/utility/ErrorMacros.hpp> #include <opm/core/utility/ErrorMacros.hpp>
#include <string> #include <string>
@ -70,6 +75,12 @@ namespace Opm
#endif #endif
} }
else if (ls == "agmg") {
#if HAVE_AGMG
solver_.reset(new LinearSolverAGMG(param));
#endif
}
else { else {
THROW("Linear solver " << ls << " is unknown."); THROW("Linear solver " << ls << " is unknown.");
} }

View File

@ -24,10 +24,11 @@
#include <opm/core/linalg/LinearSolverIstl.hpp> #include <opm/core/linalg/LinearSolverIstl.hpp>
// Work around the fact that istl headers expect #include <opm/core/utility/have_boost_redef.hpp>
// HAVE_BOOST to be 1, and not just defined.
#undef HAVE_BOOST // Silence compatibility warning from DUNE headers since we don't use
#define HAVE_BOOST 1 // the deprecated member anyway (in this compilation unit)
#define DUNE_COMMON_FIELDVECTOR_SIZE_IS_METHOD 1
// TODO: clean up includes. // TODO: clean up includes.
#include <dune/common/deprecated.hh> #include <dune/common/deprecated.hh>

View File

@ -30,11 +30,13 @@
#include <opm/core/newwells.h> #include <opm/core/newwells.h>
#include <opm/core/simulator/BlackoilState.hpp> #include <opm/core/simulator/BlackoilState.hpp>
#include <opm/core/simulator/WellState.hpp> #include <opm/core/simulator/WellState.hpp>
#include <opm/core/fluid/RockCompressibility.hpp>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <numeric>
namespace Opm namespace Opm
{ {
@ -58,6 +60,7 @@ namespace Opm
/// to change. /// to change.
CompressibleTpfa::CompressibleTpfa(const UnstructuredGrid& grid, CompressibleTpfa::CompressibleTpfa(const UnstructuredGrid& grid,
const BlackoilPropertiesInterface& props, const BlackoilPropertiesInterface& props,
const RockCompressibility* rock_comp_props,
const LinearSolverInterface& linsolver, const LinearSolverInterface& linsolver,
const double residual_tol, const double residual_tol,
const double change_tol, const double change_tol,
@ -66,6 +69,7 @@ namespace Opm
const struct Wells* wells) const struct Wells* wells)
: grid_(grid), : grid_(grid),
props_(props), props_(props),
rock_comp_props_(rock_comp_props),
linsolver_(linsolver), linsolver_(linsolver),
residual_tol_(residual_tol), residual_tol_(residual_tol),
change_tol_(change_tol), change_tol_(change_tol),
@ -74,8 +78,8 @@ namespace Opm
wells_(wells), wells_(wells),
htrans_(grid.cell_facepos[ grid.number_of_cells ]), htrans_(grid.cell_facepos[ grid.number_of_cells ]),
trans_ (grid.number_of_faces), trans_ (grid.number_of_faces),
porevol_(grid.number_of_cells), allcells_(grid.number_of_cells),
allcells_(grid.number_of_cells) singular_(false)
{ {
if (wells_ && (wells_->number_of_phases != props.numPhases())) { if (wells_ && (wells_->number_of_phases != props.numPhases())) {
THROW("Inconsistent number of phases specified (wells vs. props): " THROW("Inconsistent number of phases specified (wells vs. props): "
@ -86,7 +90,12 @@ namespace Opm
UnstructuredGrid* gg = const_cast<UnstructuredGrid*>(&grid_); UnstructuredGrid* gg = const_cast<UnstructuredGrid*>(&grid_);
tpfa_htrans_compute(gg, props.permeability(), &htrans_[0]); tpfa_htrans_compute(gg, props.permeability(), &htrans_[0]);
tpfa_trans_compute(gg, &htrans_[0], &trans_[0]); tpfa_trans_compute(gg, &htrans_[0], &trans_[0]);
computePorevolume(grid_, props.porosity(), porevol_); // If we have rock compressibility, pore volumes are updated
// in the compute*() methods, otherwise they are constant and
// hence may be computed here.
if (rock_comp_props_ == NULL || !rock_comp_props_->isActive()) {
computePorevolume(grid_, props.porosity(), porevol_);
}
for (int c = 0; c < grid.number_of_cells; ++c) { for (int c = 0; c < grid.number_of_cells; ++c) {
allcells_[c] = c; allcells_[c] = c;
} }
@ -114,7 +123,7 @@ namespace Opm
WellState& well_state) WellState& well_state)
{ {
const int nc = grid_.number_of_cells; const int nc = grid_.number_of_cells;
const int nw = wells_->number_of_wells; const int nw = (wells_ != 0) ? wells_->number_of_wells : 0;
// Set up dynamic data. // Set up dynamic data.
computePerSolveDynamicData(dt, state, well_state); computePerSolveDynamicData(dt, state, well_state);
@ -182,6 +191,21 @@ namespace Opm
/// @brief After solve(), was the resulting pressure singular.
/// Returns true if the pressure is singular in the following
/// sense: if everything is incompressible and there are no
/// pressure conditions, the absolute values of the pressure
/// solution are arbitrary. (But the differences in pressure
/// are significant.)
bool CompressibleTpfa::singularPressure() const
{
return singular_;
}
/// Compute well potentials. /// Compute well potentials.
void CompressibleTpfa::computeWellPotentials(const BlackoilState& state) void CompressibleTpfa::computeWellPotentials(const BlackoilState& state)
{ {
@ -230,6 +254,9 @@ namespace Opm
const WellState& /*well_state*/) const WellState& /*well_state*/)
{ {
computeWellPotentials(state); computeWellPotentials(state);
if (rock_comp_props_ && rock_comp_props_->isActive()) {
computePorevolume(grid_, props_.porosity(), *rock_comp_props_, state.pressure(), initial_porevol_);
}
} }
@ -252,6 +279,8 @@ namespace Opm
// std::vector<double> face_gravcap_; // std::vector<double> face_gravcap_;
// std::vector<double> wellperf_A_; // std::vector<double> wellperf_A_;
// std::vector<double> wellperf_phasemob_; // std::vector<double> wellperf_phasemob_;
// std::vector<double> porevol_; // Only modified if rock_comp_props_ is non-null.
// std::vector<double> rock_comp_; // Empty unless rock_comp_props_ is non-null.
computeCellDynamicData(dt, state, well_state); computeCellDynamicData(dt, state, well_state);
computeFaceDynamicData(dt, state, well_state); computeFaceDynamicData(dt, state, well_state);
computeWellDynamicData(dt, state, well_state); computeWellDynamicData(dt, state, well_state);
@ -273,6 +302,8 @@ namespace Opm
// std::vector<double> cell_viscosity_; // std::vector<double> cell_viscosity_;
// std::vector<double> cell_phasemob_; // std::vector<double> cell_phasemob_;
// std::vector<double> cell_voldisc_; // std::vector<double> cell_voldisc_;
// std::vector<double> porevol_; // Only modified if rock_comp_props_ is non-null.
// std::vector<double> rock_comp_; // Empty unless rock_comp_props_ is non-null.
const int nc = grid_.number_of_cells; const int nc = grid_.number_of_cells;
const int np = props_.numPhases(); const int np = props_.numPhases();
const double* cell_p = &state.pressure()[0]; const double* cell_p = &state.pressure()[0];
@ -296,6 +327,14 @@ namespace Opm
// TODO: Check this! // TODO: Check this!
cell_voldisc_.clear(); cell_voldisc_.clear();
cell_voldisc_.resize(nc, 0.0); cell_voldisc_.resize(nc, 0.0);
if (rock_comp_props_ && rock_comp_props_->isActive()) {
computePorevolume(grid_, props_.porosity(), *rock_comp_props_, state.pressure(), porevol_);
rock_comp_.resize(nc);
for (int cell = 0; cell < nc; ++cell) {
rock_comp_[cell] = rock_comp_props_->rockComp(state.pressure()[cell]);
}
}
} }
@ -341,7 +380,7 @@ namespace Opm
const double depth_diff = face_depth - grid_.cell_centroids[c[j]*dim + dim - 1]; const double depth_diff = face_depth - grid_.cell_centroids[c[j]*dim + dim - 1];
props_.density(1, &cell_A_[np*np*c[j]], &gravcontrib[j][0]); props_.density(1, &cell_A_[np*np*c[j]], &gravcontrib[j][0]);
for (int p = 0; p < np; ++p) { for (int p = 0; p < np; ++p) {
gravcontrib[j][p] *= depth_diff; gravcontrib[j][p] *= depth_diff*grav;
} }
} else { } else {
std::fill(gravcontrib[j].begin(), gravcontrib[j].end(), 0.0); std::fill(gravcontrib[j].begin(), gravcontrib[j].end(), 0.0);
@ -408,30 +447,54 @@ namespace Opm
/// Compute per-iteration dynamic properties for wells. /// Compute per-iteration dynamic properties for wells.
void CompressibleTpfa::computeWellDynamicData(const double /*dt*/, void CompressibleTpfa::computeWellDynamicData(const double /*dt*/,
const BlackoilState& /*state*/, const BlackoilState& /*state*/,
const WellState& /*well_state*/) const WellState& well_state)
{ {
// These are the variables that get computed by this function: // These are the variables that get computed by this function:
// //
// std::vector<double> wellperf_A_; // std::vector<double> wellperf_A_;
// std::vector<double> wellperf_phasemob_; // std::vector<double> wellperf_phasemob_;
const int np = props_.numPhases(); const int np = props_.numPhases();
const int nw = wells_->number_of_wells; const int nw = (wells_ != 0) ? wells_->number_of_wells : 0;
const int nperf = wells_->well_connpos[nw]; const int nperf = (wells_ != 0) ? wells_->well_connpos[nw] : 0;
wellperf_A_.resize(nperf*np*np); wellperf_A_.resize(nperf*np*np);
wellperf_phasemob_.resize(nperf*np); wellperf_phasemob_.resize(nperf*np);
// The A matrix is set equal to the perforation grid cells' // The A matrix is set equal to the perforation grid cells'
// matrix, for both injectors and producers. // matrix for producers, computed from bhp and injection
// component fractions from
// The mobilities are set equal to the perforation grid cells' // The mobilities are set equal to the perforation grid cells'
// mobilities, for both injectors and producers. // mobilities for producers.
std::vector<double> mu(np);
for (int w = 0; w < nw; ++w) { for (int w = 0; w < nw; ++w) {
bool producer = (wells_->type[w] == PRODUCER);
const double* comp_frac = &wells_->comp_frac[np*w];
for (int j = wells_->well_connpos[w]; j < wells_->well_connpos[w+1]; ++j) { for (int j = wells_->well_connpos[w]; j < wells_->well_connpos[w+1]; ++j) {
const int c = wells_->well_cells[j]; const int c = wells_->well_cells[j];
const double* cA = &cell_A_[np*np*c];
double* wpA = &wellperf_A_[np*np*j]; double* wpA = &wellperf_A_[np*np*j];
std::copy(cA, cA + np*np, wpA);
const double* cM = &cell_phasemob_[np*c];
double* wpM = &wellperf_phasemob_[np*j]; double* wpM = &wellperf_phasemob_[np*j];
std::copy(cM, cM + np, wpM); if (producer) {
const double* cA = &cell_A_[np*np*c];
std::copy(cA, cA + np*np, wpA);
const double* cM = &cell_phasemob_[np*c];
std::copy(cM, cM + np, wpM);
} else {
const double bhp = well_state.bhp()[w];
double perf_p = bhp;
for (int phase = 0; phase < np; ++phase) {
perf_p += wellperf_gpot_[np*j + phase]*comp_frac[phase];
}
// Hack warning: comp_frac is used as a component
// surface-volume variable in calls to matrix() and
// viscosity(), but as a saturation in the call to
// relperm(). This is probably ok as long as injectors
// only inject pure fluids.
props_.matrix(1, &perf_p, comp_frac, &c, wpA, NULL);
props_.viscosity(1, &perf_p, comp_frac, &c, &mu[0], NULL);
ASSERT(std::fabs(std::accumulate(comp_frac, comp_frac + np, 0.0) - 1.0) < 1e-6);
props_.relperm (1, comp_frac, &c, wpM , NULL);
for (int phase = 0; phase < np; ++phase) {
wpM[phase] /= mu[phase];
}
}
} }
} }
} }
@ -449,9 +512,9 @@ namespace Opm
const double* z = &state.surfacevol()[0]; const double* z = &state.surfacevol()[0];
UnstructuredGrid* gg = const_cast<UnstructuredGrid*>(&grid_); UnstructuredGrid* gg = const_cast<UnstructuredGrid*>(&grid_);
CompletionData completion_data; CompletionData completion_data;
completion_data.gpot = &wellperf_gpot_[0]; completion_data.gpot = ! wellperf_gpot_.empty() ? &wellperf_gpot_[0] : 0;
completion_data.A = &wellperf_A_[0]; completion_data.A = ! wellperf_A_.empty() ? &wellperf_A_[0] : 0;
completion_data.phasemob = &wellperf_phasemob_[0]; completion_data.phasemob = ! wellperf_phasemob_.empty() ? &wellperf_phasemob_[0] : 0;
cfs_tpfa_res_wells wells_tmp; cfs_tpfa_res_wells wells_tmp;
wells_tmp.W = const_cast<Wells*>(wells_); wells_tmp.W = const_cast<Wells*>(wells_);
wells_tmp.data = &completion_data; wells_tmp.data = &completion_data;
@ -465,9 +528,20 @@ namespace Opm
cq.Af = &face_A_[0]; cq.Af = &face_A_[0];
cq.phasemobf = &face_phasemob_[0]; cq.phasemobf = &face_phasemob_[0];
cq.voldiscr = &cell_voldisc_[0]; cq.voldiscr = &cell_voldisc_[0];
cfs_tpfa_res_assemble(gg, dt, &forces, z, &cq, &trans_[0], int was_adjusted = 0;
&face_gravcap_[0], cell_press, well_bhp, if (! (rock_comp_props_ && rock_comp_props_->isActive())) {
&porevol_[0], h_); was_adjusted =
cfs_tpfa_res_assemble(gg, dt, &forces, z, &cq, &trans_[0],
&face_gravcap_[0], cell_press, well_bhp,
&porevol_[0], h_);
} else {
was_adjusted =
cfs_tpfa_res_comprock_assemble(gg, dt, &forces, z, &cq, &trans_[0],
&face_gravcap_[0], cell_press, well_bhp,
&porevol_[0], &initial_porevol_[0],
&rock_comp_[0], h_);
}
singular_ = (was_adjusted == 1);
} }
@ -525,9 +599,9 @@ namespace Opm
{ {
UnstructuredGrid* gg = const_cast<UnstructuredGrid*>(&grid_); UnstructuredGrid* gg = const_cast<UnstructuredGrid*>(&grid_);
CompletionData completion_data; CompletionData completion_data;
completion_data.gpot = const_cast<double*>(&wellperf_gpot_[0]); completion_data.gpot = ! wellperf_gpot_.empty() ? const_cast<double*>(&wellperf_gpot_[0]) : 0;
completion_data.A = const_cast<double*>(&wellperf_A_[0]); completion_data.A = ! wellperf_A_.empty() ? const_cast<double*>(&wellperf_A_[0]) : 0;
completion_data.phasemob = const_cast<double*>(&wellperf_phasemob_[0]); completion_data.phasemob = ! wellperf_phasemob_.empty() ? const_cast<double*>(&wellperf_phasemob_[0]) : 0;
cfs_tpfa_res_wells wells_tmp; cfs_tpfa_res_wells wells_tmp;
wells_tmp.W = const_cast<Wells*>(wells_); wells_tmp.W = const_cast<Wells*>(wells_);
wells_tmp.data = &completion_data; wells_tmp.data = &completion_data;
@ -535,6 +609,9 @@ namespace Opm
forces.wells = &wells_tmp; forces.wells = &wells_tmp;
forces.src = NULL; forces.src = NULL;
double* wpress = ! well_state.bhp ().empty() ? & well_state.bhp ()[0] : 0;
double* wflux = ! well_state.perfRates().empty() ? & well_state.perfRates()[0] : 0;
cfs_tpfa_res_flux(gg, cfs_tpfa_res_flux(gg,
&forces, &forces,
props_.numPhases(), props_.numPhases(),
@ -543,9 +620,9 @@ namespace Opm
&face_phasemob_[0], &face_phasemob_[0],
&face_gravcap_[0], &face_gravcap_[0],
&state.pressure()[0], &state.pressure()[0],
&well_state.bhp()[0], wpress,
&state.faceflux()[0], &state.faceflux()[0],
&well_state.perfRates()[0]); wflux);
cfs_tpfa_res_fpress(gg, cfs_tpfa_res_fpress(gg,
props_.numPhases(), props_.numPhases(),
&htrans_[0], &htrans_[0],

View File

@ -33,6 +33,7 @@ namespace Opm
class BlackoilState; class BlackoilState;
class BlackoilPropertiesInterface; class BlackoilPropertiesInterface;
class RockCompressibility;
class LinearSolverInterface; class LinearSolverInterface;
class WellState; class WellState;
@ -44,23 +45,25 @@ namespace Opm
{ {
public: public:
/// Construct solver. /// Construct solver.
/// \param[in] grid A 2d or 3d grid. /// \param[in] grid A 2d or 3d grid.
/// \param[in] props Rock and fluid properties. /// \param[in] props Rock and fluid properties.
/// \param[in] linsolver Linear solver to use. /// \param[in] rock_comp_props Rock compressibility properties. May be null.
/// \param[in] residual_tol Solution accepted if inf-norm of residual is smaller. /// \param[in] linsolver Linear solver to use.
/// \param[in] change_tol Solution accepted if inf-norm of change in pressure is smaller. /// \param[in] residual_tol Solution accepted if inf-norm of residual is smaller.
/// \param[in] maxiter Maximum acceptable number of iterations. /// \param[in] change_tol Solution accepted if inf-norm of change in pressure is smaller.
/// \param[in] gravity Gravity vector. If non-null, the array should /// \param[in] maxiter Maximum acceptable number of iterations.
/// have D elements. /// \param[in] gravity Gravity vector. If non-null, the array should
/// \param[in] wells The wells argument. Will be used in solution, /// have D elements.
/// is ignored if NULL. /// \param[in] wells The wells argument. Will be used in solution,
/// Note: this class observes the well object, and /// is ignored if NULL.
/// makes the assumption that the well topology /// Note: this class observes the well object, and
/// and completions does not change during the /// makes the assumption that the well topology
/// run. However, controls (only) are allowed /// and completions does not change during the
/// to change. /// run. However, controls (only) are allowed
CompressibleTpfa(const UnstructuredGrid& grid, /// to change.
CompressibleTpfa(const UnstructuredGrid& grid,
const BlackoilPropertiesInterface& props, const BlackoilPropertiesInterface& props,
const RockCompressibility* rock_comp_props,
const LinearSolverInterface& linsolver, const LinearSolverInterface& linsolver,
const double residual_tol, const double residual_tol,
const double change_tol, const double change_tol,
@ -68,8 +71,8 @@ namespace Opm
const double* gravity, const double* gravity,
const Wells* wells); const Wells* wells);
/// Destructor. /// Destructor.
~CompressibleTpfa(); ~CompressibleTpfa();
/// Solve the pressure equation by Newton-Raphson scheme. /// Solve the pressure equation by Newton-Raphson scheme.
/// May throw an exception if the number of iterations /// May throw an exception if the number of iterations
@ -78,17 +81,24 @@ namespace Opm
BlackoilState& state, BlackoilState& state,
WellState& well_state); WellState& well_state);
/// @brief After solve(), was the resulting pressure singular.
/// Returns true if the pressure is singular in the following
/// sense: if everything is incompressible and there are no
/// pressure conditions, the absolute values of the pressure
/// solution are arbitrary. (But the differences in pressure
/// are significant.)
bool singularPressure() const;
private: private:
void computePerSolveDynamicData(const double dt, virtual void computePerSolveDynamicData(const double dt,
const BlackoilState& state, const BlackoilState& state,
const WellState& well_state); const WellState& well_state);
void computeWellPotentials(const BlackoilState& state);
void computePerIterationDynamicData(const double dt, void computePerIterationDynamicData(const double dt,
const BlackoilState& state, const BlackoilState& state,
const WellState& well_state); const WellState& well_state);
void computeCellDynamicData(const double dt, virtual void computeCellDynamicData(const double dt,
const BlackoilState& state, const BlackoilState& state,
const WellState& well_state); const WellState& well_state);
void computeFaceDynamicData(const double dt, void computeFaceDynamicData(const double dt,
const BlackoilState& state, const BlackoilState& state,
const WellState& well_state); const WellState& well_state);
@ -101,28 +111,31 @@ namespace Opm
void solveIncrement(); void solveIncrement();
double residualNorm() const; double residualNorm() const;
double incrementNorm() const; double incrementNorm() const;
void computeResults(BlackoilState& state, void computeResults(BlackoilState& state,
WellState& well_state) const; WellState& well_state) const;
protected:
void computeWellPotentials(const BlackoilState& state);
// ------ Data that will remain unmodified after construction. ------ // ------ Data that will remain unmodified after construction. ------
const UnstructuredGrid& grid_; const UnstructuredGrid& grid_;
const BlackoilPropertiesInterface& props_; const BlackoilPropertiesInterface& props_;
const RockCompressibility* rock_comp_props_;
const LinearSolverInterface& linsolver_; const LinearSolverInterface& linsolver_;
const double residual_tol_; const double residual_tol_;
const double change_tol_; const double change_tol_;
const int maxiter_; const int maxiter_;
const double* gravity_; // May be NULL const double* gravity_; // May be NULL
const Wells* wells_; // May be NULL, outside may modify controls (only) between calls to solve(). const Wells* wells_; // May be NULL, outside may modify controls (only) between calls to solve().
std::vector<double> htrans_; std::vector<double> htrans_;
std::vector<double> trans_ ; std::vector<double> trans_ ;
std::vector<double> porevol_;
std::vector<int> allcells_; std::vector<int> allcells_;
// ------ Internal data for the cfs_tpfa_res solver. ------ // ------ Internal data for the cfs_tpfa_res solver. ------
struct cfs_tpfa_res_data* h_; struct cfs_tpfa_res_data* h_;
// ------ Data that will be modified for every solve. ------ // ------ Data that will be modified for every solve. ------
std::vector<double> wellperf_gpot_; std::vector<double> wellperf_gpot_;
std::vector<double> initial_porevol_;
// ------ Data that will be modified for every solver iteration. ------ // ------ Data that will be modified for every solver iteration. ------
std::vector<double> cell_A_; std::vector<double> cell_A_;
@ -135,13 +148,15 @@ namespace Opm
std::vector<double> face_gravcap_; std::vector<double> face_gravcap_;
std::vector<double> wellperf_A_; std::vector<double> wellperf_A_;
std::vector<double> wellperf_phasemob_; std::vector<double> wellperf_phasemob_;
std::vector<double> porevol_; // Only modified if rock_comp_props_ is non-null.
std::vector<double> rock_comp_; // Empty unless rock_comp_props_ is non-null.
// The update to be applied to the pressures (cell and bhp). // The update to be applied to the pressures (cell and bhp).
std::vector<double> pressure_increment_; std::vector<double> pressure_increment_;
// True if the matrix assembled would be singular but for the
// adjustment made in the cfs_*_assemble() calls. This happens
// if everything is incompressible and there are no pressure
// conditions.
bool singular_;
}; };
} // namespace Opm } // namespace Opm

View File

@ -27,8 +27,9 @@
#include <opm/core/pressure/flow_bc.h> #include <opm/core/pressure/flow_bc.h>
#include <opm/core/pressure/mimetic/mimetic.h> // for updating gpress #include <opm/core/pressure/mimetic/mimetic.h> // for updating gpress
#include <opm/core/GridAdapter.hpp> #include <opm/core/GridAdapter.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <stdexcept> #include <stdexcept>
#include <cassert>
/// @brief /// @brief

View File

@ -358,28 +358,193 @@ hybsys_schur_comp_gen(int nc, const int *pconn,
const double *Binv, const double *C2, const double *Binv, const double *C2,
const double *P, struct hybsys *sys); 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 void
hybsys_well_schur_comp_symm(int nc, const int *cwpos, hybsys_well_schur_comp_symm(int nc, const int *cwpos,
double *WI, double *WI,
struct hybsys *sys, struct hybsys *sys,
struct hybsys_well *wsys); 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 void
hybsys_cellcontrib_symm(int c, int nconn, int p1, int p2, hybsys_cellcontrib_symm(int c, int nconn, int p1, int p2,
const double *gpress, const double *src, const double *gpress, const double *src,
const double *Binv, struct hybsys *sys); 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 void
hybsys_cellcontrib_unsymm(int c, int nconn, int p1, int p2, hybsys_cellcontrib_unsymm(int c, int nconn, int p1, int p2,
const double *gpress, const double *src, const double *gpress, const double *src,
const double *Binv, struct hybsys *sys); 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 void
hybsys_well_cellcontrib_symm(int c, int ngconn, int p1, hybsys_well_cellcontrib_symm(int c, int ngconn, int p1,
const int *cwpos, const int *cwpos,
const double *WI, const double *wdp, const double *WI, const double *wdp,
struct hybsys *sys, struct hybsys_well *wsys); 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 void
hybsys_compute_press_flux(int nc, const int *pconn, const int *conn, hybsys_compute_press_flux(int nc, const int *pconn, const int *conn,
const double *gpress, const double *gpress,
@ -387,6 +552,52 @@ hybsys_compute_press_flux(int nc, const int *pconn, const int *conn,
const double *pi, double *press, double *flux, const double *pi, double *press, double *flux,
double *work); 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 void
hybsys_compute_press_flux_well(int nc, const int *pgconn, int nf, hybsys_compute_press_flux_well(int nc, const int *pgconn, int nf,
int nw, const int *pwconn, const int *wconn, int nw, const int *pwconn, const int *wconn,

View File

@ -142,7 +142,7 @@ impl_allocate(struct UnstructuredGrid *G ,
nnu = G->number_of_cells; nnu = G->number_of_cells;
nwperf = 0; nwperf = 0;
if (wells != NULL) { assert (wells->W != NULL); if ((wells != NULL) && (wells->W != NULL)) {
nnu += wells->W->number_of_wells; nnu += wells->W->number_of_wells;
nwperf = wells->W->well_connpos[ wells->W->number_of_wells ]; nwperf = wells->W->well_connpos[ wells->W->number_of_wells ];
} }
@ -185,13 +185,15 @@ construct_matrix(struct UnstructuredGrid *G ,
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
{ {
int f, c1, c2, w, i, nc, nnu; int f, c1, c2, w, i, nc, nnu;
int wells_present;
size_t nnz; size_t nnz;
struct CSRMatrix *A; struct CSRMatrix *A;
nc = nnu = G->number_of_cells; nc = nnu = G->number_of_cells;
if (wells != NULL) {
assert (wells->W != NULL); wells_present = (wells != NULL) && (wells->W != NULL);
if (wells_present) {
nnu += wells->W->number_of_wells; nnu += wells->W->number_of_wells;
} }
@ -214,7 +216,7 @@ construct_matrix(struct UnstructuredGrid *G ,
} }
} }
if (wells != NULL) { if (wells_present) {
/* Well <-> cell connections */ /* Well <-> cell connections */
struct Wells *W = wells->W; struct Wells *W = wells->W;
@ -252,7 +254,7 @@ construct_matrix(struct UnstructuredGrid *G ,
} }
} }
if (wells != NULL) { if (wells_present) {
/* Fill well <-> cell connections */ /* Fill well <-> cell connections */
struct Wells *W = wells->W; struct Wells *W = wells->W;
@ -741,6 +743,29 @@ assemble_completion_to_cell(int c, int wdof, int np, double dt,
} }
/* ---------------------------------------------------------------------- */
static void
welleq_coeff_shut(int np, struct cfs_tpfa_res_data *h,
double *res, double *w2c, double *w2w)
/* ---------------------------------------------------------------------- */
{
int p;
double fwi;
const double *dpflux_w;
/* Sum reservoir phase flux derivatives set by
* compute_darcyflux_and_deriv(). */
dpflux_w = h->pimpl->flux_work + (1 * np);
for (p = 0, fwi = 0.0; p < np; p++) {
fwi += dpflux_w[ p ];
}
*res = 0.0;
*w2c = 0.0;
*w2w = fwi;
}
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static void static void
welleq_coeff_bhp(int np, double dp, struct cfs_tpfa_res_data *h, welleq_coeff_bhp(int np, double dp, struct cfs_tpfa_res_data *h,
@ -795,7 +820,34 @@ welleq_coeff_resv(int np, struct cfs_tpfa_res_data *h,
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static void static void
assemble_completion_to_well(int w, int c, int nc, int np, welleq_coeff_surfrate(int i, int np, struct cfs_tpfa_res_data *h,
struct WellControls *ctrl,
double *res, double *w2c, double *w2w)
/* ---------------------------------------------------------------------- */
{
int p;
double f;
const double *pflux, *dpflux_w, *dpflux_c, *distr;
pflux = h->pimpl->compflux_p + (i * (1 * np));
dpflux_w = h->pimpl->compflux_deriv_p + (i * (2 * np));
dpflux_c = dpflux_w + (1 * (1 * np));
distr = ctrl->distr + (ctrl->current * (1 * np));
*res = *w2c = *w2w = 0.0;
for (p = 0; p < np; p++) {
f = distr[ p ];
*res += f * pflux [ p ];
*w2w += f * dpflux_w[ p ];
*w2c += f * dpflux_c[ p ];
}
}
/* ---------------------------------------------------------------------- */
static void
assemble_completion_to_well(int i, int w, int c, int nc, int np,
double pw, double dt, double pw, double dt,
struct cfs_tpfa_res_wells *wells, struct cfs_tpfa_res_wells *wells,
struct cfs_tpfa_res_data *h ) struct cfs_tpfa_res_data *h )
@ -815,23 +867,25 @@ assemble_completion_to_well(int w, int c, int nc, int np,
ctrl = W->ctrls[ w ]; ctrl = W->ctrls[ w ];
if (ctrl->current < 0) { if (ctrl->current < 0) {
assert (0); /* Shut wells currently not supported */ /* Interpreting a negative current control index to mean a shut well */
welleq_coeff_shut(np, h, &res, &w2c, &w2w);
} }
else {
switch (ctrl->type[ ctrl->current ]) {
case BHP :
welleq_coeff_bhp(np, pw - ctrl->target[ ctrl->current ],
h, &res, &w2c, &w2w);
break;
switch (ctrl->type[ ctrl->current ]) { case RESERVOIR_RATE:
case BHP : assert (W->number_of_phases == np);
welleq_coeff_bhp(np, pw - ctrl->target[ ctrl->current ], welleq_coeff_resv(np, h, ctrl, &res, &w2c, &w2w);
h, &res, &w2c, &w2w); break;
break;
case RESERVOIR_RATE: case SURFACE_RATE:
assert (W->number_of_phases == np); welleq_coeff_surfrate(i, np, h, ctrl, &res, &w2c, &w2w);
welleq_coeff_resv(np, h, ctrl, &res, &w2c, &w2w); break;
break; }
case SURFACE_RATE:
assert (0); /* Surface rate currently not supported */
break;
} }
/* Assemble completion contributions */ /* Assemble completion contributions */
@ -854,7 +908,7 @@ assemble_well_contrib(struct cfs_tpfa_res_wells *wells ,
struct cfs_tpfa_res_data *h ) struct cfs_tpfa_res_data *h )
{ {
int w, i, c, np, np2, nc; int w, i, c, np, np2, nc;
int is_neumann; int is_neumann, is_open;
double pw, dp; double pw, dp;
double *WI, *gpot, *pmobp; double *WI, *gpot, *pmobp;
const double *Ac, *dAc; const double *Ac, *dAc;
@ -876,6 +930,7 @@ assemble_well_contrib(struct cfs_tpfa_res_wells *wells ,
for (w = i = 0; w < W->number_of_wells; w++) { for (w = i = 0; w < W->number_of_wells; w++) {
pw = wpress[ w ]; pw = wpress[ w ];
is_open = W->ctrls[w]->current >= 0;
for (; i < W->well_connpos[w + 1]; for (; i < W->well_connpos[w + 1];
i++, gpot += np, pmobp += np) { i++, gpot += np, pmobp += np) {
@ -888,14 +943,16 @@ assemble_well_contrib(struct cfs_tpfa_res_wells *wells ,
init_completion_contrib(i, np, Ac, dAc, h->pimpl); init_completion_contrib(i, np, Ac, dAc, h->pimpl);
assemble_completion_to_cell(c, nc + w, np, dt, h); if (is_open) {
assemble_completion_to_cell(c, nc + w, np, dt, h);
}
/* Prepare for RESV controls */ /* Prepare for RESV controls */
compute_darcyflux_and_deriv(np, WI[i], dp, pmobp, gpot, compute_darcyflux_and_deriv(np, WI[i], dp, pmobp, gpot,
h->pimpl->flux_work, h->pimpl->flux_work,
h->pimpl->flux_work + np); h->pimpl->flux_work + np);
assemble_completion_to_well(w, c, nc, np, pw, dt, wells, h); assemble_completion_to_well(i, w, c, nc, np, pw, dt, wells, h);
} }
ctrl = W->ctrls[ w ]; ctrl = W->ctrls[ w ];
@ -1127,8 +1184,7 @@ cfs_tpfa_res_construct(struct UnstructuredGrid *G ,
nf = G->number_of_faces; nf = G->number_of_faces;
nwperf = 0; nwperf = 0;
if (wells != NULL) { if ((wells != NULL) && (wells->W != NULL)) {
assert (wells->W != NULL);
nwperf = wells->W->well_connpos[ wells->W->number_of_wells ]; nwperf = wells->W->well_connpos[ wells->W->number_of_wells ];
} }
@ -1156,7 +1212,7 @@ cfs_tpfa_res_construct(struct UnstructuredGrid *G ,
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
void int
cfs_tpfa_res_assemble(struct UnstructuredGrid *G , cfs_tpfa_res_assemble(struct UnstructuredGrid *G ,
double dt , double dt ,
struct cfs_tpfa_res_forces *forces , struct cfs_tpfa_res_forces *forces ,
@ -1170,7 +1226,7 @@ cfs_tpfa_res_assemble(struct UnstructuredGrid *G ,
struct cfs_tpfa_res_data *h ) struct cfs_tpfa_res_data *h )
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
{ {
int res_is_neumann, well_is_neumann, c, np2; int res_is_neumann, well_is_neumann, c, np2, singular;
csrmatrix_zero( h->J); csrmatrix_zero( h->J);
vector_zero (h->J->m, h->F); vector_zero (h->J->m, h->F);
@ -1194,7 +1250,9 @@ cfs_tpfa_res_assemble(struct UnstructuredGrid *G ,
assemble_cell_contrib(G, c, h); assemble_cell_contrib(G, c, h);
} }
if ((forces != NULL) && (forces->wells != NULL)) { if ((forces != NULL) &&
(forces->wells != NULL) &&
(forces->wells->W != NULL)) {
compute_well_compflux_and_deriv(forces->wells, cq->nphases, compute_well_compflux_and_deriv(forces->wells, cq->nphases,
cpress, wpress, h->pimpl); cpress, wpress, h->pimpl);
@ -1207,9 +1265,76 @@ cfs_tpfa_res_assemble(struct UnstructuredGrid *G ,
assemble_sources(dt, forces->src, h); assemble_sources(dt, forces->src, h);
} }
if (res_is_neumann && well_is_neumann && h->pimpl->is_incomp) { singular = res_is_neumann && well_is_neumann && h->pimpl->is_incomp;
h->J->sa[0] *= 2; if (singular) {
h->J->sa[0] *= 2.0;
} }
return singular;
}
/* ---------------------------------------------------------------------- */
int
cfs_tpfa_res_comprock_assemble(
struct UnstructuredGrid *G ,
double dt ,
struct cfs_tpfa_res_forces *forces ,
const double *zc ,
struct compr_quantities_gen *cq ,
const double *trans ,
const double *gravcap_f,
const double *cpress ,
const double *wpress ,
const double *porevol ,
const double *porevol0 ,
const double *rock_comp,
struct cfs_tpfa_res_data *h )
/* ---------------------------------------------------------------------- */
{
/* We want to add this term to the usual residual:
*
* (porevol(pressure)-porevol(initial_pressure))/dt.
*
* Its derivative (for the diagonal term of the Jacobian) is:
*
* porevol(pressure)*rock_comp(pressure)/dt
*/
int c, rock_is_incomp, singular;
size_t j;
double dpv;
/* Assemble usual system (without rock compressibility). */
singular = cfs_tpfa_res_assemble(G, dt, forces, zc, cq, trans, gravcap_f,
cpress, wpress, porevol0, h);
/* If we made a singularity-removing adjustment in the
regular assembly, we undo it here. */
if (singular) {
h->J->sa[0] /= 2.0;
}
/* Add new terms to residual and Jacobian. */
rock_is_incomp = 1;
for (c = 0; c < G->number_of_cells; c++) {
j = csrmatrix_elm_index(c, c, h->J);
dpv = (porevol[c] - porevol0[c]);
if (dpv != 0.0 || rock_comp[c] != 0.0) {
rock_is_incomp = 0;
}
h->J->sa[j] += porevol[c] * rock_comp[c];
h->F[c] += dpv;
}
/* Re-do the singularity-removing adjustment if necessary */
if (rock_is_incomp && singular) {
h->J->sa[0] *= 2.0;
}
return rock_is_incomp && singular;
} }
@ -1230,8 +1355,9 @@ cfs_tpfa_res_flux(struct UnstructuredGrid *G ,
{ {
compute_flux(G, np, trans, pmobf, gravcap_f, cpress, fflux); compute_flux(G, np, trans, pmobf, gravcap_f, cpress, fflux);
if ((forces != NULL) && (forces->wells != NULL) && if ((forces != NULL) &&
(wpress != NULL) && (wflux != NULL)) { (forces->wells != NULL) &&
(forces->wells->W != NULL) && (wpress != NULL) && (wflux != NULL)) {
compute_wflux(np, forces->wells, pmobc, cpress, wpress, wflux); compute_wflux(np, forces->wells, pmobc, cpress, wpress, wflux);
} }

View File

@ -59,7 +59,11 @@ cfs_tpfa_res_construct(struct UnstructuredGrid *G ,
void void
cfs_tpfa_res_destroy(struct cfs_tpfa_res_data *h); cfs_tpfa_res_destroy(struct cfs_tpfa_res_data *h);
void /* Return value is 1 if the assembled matrix was adjusted to remove a
singularity. This happens if all fluids are incompressible and
there are no pressure conditions on wells or boundaries.
Otherwise return 0. */
int
cfs_tpfa_res_assemble(struct UnstructuredGrid *G, cfs_tpfa_res_assemble(struct UnstructuredGrid *G,
double dt, double dt,
struct cfs_tpfa_res_forces *forces, struct cfs_tpfa_res_forces *forces,
@ -72,6 +76,27 @@ cfs_tpfa_res_assemble(struct UnstructuredGrid *G,
const double *porevol, const double *porevol,
struct cfs_tpfa_res_data *h); struct cfs_tpfa_res_data *h);
/* Return value is 1 if the assembled matrix was adjusted to remove a
singularity. This happens if all fluids are incompressible, the
rock is incompressible, and there are no pressure conditions on
wells or boundaries.
Otherwise return 0. */
int
cfs_tpfa_res_comprock_assemble(
struct UnstructuredGrid *G,
double dt,
struct cfs_tpfa_res_forces *forces,
const double *zc,
struct compr_quantities_gen *cq,
const double *trans,
const double *gravcap_f,
const double *cpress,
const double *wpress,
const double *porevol,
const double *porevol0,
const double *rock_comp,
struct cfs_tpfa_res_data *h);
void void
cfs_tpfa_res_flux(struct UnstructuredGrid *G , cfs_tpfa_res_flux(struct UnstructuredGrid *G ,
struct cfs_tpfa_res_forces *forces , struct cfs_tpfa_res_forces *forces ,

View File

@ -771,7 +771,7 @@ ifs_tpfa_assemble_comprock_increment(struct UnstructuredGrid *G ,
assemble_incompressible(G, F, trans, gpress, h, &system_singular, &ok); assemble_incompressible(G, F, trans, gpress, h, &system_singular, &ok);
/* We want to solve a Newton step for the residual /* We want to solve a Newton step for the residual
* (porevol(pressure)-porevol(initial_pressure))/dt + residual_for_imcompressible * (porevol(pressure)-porevol(initial_pressure))/dt + residual_for_incompressible
* *
*/ */

View File

@ -20,6 +20,16 @@
#ifndef OPM_IFS_TPFA_HEADER_INCLUDED #ifndef OPM_IFS_TPFA_HEADER_INCLUDED
#define OPM_IFS_TPFA_HEADER_INCLUDED #define OPM_IFS_TPFA_HEADER_INCLUDED
/**
* \file
* Interfaces and data structures to assemble a system of simultaneous linear
* equations discretising a flow problem that is either incompressible or
* features rock compressibility using the two-point flux approximation method.
*
* Includes support for reconstructing the Darcy flux field as well as well
* connection fluxes.
*/
#include <opm/core/grid.h> #include <opm/core/grid.h>
#ifdef __cplusplus #ifdef __cplusplus
@ -31,37 +41,66 @@ struct CSRMatrix;
struct FlowBoundaryConditions; struct FlowBoundaryConditions;
struct Wells; struct Wells;
/**
* Main data structure presenting a view of an assembled system of simultaneous
* linear equations which may be solved using external software.
*/
struct ifs_tpfa_data { struct ifs_tpfa_data {
struct CSRMatrix *A; struct CSRMatrix *A; /**< Coefficient matrix */
double *b; double *b; /**< Right-hand side */
double *x; double *x; /**< Solution */
struct ifs_tpfa_impl *pimpl; struct ifs_tpfa_impl *pimpl; /**< Internal management structure */
}; };
/**
* Solution variables.
*/
struct ifs_tpfa_solution { struct ifs_tpfa_solution {
double *cell_press; double *cell_press; /**< Cell pressures */
double *face_flux ; double *face_flux ; /**< Interface fluxes */
double *well_press; /* BHP */ double *well_press; /**< Bottom-hole pressures for each well */
double *well_flux ; /* Perforation (total) fluxes */ double *well_flux ; /**< Well connection total fluxes */
}; };
/**
* Driving forces pertaining to a particular model setup.
*/
struct ifs_tpfa_forces { struct ifs_tpfa_forces {
const double *src; const double *src; /**< Explicit source terms */
const struct FlowBoundaryConditions *bc ; const struct FlowBoundaryConditions *bc ; /**< Boundary conditions */
const struct Wells *W ; const struct Wells *W ; /**< Well topology */
const double *totmob; const double *totmob; /**< Total mobility in each cell */
const double *wdp ; const double *wdp ; /**< Gravity adjustment at each perforation */
}; };
/**
* Allocate TPFA management structure capable of assembling a system of
* simultaneous linear equations corresponding to a particular grid and well
* configuration.
*
* @param[in] G Grid.
* @param[in] W Well topology.
* @return Fully formed TPFA management structure if successful, @c NULL in case
* of allocation failure.
*/
struct ifs_tpfa_data * struct ifs_tpfa_data *
ifs_tpfa_construct(struct UnstructuredGrid *G, ifs_tpfa_construct(struct UnstructuredGrid *G,
struct Wells *W); struct Wells *W);
/**
*
* @param[in] G
* @param[in] F
* @param[in] trans
* @param[in] gpress
* @param[in,out] h
* @return
*/
int int
ifs_tpfa_assemble(struct UnstructuredGrid *G , ifs_tpfa_assemble(struct UnstructuredGrid *G ,
const struct ifs_tpfa_forces *F , const struct ifs_tpfa_forces *F ,

View File

@ -20,23 +20,88 @@
#ifndef OPM_TRANS_TPFA_HEADER_INCLUDED #ifndef OPM_TRANS_TPFA_HEADER_INCLUDED
#define OPM_TRANS_TPFA_HEADER_INCLUDED #define OPM_TRANS_TPFA_HEADER_INCLUDED
/**
* \file
* Routines to assist in the calculation of two-point transmissibilities.
*/
#include <opm/core/grid.h> #include <opm/core/grid.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/**
* Calculate static, one-sided transmissibilities for use in the two-point flux
* approximation method.
*
* The one-sided transmissibilities are defined by the formula
* \f[
* t_i = \frac{\vec{n}_f \mathsf{K}_c \vec{c}_c}{\lVert \vec{c}_c \rVert^2}
* \f]
* in which @c i is the half-face index corresponding to the cell-face index
* pair <CODE>(c,f)</CODE> and \f$\vec{c}_{cf} = \Bar{x}_f - \Bar{x}_c\f$ is the
* centroid difference vector.
*
* @param[in] G Grid.
* @param[in] perm Permeability. One symmetric, positive definite tensor
* per grid cell.
* @param[out] htrans One-sided transmissibilities. Array of size at least
* <CODE>G->cell_facepos[ G->number_of_cells ]</CODE>.
*/
void void
tpfa_htrans_compute(struct UnstructuredGrid *G, const double *perm, double *htrans); tpfa_htrans_compute(struct UnstructuredGrid *G ,
const double *perm ,
double *htrans);
/**
* Compute two-point transmissibilities from one-sided transmissibilities.
*
* The two-point transmissibilities are given by the simple, near-harmonic
* average (save a factor of two)
* \f[
* \mathsf{T}_f = \big(\frac{1}{t_1} + \frac{1}{t_2}\big)^{-1}
* = \frac{t_1t_2}{t_1 + t_2}
* \f]
* in which \f$t_1\f$ and \f$t_2\f$ are the one-sided transmissibilities that
* connect the neighbouring cells of face @c f.
*
* @param[in] G Grid.
* @param[in] htrans One-sided transmissibilities as defined by function
* tpfa_htrans_compute().
* @param[out] trans Interface, two-point transmissibilities. Array of size
* at least <CODE>G->number_of_faces</CODE>.
*/
void void
tpfa_trans_compute(struct UnstructuredGrid *G, const double *htrans, double *trans); tpfa_trans_compute(struct UnstructuredGrid *G ,
const double *htrans,
double *trans );
/**
* Calculate effective two-point transmissibilities from one-sided, total
* mobility weighted, transmissibilities.
*
* Specifically, compute the following product
* \f[
* \mathsf{T}_f = \big(\frac{1}{\lambda_1t_1} + \frac{1}{\lambda_2t_2}\big)^{-1}
* = \lambda_1\lambda_2 \frac{t_1t_2}{t_1 + t_2}
* \f]
* in which \f$t_1\f$ and \f$t_2\f$ are the one-sided, static transmissibility
* values connecting the cells of face @c f and \f$\lambda_1\f$ and
* \f$\lambda_2\f$ denote the total mobilities of the respective cells.
*
* @param[in] G Grid.
* @param[in] totmob Total mobilities. One positive scalar value for each cell.
* @param[in] htrans One-sided transmissibilities as defined by function
* tpfa_htrans_compute().
* @param[out] trans Effective, two-point transmissibilities. Array of size at
* least <CODE>G->number_of_faces</CODE>.
*/
void void
tpfa_eff_trans_compute(struct UnstructuredGrid *G, tpfa_eff_trans_compute(struct UnstructuredGrid *G ,
const double *totmob, const double *totmob,
const double *htrans, const double *htrans,
double *trans); double *trans );
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -21,11 +21,11 @@
#include "config.h" #include "config.h"
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
#include <opm/core/simulator/SimulatorTwophase.hpp> #include <opm/core/simulator/SimulatorCompressibleTwophase.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp> #include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/utility/ErrorMacros.hpp> #include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/pressure/IncompTpfa.hpp> #include <opm/core/pressure/CompressibleTpfa.hpp>
#include <opm/core/grid.h> #include <opm/core/grid.h>
#include <opm/core/newwells.h> #include <opm/core/newwells.h>
@ -36,16 +36,19 @@
#include <opm/core/utility/StopWatch.hpp> #include <opm/core/utility/StopWatch.hpp>
#include <opm/core/utility/writeVtkData.hpp> #include <opm/core/utility/writeVtkData.hpp>
#include <opm/core/utility/miscUtilities.hpp> #include <opm/core/utility/miscUtilities.hpp>
#include <opm/core/utility/miscUtilitiesBlackoil.hpp>
#include <opm/core/fluid/IncompPropertiesInterface.hpp> #include <opm/core/wells/WellsManager.hpp>
#include <opm/core/fluid/BlackoilPropertiesInterface.hpp>
#include <opm/core/fluid/RockCompressibility.hpp> #include <opm/core/fluid/RockCompressibility.hpp>
#include <opm/core/utility/ColumnExtract.hpp> #include <opm/core/utility/ColumnExtract.hpp>
#include <opm/core/simulator/TwophaseState.hpp> #include <opm/core/simulator/BlackoilState.hpp>
#include <opm/core/simulator/WellState.hpp> #include <opm/core/simulator/WellState.hpp>
#include <opm/core/transport/reorder/TransportModelTwophase.hpp> #include <opm/core/transport/reorder/TransportModelCompressibleTwophase.hpp>
#include <boost/filesystem/convenience.hpp> #include <boost/filesystem.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@ -56,21 +59,21 @@
namespace Opm namespace Opm
{ {
class SimulatorTwophase::Impl class SimulatorCompressibleTwophase::Impl
{ {
public: public:
Impl(const parameter::ParameterGroup& param, Impl(const parameter::ParameterGroup& param,
const UnstructuredGrid& grid, const UnstructuredGrid& grid,
const IncompPropertiesInterface& props, const BlackoilPropertiesInterface& props,
const RockCompressibility* rock_comp, const RockCompressibility* rock_comp,
const Wells* wells, WellsManager& wells_manager,
const std::vector<double>& src, const std::vector<double>& src,
const FlowBoundaryConditions* bcs, const FlowBoundaryConditions* bcs,
LinearSolverInterface& linsolver, LinearSolverInterface& linsolver,
const double* gravity); const double* gravity);
SimulatorReport run(SimulatorTimer& timer, SimulatorReport run(SimulatorTimer& timer,
TwophaseState& state, BlackoilState& state,
WellState& well_state); WellState& well_state);
private: private:
@ -78,23 +81,27 @@ namespace Opm
// Parameters for output. // Parameters for output.
bool output_; bool output_;
bool output_vtk_;
std::string output_dir_; std::string output_dir_;
int output_interval_; int output_interval_;
// Parameters for well control
bool check_well_controls_;
int max_well_control_iterations_;
// Parameters for transport solver. // Parameters for transport solver.
int num_transport_substeps_; int num_transport_substeps_;
bool use_segregation_split_; bool use_segregation_split_;
// Observed objects. // Observed objects.
const UnstructuredGrid& grid_; const UnstructuredGrid& grid_;
const IncompPropertiesInterface& props_; const BlackoilPropertiesInterface& props_;
const RockCompressibility* rock_comp_; const RockCompressibility* rock_comp_;
WellsManager& wells_manager_;
const Wells* wells_; const Wells* wells_;
const std::vector<double>& src_; const std::vector<double>& src_;
const FlowBoundaryConditions* bcs_; const FlowBoundaryConditions* bcs_;
const LinearSolverInterface& linsolver_;
const double* gravity_; const double* gravity_;
// Solvers // Solvers
IncompTpfa psolver_; CompressibleTpfa psolver_;
TransportModelTwophase tsolver_; TransportModelCompressibleTwophase tsolver_;
// Needed by column-based gravity segregation solver. // Needed by column-based gravity segregation solver.
std::vector< std::vector<int> > columns_; std::vector< std::vector<int> > columns_;
// Misc. data // Misc. data
@ -104,40 +111,48 @@ namespace Opm
SimulatorTwophase::SimulatorTwophase(const parameter::ParameterGroup& param, SimulatorCompressibleTwophase::SimulatorCompressibleTwophase(const parameter::ParameterGroup& param,
const UnstructuredGrid& grid, const UnstructuredGrid& grid,
const IncompPropertiesInterface& props, const BlackoilPropertiesInterface& props,
const RockCompressibility* rock_comp, const RockCompressibility* rock_comp,
const Wells* wells, WellsManager& wells_manager,
const std::vector<double>& src, const std::vector<double>& src,
const FlowBoundaryConditions* bcs, const FlowBoundaryConditions* bcs,
LinearSolverInterface& linsolver, LinearSolverInterface& linsolver,
const double* gravity) const double* gravity)
{ {
pimpl_.reset(new Impl(param, grid, props, rock_comp, wells, src, bcs, linsolver, gravity)); pimpl_.reset(new Impl(param, grid, props, rock_comp, wells_manager, src, bcs, linsolver, gravity));
} }
SimulatorReport SimulatorTwophase::run(SimulatorTimer& timer, SimulatorReport SimulatorCompressibleTwophase::run(SimulatorTimer& timer,
TwophaseState& state, BlackoilState& state,
WellState& well_state) WellState& well_state)
{ {
return pimpl_->run(timer, state, well_state); return pimpl_->run(timer, state, well_state);
} }
static void outputState(const UnstructuredGrid& grid, static void outputStateVtk(const UnstructuredGrid& grid,
const Opm::TwophaseState& state, const Opm::BlackoilState& state,
const int step, const int step,
const std::string& output_dir) const std::string& output_dir)
{ {
// Write data in VTK format. // Write data in VTK format.
std::ostringstream vtkfilename; std::ostringstream vtkfilename;
vtkfilename << output_dir << "/output-" << std::setw(3) << std::setfill('0') << step << ".vtu"; vtkfilename << output_dir << "/vtk_files";
boost::filesystem::path fpath(vtkfilename.str());
try {
create_directories(fpath);
}
catch (...) {
THROW("Creating directories failed: " << fpath);
}
vtkfilename << "/output-" << std::setw(3) << std::setfill('0') << step << ".vtu";
std::ofstream vtkfile(vtkfilename.str().c_str()); std::ofstream vtkfile(vtkfilename.str().c_str());
if (!vtkfile) { if (!vtkfile) {
THROW("Failed to open " << vtkfilename.str()); THROW("Failed to open " << vtkfilename.str());
@ -149,11 +164,34 @@ namespace Opm
Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity); Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity);
dm["velocity"] = &cell_velocity; dm["velocity"] = &cell_velocity;
Opm::writeVtkData(grid, dm, vtkfile); Opm::writeVtkData(grid, dm, vtkfile);
}
static void outputStateMatlab(const UnstructuredGrid& grid,
const Opm::BlackoilState& state,
const int step,
const std::string& output_dir)
{
Opm::DataMap dm;
dm["saturation"] = &state.saturation();
dm["pressure"] = &state.pressure();
dm["surfvolume"] = &state.surfacevol();
std::vector<double> cell_velocity;
Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity);
dm["velocity"] = &cell_velocity;
// Write data (not grid) in Matlab format // Write data (not grid) in Matlab format
for (Opm::DataMap::const_iterator it = dm.begin(); it != dm.end(); ++it) { for (Opm::DataMap::const_iterator it = dm.begin(); it != dm.end(); ++it) {
std::ostringstream fname; std::ostringstream fname;
fname << output_dir << "/" << it->first << "-" << std::setw(3) << std::setfill('0') << step << ".dat"; fname << output_dir << "/" << it->first;
boost::filesystem::path fpath = fname.str();
try {
create_directories(fpath);
}
catch (...) {
THROW("Creating directories failed: " << fpath);
}
fname << "/" << std::setw(3) << std::setfill('0') << step << ".txt";
std::ofstream file(fname.str().c_str()); std::ofstream file(fname.str().c_str());
if (!file) { if (!file) {
THROW("Failed to open " << fname.str()); THROW("Failed to open " << fname.str());
@ -191,30 +229,29 @@ namespace Opm
// \TODO: make CompressibleTpfa take src and bcs.
SimulatorCompressibleTwophase::Impl::Impl(const parameter::ParameterGroup& param,
SimulatorTwophase::Impl::Impl(const parameter::ParameterGroup& param, const UnstructuredGrid& grid,
const UnstructuredGrid& grid, const BlackoilPropertiesInterface& props,
const IncompPropertiesInterface& props, const RockCompressibility* rock_comp,
const RockCompressibility* rock_comp, WellsManager& wells_manager,
const Wells* wells, const std::vector<double>& src,
const std::vector<double>& src, const FlowBoundaryConditions* bcs,
const FlowBoundaryConditions* bcs, LinearSolverInterface& linsolver,
LinearSolverInterface& linsolver, const double* gravity)
const double* gravity)
: grid_(grid), : grid_(grid),
props_(props), props_(props),
rock_comp_(rock_comp), rock_comp_(rock_comp),
wells_(wells), wells_manager_(wells_manager),
wells_(wells_manager.c_wells()),
src_(src), src_(src),
bcs_(bcs), bcs_(bcs),
linsolver_(linsolver),
gravity_(gravity), gravity_(gravity),
psolver_(grid, props, rock_comp, linsolver, psolver_(grid, props, rock_comp, linsolver,
param.getDefault("nl_pressure_residual_tolerance", 0.0), param.getDefault("nl_pressure_residual_tolerance", 0.0),
param.getDefault("nl_pressure_change_tolerance", 1.0), param.getDefault("nl_pressure_change_tolerance", 1.0),
param.getDefault("nl_pressure_maxiter", 10), param.getDefault("nl_pressure_maxiter", 10),
gravity, wells, src, bcs), gravity, wells_manager.c_wells() /*, src, bcs*/),
tsolver_(grid, props, tsolver_(grid, props,
param.getDefault("nl_tolerance", 1e-9), param.getDefault("nl_tolerance", 1e-9),
param.getDefault("nl_maxiter", 30)) param.getDefault("nl_maxiter", 30))
@ -222,6 +259,7 @@ namespace Opm
// For output. // For output.
output_ = param.getDefault("output", true); output_ = param.getDefault("output", true);
if (output_) { if (output_) {
output_vtk_ = param.getDefault("output_vtk", true);
output_dir_ = param.getDefault("output_dir", std::string("output")); output_dir_ = param.getDefault("output_dir", std::string("output"));
// Ensure that output dir exists // Ensure that output dir exists
boost::filesystem::path fpath(output_dir_); boost::filesystem::path fpath(output_dir_);
@ -234,6 +272,10 @@ namespace Opm
output_interval_ = param.getDefault("output_interval", 1); output_interval_ = param.getDefault("output_interval", 1);
} }
// Well control related init.
check_well_controls_ = param.getDefault("check_well_controls", false);
max_well_control_iterations_ = param.getDefault("max_well_control_iterations", 10);
// Transport related init. // Transport related init.
num_transport_substeps_ = param.getDefault("num_transport_substeps", 1); num_transport_substeps_ = param.getDefault("num_transport_substeps", 1);
use_segregation_split_ = param.getDefault("use_segregation_split", false); use_segregation_split_ = param.getDefault("use_segregation_split", false);
@ -253,9 +295,9 @@ namespace Opm
SimulatorReport SimulatorTwophase::Impl::run(SimulatorTimer& timer, SimulatorReport SimulatorCompressibleTwophase::Impl::run(SimulatorTimer& timer,
TwophaseState& state, BlackoilState& state,
WellState& well_state) WellState& well_state)
{ {
std::vector<double> transport_src; std::vector<double> transport_src;
@ -267,13 +309,14 @@ namespace Opm
computePorevolume(grid_, props_.porosity(), porevol); computePorevolume(grid_, props_.porosity(), porevol);
} }
const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0); const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
std::vector<double> initial_porevol = porevol;
// Main simulation loop. // Main simulation loop.
Opm::time::StopWatch pressure_timer; Opm::time::StopWatch pressure_timer;
double ptime = 0.0; double ptime = 0.0;
Opm::time::StopWatch transport_timer; Opm::time::StopWatch transport_timer;
double ttime = 0.0; double ttime = 0.0;
Opm::time::StopWatch step_timer;
Opm::time::StopWatch total_timer; Opm::time::StopWatch total_timer;
total_timer.start(); total_timer.start();
double init_satvol[2] = { 0.0 }; double init_satvol[2] = { 0.0 };
@ -292,27 +335,102 @@ namespace Opm
std::vector<double> well_resflows_phase; std::vector<double> well_resflows_phase;
if (wells_) { if (wells_) {
well_resflows_phase.resize((wells_->number_of_phases)*(wells_->number_of_wells), 0.0); well_resflows_phase.resize((wells_->number_of_phases)*(wells_->number_of_wells), 0.0);
wellreport.push(props_, *wells_, state.saturation(), 0.0, well_state.bhp(), well_state.perfRates()); wellreport.push(props_, *wells_,
state.pressure(), state.surfacevol(), state.saturation(),
0.0, well_state.bhp(), well_state.perfRates());
}
std::fstream tstep_os;
if (output_) {
std::string filename = output_dir_ + "/step_timing.param";
tstep_os.open(filename.c_str(), std::fstream::out | std::fstream::app);
} }
for (; !timer.done(); ++timer) { for (; !timer.done(); ++timer) {
// Report timestep and (optionally) write state to disk. // Report timestep and (optionally) write state to disk.
step_timer.start();
timer.report(std::cout); timer.report(std::cout);
if (output_ && (timer.currentStepNum() % output_interval_ == 0)) { if (output_ && (timer.currentStepNum() % output_interval_ == 0)) {
outputState(grid_, state, timer.currentStepNum(), output_dir_); if (output_vtk_) {
outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
}
outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
} }
// Solve pressure. SimulatorReport sreport;
// Solve pressure equation.
if (check_well_controls_) {
computeFractionalFlow(props_, allcells_,
state.pressure(), state.surfacevol(), state.saturation(),
fractional_flows);
wells_manager_.applyExplicitReinjectionControls(well_resflows_phase, well_resflows_phase);
}
bool well_control_passed = !check_well_controls_;
int well_control_iteration = 0;
do { do {
// Run solver.
pressure_timer.start(); pressure_timer.start();
std::vector<double> initial_pressure = state.pressure();
psolver_.solve(timer.currentStepLength(), state, well_state); psolver_.solve(timer.currentStepLength(), state, well_state);
// Renormalize pressure if both fluids and rock are
// incompressible, and there are no pressure
// conditions (bcs or wells). It is deemed sufficient
// for now to renormalize using geometric volume
// instead of pore volume.
if (psolver_.singularPressure()) {
// Compute average pressures of previous and last
// step, and total volume.
double av_prev_press = 0.0;
double av_press = 0.0;
double tot_vol = 0.0;
const int num_cells = grid_.number_of_cells;
for (int cell = 0; cell < num_cells; ++cell) {
av_prev_press += initial_pressure[cell]*grid_.cell_volumes[cell];
av_press += state.pressure()[cell]*grid_.cell_volumes[cell];
tot_vol += grid_.cell_volumes[cell];
}
// Renormalization constant
const double ren_const = (av_prev_press - av_press)/tot_vol;
for (int cell = 0; cell < num_cells; ++cell) {
state.pressure()[cell] += ren_const;
}
const int num_wells = (wells_ == NULL) ? 0 : wells_->number_of_wells;
for (int well = 0; well < num_wells; ++well) {
well_state.bhp()[well] += ren_const;
}
}
// Stop timer and report.
pressure_timer.stop(); pressure_timer.stop();
double pt = pressure_timer.secsSinceStart(); double pt = pressure_timer.secsSinceStart();
std::cout << "Pressure solver took: " << pt << " seconds." << std::endl; std::cout << "Pressure solver took: " << pt << " seconds." << std::endl;
ptime += pt; ptime += pt;
} while (false); sreport.pressure_time = pt;
// Optionally, check if well controls are satisfied.
if (check_well_controls_) {
Opm::computePhaseFlowRatesPerWell(*wells_,
fractional_flows,
well_state.perfRates(),
well_resflows_phase);
std::cout << "Checking well conditions." << std::endl;
// For testing we set surface := reservoir
well_control_passed = wells_manager_.conditionsMet(well_state.bhp(), well_resflows_phase, well_resflows_phase);
++well_control_iteration;
if (!well_control_passed && well_control_iteration > max_well_control_iterations_) {
THROW("Could not satisfy well conditions in " << max_well_control_iterations_ << " tries.");
}
if (!well_control_passed) {
std::cout << "Well controls not passed, solving again." << std::endl;
} else {
std::cout << "Well conditions met." << std::endl;
}
}
} while (!well_control_passed);
// Update pore volumes if rock is compressible. // Update pore volumes if rock is compressible.
if (rock_comp_ && rock_comp_->isActive()) { if (rock_comp_ && rock_comp_->isActive()) {
initial_porevol = porevol;
computePorevolume(grid_, props_.porosity(), *rock_comp_, state.pressure(), porevol); computePorevolume(grid_, props_.porosity(), *rock_comp_, state.pressure(), porevol);
} }
@ -328,18 +446,21 @@ namespace Opm
std::cout << "Making " << num_transport_substeps_ << " transport substeps." << std::endl; std::cout << "Making " << num_transport_substeps_ << " transport substeps." << std::endl;
} }
for (int tr_substep = 0; tr_substep < num_transport_substeps_; ++tr_substep) { for (int tr_substep = 0; tr_substep < num_transport_substeps_; ++tr_substep) {
tsolver_.solve(&state.faceflux()[0], &porevol[0], &transport_src[0], tsolver_.solve(&state.faceflux()[0], &state.pressure()[0],
stepsize, state.saturation()); &initial_porevol[0], &porevol[0], &transport_src[0], stepsize,
Opm::computeInjectedProduced(props_, state.saturation(), transport_src, stepsize, injected, produced); state.saturation(), state.surfacevol());
if (use_segregation_split_) { Opm::computeInjectedProduced(props_,
tsolver_.solveGravity(columns_, &porevol[0], stepsize, state.saturation()); state.pressure(), state.surfacevol(), state.saturation(),
transport_src, stepsize, injected, produced);
if (gravity_ != 0 && use_segregation_split_) {
tsolver_.solveGravity(columns_, stepsize, state.saturation(), state.surfacevol());
} }
} }
transport_timer.stop(); transport_timer.stop();
double tt = transport_timer.secsSinceStart(); double tt = transport_timer.secsSinceStart();
sreport.transport_time = tt;
std::cout << "Transport solver took: " << tt << " seconds." << std::endl; std::cout << "Transport solver took: " << tt << " seconds." << std::endl;
ttime += tt; ttime += tt;
// Report volume balances. // Report volume balances.
Opm::computeSaturatedVol(porevol, state.saturation(), satvol); Opm::computeSaturatedVol(porevol, state.saturation(), satvol);
tot_injected[0] += injected[0]; tot_injected[0] += injected[0];
@ -377,18 +498,27 @@ namespace Opm
produced[0]/(produced[0] + produced[1]), produced[0]/(produced[0] + produced[1]),
tot_produced[0]/tot_porevol_init); tot_produced[0]/tot_porevol_init);
if (wells_) { if (wells_) {
wellreport.push(props_, *wells_, state.saturation(), wellreport.push(props_, *wells_,
state.pressure(), state.surfacevol(), state.saturation(),
timer.currentTime() + timer.currentStepLength(), timer.currentTime() + timer.currentStepLength(),
well_state.bhp(), well_state.perfRates()); well_state.bhp(), well_state.perfRates());
} }
sreport.total_time = step_timer.secsSinceStart();
if (output_) {
sreport.reportParam(tstep_os);
}
} }
if (output_) { if (output_) {
outputState(grid_, state, timer.currentStepNum(), output_dir_); if (output_vtk_) {
outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
}
outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
outputWaterCut(watercut, output_dir_); outputWaterCut(watercut, output_dir_);
if (wells_) { if (wells_) {
outputWellReport(wellreport, output_dir_); outputWellReport(wellreport, output_dir_);
} }
tstep_os.close();
} }
total_timer.stop(); total_timer.stop();

View File

@ -0,0 +1,99 @@
/*
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_SIMULATORCOMPRESSIBLETWOPHASE_HEADER_INCLUDED
#define OPM_SIMULATORCOMPRESSIBLETWOPHASE_HEADER_INCLUDED
#include <boost/shared_ptr.hpp>
#include <vector>
struct UnstructuredGrid;
struct Wells;
struct FlowBoundaryConditions;
namespace Opm
{
namespace parameter { class ParameterGroup; }
class BlackoilPropertiesInterface;
class RockCompressibility;
class WellsManager;
class LinearSolverInterface;
class SimulatorTimer;
class BlackoilState;
class WellState;
struct SimulatorReport;
/// Class collecting all necessary components for a two-phase simulation.
class SimulatorCompressibleTwophase
{
public:
/// Initialise from parameters and objects to observe.
/// \param[in] param parameters, this class accepts the following:
/// parameter (default) effect
/// -----------------------------------------------------------
/// output (true) write output to files?
/// output_dir ("output") output directoty
/// output_interval (1) output every nth step
/// nl_pressure_residual_tolerance (0.0) pressure solver residual tolerance (in Pascal)
/// nl_pressure_change_tolerance (1.0) pressure solver change tolerance (in Pascal)
/// nl_pressure_maxiter (10) max nonlinear iterations in pressure
/// nl_maxiter (30) max nonlinear iterations in transport
/// nl_tolerance (1e-9) transport solver absolute residual tolerance
/// num_transport_substeps (1) number of transport steps per pressure step
/// use_segregation_split (false) solve for gravity segregation (if false,
/// segregation is ignored).
///
/// \param[in] grid grid data structure
/// \param[in] props fluid and rock properties
/// \param[in] rock_comp if non-null, rock compressibility properties
/// \param[in] well_manager well manager, may manage no (null) wells
/// \param[in] src source terms
/// \param[in] bcs boundary conditions, treat as all noflow if null
/// \param[in] linsolver linear solver
/// \param[in] gravity if non-null, gravity vector
SimulatorCompressibleTwophase(const parameter::ParameterGroup& param,
const UnstructuredGrid& grid,
const BlackoilPropertiesInterface& props,
const RockCompressibility* rock_comp,
WellsManager& wells_manager,
const std::vector<double>& src,
const FlowBoundaryConditions* bcs,
LinearSolverInterface& linsolver,
const double* gravity);
/// Run the simulation.
/// This will run succesive timesteps until timer.done() is true. It will
/// modify the reservoir and well states.
/// \param[in,out] timer governs the requested reporting timesteps
/// \param[in,out] state state of reservoir: pressure, fluxes
/// \param[in,out] well_state state of wells: bhp, perforation rates
/// \return simulation report, with timing data
SimulatorReport run(SimulatorTimer& timer,
BlackoilState& state,
WellState& well_state);
private:
class Impl;
// Using shared_ptr instead of scoped_ptr since scoped_ptr requires complete type for Impl.
boost::shared_ptr<Impl> pimpl_;
};
} // namespace Opm
#endif // OPM_SIMULATORCOMPRESSIBLETWOPHASE_HEADER_INCLUDED

View File

@ -0,0 +1,586 @@
/*
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/simulator/SimulatorIncompTwophase.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/pressure/IncompTpfa.hpp>
#include <opm/core/grid.h>
#include <opm/core/newwells.h>
#include <opm/core/pressure/flow_bc.h>
#include <opm/core/simulator/SimulatorReport.hpp>
#include <opm/core/simulator/SimulatorTimer.hpp>
#include <opm/core/utility/StopWatch.hpp>
#include <opm/core/utility/writeVtkData.hpp>
#include <opm/core/utility/miscUtilities.hpp>
#include <opm/core/wells/WellsManager.hpp>
#include <opm/core/fluid/IncompPropertiesInterface.hpp>
#include <opm/core/fluid/RockCompressibility.hpp>
#include <opm/core/utility/ColumnExtract.hpp>
#include <opm/core/simulator/TwophaseState.hpp>
#include <opm/core/simulator/WellState.hpp>
#include <opm/core/transport/reorder/TransportModelTwophase.hpp>
#include <boost/filesystem.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <numeric>
#include <fstream>
namespace Opm
{
class SimulatorIncompTwophase::Impl
{
public:
Impl(const parameter::ParameterGroup& param,
const UnstructuredGrid& grid,
const IncompPropertiesInterface& props,
const RockCompressibility* rock_comp,
WellsManager& wells_manager,
const std::vector<double>& src,
const FlowBoundaryConditions* bcs,
LinearSolverInterface& linsolver,
const double* gravity);
SimulatorReport run(SimulatorTimer& timer,
TwophaseState& state,
WellState& well_state);
private:
// Data.
// Parameters for output.
bool output_;
bool output_vtk_;
std::string output_dir_;
int output_interval_;
// Parameters for well control
bool check_well_controls_;
int max_well_control_iterations_;
// Parameters for transport solver.
int num_transport_substeps_;
bool use_segregation_split_;
// Observed objects.
const UnstructuredGrid& grid_;
const IncompPropertiesInterface& props_;
const RockCompressibility* rock_comp_;
WellsManager& wells_manager_;
const Wells* wells_;
const std::vector<double>& src_;
const FlowBoundaryConditions* bcs_;
// Solvers
IncompTpfa psolver_;
TransportModelTwophase tsolver_;
// Needed by column-based gravity segregation solver.
std::vector< std::vector<int> > columns_;
// Misc. data
std::vector<int> allcells_;
};
SimulatorIncompTwophase::SimulatorIncompTwophase(const parameter::ParameterGroup& param,
const UnstructuredGrid& grid,
const IncompPropertiesInterface& props,
const RockCompressibility* rock_comp,
WellsManager& wells_manager,
const std::vector<double>& src,
const FlowBoundaryConditions* bcs,
LinearSolverInterface& linsolver,
const double* gravity)
{
pimpl_.reset(new Impl(param, grid, props, rock_comp, wells_manager, src, bcs, linsolver, gravity));
}
SimulatorReport SimulatorIncompTwophase::run(SimulatorTimer& timer,
TwophaseState& state,
WellState& well_state)
{
return pimpl_->run(timer, state, well_state);
}
static void reportVolumes(std::ostream &os, double satvol[2], double tot_porevol_init,
double tot_injected[2], double tot_produced[2],
double injected[2], double produced[2],
double init_satvol[2])
{
std::cout.precision(5);
const int width = 18;
os << "\nVolume balance report (all numbers relative to total pore volume).\n";
os << " Saturated volumes: "
<< std::setw(width) << satvol[0]/tot_porevol_init
<< std::setw(width) << satvol[1]/tot_porevol_init << std::endl;
os << " Injected volumes: "
<< std::setw(width) << injected[0]/tot_porevol_init
<< std::setw(width) << injected[1]/tot_porevol_init << std::endl;
os << " Produced volumes: "
<< std::setw(width) << produced[0]/tot_porevol_init
<< std::setw(width) << produced[1]/tot_porevol_init << std::endl;
os << " Total inj volumes: "
<< std::setw(width) << tot_injected[0]/tot_porevol_init
<< std::setw(width) << tot_injected[1]/tot_porevol_init << std::endl;
os << " Total prod volumes: "
<< std::setw(width) << tot_produced[0]/tot_porevol_init
<< std::setw(width) << tot_produced[1]/tot_porevol_init << std::endl;
os << " In-place + prod - inj: "
<< std::setw(width) << (satvol[0] + tot_produced[0] - tot_injected[0])/tot_porevol_init
<< std::setw(width) << (satvol[1] + tot_produced[1] - tot_injected[1])/tot_porevol_init << std::endl;
os << " Init - now - pr + inj: "
<< std::setw(width) << (init_satvol[0] - satvol[0] - tot_produced[0] + tot_injected[0])/tot_porevol_init
<< std::setw(width) << (init_satvol[1] - satvol[1] - tot_produced[1] + tot_injected[1])/tot_porevol_init
<< std::endl;
os.precision(8);
}
static void outputStateVtk(const UnstructuredGrid& grid,
const Opm::TwophaseState& state,
const int step,
const std::string& output_dir)
{
// Write data in VTK format.
std::ostringstream vtkfilename;
vtkfilename << output_dir << "/vtk_files";
boost::filesystem::path fpath(vtkfilename.str());
try {
create_directories(fpath);
}
catch (...) {
THROW("Creating directories failed: " << fpath);
}
vtkfilename << "/output-" << std::setw(3) << std::setfill('0') << step << ".vtu";
std::ofstream vtkfile(vtkfilename.str().c_str());
if (!vtkfile) {
THROW("Failed to open " << vtkfilename.str());
}
Opm::DataMap dm;
dm["saturation"] = &state.saturation();
dm["pressure"] = &state.pressure();
std::vector<double> cell_velocity;
Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity);
dm["velocity"] = &cell_velocity;
Opm::writeVtkData(grid, dm, vtkfile);
}
static void outputVectorMatlab(const std::string& name,
const std::vector<int>& vec,
const int step,
const std::string& output_dir)
{
std::ostringstream fname;
fname << output_dir << "/" << name;
boost::filesystem::path fpath = fname.str();
try {
create_directories(fpath);
}
catch (...) {
THROW("Creating directories failed: " << fpath);
}
fname << "/" << std::setw(3) << std::setfill('0') << step << ".txt";
std::ofstream file(fname.str().c_str());
if (!file) {
THROW("Failed to open " << fname.str());
}
std::copy(vec.begin(), vec.end(), std::ostream_iterator<double>(file, "\n"));
}
static void outputStateMatlab(const UnstructuredGrid& grid,
const Opm::TwophaseState& state,
const int step,
const std::string& output_dir)
{
Opm::DataMap dm;
dm["saturation"] = &state.saturation();
dm["pressure"] = &state.pressure();
std::vector<double> cell_velocity;
Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity);
dm["velocity"] = &cell_velocity;
// Write data (not grid) in Matlab format
for (Opm::DataMap::const_iterator it = dm.begin(); it != dm.end(); ++it) {
std::ostringstream fname;
fname << output_dir << "/" << it->first;
boost::filesystem::path fpath = fname.str();
try {
create_directories(fpath);
}
catch (...) {
THROW("Creating directories failed: " << fpath);
}
fname << "/" << std::setw(3) << std::setfill('0') << step << ".txt";
std::ofstream file(fname.str().c_str());
if (!file) {
THROW("Failed to open " << fname.str());
}
const std::vector<double>& d = *(it->second);
std::copy(d.begin(), d.end(), std::ostream_iterator<double>(file, "\n"));
}
}
static void outputWaterCut(const Opm::Watercut& watercut,
const std::string& output_dir)
{
// Write water cut curve.
std::string fname = output_dir + "/watercut.txt";
std::ofstream os(fname.c_str());
if (!os) {
THROW("Failed to open " << fname);
}
watercut.write(os);
}
static void outputWellReport(const Opm::WellReport& wellreport,
const std::string& output_dir)
{
// Write well report.
std::string fname = output_dir + "/wellreport.txt";
std::ofstream os(fname.c_str());
if (!os) {
THROW("Failed to open " << fname);
}
wellreport.write(os);
}
static bool allNeumannBCs(const FlowBoundaryConditions* bcs)
{
if (bcs == NULL) {
return true;
} else {
return std::find(bcs->type, bcs->type + bcs->nbc, BC_PRESSURE)
== bcs->type + bcs->nbc;
}
}
static bool allRateWells(const Wells* wells)
{
if (wells == NULL) {
return true;
}
const int nw = wells->number_of_wells;
for (int w = 0; w < nw; ++w) {
const WellControls* wc = wells->ctrls[w];
if (wc->current >= 0) {
if (wc->type[wc->current] == BHP) {
return false;
}
}
}
return true;
}
SimulatorIncompTwophase::Impl::Impl(const parameter::ParameterGroup& param,
const UnstructuredGrid& grid,
const IncompPropertiesInterface& props,
const RockCompressibility* rock_comp,
WellsManager& wells_manager,
const std::vector<double>& src,
const FlowBoundaryConditions* bcs,
LinearSolverInterface& linsolver,
const double* gravity)
: grid_(grid),
props_(props),
rock_comp_(rock_comp),
wells_manager_(wells_manager),
wells_(wells_manager.c_wells()),
src_(src),
bcs_(bcs),
psolver_(grid, props, rock_comp, linsolver,
param.getDefault("nl_pressure_residual_tolerance", 0.0),
param.getDefault("nl_pressure_change_tolerance", 1.0),
param.getDefault("nl_pressure_maxiter", 10),
gravity, wells_manager.c_wells(), src, bcs),
tsolver_(grid, props,
param.getDefault("nl_tolerance", 1e-9),
param.getDefault("nl_maxiter", 30))
{
// For output.
output_ = param.getDefault("output", true);
if (output_) {
output_vtk_ = param.getDefault("output_vtk", true);
output_dir_ = param.getDefault("output_dir", std::string("output"));
// Ensure that output dir exists
boost::filesystem::path fpath(output_dir_);
try {
create_directories(fpath);
}
catch (...) {
THROW("Creating directories failed: " << fpath);
}
output_interval_ = param.getDefault("output_interval", 1);
}
// Well control related init.
check_well_controls_ = param.getDefault("check_well_controls", false);
max_well_control_iterations_ = param.getDefault("max_well_control_iterations", 10);
// Transport related init.
num_transport_substeps_ = param.getDefault("num_transport_substeps", 1);
use_segregation_split_ = param.getDefault("use_segregation_split", false);
if (gravity != 0 && use_segregation_split_){
tsolver_.initGravity(gravity);
extractColumn(grid_, columns_);
}
// Misc init.
const int num_cells = grid.number_of_cells;
allcells_.resize(num_cells);
for (int cell = 0; cell < num_cells; ++cell) {
allcells_[cell] = cell;
}
}
SimulatorReport SimulatorIncompTwophase::Impl::run(SimulatorTimer& timer,
TwophaseState& state,
WellState& well_state)
{
std::vector<double> transport_src;
// Initialisation.
std::vector<double> porevol;
if (rock_comp_ && rock_comp_->isActive()) {
computePorevolume(grid_, props_.porosity(), *rock_comp_, state.pressure(), porevol);
} else {
computePorevolume(grid_, props_.porosity(), porevol);
}
const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
std::vector<double> initial_porevol = porevol;
// Main simulation loop.
Opm::time::StopWatch pressure_timer;
double ptime = 0.0;
Opm::time::StopWatch transport_timer;
double ttime = 0.0;
Opm::time::StopWatch step_timer;
Opm::time::StopWatch total_timer;
total_timer.start();
double init_satvol[2] = { 0.0 };
double satvol[2] = { 0.0 };
double injected[2] = { 0.0 };
double produced[2] = { 0.0 };
double tot_injected[2] = { 0.0 };
double tot_produced[2] = { 0.0 };
Opm::computeSaturatedVol(porevol, state.saturation(), init_satvol);
std::cout << "\nInitial saturations are " << init_satvol[0]/tot_porevol_init
<< " " << init_satvol[1]/tot_porevol_init << std::endl;
Opm::Watercut watercut;
watercut.push(0.0, 0.0, 0.0);
Opm::WellReport wellreport;
std::vector<double> fractional_flows;
std::vector<double> well_resflows_phase;
if (wells_) {
well_resflows_phase.resize((wells_->number_of_phases)*(wells_->number_of_wells), 0.0);
wellreport.push(props_, *wells_, state.saturation(), 0.0, well_state.bhp(), well_state.perfRates());
}
std::fstream tstep_os;
if (output_) {
std::string filename = output_dir_ + "/step_timing.param";
tstep_os.open(filename.c_str(), std::fstream::out | std::fstream::app);
}
for (; !timer.done(); ++timer) {
// Report timestep and (optionally) write state to disk.
step_timer.start();
timer.report(std::cout);
if (output_ && (timer.currentStepNum() % output_interval_ == 0)) {
if (output_vtk_) {
outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
}
outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
outputVectorMatlab(std::string("reorder_it"),
tsolver_.getReorderIterations(),
timer.currentStepNum(), output_dir_);
}
SimulatorReport sreport;
// Solve pressure equation.
if (check_well_controls_) {
computeFractionalFlow(props_, allcells_, state.saturation(), fractional_flows);
wells_manager_.applyExplicitReinjectionControls(well_resflows_phase, well_resflows_phase);
}
bool well_control_passed = !check_well_controls_;
int well_control_iteration = 0;
do {
// Run solver.
pressure_timer.start();
std::vector<double> initial_pressure = state.pressure();
psolver_.solve(timer.currentStepLength(), state, well_state);
// Renormalize pressure if rock is incompressible, and
// there are no pressure conditions (bcs or wells).
// It is deemed sufficient for now to renormalize
// using geometric volume instead of pore volume.
if ((rock_comp_ == NULL || !rock_comp_->isActive())
&& allNeumannBCs(bcs_) && allRateWells(wells_)) {
// Compute average pressures of previous and last
// step, and total volume.
double av_prev_press = 0.0;
double av_press = 0.0;
double tot_vol = 0.0;
const int num_cells = grid_.number_of_cells;
for (int cell = 0; cell < num_cells; ++cell) {
av_prev_press += initial_pressure[cell]*grid_.cell_volumes[cell];
av_press += state.pressure()[cell]*grid_.cell_volumes[cell];
tot_vol += grid_.cell_volumes[cell];
}
// Renormalization constant
const double ren_const = (av_prev_press - av_press)/tot_vol;
for (int cell = 0; cell < num_cells; ++cell) {
state.pressure()[cell] += ren_const;
}
const int num_wells = (wells_ == NULL) ? 0 : wells_->number_of_wells;
for (int well = 0; well < num_wells; ++well) {
well_state.bhp()[well] += ren_const;
}
}
// Stop timer and report.
pressure_timer.stop();
double pt = pressure_timer.secsSinceStart();
std::cout << "Pressure solver took: " << pt << " seconds." << std::endl;
ptime += pt;
sreport.pressure_time = pt;
// Optionally, check if well controls are satisfied.
if (check_well_controls_) {
Opm::computePhaseFlowRatesPerWell(*wells_,
fractional_flows,
well_state.perfRates(),
well_resflows_phase);
std::cout << "Checking well conditions." << std::endl;
// For testing we set surface := reservoir
well_control_passed = wells_manager_.conditionsMet(well_state.bhp(), well_resflows_phase, well_resflows_phase);
++well_control_iteration;
if (!well_control_passed && well_control_iteration > max_well_control_iterations_) {
THROW("Could not satisfy well conditions in " << max_well_control_iterations_ << " tries.");
}
if (!well_control_passed) {
std::cout << "Well controls not passed, solving again." << std::endl;
} else {
std::cout << "Well conditions met." << std::endl;
}
}
} while (!well_control_passed);
// Update pore volumes if rock is compressible.
if (rock_comp_ && rock_comp_->isActive()) {
initial_porevol = porevol;
computePorevolume(grid_, props_.porosity(), *rock_comp_, state.pressure(), porevol);
}
// Process transport sources (to include bdy terms and well flows).
Opm::computeTransportSource(grid_, src_, state.faceflux(), 1.0,
wells_, well_state.perfRates(), transport_src);
// Solve transport.
transport_timer.start();
double stepsize = timer.currentStepLength();
if (num_transport_substeps_ != 1) {
stepsize /= double(num_transport_substeps_);
std::cout << "Making " << num_transport_substeps_ << " transport substeps." << std::endl;
}
for (int tr_substep = 0; tr_substep < num_transport_substeps_; ++tr_substep) {
tsolver_.solve(&state.faceflux()[0], &initial_porevol[0], &transport_src[0],
stepsize, state.saturation());
Opm::computeInjectedProduced(props_, state.saturation(), transport_src, stepsize, injected, produced);
if (use_segregation_split_) {
tsolver_.solveGravity(columns_, &initial_porevol[0], stepsize, state.saturation());
}
watercut.push(timer.currentTime() + timer.currentStepLength(),
produced[0]/(produced[0] + produced[1]),
tot_produced[0]/tot_porevol_init);
if (wells_) {
wellreport.push(props_, *wells_, state.saturation(),
timer.currentTime() + timer.currentStepLength(),
well_state.bhp(), well_state.perfRates());
}
}
transport_timer.stop();
double tt = transport_timer.secsSinceStart();
sreport.transport_time = tt;
std::cout << "Transport solver took: " << tt << " seconds." << std::endl;
ttime += tt;
// Report volume balances.
Opm::computeSaturatedVol(porevol, state.saturation(), satvol);
tot_injected[0] += injected[0];
tot_injected[1] += injected[1];
tot_produced[0] += produced[0];
tot_produced[1] += produced[1];
reportVolumes(std::cout,satvol, tot_porevol_init,
tot_injected, tot_produced,
injected, produced,
init_satvol);
sreport.total_time = step_timer.secsSinceStart();
if (output_) {
sreport.reportParam(tstep_os);
}
}
if (output_) {
if (output_vtk_) {
outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
}
outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
outputVectorMatlab(std::string("reorder_it"),
tsolver_.getReorderIterations(),
timer.currentStepNum(), output_dir_);
outputWaterCut(watercut, output_dir_);
if (wells_) {
outputWellReport(wellreport, output_dir_);
}
tstep_os.close();
}
total_timer.stop();
SimulatorReport report;
report.pressure_time = ptime;
report.transport_time = ttime;
report.total_time = total_timer.secsSinceStart();
return report;
}
} // namespace Opm

View File

@ -17,8 +17,8 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef OPM_SIMULATORTWOPHASE_HEADER_INCLUDED #ifndef OPM_SIMULATORINCOMPTWOPHASE_HEADER_INCLUDED
#define OPM_SIMULATORTWOPHASE_HEADER_INCLUDED #define OPM_SIMULATORINCOMPTWOPHASE_HEADER_INCLUDED
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <vector> #include <vector>
@ -32,14 +32,15 @@ namespace Opm
namespace parameter { class ParameterGroup; } namespace parameter { class ParameterGroup; }
class IncompPropertiesInterface; class IncompPropertiesInterface;
class RockCompressibility; class RockCompressibility;
class WellsManager;
class LinearSolverInterface; class LinearSolverInterface;
class SimulatorTimer; class SimulatorTimer;
class TwophaseState; class TwophaseState;
class WellState; class WellState;
class SimulatorReport; struct SimulatorReport;
/// Class collecting all necessary components for a two-phase simulation. /// Class collecting all necessary components for a two-phase simulation.
class SimulatorTwophase class SimulatorIncompTwophase
{ {
public: public:
/// Initialise from parameters and objects to observe. /// Initialise from parameters and objects to observe.
@ -58,23 +59,23 @@ namespace Opm
/// use_segregation_split (false) solve for gravity segregation (if false, /// use_segregation_split (false) solve for gravity segregation (if false,
/// segregation is ignored). /// segregation is ignored).
/// ///
/// \param[in] grid grid data structure /// \param[in] grid grid data structure
/// \param[in] props fluid and rock properties /// \param[in] props fluid and rock properties
/// \param[in] rock_comp if non-null, rock compressibility properties /// \param[in] rock_comp if non-null, rock compressibility properties
/// \param[in] wells if non-null, wells data structure /// \param[in] well_manager well manager, may manage no (null) wells
/// \param[in] src source terms /// \param[in] src source terms
/// \param[in] bcs boundary conditions, treat as all noflow if null /// \param[in] bcs boundary conditions, treat as all noflow if null
/// \param[in] linsolver linear solver /// \param[in] linsolver linear solver
/// \param[in] gravity if non-null, gravity vector /// \param[in] gravity if non-null, gravity vector
SimulatorTwophase(const parameter::ParameterGroup& param, SimulatorIncompTwophase(const parameter::ParameterGroup& param,
const UnstructuredGrid& grid, const UnstructuredGrid& grid,
const IncompPropertiesInterface& props, const IncompPropertiesInterface& props,
const RockCompressibility* rock_comp, const RockCompressibility* rock_comp,
const Wells* wells, WellsManager& wells_manager,
const std::vector<double>& src, const std::vector<double>& src,
const FlowBoundaryConditions* bcs, const FlowBoundaryConditions* bcs,
LinearSolverInterface& linsolver, LinearSolverInterface& linsolver,
const double* gravity); const double* gravity);
/// Run the simulation. /// Run the simulation.
/// This will run succesive timesteps until timer.done() is true. It will /// This will run succesive timesteps until timer.done() is true. It will
@ -95,4 +96,4 @@ namespace Opm
} // namespace Opm } // namespace Opm
#endif // OPM_SIMULATORTWOPHASE_HEADER_INCLUDED #endif // OPM_SIMULATORINCOMPTWOPHASE_HEADER_INCLUDED

View File

@ -42,6 +42,12 @@ namespace Opm
<< "\n Pressure time: " << pressure_time << "\n Pressure time: " << pressure_time
<< "\n Transport time: " << transport_time << std::endl; << "\n Transport time: " << transport_time << std::endl;
} }
void SimulatorReport::reportParam(std::ostream& os)
{
os << "/timing/total_time=" << total_time
<< "\n/timing/pressure/total_time=" << pressure_time
<< "\n/timing/transport/total_time=" << transport_time << std::endl;
}
} // namespace Opm } // namespace Opm

View File

@ -38,6 +38,7 @@ namespace Opm
void operator+=(const SimulatorReport& sr); void operator+=(const SimulatorReport& sr);
/// Print a report to the given stream. /// Print a report to the given stream.
void report(std::ostream& os); void report(std::ostream& os);
void reportParam(std::ostream& os);
}; };
} // namespace Opm } // namespace Opm

View File

@ -37,10 +37,17 @@ namespace Opm
if (wells) { if (wells) {
const int nw = wells->number_of_wells; const int nw = wells->number_of_wells;
bhp_.resize(nw); bhp_.resize(nw);
// Initialize bhp to be pressure in first perforation cell. // Initialize bhp to be target pressure
// if bhp-controlled well, otherwise set
// to pressure in first perforation cell.
for (int w = 0; w < nw; ++w) { for (int w = 0; w < nw; ++w) {
const int cell = wells->well_cells[wells->well_connpos[w]]; const WellControls* ctrl = wells->ctrls[w];
bhp_[w] = state.pressure()[cell]; if (ctrl->type[ctrl->current] == BHP) {
bhp_[w] = ctrl->target[ctrl->current];
} else {
const int cell = wells->well_cells[wells->well_connpos[w]];
bhp_[w] = state.pressure()[cell];
}
} }
perfrates_.resize(wells->well_connpos[nw]); perfrates_.resize(wells->well_connpos[nw]);
} }

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