mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Add polymer option to flow_ebos
No extra equation is added for polymer in the well equation. Seperate executables are added for polymer: flow_ebos_polymer and solvent: flow_ebos_solvent Tested and verified on the test cases in polymer_test_suite This PR should not effect the performance and results of the blackoil simulator
This commit is contained in:
@@ -18,6 +18,7 @@ namespace Opm {
|
||||
, param_(param)
|
||||
, terminal_output_(terminal_output)
|
||||
, has_solvent_(GET_PROP_VALUE(TypeTag, EnableSolvent))
|
||||
, has_polymer_(GET_PROP_VALUE(TypeTag, EnablePolymer))
|
||||
, current_timeIdx_(current_timeIdx)
|
||||
, well_perforation_efficiency_factors_((wells_!=nullptr ? wells_->well_connpos[wells_->number_of_wells] : 0), 1.0)
|
||||
, well_perforation_densities_( wells_ ? wells_arg->well_connpos[wells_arg->number_of_wells] : 0)
|
||||
@@ -47,7 +48,8 @@ namespace Opm {
|
||||
const std::vector<double>& depth_arg,
|
||||
const std::vector<double>& pv_arg,
|
||||
const RateConverterType* rate_converter,
|
||||
long int global_nc)
|
||||
long int global_nc,
|
||||
const auto& grid)
|
||||
{
|
||||
// has to be set always for the convergence check!
|
||||
global_nc_ = global_nc;
|
||||
@@ -118,6 +120,14 @@ namespace Opm {
|
||||
// resize temporary class variables
|
||||
Cx_.resize( duneC_.N() );
|
||||
invDrw_.resize( invDuneD_.N() );
|
||||
|
||||
if (has_polymer_)
|
||||
{
|
||||
if (PolymerModule::hasPlyshlog()) {
|
||||
computeRepRadiusPerfLength(grid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -197,6 +207,37 @@ namespace Opm {
|
||||
getMobility(ebosSimulator, perf, cell_idx, mob);
|
||||
computeWellFlux(w, wells().WI[perf], intQuants, mob, bhp, wellPerforationPressureDiffs()[perf], allow_cf, cq_s);
|
||||
|
||||
if (has_polymer_) {
|
||||
if (PolymerModule::hasPlyshlog()) {
|
||||
// compute the well water velocity based on the perforation rates.
|
||||
double area = 2 * M_PI * wells_rep_radius_[perf] * wells_perf_length_[perf];
|
||||
const auto& materialLawManager = ebosSimulator.problem().materialLawManager();
|
||||
const auto& scaledDrainageInfo =
|
||||
materialLawManager->oilWaterScaledEpsInfoDrainage(cell_idx);
|
||||
const Scalar& Swcr = scaledDrainageInfo.Swcr;
|
||||
const EvalWell poro = extendEval(intQuants.porosity());
|
||||
const EvalWell Sw = extendEval(intQuants.fluidState().saturation(flowPhaseToEbosPhaseIdx(Water)));
|
||||
// guard against zero porosity and no water
|
||||
const EvalWell denom = Opm::max( (area * poro * (Sw - Swcr)), 1e-12);
|
||||
EvalWell waterVelocity = cq_s[ Water ] / denom * extendEval(intQuants.fluidState().invB(flowPhaseToEbosPhaseIdx(Water)));
|
||||
EvalWell polymerConcentration = extendEval(intQuants.polymerConcentration());
|
||||
|
||||
if (PolymerModule::hasShrate()) {
|
||||
// TODO Use the same conversion as for the reservoar equations.
|
||||
// Need the "permeability" of the well?
|
||||
// For now use the same formula as in legacy.
|
||||
waterVelocity *= PolymerModule::shrate( intQuants.pvtRegionIndex() ) / wells_bore_diameter_[perf];
|
||||
}
|
||||
EvalWell shearFactor = PolymerModule::computeShearFactor(polymerConcentration,
|
||||
intQuants.pvtRegionIndex(),
|
||||
waterVelocity);
|
||||
|
||||
// modify the mobility with the shear factor and recompute the well fluxes.
|
||||
mob[ Water ] /= shearFactor;
|
||||
computeWellFlux(w, wells().WI[perf], intQuants, mob, bhp, wellPerforationPressureDiffs()[perf], allow_cf, cq_s);
|
||||
}
|
||||
}
|
||||
|
||||
for (int componentIdx = 0; componentIdx < numComp; ++componentIdx) {
|
||||
|
||||
// the cq_s entering mass balance equations need to consider the efficiency factors.
|
||||
@@ -209,17 +250,16 @@ namespace Opm {
|
||||
}
|
||||
|
||||
// subtract sum of phase fluxes in the well equations.
|
||||
resWell_[w][componentIdx] -= cq_s[componentIdx].value();
|
||||
resWell_[w][flowPhaseToEbosCompIdx(componentIdx)] -= cq_s[componentIdx].value();
|
||||
|
||||
// assemble the jacobians
|
||||
for (int pvIdx = 0; pvIdx < numWellEq; ++pvIdx) {
|
||||
if (!only_wells) {
|
||||
// also need to consider the efficiency factor when manipulating the jacobians.
|
||||
ebosJac[cell_idx][cell_idx][flowPhaseToEbosCompIdx(componentIdx)][flowToEbosPvIdx(pvIdx)] -= cq_s_effective.derivative(pvIdx);
|
||||
duneB_[w][cell_idx][pvIdx][flowPhaseToEbosCompIdx(componentIdx)] -= cq_s_effective.derivative(pvIdx+numEq); // intput in transformed matrix
|
||||
duneC_[w][cell_idx][componentIdx][flowToEbosPvIdx(pvIdx)] -= cq_s_effective.derivative(pvIdx);
|
||||
duneB_[w][cell_idx][flowToEbosPvIdx(pvIdx)][flowPhaseToEbosCompIdx(componentIdx)] -= cq_s_effective.derivative(pvIdx+numEq); // intput in transformed matrix
|
||||
}
|
||||
invDuneD_[w][w][componentIdx][pvIdx] -= cq_s[componentIdx].derivative(pvIdx+numEq);
|
||||
invDuneD_[w][w][flowPhaseToEbosCompIdx(componentIdx)][pvIdx] -= cq_s[componentIdx].derivative(pvIdx+numEq);
|
||||
}
|
||||
|
||||
// add trivial equation for 2p cases (Only support water + oil)
|
||||
@@ -229,7 +269,7 @@ namespace Opm {
|
||||
}
|
||||
|
||||
// Store the perforation phase flux for later usage.
|
||||
if (componentIdx == solventCompIdx) {// if (flowPhaseToEbosCompIdx(componentIdx) == Solvent)
|
||||
if (has_solvent_ && componentIdx == solventSaturationIdx) {// if (flowPhaseToEbosCompIdx(componentIdx) == Solvent)
|
||||
well_state.perfRateSolvent()[perf] = cq_s[componentIdx].value();
|
||||
} else {
|
||||
well_state.perfPhaseRates()[perf*np + componentIdx] = cq_s[componentIdx].value();
|
||||
@@ -455,13 +495,31 @@ namespace Opm {
|
||||
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
int
|
||||
StandardWellsDense<TypeTag>::
|
||||
flowToEbosPvIdx( const int flowPv ) const
|
||||
{
|
||||
const int flowToEbos[ 3 ] = {
|
||||
BlackoilIndices::pressureSwitchIdx,
|
||||
BlackoilIndices::waterSaturationIdx,
|
||||
BlackoilIndices::compositionSwitchIdx
|
||||
};
|
||||
|
||||
if (flowPv > 2 )
|
||||
return flowPv;
|
||||
|
||||
return flowToEbos[ flowPv ];
|
||||
}
|
||||
|
||||
template<typename TypeTag>
|
||||
int
|
||||
StandardWellsDense<TypeTag>::
|
||||
flowPhaseToEbosCompIdx( const int phaseIdx ) const
|
||||
{
|
||||
const int phaseToComp[ 4 ] = { FluidSystem::waterCompIdx, FluidSystem::oilCompIdx, FluidSystem::gasCompIdx, solventCompIdx };
|
||||
const int phaseToComp[ 3 ] = { FluidSystem::waterCompIdx, FluidSystem::oilCompIdx, FluidSystem::gasCompIdx};
|
||||
if (phaseIdx > 2 )
|
||||
return phaseIdx;
|
||||
return phaseToComp[ phaseIdx ];
|
||||
}
|
||||
|
||||
@@ -469,24 +527,6 @@ namespace Opm {
|
||||
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
int
|
||||
StandardWellsDense<TypeTag>::
|
||||
flowToEbosPvIdx( const int flowPv ) const
|
||||
{
|
||||
const int flowToEbos[ 4 ] = {
|
||||
BlackoilIndices::pressureSwitchIdx,
|
||||
BlackoilIndices::waterSaturationIdx,
|
||||
BlackoilIndices::compositionSwitchIdx,
|
||||
BlackoilIndices::solventSaturationIdx
|
||||
};
|
||||
return flowToEbos[ flowPv ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
int
|
||||
StandardWellsDense<TypeTag>::
|
||||
@@ -497,10 +537,6 @@ namespace Opm {
|
||||
return flowToEbos[ phaseIdx ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
std::vector<double>
|
||||
StandardWellsDense<TypeTag>::
|
||||
@@ -687,8 +723,8 @@ namespace Opm {
|
||||
{
|
||||
const int nw = wells().number_of_wells;
|
||||
// for two-phase numComp < numEq
|
||||
const int numComp = numComponents();
|
||||
for (int eqIdx = 0; eqIdx < numComp; ++eqIdx) {
|
||||
//const int numComp = numComponents();
|
||||
for (int eqIdx = 0; eqIdx < numWellEq; ++eqIdx) {
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
const unsigned int idx = nw * eqIdx + w;
|
||||
assert( idx < wellVariables_.size() );
|
||||
@@ -697,7 +733,7 @@ namespace Opm {
|
||||
|
||||
eval = 0.0;
|
||||
eval.setValue( xw.wellSolutions()[ idx ] );
|
||||
eval.setDerivative(numWellEq + eqIdx, 1.0);
|
||||
eval.setDerivative(numEq + eqIdx, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -765,7 +801,7 @@ namespace Opm {
|
||||
b_perfcells_dense[phase] = extendEval(fs.invB(ebosPhaseIdx));
|
||||
}
|
||||
if (has_solvent_) {
|
||||
b_perfcells_dense[solventCompIdx] = extendEval(intQuants.solventInverseFormationVolumeFactor());
|
||||
b_perfcells_dense[solventSaturationIdx] = extendEval(intQuants.solventInverseFormationVolumeFactor());
|
||||
}
|
||||
|
||||
// Pressure drawdown (also used to determine direction of flow)
|
||||
@@ -817,7 +853,7 @@ namespace Opm {
|
||||
}
|
||||
|
||||
if (has_solvent_) {
|
||||
volumeRatio += cmix_s[solventCompIdx] / b_perfcells_dense[solventCompIdx];
|
||||
volumeRatio += cmix_s[solventSaturationIdx] / b_perfcells_dense[solventSaturationIdx];
|
||||
}
|
||||
|
||||
if (active_[Oil] && active_[Gas]) {
|
||||
@@ -952,8 +988,9 @@ namespace Opm {
|
||||
|
||||
const int nw = wells().number_of_wells;
|
||||
const int numComp = numComponents();
|
||||
std::vector<double> res(numComp*nw);
|
||||
std::vector<double> res(numEq*nw, 0.0);
|
||||
for( int compIdx = 0; compIdx < numComp; ++compIdx) {
|
||||
|
||||
for (int wellIdx = 0; wellIdx < nw; ++wellIdx) {
|
||||
int idx = wellIdx + nw*compIdx;
|
||||
res[idx] = resWell_[ wellIdx ][ compIdx ];
|
||||
@@ -1006,7 +1043,7 @@ namespace Opm {
|
||||
B += 1 / fs.invB(ebosPhaseIdx).value();
|
||||
}
|
||||
if (has_solvent_) {
|
||||
auto& B = B_avg[ solventCompIdx ];
|
||||
auto& B = B_avg[ solventSaturationIdx ];
|
||||
B += 1 / intQuants.solventInverseFormationVolumeFactor().value();
|
||||
}
|
||||
}
|
||||
@@ -1204,8 +1241,8 @@ namespace Opm {
|
||||
|
||||
// We use cell values for solvent injector
|
||||
if (has_solvent_) {
|
||||
b_perf[numComp*perf + solventCompIdx] = intQuants.solventInverseFormationVolumeFactor().value();
|
||||
surf_dens_perf[numComp*perf + solventCompIdx] = intQuants.solventRefDensity();
|
||||
b_perf[numComp*perf + solventSaturationIdx] = intQuants.solventInverseFormationVolumeFactor().value();
|
||||
surf_dens_perf[numComp*perf + solventSaturationIdx] = intQuants.solventRefDensity();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1235,20 +1272,20 @@ namespace Opm {
|
||||
// update the second and third well variable (The flux fractions)
|
||||
std::vector<double> F(np,0.0);
|
||||
if (active_[ Water ]) {
|
||||
const int sign2 = dwells[w][WFrac] > 0 ? 1: -1;
|
||||
const double dx2_limited = sign2 * std::min(std::abs(dwells[w][WFrac]),dFLimit);
|
||||
const int sign2 = dwells[w][flowPhaseToEbosCompIdx(WFrac)] > 0 ? 1: -1;
|
||||
const double dx2_limited = sign2 * std::min(std::abs(dwells[w][flowPhaseToEbosCompIdx(WFrac)]),dFLimit);
|
||||
well_state.wellSolutions()[WFrac*nw + w] = xvar_well_old[WFrac*nw + w] - dx2_limited;
|
||||
}
|
||||
|
||||
if (active_[ Gas ]) {
|
||||
const int sign3 = dwells[w][GFrac] > 0 ? 1: -1;
|
||||
const double dx3_limited = sign3 * std::min(std::abs(dwells[w][GFrac]),dFLimit);
|
||||
const int sign3 = dwells[w][flowPhaseToEbosCompIdx(GFrac)] > 0 ? 1: -1;
|
||||
const double dx3_limited = sign3 * std::min(std::abs(dwells[w][flowPhaseToEbosCompIdx(GFrac)]),dFLimit);
|
||||
well_state.wellSolutions()[GFrac*nw + w] = xvar_well_old[GFrac*nw + w] - dx3_limited;
|
||||
}
|
||||
|
||||
if (has_solvent_) {
|
||||
const int sign4 = dwells[w][SFrac] > 0 ? 1: -1;
|
||||
const double dx4_limited = sign4 * std::min(std::abs(dwells[w][SFrac]),dFLimit);
|
||||
const int sign4 = dwells[w][flowPhaseToEbosCompIdx(SFrac)] > 0 ? 1: -1;
|
||||
const double dx4_limited = sign4 * std::min(std::abs(dwells[w][flowPhaseToEbosCompIdx(SFrac)]),dFLimit);
|
||||
well_state.wellSolutions()[SFrac*nw + w] = xvar_well_old[SFrac*nw + w] - dx4_limited;
|
||||
}
|
||||
|
||||
@@ -1352,7 +1389,7 @@ namespace Opm {
|
||||
case THP: // The BHP and THP both uses the total rate as first well variable.
|
||||
case BHP:
|
||||
{
|
||||
well_state.wellSolutions()[nw*XvarWell + w] = xvar_well_old[nw*XvarWell + w] - dwells[w][XvarWell];
|
||||
well_state.wellSolutions()[nw*XvarWell + w] = xvar_well_old[nw*XvarWell + w] - dwells[w][flowPhaseToEbosCompIdx(XvarWell)];
|
||||
|
||||
switch (wells().type[w]) {
|
||||
case INJECTOR:
|
||||
@@ -1420,8 +1457,8 @@ namespace Opm {
|
||||
case SURFACE_RATE: // Both rate controls use bhp as first well variable
|
||||
case RESERVOIR_RATE:
|
||||
{
|
||||
const int sign1 = dwells[w][XvarWell] > 0 ? 1: -1;
|
||||
const double dx1_limited = sign1 * std::min(std::abs(dwells[w][XvarWell]),std::abs(xvar_well_old[nw*XvarWell + w])*dBHPLimit);
|
||||
const int sign1 = dwells[w][flowPhaseToEbosCompIdx(XvarWell)] > 0 ? 1: -1;
|
||||
const double dx1_limited = sign1 * std::min(std::abs(dwells[w][flowPhaseToEbosCompIdx(XvarWell)]),std::abs(xvar_well_old[nw*XvarWell + w])*dBHPLimit);
|
||||
well_state.wellSolutions()[nw*XvarWell + w] = std::max(xvar_well_old[nw*XvarWell + w] - dx1_limited,1e5);
|
||||
well_state.bhp()[w] = well_state.wellSolutions()[nw*XvarWell + w];
|
||||
|
||||
@@ -1764,7 +1801,7 @@ namespace Opm {
|
||||
perfRates[perf*numComponent + phase] = xw.perfPhaseRates()[perf*np + phase];
|
||||
}
|
||||
if(has_solvent_) {
|
||||
perfRates[perf*numComponent + solventCompIdx] = xw.perfRateSolvent()[perf];
|
||||
perfRates[perf*numComponent + solventSaturationIdx] = xw.perfRateSolvent()[perf];
|
||||
}
|
||||
}
|
||||
well_perforation_densities_ =
|
||||
@@ -2143,7 +2180,7 @@ namespace Opm {
|
||||
if (wells().type[wellIdx] == INJECTOR) {
|
||||
if (has_solvent_ ) {
|
||||
double comp_frac = 0.0;
|
||||
if (compIdx == solventCompIdx) { // solvent
|
||||
if (has_solvent_ && compIdx == solventSaturationIdx) { // solvent
|
||||
comp_frac = wells().comp_frac[np*wellIdx + pu.phase_pos[ Gas ]] * wsolvent(wellIdx);
|
||||
} else if (compIdx == pu.phase_pos[ Gas ]) {
|
||||
comp_frac = wells().comp_frac[np*wellIdx + compIdx] * (1.0 - wsolvent(wellIdx));
|
||||
@@ -2209,7 +2246,7 @@ namespace Opm {
|
||||
EvalWell wellVolumeFractionScaledPhaseUnderControl = wellVolumeFractionScaled(wellIdx, phase_under_control);
|
||||
if (has_solvent_ && phase_under_control == Gas) {
|
||||
// for GRAT controlled wells solvent is included in the target
|
||||
wellVolumeFractionScaledPhaseUnderControl += wellVolumeFractionScaled(wellIdx, solventCompIdx);
|
||||
wellVolumeFractionScaledPhaseUnderControl += wellVolumeFractionScaled(wellIdx, solventSaturationIdx);
|
||||
}
|
||||
|
||||
if (compIdx == phase_under_control) {
|
||||
@@ -2274,7 +2311,7 @@ namespace Opm {
|
||||
return wellVariables_[GFrac * nw + wellIdx];
|
||||
}
|
||||
|
||||
if (compIdx == solventCompIdx) {
|
||||
if (has_solvent_ && compIdx == solventSaturationIdx) {
|
||||
return wellVariables_[SFrac * nw + wellIdx];
|
||||
}
|
||||
|
||||
@@ -2305,7 +2342,7 @@ namespace Opm {
|
||||
const WellControls* wc = wells().ctrls[wellIdx];
|
||||
if (well_controls_get_current_type(wc) == RESERVOIR_RATE) {
|
||||
|
||||
if (has_solvent_ && compIdx == solventCompIdx) {
|
||||
if (has_solvent_ && compIdx == solventSaturationIdx) {
|
||||
return wellVolumeFraction(wellIdx, compIdx);
|
||||
}
|
||||
const double* distr = well_controls_get_current_distr(wc);
|
||||
@@ -2710,10 +2747,10 @@ namespace Opm {
|
||||
xw.wellSolutions()[WFrac*nw + well_index] = g[Water] * xw.wellRates()[np*well_index + Water] / tot_well_rate;
|
||||
}
|
||||
if (active_[ Gas ]) {
|
||||
xw.wellSolutions()[GFrac*nw + well_index] = g[Gas] * (1.0 - wsolvent(well_index)) * xw.wellRates()[np*well_index + Gas] / tot_well_rate ;
|
||||
xw.wellSolutions()[GFrac*nw + well_index] = g[Gas] * (xw.wellRates()[np*well_index + Gas] - xw.solventWellRate(well_index)) / tot_well_rate ;
|
||||
}
|
||||
if (has_solvent_) {
|
||||
xw.wellSolutions()[SFrac*nw + well_index] = g[Gas] * wsolvent(well_index) * xw.wellRates()[np*well_index + Gas] / tot_well_rate ;
|
||||
xw.wellSolutions()[SFrac*nw + well_index] = g[Gas] * xw.solventWellRate(well_index) / tot_well_rate ;
|
||||
}
|
||||
} else {
|
||||
const WellType& well_type = wells().type[well_index];
|
||||
@@ -3027,6 +3064,171 @@ namespace Opm {
|
||||
}
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
double
|
||||
StandardWellsDense<TypeTag>::
|
||||
wpolymer(const int well_index) const {
|
||||
|
||||
if (!has_polymer_) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// loop over all wells until we find the well with the matching name
|
||||
for (const auto& well : wells_ecl_) {
|
||||
if (well->getStatus( current_timeIdx_ ) == WellCommon::SHUT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WellInjectionProperties injection = well->getInjectionProperties(current_timeIdx_);
|
||||
WellPolymerProperties polymer = well->getPolymerProperties(current_timeIdx_);
|
||||
if (injection.injectorType == WellInjector::WATER) {
|
||||
|
||||
double polymerFraction = polymer.m_polymerConcentration;
|
||||
|
||||
// Look until we find the correct well
|
||||
if (well->name() == wells().name[well_index]) {
|
||||
return polymerFraction;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we didn't find it return 0;
|
||||
assert(false);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
StandardWellsDense<TypeTag>::
|
||||
setupCompressedToCartesian(const int* global_cell, int number_of_cells, std::map<int,int>& cartesian_to_compressed ) const
|
||||
{
|
||||
if (global_cell) {
|
||||
for (int i = 0; i < number_of_cells; ++i) {
|
||||
cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < number_of_cells; ++i) {
|
||||
cartesian_to_compressed.insert(std::make_pair(i, i));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
StandardWellsDense<TypeTag>::
|
||||
computeRepRadiusPerfLength(const auto& grid)
|
||||
{
|
||||
|
||||
// TODO, the function does not work for parallel running
|
||||
// to be fixed later.
|
||||
int number_of_cells = Opm::UgGridHelpers::numCells(grid);
|
||||
const int* global_cell = Opm::UgGridHelpers::globalCell(grid);
|
||||
const int* cart_dims = Opm::UgGridHelpers::cartDims(grid);
|
||||
auto cell_to_faces = Opm::UgGridHelpers::cell2Faces(grid);
|
||||
auto begin_face_centroids = Opm::UgGridHelpers::beginFaceCentroids(grid);
|
||||
|
||||
if (wells_ecl_.size() == 0) {
|
||||
OPM_MESSAGE("No wells specified in Schedule section, "
|
||||
"initializing no wells");
|
||||
return;
|
||||
}
|
||||
|
||||
const int nw = wells().number_of_wells;
|
||||
const int nperf = wells().well_connpos[nw];
|
||||
|
||||
const size_t timeStep = current_timeIdx_;
|
||||
|
||||
wells_rep_radius_.clear();
|
||||
wells_perf_length_.clear();
|
||||
wells_bore_diameter_.clear();
|
||||
|
||||
wells_rep_radius_.reserve(nperf);
|
||||
wells_perf_length_.reserve(nperf);
|
||||
wells_bore_diameter_.reserve(nperf);
|
||||
|
||||
std::map<int,int> cartesian_to_compressed;
|
||||
|
||||
setupCompressedToCartesian(global_cell, number_of_cells,
|
||||
cartesian_to_compressed);
|
||||
|
||||
int well_index = 0;
|
||||
|
||||
for (auto wellIter= wells_ecl_.begin(); wellIter != wells_ecl_.end(); ++wellIter) {
|
||||
const auto* well = (*wellIter);
|
||||
|
||||
if (well->getStatus(timeStep) == WellCommon::SHUT) {
|
||||
continue;
|
||||
}
|
||||
{ // COMPDAT handling
|
||||
const auto& completionSet = well->getCompletions(timeStep);
|
||||
for (size_t c=0; c<completionSet.size(); c++) {
|
||||
const auto& completion = completionSet.get(c);
|
||||
if (completion.getState() == WellCompletion::OPEN) {
|
||||
int i = completion.getI();
|
||||
int j = completion.getJ();
|
||||
int k = completion.getK();
|
||||
|
||||
const int* cpgdim = cart_dims;
|
||||
int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k);
|
||||
std::map<int, int>::const_iterator cgit = cartesian_to_compressed.find(cart_grid_indx);
|
||||
if (cgit == cartesian_to_compressed.end()) {
|
||||
OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' '
|
||||
<< k << " not found in grid (well = " << well->name() << ')');
|
||||
}
|
||||
int cell = cgit->second;
|
||||
|
||||
{
|
||||
double radius = 0.5*completion.getDiameter();
|
||||
if (radius <= 0.0) {
|
||||
radius = 0.5*unit::feet;
|
||||
OPM_MESSAGE("**** Warning: Well bore internal radius set to " << radius);
|
||||
}
|
||||
|
||||
const std::array<double, 3> cubical =
|
||||
WellsManagerDetail::getCubeDim<3>(cell_to_faces, begin_face_centroids, cell);
|
||||
|
||||
WellCompletion::DirectionEnum direction = completion.getDirection();
|
||||
|
||||
double re; // area equivalent radius of the grid block
|
||||
double perf_length; // the length of the well perforation
|
||||
|
||||
switch (direction) {
|
||||
case Opm::WellCompletion::DirectionEnum::X:
|
||||
re = std::sqrt(cubical[1] * cubical[2] / M_PI);
|
||||
perf_length = cubical[0];
|
||||
break;
|
||||
case Opm::WellCompletion::DirectionEnum::Y:
|
||||
re = std::sqrt(cubical[0] * cubical[2] / M_PI);
|
||||
perf_length = cubical[1];
|
||||
break;
|
||||
case Opm::WellCompletion::DirectionEnum::Z:
|
||||
re = std::sqrt(cubical[0] * cubical[1] / M_PI);
|
||||
perf_length = cubical[2];
|
||||
break;
|
||||
default:
|
||||
OPM_THROW(std::runtime_error, " Dirtecion of well is not supported ");
|
||||
}
|
||||
|
||||
double repR = std::sqrt(re * radius);
|
||||
wells_rep_radius_.push_back(repR);
|
||||
wells_perf_length_.push_back(perf_length);
|
||||
wells_bore_diameter_.push_back(2. * radius);
|
||||
}
|
||||
} else {
|
||||
if (completion.getState() != WellCompletion::SHUT) {
|
||||
OPM_THROW(std::runtime_error, "Completion state: " << WellCompletion::StateEnum2String( completion.getState() ) << " not handled");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
well_index++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
Reference in New Issue
Block a user