Handle cleaning of filter cake in a more intuitive way, also report actual thickness for radial case

This commit is contained in:
Vegard Kippe 2024-09-03 10:31:16 +02:00
parent 3bb137be47
commit 60d622fa12
2 changed files with 49 additions and 12 deletions

View File

@ -43,21 +43,37 @@ updateFiltrationParticleVolume(const WellInterfaceGeneric<Scalar>& well,
const std::size_t water_index,
WellState<Scalar>& well_state)
{
// Reset any filter cake cleaning multipliers (for all wells/perfs)
const auto& connections = well.wellEcl().getConnections();
for (auto& conn : connections) {
if (conn.filterCakeActive()) {
conn.getFilterCake().sf_multiplier = 1.0;
}
}
if (!well.isInjector()) {
return;
}
auto& ws = well_state.well(well.indexOfWell());
const auto nperf = ws.perf_data.size();
if (filtration_particle_volume_.empty()) {
const auto& ws = well_state.well(well.indexOfWell());
filtration_particle_volume_.assign(ws.perf_data.size(), 0.); // initializing to be zero
filtration_particle_volume_.assign(ws.perf_data.size(), 0.); // initializing to be zero (for each step..)
prev_skin_factor_.assign(nperf, 0.);
skin_factor_.assign(nperf, 0.);
thickness_.assign(nperf, 0.);
prev_thickness_.assign(nperf, 0.);
}
prev_skin_factor_ = skin_factor_;
prev_thickness_ = thickness_;
const auto injectorType = well.wellEcl().injectorType();
if (injectorType != InjectorType::WATER) {
return;
}
auto& ws = well_state.well(well.indexOfWell());
ws.filtrate_conc = conc;
if (conc == 0.) {
@ -71,9 +87,9 @@ updateFiltrationParticleVolume(const WellInterfaceGeneric<Scalar>& well,
// not considering the production water
const Scalar water_rates = std::max(Scalar{0.}, connection_rates[perf * np + water_index]);
const Scalar filtrate_rate = water_rates * conc;
filtration_particle_volume_[perf] += filtrate_rate * dt;
filtration_particle_volume_[perf] = filtrate_rate * dt;
ws.perf_data.filtrate_data.rates[perf] = filtrate_rate;
ws.perf_data.filtrate_data.total[perf] = filtration_particle_volume_[perf];
ws.perf_data.filtrate_data.total[perf] += filtration_particle_volume_[perf];
}
}
@ -101,24 +117,39 @@ updateInjFCMult(const WellInterfaceGeneric<Scalar>& well,
const Scalar rw = connection.getFilterCakeRadius();
const Scalar K = connection.Kh() / connection.connectionLength();
const Scalar factor = filter_cake.sf_multiplier;
// the thickness of the filtration cake
const Scalar thickness = filtration_particle_volume_[perf] / (area * (1. - poro));
// The thickness of the filtration cake due to particle deposition at current time step
const Scalar delta_thickness = filtration_particle_volume_[perf] / (area * (1. - poro));
auto& filtrate_data = perf_data.filtrate_data;
filtrate_data.thickness[perf] = thickness;
filtrate_data.poro[perf] = poro;
filtrate_data.perm[perf] = perm;
filtrate_data.radius[perf] = connection.getFilterCakeRadius();
filtrate_data.area_of_flow[perf] = connection.getFilterCakeArea();
Scalar skin_factor = 0.;
Scalar thickness = 0.;
switch (filter_cake.geometry) {
case FilterCake::FilterCakeGeometry::LINEAR: {
skin_factor = thickness / rw * K / perm * factor;
// Previuos thickness adjusted to give correct cleaning multiplier at start of time step
const auto prev_thickness = prev_thickness_[perf]*factor;
thickness = prev_thickness + delta_thickness;
skin_factor = thickness / rw * K / perm;
filtrate_data.thickness[perf] = thickness;
break;
}
case FilterCake::FilterCakeGeometry::RADIAL: {
auto prev_thickness = prev_thickness_[perf];
Scalar rc_prev = std::sqrt(rw * rw + 2. * rw * prev_thickness);
// Previuos thickness and rc adjusted to give correct cleaning multiplier at start of time step
if (factor != 1.0) {
rc_prev = rw*std::exp(factor*std::log(rc_prev/rw));
prev_thickness = (rc_prev * rc_prev - rw * rw) / (2. * rw);
}
thickness = prev_thickness + delta_thickness;
//const Scalar rc_prev = std::sqrt(rw * rw + 2. * rw * prev_thickness);
const Scalar rc = std::sqrt(rw * rw + 2. * rw * thickness);
skin_factor = K / perm * std::log(rc / rw) * factor;
filtrate_data.thickness[perf] = rc - rw;
skin_factor = K / perm * std::log(rc / rc_prev);
break;
}
default:
@ -129,10 +160,12 @@ updateInjFCMult(const WellInterfaceGeneric<Scalar>& well,
geometry, well.name()),
deferred_logger);
}
filtrate_data.skin_factor[perf] = skin_factor;
skin_factor_[perf] = prev_skin_factor_[perf]*factor + skin_factor;
filtrate_data.skin_factor[perf] = skin_factor_[perf];
thickness_[perf] = thickness;
const auto denom = connection.ctfProperties().peaceman_denom;
const auto denom2 = denom + skin_factor;
const auto denom2 = denom + skin_factor_[perf];
inj_fc_multiplier_[perf] = denom / denom2;
} else {
inj_fc_multiplier_[perf] = 1.0;

View File

@ -55,6 +55,10 @@ public:
private:
std::vector<Scalar> filtration_particle_volume_; //!<// Volume of filtration particles during water injection
std::vector<Scalar> inj_fc_multiplier_; //!< Multiplier due to injection filtration cake
std::vector<Scalar> skin_factor_;
std::vector<Scalar> prev_skin_factor_;
std::vector<Scalar> thickness_;
std::vector<Scalar> prev_thickness_;
};
}