/* Copyright 2015 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 . */ #include #define BOOST_TEST_MODULE VFPTest #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const double max_d_tol = 1.0e-10; const double sad_tol = 1.0e-8; struct ConversionFixture { typedef Opm::VFPProdPropertiesLegacy::ADB ADB; ConversionFixture() : num_wells(5), aqua(ADB::null()), liquid(ADB::null()), vapour(ADB::null()) { ADB::V aqua_v(num_wells); ADB::V liquid_v(num_wells); ADB::V vapour_v(num_wells); for (int i=0; i ref_flo_oil(num_wells); std::vector ref_flo_liq(num_wells); std::vector ref_flo_gas(num_wells); for (int i=0; i ref_wfr_wor(num_wells); std::vector ref_wfr_wct(num_wells); std::vector ref_wfr_wgr(num_wells); for (int i=0; i ref_gfr_gor(num_wells); std::vector ref_gfr_glr(num_wells); std::vector ref_gfr_ogr(num_wells); for (int i=0; i(nx-1); for (int j=0; j(ny-1); for (int k=0; k(nz-1); for (int l=0; l(nu-1); for (int m=0; m(nv-1); // table[thp_idx][wfr_idx][gfr_idx][alq_idx][flo_idx]; data[i][j][k][l][m] = x + 2*y + 3*z + 4*u + 5*v; } } } } } } /** * Fills our interpolation data with "random" values */ inline void fillDataRandom() { unsigned long randx = 42; static double max_val = static_cast(std::numeric_limits::max()); for (int i=0; i properties; std::shared_ptr table; std::vector table_ids; private: const std::vector thp_axis; const std::vector wfr_axis; const std::vector gfr_axis; const std::vector alq_axis; const std::vector flo_axis; int nx; int ny; int nz; int nu; int nv; Opm::VFPProdTable::extents size; Opm::VFPProdTable::array_type data; }; //Set F to be our test suite fixture for our "trivial" tests BOOST_FIXTURE_TEST_SUITE( TrivialTests, TrivialFixture ) BOOST_AUTO_TEST_CASE(GetTable) { fillDataRandom(); initProperties(); //Create wells const int nphases = 3; const int nwells = 1; const int nperfs = 1; std::shared_ptr wells(create_wells(nphases, nwells, nperfs), destroy_wells); const int cells[] = {5}; add_well(INJECTOR, 100, 1, NULL, cells, NULL, 0, NULL, true, wells.get()); //Create interpolation points double aqua_d = -0.15; double liquid_d = -0.25; double vapour_d = -0.35; double thp_d = 0.45; double alq_d = 0.55; ADB aqua_adb = createConstantScalarADB(aqua_d); ADB liquid_adb = createConstantScalarADB(liquid_d); ADB vapour_adb = createConstantScalarADB(vapour_d); ADB thp_adb = createConstantScalarADB(thp_d); ADB alq_adb = createConstantScalarADB(alq_d); ADB::V qs_adb_v(3); qs_adb_v << aqua_adb.value(), liquid_adb.value(), vapour_adb.value(); ADB qs_adb = ADB::constant(qs_adb_v); //Check that our reference has not changed Opm::detail::VFPEvaluation ref = Opm::detail::bhp(table.get(), aqua_d, liquid_d, vapour_d, thp_d, alq_d); BOOST_CHECK_CLOSE(ref.value, 1.0923565702101556, max_d_tol); BOOST_CHECK_CLOSE(ref.dthp, 0.13174065498177251, max_d_tol); BOOST_CHECK_CLOSE(ref.dwfr, -1.2298177745501071, max_d_tol); BOOST_CHECK_CLOSE(ref.dgfr, 0.82988935779290274, max_d_tol); BOOST_CHECK_CLOSE(ref.dalq, 1.8148520254931713, max_d_tol); BOOST_CHECK_CLOSE(ref.dflo, 9.0944843574181924, max_d_tol); //Check that different versions of the prod_bph function work ADB a = properties->bhp(table_ids, aqua_adb, liquid_adb, vapour_adb, thp_adb, alq_adb); double b =properties->bhp(table_ids[0], aqua_d, liquid_d, vapour_d, thp_d, alq_d); ADB c = properties->bhp(table_ids, *wells, qs_adb, thp_adb, alq_adb); //Check that results are actually equal reference BOOST_CHECK_EQUAL(a.value()[0], ref.value); BOOST_CHECK_EQUAL(b, ref.value); BOOST_CHECK_EQUAL(c.value()[0], ref.value); //Table 2 does not exist. std::vector table_ids_wrong(1, 2); BOOST_CHECK_THROW(properties->bhp(table_ids_wrong, *wells, qs_adb, thp_adb, alq_adb), std::invalid_argument); } /** * Test that we can generate some dummy data representing an ND plane, * interpolate using ADBs as input, and compare against the analytic solution */ BOOST_AUTO_TEST_CASE(ExtrapolatePlaneADB) { fillDataPlane(); initProperties(); //Check linear extrapolation (i.e., using values of x, y, etc. outside our interpolant domain) double sum = 0.0; double reference_sum = 0.0; double sad = 0.0; // Sum absolute difference double max_d = 0.0; // Maximum difference int n=1; int o=5; for (int i=0; i<=n+o; ++i) { const double x = i / static_cast(n); for (int j=1; j<=n+o; ++j) { const double aqua = -j / static_cast(n); for (int k=1; k<=n+o; ++k) { const double vapour = -k / static_cast(n); for (int l=0; l<=n+o; ++l) { const double u = l / static_cast(n); for (int m=1; m<=n+o; ++m) { const double liquid = -m / static_cast(n); //Temporary variables used to represent independent wells const int num_wells = 5; ADB::V adb_v_x(num_wells); ADB::V adb_v_aqua(num_wells); ADB::V adb_v_vapour(num_wells); ADB::V adb_v_u(num_wells); ADB::V adb_v_liquid(num_wells); table_ids.resize(num_wells); for (unsigned int w=0; wbhp(table_ids, adb_aqua, adb_liquid, adb_vapour, adb_x, adb_u); ADB::V bhp_val = bhp.value(); double value = 0.0; double reference = 0.0; for (int w=0; w < num_wells; ++w) { //Find values that should be in table double v = Opm::detail::getFlo(aqua*(w+1), liquid*(w+1), vapour*(w+1), table->getFloType()); double y = Opm::detail::getWFR(aqua*(w+1), liquid*(w+1), vapour*(w+1), table->getWFRType()); double z = Opm::detail::getGFR(aqua*(w+1), liquid*(w+1), vapour*(w+1), table->getGFRType()); reference = x*(w+1) + 2*y + 3*z + 4*u*(w+1) - 5*v; value = bhp_val[w]; sum += value; reference_sum += reference; double abs_diff = std::abs(value - reference); sad += std::abs(abs_diff); max_d = std::max(max_d, abs_diff); } } } } } } BOOST_CHECK_CLOSE(sum, reference_sum, 0.0001); BOOST_CHECK_SMALL(max_d, max_d_tol); BOOST_CHECK_SMALL(sad, sad_tol); } /** * Test that we can generate some dummy data representing an ND plane, * interpolate using well flow rates and ADBs as input, and compare against the analytic solution */ BOOST_AUTO_TEST_CASE(InterpolateADBAndQs) { fillDataPlane(); initProperties(); //Create wells const int nphases = 3; const int nwells = 5; const int nperfs = 1; std::shared_ptr wells(create_wells(nphases, nwells, nperfs), destroy_wells); int cells = 1; for (int i=0; i(nwells*nphases-1.0); } } ADB qs = ADB::constant(qs_v); //Create the THP for each well ADB::V thp_v(nwells); for (int i=0; i(nwells-1.0); } ADB thp = ADB::constant(thp_v); //Create the ALQ for each well ADB::V alq_v(nwells); for (int i=0; ibhp(table_ids, *wells, qs, thp, alq).value(); //Calculate reference //First, find the three phases std::vector water(nwells); std::vector oil(nwells); std::vector gas(nwells); for (int i=0; i reference(nwells); for (int i=0; i