mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Fix mass exchange term.
Additionally, store separate well terms for free and solution tracers
This commit is contained in:
parent
050ce2de3b
commit
1645559342
@ -68,6 +68,8 @@ public:
|
|||||||
const std::string& name(int tracerIdx) const;
|
const std::string& name(int tracerIdx) const;
|
||||||
std::string fname(int tracerIdx) const;
|
std::string fname(int tracerIdx) const;
|
||||||
std::string sname(int tracerIdx) const;
|
std::string sname(int tracerIdx) const;
|
||||||
|
std::string wellfname(int tracerIdx) const;
|
||||||
|
std::string wellsname(int tracerIdx) const;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -83,12 +85,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
const std::map<std::pair<std::string, std::string>, Scalar>&
|
const std::map<std::pair<std::string, std::string>, Scalar>&
|
||||||
getWellTracerRates() const {return wellTracerRate_;}
|
getWellTracerRates() const {return wellTracerRate_;}
|
||||||
|
const std::map<std::pair<std::string, std::string>, double>&
|
||||||
|
getWellFreeTracerRates() const {return wellFreeTracerRate_;}
|
||||||
|
const std::map<std::pair<std::string, std::string>, double>&
|
||||||
|
getWellSolTracerRates() const {return wellSolTracerRate_;}
|
||||||
|
|
||||||
template<class Serializer>
|
template<class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
{
|
{
|
||||||
serializer(tracerConcentration_);
|
serializer(tracerConcentration_);
|
||||||
serializer(wellTracerRate_);
|
serializer(wellTracerRate_);
|
||||||
|
serializer(wellFreeTracerRate_);
|
||||||
|
serializer(wellSolTracerRate_);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -128,6 +136,8 @@ protected:
|
|||||||
|
|
||||||
// <wellName, tracerIdx> -> wellRate
|
// <wellName, tracerIdx> -> wellRate
|
||||||
std::map<std::pair<std::string, std::string>, Scalar> wellTracerRate_;
|
std::map<std::pair<std::string, std::string>, Scalar> wellTracerRate_;
|
||||||
|
std::map<std::pair<std::string, std::string>, double> wellFreeTracerRate_;
|
||||||
|
std::map<std::pair<std::string, std::string>, double> wellSolTracerRate_;
|
||||||
/// \brief Function returning the cell centers
|
/// \brief Function returning the cell centers
|
||||||
std::function<std::array<double,dimWorld>(int)> centroids_;
|
std::function<std::array<double,dimWorld>(int)> centroids_;
|
||||||
};
|
};
|
||||||
|
@ -167,6 +167,20 @@ sname(int tracerIdx) const
|
|||||||
return this->eclState_.tracer()[tracerIdx].sname();
|
return this->eclState_.tracer()[tracerIdx].sname();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class Grid,class GridView, class DofMapper, class Stencil, class Scalar>
|
||||||
|
std::string GenericTracerModel<Grid,GridView,DofMapper,Stencil,Scalar>::
|
||||||
|
wellfname(int tracerIdx) const
|
||||||
|
{
|
||||||
|
return this->eclState_.tracer()[tracerIdx].wellfname();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Grid,class GridView, class DofMapper, class Stencil, class Scalar>
|
||||||
|
std::string GenericTracerModel<Grid,GridView,DofMapper,Stencil,Scalar>::
|
||||||
|
wellsname(int tracerIdx) const
|
||||||
|
{
|
||||||
|
return this->eclState_.tracer()[tracerIdx].wellsname();
|
||||||
|
}
|
||||||
|
|
||||||
template<class Grid,class GridView, class DofMapper, class Stencil, class Scalar>
|
template<class Grid,class GridView, class DofMapper, class Stencil, class Scalar>
|
||||||
Scalar GenericTracerModel<Grid,GridView,DofMapper,Stencil,Scalar>::
|
Scalar GenericTracerModel<Grid,GridView,DofMapper,Stencil,Scalar>::
|
||||||
currentConcentration_(const Well& eclWell, const std::string& name) const
|
currentConcentration_(const Well& eclWell, const std::string& name) const
|
||||||
@ -376,7 +390,7 @@ template<class Grid,class GridView, class DofMapper, class Stencil, class Scalar
|
|||||||
bool GenericTracerModel<Grid,GridView,DofMapper,Stencil,Scalar>::
|
bool GenericTracerModel<Grid,GridView,DofMapper,Stencil,Scalar>::
|
||||||
linearSolveBatchwise_(const TracerMatrix& M, std::vector<TracerVector>& x, std::vector<TracerVector>& b)
|
linearSolveBatchwise_(const TracerMatrix& M, std::vector<TracerVector>& x, std::vector<TracerVector>& b)
|
||||||
{
|
{
|
||||||
Scalar tolerance = 1e-2;
|
Scalar tolerance = 1e-6;
|
||||||
int maxIter = 100;
|
int maxIter = 100;
|
||||||
|
|
||||||
int verbosity = 0;
|
int verbosity = 0;
|
||||||
|
@ -158,6 +158,8 @@ public:
|
|||||||
// resize free and solution volume storages
|
// resize free and solution volume storages
|
||||||
fVol1_[this->tracerPhaseIdx_[tracerIdx]].resize(this->freeTracerConcentration_[tracerIdx].size());
|
fVol1_[this->tracerPhaseIdx_[tracerIdx]].resize(this->freeTracerConcentration_[tracerIdx].size());
|
||||||
sVol1_[this->tracerPhaseIdx_[tracerIdx]].resize(this->solTracerConcentration_[tracerIdx].size());
|
sVol1_[this->tracerPhaseIdx_[tracerIdx]].resize(this->solTracerConcentration_[tracerIdx].size());
|
||||||
|
dsVol_[this->tracerPhaseIdx_[tracerIdx]].resize(this->solTracerConcentration_[tracerIdx].size());
|
||||||
|
dfVol_[this->tracerPhaseIdx_[tracerIdx]].resize(this->solTracerConcentration_[tracerIdx].size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// will be valid after we move out of tracerMatrix_
|
// will be valid after we move out of tracerMatrix_
|
||||||
@ -391,6 +393,8 @@ protected:
|
|||||||
|
|
||||||
TracerEvaluation fVol = computeFreeVolume_(tr.phaseIdx_, I, 0) * variable<TracerEvaluation>(1.0, 0);
|
TracerEvaluation fVol = computeFreeVolume_(tr.phaseIdx_, I, 0) * variable<TracerEvaluation>(1.0, 0);
|
||||||
TracerEvaluation sVol = computeSolutionVolume_(tr.phaseIdx_, I, 0) * variable<TracerEvaluation>(1.0, 0);
|
TracerEvaluation sVol = computeSolutionVolume_(tr.phaseIdx_, I, 0) * variable<TracerEvaluation>(1.0, 0);
|
||||||
|
dsVol_[tr.phaseIdx_][I] += sVol.value() * scvVolume - sVol1_[tr.phaseIdx_][I];
|
||||||
|
dfVol_[tr.phaseIdx_][I] += fVol.value() * scvVolume - fVol1_[tr.phaseIdx_][I];
|
||||||
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
||||||
// Free part
|
// Free part
|
||||||
Scalar fStorageOfTimeIndex0 = fVol.value() * tr.concentration_[tIdx][I][0];
|
Scalar fStorageOfTimeIndex0 = fVol.value() * tr.concentration_[tIdx][I][0];
|
||||||
@ -415,7 +419,8 @@ protected:
|
|||||||
const ElementContext& elemCtx,
|
const ElementContext& elemCtx,
|
||||||
unsigned scvfIdx,
|
unsigned scvfIdx,
|
||||||
unsigned I,
|
unsigned I,
|
||||||
unsigned J)
|
unsigned J,
|
||||||
|
const Scalar dt)
|
||||||
{
|
{
|
||||||
if (tr.numTracer() == 0)
|
if (tr.numTracer() == 0)
|
||||||
return;
|
return;
|
||||||
@ -426,6 +431,8 @@ protected:
|
|||||||
bool isUpS;
|
bool isUpS;
|
||||||
computeFreeFlux_(fFlux, isUpF, tr.phaseIdx_, elemCtx, scvfIdx, 0);
|
computeFreeFlux_(fFlux, isUpF, tr.phaseIdx_, elemCtx, scvfIdx, 0);
|
||||||
computeSolFlux_(sFlux, isUpS, tr.phaseIdx_, elemCtx, scvfIdx, 0);
|
computeSolFlux_(sFlux, isUpS, tr.phaseIdx_, elemCtx, scvfIdx, 0);
|
||||||
|
dsVol_[tr.phaseIdx_][I] += sFlux.value() * dt;
|
||||||
|
dfVol_[tr.phaseIdx_][I] += fFlux.value() * dt;
|
||||||
int fGlobalUpIdx = isUpF ? I : J;
|
int fGlobalUpIdx = isUpF ? I : J;
|
||||||
int sGlobalUpIdx = isUpS ? I : J;
|
int sGlobalUpIdx = isUpS ? I : J;
|
||||||
for (int tIdx =0; tIdx < tr.numTracer(); ++tIdx) {
|
for (int tIdx =0; tIdx < tr.numTracer(); ++tIdx) {
|
||||||
@ -455,6 +462,8 @@ protected:
|
|||||||
const auto& eclWell = well.wellEcl();
|
const auto& eclWell = well.wellEcl();
|
||||||
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
||||||
this->wellTracerRate_[std::make_pair(eclWell.name(), this->name(tr.idx_[tIdx]))] = 0.0;
|
this->wellTracerRate_[std::make_pair(eclWell.name(), this->name(tr.idx_[tIdx]))] = 0.0;
|
||||||
|
this->wellFreeTracerRate_[std::make_pair(eclWell.name(), this->wellfname(tr.idx_[tIdx]))] = 0.0;
|
||||||
|
this->wellSolTracerRate_[std::make_pair(eclWell.name(), this->wellsname(tr.idx_[tIdx]))] = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<double> wtracer(tr.numTracer());
|
std::vector<double> wtracer(tr.numTracer());
|
||||||
@ -462,18 +471,18 @@ protected:
|
|||||||
wtracer[tIdx] = this->currentConcentration_(eclWell, this->name(tr.idx_[tIdx]));
|
wtracer[tIdx] = this->currentConcentration_(eclWell, this->name(tr.idx_[tIdx]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scalar dt = simulator_.timeStepSize();
|
||||||
std::size_t well_index = simulator_.problem().wellModel().wellState().index(well.name()).value();
|
std::size_t well_index = simulator_.problem().wellModel().wellState().index(well.name()).value();
|
||||||
const auto& ws = simulator_.problem().wellModel().wellState().well(well_index);
|
const auto& ws = simulator_.problem().wellModel().wellState().well(well_index);
|
||||||
for (std::size_t i = 0; i < ws.perf_data.size(); ++i) {
|
for (std::size_t i = 0; i < ws.perf_data.size(); ++i) {
|
||||||
const auto I = ws.perf_data.cell_index[i];
|
const auto I = ws.perf_data.cell_index[i];
|
||||||
Scalar rate = well.volumetricSurfaceRateForConnection(I, tr.phaseIdx_);
|
Scalar rate = well.volumetricSurfaceRateForConnection(I, tr.phaseIdx_);
|
||||||
|
|
||||||
Scalar rate_s;
|
Scalar rate_s;
|
||||||
if (tr.phaseIdx_ == FluidSystem::oilPhaseIdx && FluidSystem::enableVaporizedOil()) {
|
if (tr.phaseIdx_ == FluidSystem::oilPhaseIdx && FluidSystem::enableVaporizedOil()) {
|
||||||
rate_s = ws.perf_data.phase_mixing_rates[i][ws.dissolved_gas];
|
rate_s = ws.perf_data.phase_mixing_rates[i][ws.vaporized_oil];
|
||||||
}
|
}
|
||||||
else if (tr.phaseIdx_ == FluidSystem::gasPhaseIdx && FluidSystem::enableDissolvedGas()) {
|
else if (tr.phaseIdx_ == FluidSystem::gasPhaseIdx && FluidSystem::enableDissolvedGas()) {
|
||||||
rate_s = ws.perf_data.phase_mixing_rates[i][ws.vaporized_oil];
|
rate_s = ws.perf_data.phase_mixing_rates[i][ws.dissolved_gas];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rate_s = 0.0;
|
rate_s = 0.0;
|
||||||
@ -488,21 +497,37 @@ protected:
|
|||||||
|
|
||||||
// Store _injector_ tracer rate for reporting
|
// Store _injector_ tracer rate for reporting
|
||||||
this->wellTracerRate_.at(std::make_pair(eclWell.name(),this->name(tr.idx_[tIdx]))) += rate_f*wtracer[tIdx];
|
this->wellTracerRate_.at(std::make_pair(eclWell.name(),this->name(tr.idx_[tIdx]))) += rate_f*wtracer[tIdx];
|
||||||
|
this->wellFreeTracerRate_.at(std::make_pair(eclWell.name(),this->wellfname(tr.idx_[tIdx]))) += rate_f*wtracer[tIdx];
|
||||||
}
|
}
|
||||||
|
dfVol_[tr.phaseIdx_][I] -= rate_f * dt;
|
||||||
}
|
}
|
||||||
else if (rate_f < 0) {
|
else if (rate_f < 0) {
|
||||||
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
||||||
// Free and solution tracer production
|
// Free and solution tracer production
|
||||||
tr.residual_[tIdx][I][0] -= rate_f * tr.concentration_[tIdx][I][0];
|
tr.residual_[tIdx][I][0] -= rate_f * tr.concentration_[tIdx][I][0];
|
||||||
tr.residual_[tIdx][I][1] -= rate_s * tr.concentration_[tIdx][I][1];
|
|
||||||
|
|
||||||
// Store _producer_ tracer rate for reporting
|
// Store _producer_ tracer rate for reporting
|
||||||
this->wellTracerRate_.at(std::make_pair(eclWell.name(),this->name(tr.idx_[tIdx]))) +=
|
this->wellTracerRate_.at(std::make_pair(eclWell.name(),this->name(tr.idx_[tIdx]))) +=
|
||||||
rate_f * tr.concentration_[tIdx][I][0] + rate_s * tr.concentration_[tIdx][I][1];
|
rate_f * tr.concentration_[tIdx][I][0];
|
||||||
|
this->wellFreeTracerRate_.at(std::make_pair(eclWell.name(),this->wellfname(tr.idx_[tIdx]))) +=
|
||||||
|
rate_f * tr.concentration_[tIdx][I][0];
|
||||||
}
|
}
|
||||||
|
dfVol_[tr.phaseIdx_][I] -= rate_f * dt;
|
||||||
|
|
||||||
// Derivative matrix for producer
|
// Derivative matrix for producer
|
||||||
(*tr.mat)[I][I][0][0] -= rate_f * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
(*tr.mat)[I][I][0][0] -= rate_f * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
||||||
|
}
|
||||||
|
if (rate_s < 0) {
|
||||||
|
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
||||||
|
tr.residual_[tIdx][I][1] -= rate_s * tr.concentration_[tIdx][I][1];
|
||||||
|
|
||||||
|
this->wellTracerRate_.at(std::make_pair(eclWell.name(),this->name(tr.idx_[tIdx]))) +=
|
||||||
|
rate_s * tr.concentration_[tIdx][I][1];
|
||||||
|
this->wellSolTracerRate_.at(std::make_pair(eclWell.name(),this->wellsname(tr.idx_[tIdx]))) +=
|
||||||
|
rate_s * tr.concentration_[tIdx][I][1];
|
||||||
|
}
|
||||||
|
dsVol_[tr.phaseIdx_][I] -= rate_s * dt;
|
||||||
|
|
||||||
(*tr.mat)[I][I][1][1] -= rate_s * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
(*tr.mat)[I][I][1][1] -= rate_s * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -510,22 +535,20 @@ protected:
|
|||||||
|
|
||||||
template<class TrRe>
|
template<class TrRe>
|
||||||
void assembleTracerEquationSource(TrRe& tr,
|
void assembleTracerEquationSource(TrRe& tr,
|
||||||
const Scalar scvVolume,
|
|
||||||
const Scalar dt,
|
const Scalar dt,
|
||||||
unsigned I)
|
unsigned I)
|
||||||
{
|
{
|
||||||
if (tr.numTracer() == 0)
|
if (tr.numTracer() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Diff dissolved phase volume
|
const Scalar& dsVol = dsVol_[tr.phaseIdx_][I];
|
||||||
Scalar sVol0 = computeSolutionVolume_(tr.phaseIdx_, I, 0) * scvVolume;
|
const Scalar& dfVol = dfVol_[tr.phaseIdx_][I];
|
||||||
Scalar dsVol = sVol0 - sVol1_[tr.phaseIdx_][I];
|
|
||||||
|
|
||||||
// Source term determined by sign of dsVol: if dsVol > 0 then ms -> mf, else mf -> ms
|
// Source term determined by sign of dsVol: if dsVol > 0 then ms -> mf, else mf -> ms
|
||||||
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
||||||
if (dsVol >= 0) {
|
if (dsVol >= 0) {
|
||||||
tr.residual_[tIdx][I][0] += (dsVol / dt) * tr.concentration_[tIdx][I][0];
|
tr.residual_[tIdx][I][0] -= (dfVol / dt) * tr.concentration_[tIdx][I][0];
|
||||||
tr.residual_[tIdx][I][1] -= (dsVol / dt) * tr.concentration_[tIdx][I][0];
|
tr.residual_[tIdx][I][1] += (dfVol / dt) * tr.concentration_[tIdx][I][0];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tr.residual_[tIdx][I][0] += (dsVol / dt) * tr.concentration_[tIdx][I][1];
|
tr.residual_[tIdx][I][0] += (dsVol / dt) * tr.concentration_[tIdx][I][1];
|
||||||
@ -535,12 +558,12 @@ protected:
|
|||||||
|
|
||||||
// Derivative matrix
|
// Derivative matrix
|
||||||
if (dsVol >= 0) {
|
if (dsVol >= 0) {
|
||||||
(*tr.mat)[I][I][0][0] += (dsVol / dt) * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
(*tr.mat)[I][I][0][0] -= (dfVol / dt) * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
||||||
(*tr.mat)[I][I][1][0] -= (dsVol / dt) * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
(*tr.mat)[I][I][1][0] += (dfVol / dt) * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
(*tr.mat)[I][I][1][1] += (dsVol / dt) * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
(*tr.mat)[I][I][0][1] += (dsVol / dt) * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
||||||
(*tr.mat)[I][I][0][1] -= (dsVol / dt) * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
(*tr.mat)[I][I][1][1] -= (dsVol / dt) * variable<TracerEvaluation>(1.0, 0).derivative(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,6 +584,14 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Well terms
|
||||||
|
const auto& wellPtrs = simulator_.problem().wellModel().localNonshutWells();
|
||||||
|
for (const auto& wellPtr : wellPtrs) {
|
||||||
|
for (auto& tr : tbatch) {
|
||||||
|
this->assembleTracerEquationWell(tr, *wellPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ElementContext elemCtx(simulator_);
|
ElementContext elemCtx(simulator_);
|
||||||
for (const auto& elem : elements(simulator_.gridView())) {
|
for (const auto& elem : elements(simulator_.gridView())) {
|
||||||
elemCtx.updateStencil(elem);
|
elemCtx.updateStencil(elem);
|
||||||
@ -603,25 +634,17 @@ protected:
|
|||||||
unsigned j = face.exteriorIndex();
|
unsigned j = face.exteriorIndex();
|
||||||
unsigned J = elemCtx.globalSpaceIndex(/*dofIdx=*/ j, /*timIdx=*/0);
|
unsigned J = elemCtx.globalSpaceIndex(/*dofIdx=*/ j, /*timIdx=*/0);
|
||||||
for (auto& tr : tbatch) {
|
for (auto& tr : tbatch) {
|
||||||
this->assembleTracerEquationFlux(tr, elemCtx, scvfIdx, I, J);
|
this->assembleTracerEquationFlux(tr, elemCtx, scvfIdx, I, J, dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source terms (mass transfer between free and solution tracer)
|
// Source terms (mass transfer between free and solution tracer)
|
||||||
for (auto& tr : tbatch) {
|
for (auto& tr : tbatch) {
|
||||||
this->assembleTracerEquationSource(tr, scvVolume, dt, I);
|
this->assembleTracerEquationSource(tr, dt, I);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Well terms
|
|
||||||
const auto& wellPtrs = simulator_.problem().wellModel().localNonshutWells();
|
|
||||||
for (const auto& wellPtr : wellPtrs) {
|
|
||||||
for (auto& tr : tbatch) {
|
|
||||||
this->assembleTracerEquationWell(tr, *wellPtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Communicate overlap using grid Communication
|
// Communicate overlap using grid Communication
|
||||||
for (auto& tr : tbatch) {
|
for (auto& tr : tbatch) {
|
||||||
if (tr.numTracer() == 0)
|
if (tr.numTracer() == 0)
|
||||||
@ -656,6 +679,8 @@ protected:
|
|||||||
Scalar sVol1 = computeSolutionVolume_(tr.phaseIdx_, globalDofIdx, 0);
|
Scalar sVol1 = computeSolutionVolume_(tr.phaseIdx_, globalDofIdx, 0);
|
||||||
fVol1_[tr.phaseIdx_][globalDofIdx] = fVol1 * scvVolume;
|
fVol1_[tr.phaseIdx_][globalDofIdx] = fVol1 * scvVolume;
|
||||||
sVol1_[tr.phaseIdx_][globalDofIdx] = sVol1 * scvVolume;
|
sVol1_[tr.phaseIdx_][globalDofIdx] = sVol1 * scvVolume;
|
||||||
|
dsVol_[tr.phaseIdx_][globalDofIdx] = 0.0;
|
||||||
|
dfVol_[tr.phaseIdx_][globalDofIdx] = 0.0;
|
||||||
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
||||||
tr.storageOfTimeIndex1_[tIdx][globalDofIdx][0] = fVol1 * tr.concentrationInitial_[tIdx][globalDofIdx][0];
|
tr.storageOfTimeIndex1_[tIdx][globalDofIdx][0] = fVol1 * tr.concentrationInitial_[tIdx][globalDofIdx][0];
|
||||||
tr.storageOfTimeIndex1_[tIdx][globalDofIdx][1] = sVol1 * tr.concentrationInitial_[tIdx][globalDofIdx][1];
|
tr.storageOfTimeIndex1_[tIdx][globalDofIdx][1] = sVol1 * tr.concentrationInitial_[tIdx][globalDofIdx][1];
|
||||||
@ -685,11 +710,30 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
for (int tIdx = 0; tIdx < tr.numTracer(); ++tIdx) {
|
||||||
// New concetration
|
|
||||||
tr.concentration_[tIdx] -= dx[tIdx];
|
|
||||||
|
|
||||||
// Partition concentration into free and solution tracers for output
|
|
||||||
for (std::size_t globalDofIdx = 0; globalDofIdx < tr.concentration_[tIdx].size(); ++globalDofIdx) {
|
for (std::size_t globalDofIdx = 0; globalDofIdx < tr.concentration_[tIdx].size(); ++globalDofIdx) {
|
||||||
|
// New concetration. Concentrations that are negative or where free/solution phase is not
|
||||||
|
// present are set to zero
|
||||||
|
const auto& intQuants = simulator_.model().intensiveQuantities(globalDofIdx, 0);
|
||||||
|
const auto& fs = intQuants.fluidState();
|
||||||
|
Scalar Sf = decay<Scalar>(fs.saturation(tr.phaseIdx_));
|
||||||
|
Scalar Ss = 0.0;
|
||||||
|
if (tr.phaseIdx_ == FluidSystem::gasPhaseIdx && FluidSystem::enableDissolvedGas())
|
||||||
|
Ss = decay<Scalar>(fs.saturation(FluidSystem::oilPhaseIdx));
|
||||||
|
else if (tr.phaseIdx_ == FluidSystem::oilPhaseIdx && FluidSystem::enableVaporizedOil())
|
||||||
|
Ss = decay<Scalar>(fs.saturation(FluidSystem::gasPhaseIdx));
|
||||||
|
|
||||||
|
if ((tr.concentration_[tIdx][globalDofIdx][0] - dx[tIdx][globalDofIdx][0] < 0.0)
|
||||||
|
|| Sf < 1e-6)
|
||||||
|
tr.concentration_[tIdx][globalDofIdx][0] = 0.0;
|
||||||
|
else
|
||||||
|
tr.concentration_[tIdx][globalDofIdx][0] -= dx[tIdx][globalDofIdx][0];
|
||||||
|
if (tr.concentration_[tIdx][globalDofIdx][1] - dx[tIdx][globalDofIdx][1] < 0.0
|
||||||
|
|| Ss < 1e-6)
|
||||||
|
tr.concentration_[tIdx][globalDofIdx][1] = 0.0;
|
||||||
|
else
|
||||||
|
tr.concentration_[tIdx][globalDofIdx][1] -= dx[tIdx][globalDofIdx][1];
|
||||||
|
|
||||||
|
// Partition concentration into free and solution tracers for output
|
||||||
this->freeTracerConcentration_[tr.idx_[tIdx]][globalDofIdx] = tr.concentration_[tIdx][globalDofIdx][0];
|
this->freeTracerConcentration_[tr.idx_[tIdx]][globalDofIdx] = tr.concentration_[tIdx][globalDofIdx][0];
|
||||||
this->solTracerConcentration_[tr.idx_[tIdx]][globalDofIdx] = tr.concentration_[tIdx][globalDofIdx][1];
|
this->solTracerConcentration_[tr.idx_[tIdx]][globalDofIdx] = tr.concentration_[tIdx][globalDofIdx][1];
|
||||||
}
|
}
|
||||||
@ -805,6 +849,8 @@ protected:
|
|||||||
TracerBatch<TracerVector>& gas_;
|
TracerBatch<TracerVector>& gas_;
|
||||||
std::array<std::vector<Scalar>, 3> fVol1_;
|
std::array<std::vector<Scalar>, 3> fVol1_;
|
||||||
std::array<std::vector<Scalar>, 3> sVol1_;
|
std::array<std::vector<Scalar>, 3> sVol1_;
|
||||||
|
std::array<std::vector<Scalar>, 3> dsVol_;
|
||||||
|
std::array<std::vector<Scalar>, 3> dfVol_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
|
@ -267,8 +267,14 @@ template<class Scalar> class WellContributions;
|
|||||||
{
|
{
|
||||||
const auto& tracerRates = this->simulator_.problem()
|
const auto& tracerRates = this->simulator_.problem()
|
||||||
.tracerModel().getWellTracerRates();
|
.tracerModel().getWellTracerRates();
|
||||||
|
const auto& freeTracerRates = simulator_.problem()
|
||||||
|
.tracerModel().getWellFreeTracerRates();
|
||||||
|
const auto& solTracerRates = simulator_.problem()
|
||||||
|
.tracerModel().getWellSolTracerRates();
|
||||||
|
|
||||||
this->assignWellTracerRates(wsrpt, tracerRates);
|
this->assignWellTracerRates(wsrpt, tracerRates);
|
||||||
|
this->assignWellTracerRates(wsrpt, freeTracerRates);
|
||||||
|
this->assignWellTracerRates(wsrpt, solTracerRates);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlackoilWellModelGuideRates(*this)
|
BlackoilWellModelGuideRates(*this)
|
||||||
|
Loading…
Reference in New Issue
Block a user