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);
+
+}
+
+
+