/// @brief Computes injected and produced volumes of all phases. /// Note 1: assumes that only the first phase is injected. /// Note 2: assumes that transport has been done with an /// implicit method, i.e. that the current state /// gives the mobilities used for the preceding timestep. /// @param[in] props fluid and rock properties. /// @param[in] s saturation values (for all P phases) /// @param[in] src if < 0: total outflow, if > 0: first phase inflow. /// @param[in] dt timestep used /// @param[out] injected must point to a valid array with P elements, /// where P = s.size()/src.size(). /// @param[out] produced must also point to a valid array with P elements. void computeInjectedProduced(const IncompPropertiesInterface& props, const std::vector<double>& s, const std::vector<double>& src, const double dt, double* injected, double* produced) { const int num_cells = src.size(); const int np = s.size()/src.size(); if (int(s.size()) != num_cells*np) { OPM_THROW(std::runtime_error, "Sizes of s and src vectors do not match."); } std::fill(injected, injected + np, 0.0); std::fill(produced, produced + np, 0.0); const double* visc = props.viscosity(); std::vector<double> mob(np); for (int c = 0; c < num_cells; ++c) { if (src[c] > 0.0) { injected[0] += src[c]*dt; } else if (src[c] < 0.0) { const double flux = -src[c]*dt; const double* sat = &s[np*c]; props.relperm(1, sat, &c, &mob[0], 0); double totmob = 0.0; for (int p = 0; p < np; ++p) { mob[p] /= visc[p]; totmob += mob[p]; } for (int p = 0; p < np; ++p) { produced[p] += (mob[p]/totmob)*flux; } } } }
void WellReport::push(const IncompPropertiesInterface& props, const Wells& wells, const std::vector<double>& saturation, const double time, const std::vector<double>& well_bhp, const std::vector<double>& well_perfrates) { int nw = well_bhp.size(); assert(nw == wells.number_of_wells); int np = props.numPhases(); const int max_np = 3; if (np > max_np) { OPM_THROW(std::runtime_error, "WellReport for now assumes #phases <= " << max_np); } const double* visc = props.viscosity(); std::vector<double> data_now; data_now.reserve(1 + 3*nw); data_now.push_back(time/unit::day); for (int w = 0; w < nw; ++w) { data_now.push_back(well_bhp[w]/(unit::barsa)); double well_rate_total = 0.0; double well_rate_water = 0.0; for (int perf = wells.well_connpos[w]; perf < wells.well_connpos[w + 1]; ++perf) { const double perf_rate = unit::convert::to(well_perfrates[perf], unit::cubic(unit::meter)/unit::day); well_rate_total += perf_rate; if (perf_rate > 0.0) { // Injection. well_rate_water += perf_rate*wells.comp_frac[0]; } else { // Production. const int cell = wells.well_cells[perf]; double mob[max_np]; props.relperm(1, &saturation[2*cell], &cell, mob, 0); double tmob = 0; for(int i = 0; i < np; ++i) { mob[i] /= visc[i]; tmob += mob[i]; } const double fracflow = mob[0]/tmob; well_rate_water += perf_rate*fracflow; } } data_now.push_back(well_rate_total); if (well_rate_total == 0.0) { data_now.push_back(0.0); } else { data_now.push_back(well_rate_water/well_rate_total); } } data_.push_back(data_now); }
/// @brief Computes injected and produced volumes of all phases, /// and injected and produced polymer mass. /// Note 1: assumes that only the first phase is injected. /// Note 2: assumes that transport has been done with an /// implicit method, i.e. that the current state /// gives the mobilities used for the preceding timestep. /// @param[in] props fluid and rock properties. /// @param[in] polyprops polymer properties /// @param[in] state state variables (pressure, fluxes etc.) /// @param[in] src if < 0: total reservoir volume outflow, /// if > 0: first phase reservoir volume inflow. /// @param[in] inj_c injected concentration by cell /// @param[in] dt timestep used /// @param[out] injected must point to a valid array with P elements, /// where P = s.size()/src.size(). /// @param[out] produced must also point to a valid array with P elements. /// @param[out] polyinj injected mass of polymer /// @param[out] polyprod produced mass of polymer void computeInjectedProduced(const IncompPropertiesInterface& props, const Opm::PolymerProperties& polyprops, const PolymerState& state, const std::vector<double>& transport_src, const std::vector<double>& inj_c, const double dt, double* injected, double* produced, double& polyinj, double& polyprod) { const int num_cells = transport_src.size(); if (props.numCells() != num_cells) { OPM_THROW(std::runtime_error, "Size of transport_src vector does not match number of cells in props."); } const int np = props.numPhases(); if (int(state.saturation().size()) != num_cells*np) { OPM_THROW(std::runtime_error, "Sizes of state vectors do not match number of cells."); } const std::vector<double>& s = state.saturation(); const std::vector<double>& c = state.getCellData( state.CONCENTRATION ); const std::vector<double>& cmax = state.getCellData( state.CMAX ); std::fill(injected, injected + np, 0.0); std::fill(produced, produced + np, 0.0); polyinj = 0.0; polyprod = 0.0; const double* visc = props.viscosity(); std::vector<double> kr_cell(np); double mob[2]; double mc; for (int cell = 0; cell < num_cells; ++cell) { if (transport_src[cell] > 0.0) { injected[0] += transport_src[cell]*dt; polyinj += transport_src[cell]*dt*inj_c[cell]; } else if (transport_src[cell] < 0.0) { const double flux = -transport_src[cell]*dt; const double* sat = &s[np*cell]; props.relperm(1, sat, &cell, &kr_cell[0], 0); polyprops.effectiveMobilities(c[cell], cmax[cell], visc, &kr_cell[0], mob); double totmob = mob[0] + mob[1]; for (int p = 0; p < np; ++p) { produced[p] += (mob[p]/totmob)*flux; } polyprops.computeMc(c[cell], mc); polyprod += (mob[0]/totmob)*flux*mc; } } }