mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Add well operator for NLDD domains
This commit is contained in:
parent
e53a3fd3f4
commit
3ea5c5820e
@ -169,6 +169,7 @@ public:
|
||||
loc_param.linear_solver_print_json_definition_ = false;
|
||||
const bool force_serial = true;
|
||||
domain_linsolvers_.emplace_back(model_.simulator(), loc_param, force_serial);
|
||||
domain_linsolvers_.back().setDomainIndex(index);
|
||||
}
|
||||
|
||||
assert(int(domains_.size()) == num_domains);
|
||||
|
@ -352,6 +352,8 @@ std::unique_ptr<Matrix> blockJacobiAdjacency(const Grid& grid,
|
||||
// Outch! We need to be able to scale the linear system! Hence const_cast
|
||||
matrix_ = const_cast<Matrix*>(&M);
|
||||
|
||||
is_nldd_local_solver_ = parameters_[activeSolverNum_].is_nldd_local_solver_;
|
||||
|
||||
useWellConn_ = Parameters::Get<Parameters::MatrixAddWellContributions>();
|
||||
// setup sparsity pattern for jacobi matrix for preconditioner (only used for openclSolver)
|
||||
} else {
|
||||
@ -450,6 +452,11 @@ std::unique_ptr<Matrix> blockJacobiAdjacency(const Grid& grid,
|
||||
|
||||
const CommunicationType* comm() const { return comm_.get(); }
|
||||
|
||||
void setDomainIndex(int index)
|
||||
{
|
||||
domainIndex_ = index;
|
||||
}
|
||||
|
||||
protected:
|
||||
#if HAVE_MPI
|
||||
using Comm = Dune::OwnerOverlapCopyCommunication<int, int>;
|
||||
@ -490,8 +497,15 @@ std::unique_ptr<Matrix> blockJacobiAdjacency(const Grid& grid,
|
||||
OPM_TIMEBLOCK(flexibleSolverPrepare);
|
||||
if (shouldCreateSolver()) {
|
||||
if (!useWellConn_) {
|
||||
auto wellOp = std::make_unique<WellModelOperator>(simulator_.problem().wellModel());
|
||||
flexibleSolver_[activeSolverNum_].wellOperator_ = std::move(wellOp);
|
||||
if (is_nldd_local_solver_) {
|
||||
auto wellOp = std::make_unique<DomainWellModelAsLinearOperator<WellModel, Vector, Vector>>(simulator_.problem().wellModel());
|
||||
wellOp->setDomainIndex(domainIndex_);
|
||||
flexibleSolver_[activeSolverNum_].wellOperator_ = std::move(wellOp);
|
||||
}
|
||||
else {
|
||||
auto wellOp = std::make_unique<WellModelOperator>(simulator_.problem().wellModel());
|
||||
flexibleSolver_[activeSolverNum_].wellOperator_ = std::move(wellOp);
|
||||
}
|
||||
}
|
||||
std::function<Vector()> weightCalculator = this->getWeightsCalculator(prm_[activeSolverNum_], getMatrix(), pressureIndex);
|
||||
OPM_TIMEBLOCK(flexibleSolverCreate);
|
||||
@ -651,6 +665,10 @@ std::unique_ptr<Matrix> blockJacobiAdjacency(const Grid& grid,
|
||||
std::vector<int> overlapRows_;
|
||||
std::vector<int> interiorRows_;
|
||||
|
||||
bool is_nldd_local_solver_;
|
||||
|
||||
int domainIndex_ = -1;
|
||||
|
||||
bool useWellConn_;
|
||||
|
||||
std::vector<FlowLinearSolverParameters> parameters_;
|
||||
|
@ -123,10 +123,46 @@ public:
|
||||
return wellMod_.numLocalWellsEnd();
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
const WellModel& wellMod_;
|
||||
};
|
||||
|
||||
|
||||
template <class WellModel, class X, class Y>
|
||||
class DomainWellModelAsLinearOperator : public WellModelAsLinearOperator<WellModel, X, Y>
|
||||
{
|
||||
public:
|
||||
using WBase = WellModelAsLinearOperator<WellModel, X, Y>;
|
||||
using WBase::WBase; // inherit all constructors from the base class
|
||||
using field_type = typename WBase::field_type;
|
||||
using PressureMatrix = typename WBase::PressureMatrix;
|
||||
|
||||
void setDomainIndex(int index) { domainIndex_ = index; }
|
||||
|
||||
void apply(const X& x, Y& y) const override
|
||||
{
|
||||
OPM_TIMEBLOCK(apply);
|
||||
this->wellMod_.applyDomain(x, y, domainIndex_);
|
||||
}
|
||||
|
||||
void applyscaleadd(field_type alpha, const X& x, Y& y) const override
|
||||
{
|
||||
OPM_TIMEBLOCK(applyscaleadd);
|
||||
this->wellMod_.applyScaleAddDomain(alpha, x, y, domainIndex_);
|
||||
}
|
||||
|
||||
void addWellPressureEquations(PressureMatrix& jacobian,
|
||||
const X& weights,
|
||||
const bool use_well_weights) const override
|
||||
{
|
||||
OPM_TIMEBLOCK(addWellPressureEquations);
|
||||
this->wellMod_.addWellPressureEquationsDomain(jacobian, weights, use_well_weights, domainIndex_);
|
||||
}
|
||||
|
||||
private:
|
||||
int domainIndex_ = -1;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Adapter to combine a matrix and another linear operator into
|
||||
a combined linear operator.
|
||||
|
@ -300,6 +300,8 @@ template<class Scalar> class WellContributions;
|
||||
// subtract B*inv(D)*C * x from A*x
|
||||
void apply(const BVector& x, BVector& Ax) const;
|
||||
|
||||
void applyDomain(const BVector& x, BVector& Ax, int domainIndex) const;
|
||||
|
||||
#if COMPILE_BDA_BRIDGE
|
||||
// accumulate the contributions of all Wells in the WellContributions object
|
||||
void getWellContributions(WellContributions<Scalar>& x) const;
|
||||
@ -308,6 +310,8 @@ template<class Scalar> class WellContributions;
|
||||
// apply well model with scaling of alpha
|
||||
void applyScaleAdd(const Scalar alpha, const BVector& x, BVector& Ax) const;
|
||||
|
||||
void applyScaleAddDomain(const Scalar alpha, const BVector& x, BVector& Ax, int domainIndex) const;
|
||||
|
||||
// Check if well equations is converged.
|
||||
ConvergenceReport getWellConvergence(const std::vector<Scalar>& B_avg, const bool checkWellGroupControls = false) const;
|
||||
|
||||
@ -358,6 +362,9 @@ template<class Scalar> class WellContributions;
|
||||
|
||||
void addWellPressureEquations(PressureMatrix& jacobian, const BVector& weights,const bool use_well_weights) const;
|
||||
|
||||
void addWellPressureEquationsDomain(PressureMatrix& jacobian, const BVector& weights,const bool use_well_weights, int domainIndex) const;
|
||||
|
||||
|
||||
void addWellPressureEquationsStruct(PressureMatrix& jacobian) const;
|
||||
|
||||
void initGliftEclWellMap(GLiftEclWells &ecl_well_map);
|
||||
|
@ -1749,9 +1749,36 @@ namespace Opm {
|
||||
x_local.resize(cells.size());
|
||||
Ax_local.resize(cells.size());
|
||||
|
||||
if (this->param_.nonlinear_solver_ == "nldd") {
|
||||
// transfer global cells index to local subdomain cells index
|
||||
for (size_t i = 0; i < cells.size(); ++i) {
|
||||
x_local[i] = x[cells[i]];
|
||||
Ax_local[i] = Ax[cells[i]];
|
||||
}
|
||||
|
||||
well->apply(x_local, Ax_local);
|
||||
|
||||
for (size_t i = 0; i < cells.size(); ++i) {
|
||||
// only need to update Ax
|
||||
Ax[cells[i]] = Ax_local[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ax = A x - C D^-1 B x
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModel<TypeTag>::
|
||||
applyDomain(const BVector& x, BVector& Ax, int domainIndex) const
|
||||
{
|
||||
BVector x_local;
|
||||
BVector Ax_local;
|
||||
|
||||
for (auto& well : well_container_) {
|
||||
if (well_domain_.at(well->name()) == domainIndex) {
|
||||
// Well equations B and C uses only the perforated cells, so need to apply on local vectors
|
||||
auto cells = well->cells();
|
||||
x_local.resize(cells.size());
|
||||
Ax_local.resize(cells.size());
|
||||
// transfer global cells index to local subdomain cells index
|
||||
auto domain_cells = domains_cells_[well_domain_.at(well->name())];
|
||||
|
||||
// Assuming domain_cells is sorted
|
||||
@ -1765,18 +1792,18 @@ namespace Opm {
|
||||
std::cerr << "Cell value " << cells[i] << " not found in domain_cells." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cells.size(); ++i) {
|
||||
x_local[i] = x[cells[i]];
|
||||
Ax_local[i] = Ax[cells[i]];
|
||||
}
|
||||
for (size_t i = 0; i < cells.size(); ++i) {
|
||||
x_local[i] = x[cells[i]];
|
||||
Ax_local[i] = Ax[cells[i]];
|
||||
}
|
||||
|
||||
well->apply(x_local, Ax_local);
|
||||
well->apply(x_local, Ax_local);
|
||||
|
||||
for (size_t i = 0; i < cells.size(); ++i) {
|
||||
// only need to update Ax
|
||||
Ax[cells[i]] = Ax_local[i];
|
||||
for (size_t i = 0; i < cells.size(); ++i) {
|
||||
// only need to update Ax
|
||||
Ax[cells[i]] = Ax_local[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1840,6 +1867,27 @@ namespace Opm {
|
||||
Ax.axpy( alpha, scaleAddRes_ );
|
||||
}
|
||||
|
||||
// Ax = Ax - alpha * C D^-1 B x
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModel<TypeTag>::
|
||||
applyScaleAddDomain(const Scalar alpha, const BVector& x, BVector& Ax, int domainIndex) const
|
||||
{
|
||||
if (this->well_container_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( scaleAddRes_.size() != Ax.size() ) {
|
||||
scaleAddRes_.resize( Ax.size() );
|
||||
}
|
||||
|
||||
scaleAddRes_ = 0.0;
|
||||
// scaleAddRes_ = - C D^-1 B x
|
||||
applyDomain(x, scaleAddRes_, domainIndex);
|
||||
// Ax = Ax + alpha * scaleAddRes_
|
||||
Ax.axpy( alpha, scaleAddRes_ );
|
||||
}
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModel<TypeTag>::
|
||||
@ -1867,6 +1915,28 @@ namespace Opm {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModel<TypeTag>::
|
||||
addWellPressureEquationsDomain(PressureMatrix& jacobian, const BVector& weights,const bool use_well_weights, int domainIndex) const
|
||||
{
|
||||
throw std::logic_error("CPRW is not yet implemented for NLDD subdomains");
|
||||
// To fix this function, rdofs should be the size of the domain, and the nw should be the number of wells in the domain
|
||||
// int nw = this->numLocalWellsEnd(); // should number of wells in the domain
|
||||
// int rdofs = local_num_cells_; // should be the size of the domain
|
||||
// for ( int i = 0; i < nw; i++ ){
|
||||
// int wdof = rdofs + i;
|
||||
// jacobian[wdof][wdof] = 1.0;// better scaling ?
|
||||
// }
|
||||
|
||||
// for ( const auto& well : well_container_ ) {
|
||||
// if (well_domain_.at(well->name()) == domainIndex) {
|
||||
// weights should be the size of the domain
|
||||
// well->addWellPressureEquations(jacobian, weights, pressureVarIndex, use_well_weights, this->wellState());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
template <typename TypeTag>
|
||||
void BlackoilWellModel<TypeTag>::
|
||||
addReservoirSourceTerms(GlobalEqVector& residual,
|
||||
|
Loading…
Reference in New Issue
Block a user