tracking filtration particle volume instead of water injection volume

for filter cake calculation. The main reason is that the injection
concentration may vary during the simulation, which makes the tracking
of water injection volume is not very helpful when used for filter cake
calculation.
This commit is contained in:
Kai Bao 2023-06-30 12:17:44 +02:00
parent eb08e2e863
commit 274c431492
5 changed files with 21 additions and 15 deletions

View File

@ -313,8 +313,8 @@ namespace Opm {
for (auto& well : well_container_) {
if (well->isInjector()) {
const auto& ws = this->wellState().well(well->indexOfWell());
const auto& water_inj_volume = ws.perf_data.water_injection_volume;
well->updateInjFCMult(water_inj_volume);
const auto& filtration_particle_volume = ws.perf_data.filtration_particle_volume;
well->updateInjFCMult(filtration_particle_volume);
}
}
@ -482,7 +482,7 @@ namespace Opm {
}
if (well->isInjector() && Indices::waterEnabled) {
well->updateWaterInjectionVolume(dt, FluidSystem::waterPhaseIdx, this->wellState());
well->updateFiltrationParticleVolume(dt, FluidSystem::waterPhaseIdx, this->wellState());
}
}

View File

@ -46,7 +46,7 @@ PerfData::PerfData(std::size_t num_perf, double pressure_first_connection_, bool
this->water_throughput.resize(num_perf);
this->skin_pressure.resize(num_perf);
this->water_velocity.resize(num_perf);
this->water_injection_volume.resize(num_perf);
this->filtration_particle_volume.resize(num_perf);
}
}
@ -98,7 +98,7 @@ bool PerfData::try_assign(const PerfData& other) {
this->water_throughput = other.water_throughput;
this->skin_pressure = other.skin_pressure;
this->water_velocity = other.water_velocity;
this->water_injection_volume = other.water_injection_volume;
this->filtration_particle_volume = other.filtration_particle_volume;
this->prod_index = other.prod_index;
this->micp_rates = other.micp_rates;
return true;

View File

@ -92,7 +92,10 @@ public:
// TODO: if the injection concentration change, only the water injection volume will not be enough to
// calculate the formation of the filter cake.
// TODO: will change to track the volume of the solid formed during the injection
std::vector<double> water_injection_volume;
// because the injection concentration may vary during the simulation, we track the solid particle volume
// instead of tracking the water injection volume
// std::vector<double> water_injection_volume;
std::vector<double> filtration_particle_volume;
};
} // namespace Opm

View File

@ -719,7 +719,7 @@ checkNegativeWellPotentials(std::vector<double>& well_potentials,
}
void WellInterfaceGeneric::
updateWaterInjectionVolume(const double dt, const size_t water_index, WellState& well_state) const
updateFiltrationParticleVolume(const double dt, const size_t water_index, WellState& well_state) const
{
if (!this->isInjector()) {
return;
@ -730,22 +730,27 @@ updateWaterInjectionVolume(const double dt, const size_t water_index, WellState&
return;
}
const double conc = this->well_ecl_.getFilterConc();
if (conc == 0.) {
return;
}
// it is currently used for the filter cake modeling related to formation damage study
auto& ws = well_state.well(this->index_of_well_);
const auto& connection_rates = ws.perf_data.phase_rates;
// per connection
auto& water_injection_volume = ws.perf_data.water_injection_volume;
auto& filtration_particle_volume = ws.perf_data.filtration_particle_volume;
const size_t np = well_state.numPhases();
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
// not considering the production water
const double water_rates = std::max(0., connection_rates[perf * np + water_index]);
water_injection_volume[perf] += water_rates * dt;
filtration_particle_volume[perf] += water_rates * conc * dt;
}
}
void WellInterfaceGeneric::
updateInjFCMult(const std::vector<double>& water_inj_volume) {
updateInjFCMult(const std::vector<double>& filtration_particle_volume) {
// the filter injecting concentration, the porosity, the area size
// we also need the permeability of the formation, and rw and some other information
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
@ -754,10 +759,9 @@ updateInjFCMult(const std::vector<double>& water_inj_volume) {
const auto& connection = connections[perf_ecl_index];
if (this->isInjector() && connection.filterCakeActive()) {
const auto& filter_cake = connection.getFilterCake();
const double conc = this->well_ecl_.getFilterConc();
const double area = connection.getFilterCakeArea();
const double poro = filter_cake.poro;
const double thickness = water_inj_volume[perf] * conc / (area*(1.-poro));
const double thickness = filtration_particle_volume[perf] / (area * (1. - poro));
const double perm = filter_cake.perm;
const double rw = connection.getFilterCakeRadius();
const auto cr0 = connection.r0();

View File

@ -189,10 +189,10 @@ public:
double getInjMult(const int perf, const double bhp, const double perf_pres) const;
// update the water injection volume, it will be used for calculation related to cake filtration due to injection activity
void updateWaterInjectionVolume(const double dt, const size_t water_index, WellState& well_state) const;
void updateFiltrationParticleVolume(const double dt, const size_t water_index, WellState& well_state) const;
// update the multiplier for well transmissbility due to cake filteration
void updateInjFCMult(const std::vector<double>& water_inj_volume);
void updateInjFCMult(const std::vector<double>& filtration_particle_volume);
// whether a well is specified with a non-zero and valid VFP table number
bool isVFPActive(DeferredLogger& deferred_logger) const;
@ -377,7 +377,6 @@ protected:
// the multiplier due to injection filtration cake
mutable std::vector<double> inj_fc_multiplier_;
// TODO: currently, the water_injection_volume is in PerfData, maybe we should move it here
double well_efficiency_factor_;
const VFPProperties* vfp_properties_;