diff --git a/opm/autodiff/MultisegmentWell.hpp b/opm/autodiff/MultisegmentWell.hpp index 3813c8025..b2519e62d 100644 --- a/opm/autodiff/MultisegmentWell.hpp +++ b/opm/autodiff/MultisegmentWell.hpp @@ -135,6 +135,9 @@ namespace Opm virtual void updatePrimaryVariables(const WellState& well_state) const; + virtual void solveEqAndUpdateWellState(const ModelParameters& param, + WellState& well_state); // const? + /// number of segments for this well /// int number_of_segments_; int numberOfSegments() const; @@ -200,10 +203,26 @@ namespace Opm // the values for the primary varibles // based on different solutioin strategies, the wells can have different primary variables // TODO: should we introduce a data structure for segment to simplify this? - mutable std::vector primary_variables_; + // or std::vector > + mutable std::vector > primary_variables_; // the Evaluation for the well primary variables, which contain derivativles and are used in AD calculation - mutable std::vector primary_variables_evaluation_; + mutable std::vector > primary_variables_evaluation_; + + // protected functions + // EvalWell getBhp(); this one should be something similar to getSegmentPressure(); + // EvalWell getQs(); this one should be something similar to getSegmentRates() + // EValWell wellVolumeFractionScaled, wellVolumeFraction, wellSurfaceVolumeFraction ... these should have different names, and probably will be needed. + // bool crossFlowAllowed(const Simulator& ebosSimulator) const; probably will be needed + // xw = inv(D)*(rw - C*x) + void recoverSolutionWell(const BVector& x, BVectorWell& xw) const; + + // updating the well_state based on well solution dwells + void updateWellState(const BVectorWell& dwells, + const BlackoilModelParameters& param, + WellState& well_state) const; + + // void computePerfRate() will be a key function here. }; } diff --git a/opm/autodiff/MultisegmentWell_impl.hpp b/opm/autodiff/MultisegmentWell_impl.hpp new file mode 100644 index 000000000..10f38486e --- /dev/null +++ b/opm/autodiff/MultisegmentWell_impl.hpp @@ -0,0 +1,376 @@ +/* + Copyright 2017 SINTEF Digital, Mathematics and Cybernetics. + Copyright 2017 Statoil ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + + + + +namespace Opm +{ + + template + MultisegmentWell:: + MultisegmentWell(const Well* well, const int time_step, const Wells* wells) + :Basse(well, time_step, wells) + { + // TODO: to see what information we need to process here later. + // const auto& completion_set = well->getCompletions(time_step); + // const auto& segment_set = well->getSegmentSet(time_step); + + // since we decide to use the SegmentSet from the well parser. we can reuse a lot from it. + // other facilities needed we need to process them here + + } + + + + + + template + void + MultisegmentWell:: + init(const PhaseUsage* phase_usage_arg, + const std::vector* active_arg, + const std::vector& depth_arg, + const double gravity_arg, + const int num_cells) + { + Base::init(phase_usage_arg, active_arg, + depth_arg, gravity_arg, num_cells); + + // TODO: for StandardWell, we need to update the perf depth here using depth_arg. + // for MultisegmentWell, it is much more complicated. + // It can be specified directly, it can be calculated from the segment depth, + // it can also use the cell center, which is the same for StandardWell. + // For the last case, should we update the depth with the depth_arg? For the + // future, it can be a source of wrong result with Multisegment well. + // More facility will be required from the opm-parser to make all the situations + // make sense. + } + + + + + + template + void + MultisegmentWell:: + initMatrixAndVectors(const int num_cells) const + { + duneB_.setBuildMode( OffDiagMatWell::row_wise ); + duneC_.setBuildMode( OffDiagMatWell::row_wise ); + invDuneD_.setBuildMode( DiagMatWell::row_wise ); + + // set the size and patterns for all the matrices and vectors + // [A C^T [x = [ res + // B D] x_well] res_well] + + // the number of the nnz should be numSegment() + numberOfOutlet() + invDuneD_.setSize(numSegment(), numSegment(), 100000); + duneB_.setSize(numSegment(), num_cells, number_of_perforations_); + duneC_.setSize(numSegment(), num_cells, number_of_perforations_); + + // we need to add the off diagonal ones + for (auto row=invDuneD_.createbegin(), end = invDuneD_.createend(); row!=end; ++row) { + // Add nonzeros for diagonal + row.insert(row.index()); + } + + for (auto row = duneC_.createbegin(), end = duneC_.createend(); row!=end; ++row) { + // the number of the row corresponds to the segment number now. + for (int perf = 0 ; perf < ]; ++perf) { // the segments hold some perforations + const int cell_idx = wells().well_cells[perf]; + row.insert(cell_idx); + } + } + + // make the B^T matrix + for (auto row = duneB_.createbegin(), end = duneB_.createend(); row!=end; ++row) { + // the number of the row corresponds to the segment number now. + for (int perf = wells().well_connpos[row.index()] ; perf < wells().well_connpos[row.index()+1]; ++perf) { + const int cell_idx = wells().well_cells[perf]; + row.insert(cell_idx); + } + } + + resWell_.resize( nw ); + + // resize temporary class variables + Cx_.resize( duneC_.N() ); + invDrw_.resize( invDuneD_.N() ); + } + + + + + + template + void + MultisegmentWell:: + initPrimaryVariablesEvaluation() const + { + for (int seg = 0; seg < numSegment(); ++seg) { + for (int eq_idx = 0; eq_idx < numWellEq; ++eq_idx) { + primary_variables_evaluation_[seg][eq_idx] = 0.0; + primary_variables_evaluation_[seg][eq_idx].setValue(primary_variables_[seg][eq_idx]); + primary_variables_evaluation_[seg][eq_idx].setDerivative(eq_idx + numEq, 1.0); + } + } + } + + + + + + template + void + MultisegmentWell:: + assembleWellEq(Simulator& ebosSimulator, + const double dt, + WellState& well_state, + bool only_wells) + { + } + + + + + + template + void + MultisegmentWell:: + updateWellStateWithTarget(const int current, + WellState& xw) const + { + // TODO: it can be challenging, when updating the segment and perforation related + // well rates will be okay. + } + + + + + + template + void + MultisegmentWell:: + updateWellControl(WellState& xw, + wellhelpers::WellSwitchingLogger& logger) const + { + // TODO: it will be very similar to the StandardWell, while updateWellStateWithTarget will be chanlleging. + } + + + + + + template + typename MultisegmentWell::ConvergenceReport + MultisegmentWell:: + getWellConvergence(Simulator& ebosSimulator, + const std::vector& B_avg, + const ModelParameters& param) const + { + // TODO: it will be very similar + } + + + + + + template + void + MultisegmentWell:: + computeAccumWell() + { + // it will be vector of compositions of segments + } + + + + + + template + void + MultisegmentWell:: + computeWellConnectionPressures(const Simulator& ebosSimulator, + const WellState& xw) + { + // TODO: the name of the function need to change. + // it will be calculating the pressure difference between the perforation and grid cells + // With MS well, the depth of the perforation is not necessarily the center of the grid cells. + } + + + + + + template + void + MultisegmentWell:: + void apply(const BVector& x, BVector& Ax) const + { + + + } + + + + + + template + void + MultisegmentWell:: + apply(BVector& r) const + { + + + } + + + + + + template + void + MultisegmentWell:: + recoverWellSolutionAndUpdateWellState(const BVector& x, + const ModelParameters& param, + WellState& well_state) const + { + + + + } + + + + + + template + void + MultisegmentWell:: + computeWellPotentials(const Simulator& ebosSimulator, + const WellState& well_state, + std::vector& well_potentials) const + { + + + + } + + + + + + template + void + MultisegmentWell:: + updatePrimaryVariables(const WellState& well_state) const + { + + + } + + + + + + template + void + MultisegmentWell:: + solveEqAndUpdateWellState(const ModelParameters& param, + WellState& well_state) + { + + + } + + + + + + template + const SegmentSet& + MultisegmentWell:: + segmentSet() const + { + return well_ecl_->getSegmentSet(time_step); + } + + + + + + template + int + MultisegmentWell:: + numberOfSegments() const + { + return segmentSet().numberSegment(); + } + + + + + + template + int + MultisegmentWell:: + numberOfPerforations() const + { + return segmentSet().number_of_perforations_; + } + + + + + + template + WellSegment::CompPressureDropEnum + MultisegmentWell:: + compPressureDrop() const + { + return segmentSet().compPressureDrop(); + } + + + + + + template + WellSegment::MultiPhaseModelEnum + MultisegmentWell:: + multiphaseModel() const + { + return segmentSet().multiPhaseModel(); + } + + + + + + template + int + MultisegmentWell:: + numberToLocation(const int segment_number) const + { + return segmentSet().numberToLocation(segment_number); + } + +} diff --git a/opm/autodiff/StandardWell.hpp b/opm/autodiff/StandardWell.hpp index b32b25344..2d1185d01 100644 --- a/opm/autodiff/StandardWell.hpp +++ b/opm/autodiff/StandardWell.hpp @@ -153,6 +153,8 @@ namespace Opm virtual void updatePrimaryVariables(const WellState& well_state) const; + virtual void solveEqAndUpdateWellState(const ModelParameters& param, + WellState& well_state); protected: // protected functions from the Base class @@ -268,9 +270,6 @@ namespace Opm const std::vector& rvmax_perf, const std::vector& surf_dens_perf); - virtual void solveEqAndUpdateWellState(const ModelParameters& param, - WellState& well_state); - // TODO: to check whether all the paramters are required void computePerfRate(const IntensiveQuantities& intQuants, const std::vector& mob_perfcells_dense,