diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 15ad060f..af66a669 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -41,6 +41,7 @@ list (APPEND MAIN_SOURCE_FILES opm/core/grid/cpgpreprocess/uniquepoints.c opm/core/io/eclipse/EclipseGridInspector.cpp opm/core/io/eclipse/EclipseWriter.cpp + opm/core/io/eclipse/EclipseWriteRFTHandler.cpp opm/core/io/eclipse/writeECLData.cpp opm/core/io/OutputWriter.cpp opm/core/io/vag/vag.cpp @@ -157,6 +158,7 @@ list (APPEND MAIN_SOURCE_FILES list (APPEND TEST_SOURCE_FILES tests/test_writenumwells.cpp tests/test_EclipseWriter.cpp + tests/test_EclipseWriteRFTHandler.cpp tests/test_compressedpropertyaccess.cpp tests/test_spline.cpp tests/test_propertysystem.cpp @@ -289,6 +291,7 @@ list (APPEND PUBLIC_HEADER_FILES opm/core/io/eclipse/EclipseGridInspector.hpp opm/core/io/eclipse/EclipseUnits.hpp opm/core/io/eclipse/EclipseWriter.hpp + opm/core/io/eclipse/EclipseWriteRFTHandler.hpp opm/core/io/eclipse/writeECLData.hpp opm/core/io/OutputWriter.hpp opm/core/io/vag/vag.hpp diff --git a/opm/core/io/eclipse/EclipseWriteRFTHandler.cpp b/opm/core/io/eclipse/EclipseWriteRFTHandler.cpp new file mode 100644 index 00000000..17afb147 --- /dev/null +++ b/opm/core/io/eclipse/EclipseWriteRFTHandler.cpp @@ -0,0 +1,140 @@ +/* + Copyright 2015 Statoil ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include + + +#include +#include + + + +namespace Opm { +namespace EclipseWriterDetails { + + EclipseWriteRFTHandler::EclipseWriteRFTHandler(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize) { + initGlobalToActiveIndex(compressedToCartesianCellIdx, numCells, cartesianSize); + } + + void EclipseWriteRFTHandler::writeTimeStep(const std::string& filename, + const ert_ecl_unit_enum ecl_unit, + const SimulatorTimerInterface& simulatorTimer, + std::vector& wells, + EclipseGridConstPtr eclipseGrid, + std::vector& pressure, + std::vector& swat, + std::vector& sgas) { + + + + std::vector rft_nodes; + for (std::vector::const_iterator ci = wells.begin(); ci != wells.end(); ++ci) { + WellConstPtr well = *ci; + if ((well->getRFTActive(simulatorTimer.currentStepNum())) || (well->getPLTActive(simulatorTimer.currentStepNum()))) { + ecl_rft_node_type * ecl_node = createEclRFTNode(well, + simulatorTimer, + eclipseGrid, + pressure, + swat, + sgas); + + if (well->getPLTActive(simulatorTimer.currentStepNum())) { + std::cerr << "PLT not supported, writing RFT data" << std::endl; + } + + rft_nodes.push_back(ecl_node); + } + } + + + if (rft_nodes.size() > 0) { + ecl_rft_file_update(filename.c_str(), rft_nodes.data(), rft_nodes.size(), ecl_unit); + } + } + + + + + ecl_rft_node_type * EclipseWriteRFTHandler::createEclRFTNode(WellConstPtr well, + const SimulatorTimerInterface& simulatorTimer, + EclipseGridConstPtr eclipseGrid, + const std::vector& pressure, + const std::vector& swat, + const std::vector& sgas) { + + + const std::string& well_name = well->name(); + size_t timestep = (size_t)simulatorTimer.currentStepNum(); + time_t recording_date = simulatorTimer.currentPosixTime(); + double days = Opm::unit::convert::to(simulatorTimer.simulationTimeElapsed(), Opm::unit::day); + + std::string type = "RFT"; + ecl_rft_node_type * ecl_rft_node = ecl_rft_node_alloc_new(well_name.c_str(), type.c_str(), recording_date, days); + + CompletionSetConstPtr completionsSet = well->getCompletions(timestep); + for (int index = 0; index < completionsSet->size(); ++index) { + CompletionConstPtr completion = completionsSet->get(index); + size_t i = (size_t)completion->getI(); + size_t j = (size_t)completion->getJ(); + size_t k = (size_t)completion->getK(); + + size_t global_index = eclipseGrid->getGlobalIndex(i,j,k); + int active_index = globalToActiveIndex_[global_index]; + + if (active_index > -1) { + double depth = eclipseGrid->getCellDepth(i,j,k); + double completion_pressure = pressure.size() > 0 ? pressure[active_index] : 0.0; + double saturation_water = swat.size() > 0 ? swat[active_index] : 0.0; + double saturation_gas = sgas.size() > 0 ? sgas[active_index] : 0.0; + + ecl_rft_cell_type * ecl_rft_cell = ecl_rft_cell_alloc_RFT( i ,j, k , depth, completion_pressure, saturation_water, saturation_gas); + ecl_rft_node_append_cell( ecl_rft_node , ecl_rft_cell); + } + } + + return ecl_rft_node; + } + + + void EclipseWriteRFTHandler::initGlobalToActiveIndex(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize) { + globalToActiveIndex_.resize(cartesianSize, -1); + for (int active_index = 0; active_index < numCells; ++active_index) { + //If compressedToCartesianCellIdx is NULL, assume no compressed to cartesian mapping, set global equal to active index + int global_index = (NULL != compressedToCartesianCellIdx) ? compressedToCartesianCellIdx[active_index] : active_index; + globalToActiveIndex_[global_index] = active_index; + } + } + + +}//namespace EclipseWriterDetails +}//namespace Opm diff --git a/opm/core/io/eclipse/EclipseWriteRFTHandler.hpp b/opm/core/io/eclipse/EclipseWriteRFTHandler.hpp new file mode 100644 index 00000000..97afeecb --- /dev/null +++ b/opm/core/io/eclipse/EclipseWriteRFTHandler.hpp @@ -0,0 +1,76 @@ +/* + Copyright 2015 Statoil ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + +#ifndef OPM_ECLIPSE_WRITE_RFT_HANDLER_HPP +#define OPM_ECLIPSE_WRITE_RFT_HANDLER_HPP + +#include +#include +#include + +#include + +#include +#include + + +namespace Opm { +namespace EclipseWriterDetails { + + + class EclipseWriteRFTHandler { + + public: + EclipseWriteRFTHandler(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize); + + + void writeTimeStep(const std::string& filename, + const ert_ecl_unit_enum ecl_unit, + const SimulatorTimerInterface& simulatorTimer, + std::vector& wells, + EclipseGridConstPtr eclipseGrid, + std::vector& pressure, + std::vector& swat, + std::vector& sgas); + + + + private: + + ecl_rft_node_type * createEclRFTNode(WellConstPtr well, + const SimulatorTimerInterface& simulatorTimer, + EclipseGridConstPtr eclipseGrid, + const std::vector& pressure, + const std::vector& swat, + const std::vector& sgas); + + void initGlobalToActiveIndex(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize); + + std::vector globalToActiveIndex_; + + }; + + + + +}//namespace EclipseWriterDetails +}//namespace Opm + + +#endif //OPM_ECLIPSE_WRITE_RFT_HANDLER_HPP diff --git a/tests/test_EclipseWriteRFTHandler.cpp b/tests/test_EclipseWriteRFTHandler.cpp new file mode 100755 index 00000000..66461d3d --- /dev/null +++ b/tests/test_EclipseWriteRFTHandler.cpp @@ -0,0 +1,235 @@ +/* + Copyright 2015 Statoil ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ +#include "config.h" + +#if HAVE_DYNAMIC_BOOST_TEST +#define BOOST_TEST_DYN_LINK +#endif + +#define BOOST_TEST_MODULE EclipseRFTWriter +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +void verifyRFTFile(const std::string& rft_filename) { + + ecl_rft_file_type * new_rft_file = ecl_rft_file_alloc(rft_filename.c_str()); + std::shared_ptr rft_file; + rft_file.reset(new_rft_file, ecl_rft_file_free); + + //Get RFT node for well/time OP_1/10 OKT 2008 + time_t recording_time = util_make_datetime(0, 0, 0, 10, 10, 2008); + ecl_rft_node_type * ecl_rft_node = ecl_rft_file_get_well_time_rft(rft_file.get() , "OP_1" , recording_time); + BOOST_CHECK(ecl_rft_node_is_RFT(ecl_rft_node)); + + //Verify RFT data for completions (ijk) 9 9 1, 9 9 2 and 9 9 3 for OP_1 + const ecl_rft_cell_type * ecl_rft_cell1 = ecl_rft_node_lookup_ijk(ecl_rft_node, 8, 8, 0); + const ecl_rft_cell_type * ecl_rft_cell2 = ecl_rft_node_lookup_ijk(ecl_rft_node, 8, 8, 1); + const ecl_rft_cell_type * ecl_rft_cell3 = ecl_rft_node_lookup_ijk(ecl_rft_node, 8, 8, 2); + + BOOST_CHECK_CLOSE(ecl_rft_cell_get_pressure(ecl_rft_cell1), 210088*0.00001, 0.00001); + BOOST_CHECK_CLOSE(ecl_rft_cell_get_pressure(ecl_rft_cell2), 210188*0.00001, 0.00001); + BOOST_CHECK_CLOSE(ecl_rft_cell_get_pressure(ecl_rft_cell3), 210288*0.00001, 0.00001); + + BOOST_CHECK_EQUAL(ecl_rft_cell_get_sgas(ecl_rft_cell1), 0.0); + BOOST_CHECK_EQUAL(ecl_rft_cell_get_sgas(ecl_rft_cell2), 0.0); + BOOST_CHECK_EQUAL(ecl_rft_cell_get_sgas(ecl_rft_cell3), 0.0); + + BOOST_CHECK_EQUAL(ecl_rft_cell_get_swat(ecl_rft_cell1), 0.0); + BOOST_CHECK_EQUAL(ecl_rft_cell_get_swat(ecl_rft_cell2), 0.0); + BOOST_CHECK_EQUAL(ecl_rft_cell_get_swat(ecl_rft_cell3), 0.0); + + BOOST_CHECK_EQUAL(ecl_rft_cell_get_soil(ecl_rft_cell1), 1.0); + BOOST_CHECK_EQUAL(ecl_rft_cell_get_soil(ecl_rft_cell2), 1.0); + BOOST_CHECK_EQUAL(ecl_rft_cell_get_soil(ecl_rft_cell3), 1.0); + + BOOST_CHECK_EQUAL(ecl_rft_cell_get_depth(ecl_rft_cell1), (0.250 + (0.250/2))); + BOOST_CHECK_EQUAL(ecl_rft_cell_get_depth(ecl_rft_cell2), (2*0.250 + (0.250/2))); + BOOST_CHECK_EQUAL(ecl_rft_cell_get_depth(ecl_rft_cell3), (3*0.250 + (0.250/2))); +} + + + + + +Opm::DeckConstPtr createDeck(const std::string& input_str) { + Opm::ParserPtr parser = std::make_shared(); + Opm::DeckConstPtr deck = parser->parseString(input_str); + return deck; +} + + +std::shared_ptr createWellState(std::shared_ptr blackoilState) +{ + std::shared_ptr wellState = std::make_shared(); + wellState->init(0, *blackoilState); + return wellState; +} + + + +std::shared_ptr createBlackoilState(int timeStepIdx, std::shared_ptr ourFineGridManagerPtr) +{ + const UnstructuredGrid &ourFinerUnstructuredGrid = *ourFineGridManagerPtr->c_grid(); + + std::shared_ptr blackoilState = std::make_shared(); + blackoilState->init(ourFinerUnstructuredGrid, 3); + + size_t numCells = ourFinerUnstructuredGrid.number_of_cells; + + auto &pressure = blackoilState->pressure(); + for (size_t cellIdx = 0; cellIdx < numCells; ++cellIdx) { + pressure[cellIdx] = timeStepIdx*1e5 + 1e4 + cellIdx; + } + return blackoilState; +} + + + +std::shared_ptr createEclipseWriter(std::shared_ptr deck, + std::shared_ptr eclipseState, + std::shared_ptr ourFineGridManagerPtr, + const int * compressedToCartesianCellIdx) +{ + Opm::parameter::ParameterGroup params; + params.insertParameter("deck_filename", "testcase.data"); + + Opm::PhaseUsage phaseUsage = Opm::phaseUsageFromDeck(deck); + + const UnstructuredGrid &ourFinerUnstructuredGrid = *ourFineGridManagerPtr->c_grid(); + + std::shared_ptr eclipseWriter = std::make_shared(params, + eclipseState, + phaseUsage, + ourFinerUnstructuredGrid.number_of_cells, + compressedToCartesianCellIdx); + + return eclipseWriter; +} + + + + + +BOOST_AUTO_TEST_CASE(test_EclipseWriterRFTHandler) +{ + const std::string& deckString = + "RUNSPEC\n" + "OIL\n" + "GAS\n" + "WATER\n" + "DIMENS\n" + " 10 10 10 /\n" + "GRID\n" + "DXV\n" + "10*0.25 /\n" + "DYV\n" + "10*0.25 /\n" + "DZV\n" + "10*0.25 /\n" + "TOPS\n" + "100*0.25 /\n" + "\n" + "START -- 0 \n" + "1 NOV 1979 / \n" + "SCHEDULE\n" + "DATES -- 1\n" + " 1 DES 1979/ \n" + "/\n" + "WELSPECS\n" + " 'OP_1' 'OP' 9 9 1* 'OIL' 1* 1* 1* 1* 1* 1* 1* / \n" + " 'OP_2' 'OP' 4 4 1* 'OIL' 1* 1* 1* 1* 1* 1* 1* / \n" + "/\n" + "COMPDAT\n" + " 'OP_1' 9 9 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 / \n" + " 'OP_1' 9 9 2 2 'OPEN' 1* 46.825 0.311 4332.346 1* 1* 'X' 22.123 / \n" + " 'OP_1' 9 9 3 9 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 / \n" + " 'OP_2' 4 4 4 9 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 / \n" + "/\n" + "DATES -- 2\n" + " 10 OKT 2008 / \n" + "/\n" + "WRFT \n" + "/ \n" + "WELOPEN\n" + " 'OP_1' OPEN / \n" + " 'OP_2' OPEN / \n" + "/\n" + "DATES -- 3\n" + " 10 NOV 2008 / \n" + "/\n"; + + + + test_work_area_type * new_ptr = test_work_area_alloc("test_EclipseWriterRFTHandler"); + std::shared_ptr test_area; + test_area.reset(new_ptr, test_work_area_free); + + std::shared_ptr deck = createDeck(deckString); + std::shared_ptr eclipseState = std::make_shared(deck); + + std::shared_ptr simulatorTimer = std::make_shared(); + simulatorTimer->init(eclipseState->getSchedule()->getTimeMap()); + + std::shared_ptr ourFineGridManagerPtr = std::make_shared(eclipseState->getEclipseGrid()); + const UnstructuredGrid &ourFinerUnstructuredGrid = *ourFineGridManagerPtr->c_grid(); + const int* compressedToCartesianCellIdx = Opm::UgGridHelpers::globalCell(ourFinerUnstructuredGrid); + + std::shared_ptr eclipseWriter = createEclipseWriter(deck, + eclipseState, + ourFineGridManagerPtr, + compressedToCartesianCellIdx); + eclipseWriter->writeInit(*simulatorTimer); + + + for (; simulatorTimer->currentStepNum() < simulatorTimer->numSteps(); ++ (*simulatorTimer)) { + std::shared_ptr blackoilState2 = createBlackoilState(simulatorTimer->currentStepNum(),ourFineGridManagerPtr); + std::shared_ptr wellState = createWellState(blackoilState2); + eclipseWriter->writeTimeStep(*simulatorTimer, *blackoilState2, *wellState); + } + + std::string cwd(test_work_area_get_cwd(test_area.get())); + std::string rft_filename = cwd + "/TESTCASE.RFT"; + verifyRFTFile(rft_filename); + +} + + +