/* Copyright 2013, 2015 SINTEF ICT, Applied Mathematics. Copyright 2014, 2015 Dr. Blatt - HPC-Simulation-Software & Services Copyright 2014, 2015 Statoil ASA. Copyright 2015 NTNU Copyright 2015, 2016, 2017 IRIS AS 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 . */ #ifndef OPM_BLACKOILMODEL_HEADER_INCLUDED #define OPM_BLACKOILMODEL_HEADER_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Opm { /// A model implementation for three-phase black oil. /// /// The simulator is capable of handling three-phase problems /// where gas can be dissolved in oil and vice versa. It /// uses an industry-standard TPFA discretization with per-phase /// upwind weighting of mobilities. template class BlackoilModel { public: // --------- Types and enums --------- using Simulator = GetPropType; using Grid = GetPropType; using ElementContext = GetPropType; using IntensiveQuantities = GetPropType; using SparseMatrixAdapter = GetPropType; using SolutionVector = GetPropType; using PrimaryVariables = GetPropType; using FluidSystem = GetPropType; using Indices = GetPropType; using MaterialLaw = GetPropType; using MaterialLawParams = GetPropType; using Scalar = GetPropType; using ModelParameters = BlackoilModelParameters; static constexpr int numEq = Indices::numEq; static constexpr int contiSolventEqIdx = Indices::contiSolventEqIdx; static constexpr int contiZfracEqIdx = Indices::contiZfracEqIdx; static constexpr int contiPolymerEqIdx = Indices::contiPolymerEqIdx; static constexpr int contiEnergyEqIdx = Indices::contiEnergyEqIdx; static constexpr int contiPolymerMWEqIdx = Indices::contiPolymerMWEqIdx; static constexpr int contiFoamEqIdx = Indices::contiFoamEqIdx; static constexpr int contiBrineEqIdx = Indices::contiBrineEqIdx; static constexpr int contiMicrobialEqIdx = Indices::contiMicrobialEqIdx; static constexpr int contiOxygenEqIdx = Indices::contiOxygenEqIdx; static constexpr int contiUreaEqIdx = Indices::contiUreaEqIdx; static constexpr int contiBiofilmEqIdx = Indices::contiBiofilmEqIdx; static constexpr int contiCalciteEqIdx = Indices::contiCalciteEqIdx; static constexpr int solventSaturationIdx = Indices::solventSaturationIdx; static constexpr int zFractionIdx = Indices::zFractionIdx; static constexpr int polymerConcentrationIdx = Indices::polymerConcentrationIdx; static constexpr int polymerMoleWeightIdx = Indices::polymerMoleWeightIdx; static constexpr int temperatureIdx = Indices::temperatureIdx; static constexpr int foamConcentrationIdx = Indices::foamConcentrationIdx; static constexpr int saltConcentrationIdx = Indices::saltConcentrationIdx; static constexpr int microbialConcentrationIdx = Indices::microbialConcentrationIdx; static constexpr int oxygenConcentrationIdx = Indices::oxygenConcentrationIdx; static constexpr int ureaConcentrationIdx = Indices::ureaConcentrationIdx; static constexpr int biofilmConcentrationIdx = Indices::biofilmConcentrationIdx; static constexpr int calciteConcentrationIdx = Indices::calciteConcentrationIdx; using VectorBlockType = Dune::FieldVector; using MatrixBlockType = typename SparseMatrixAdapter::MatrixBlock; using Mat = typename SparseMatrixAdapter::IstlMatrix; using BVector = Dune::BlockVector; using ComponentName = ::Opm::ComponentName; // --------- Public methods --------- /// Construct the model. It will retain references to the /// arguments of this functions, and they are expected to /// remain in scope for the lifetime of the solver. /// \param[in] param parameters /// \param[in] grid grid data structure /// \param[in] wells well structure /// \param[in] vfp_properties Vertical flow performance tables /// \param[in] linsolver linear solver /// \param[in] eclState eclipse state /// \param[in] terminal_output request output to cout/cerr BlackoilModel(Simulator& simulator, const ModelParameters& param, BlackoilWellModel& well_model, const bool terminal_output); bool isParallel() const { return grid_.comm().size() > 1; } const EclipseState& eclState() const { return simulator_.vanguard().eclState(); } /// Called once before each time step. /// \param[in] timer simulation timer SimulatorReportSingle prepareStep(const SimulatorTimerInterface& timer); void initialLinearization(SimulatorReportSingle& report, const int iteration, const int minIter, const int maxIter, const SimulatorTimerInterface& timer); /// Called once per nonlinear iteration. /// This model will perform a Newton-Raphson update, changing reservoir_state /// and well_state. It will also use the nonlinear_solver to do relaxation of /// updates if necessary. /// \param[in] iteration should be 0 for the first call of a new timestep /// \param[in] timer simulation timer /// \param[in] nonlinear_solver nonlinear solver used (for oscillation/relaxation control) template SimulatorReportSingle nonlinearIteration(const int iteration, const SimulatorTimerInterface& timer, NonlinearSolverType& nonlinear_solver); template SimulatorReportSingle nonlinearIterationNewton(const int iteration, const SimulatorTimerInterface& timer, NonlinearSolverType& nonlinear_solver); /// Called once after each time step. /// In this class, this function does nothing. /// \param[in] timer simulation timer SimulatorReportSingle afterStep(const SimulatorTimerInterface&); /// Assemble the residual and Jacobian of the nonlinear system. SimulatorReportSingle assembleReservoir(const SimulatorTimerInterface& /* timer */, const int iterationIdx); // compute the "relative" change of the solution between time steps Scalar relativeChange() const; /// Number of linear iterations used in last call to solveJacobianSystem(). int linearIterationsLastSolve() const { return simulator_.model().newtonMethod().linearSolver().iterations (); } // Obtain reference to linear solver setup time double& linearSolveSetupTime() { return linear_solve_setup_time_; } /// Solve the Jacobian system Jx = r where J is the Jacobian and /// r is the residual. void solveJacobianSystem(BVector& x); /// Apply an update to the primary variables. void updateSolution(const BVector& dx); /// Return true if output to cout is wanted. bool terminalOutputEnabled() const { return terminal_output_; } std::tuple convergenceReduction(Parallel::Communication comm, const Scalar pvSumLocal, const Scalar numAquiferPvSumLocal, std::vector& R_sum, std::vector& maxCoeff, std::vector& B_avg); /// \brief Get reservoir quantities on this process needed for convergence calculations. /// \return A pair of the local pore volume of interior cells and the pore volumes /// of the cells associated with a numerical aquifer. std::pair localConvergenceData(std::vector& R_sum, std::vector& maxCoeff, std::vector& B_avg, std::vector& maxCoeffCell); /// \brief Compute pore-volume/cell count split among "converged", /// "relaxed converged", "unconverged" cells based on CNV point /// measures. std::pair, std::vector> characteriseCnvPvSplit(const std::vector& B_avg, const double dt); void updateTUNING(const Tuning& tuning); ConvergenceReport getReservoirConvergence(const double reportTime, const double dt, const int iteration, const int maxIter, std::vector& B_avg, std::vector& residual_norms); /// Compute convergence based on total mass balance (tol_mb) and maximum /// residual mass balance (tol_cnv). /// \param[in] timer simulation timer /// \param[in] iteration current iteration number /// \param[in] maxIter maximum number of iterations /// \param[out] residual_norms CNV residuals by phase ConvergenceReport getConvergence(const SimulatorTimerInterface& timer, const int iteration, const int maxIter, std::vector& residual_norms); /// The number of active fluid phases in the model. int numPhases() const { return phaseUsage_.num_phases; } /// Wrapper required due to not following generic API template std::vector > computeFluidInPlace(const T&, const std::vector& fipnum) const { return this->computeFluidInPlace(fipnum); } /// Should not be called std::vector > computeFluidInPlace(const std::vector& /*fipnum*/) const; const Simulator& simulator() const { return simulator_; } Simulator& simulator() { return simulator_; } /// return the statistics if the nonlinearIteration() method failed const SimulatorReportSingle& failureReport() const { return failureReport_; } /// return the statistics if the nonlinearIteration() method failed SimulatorReportSingle localAccumulatedReports() const; const std::vector& stepReports() const { return convergence_reports_; } void writePartitions(const std::filesystem::path& odir) const; const std::vector>& getConvCells() const { return rst_conv_.getData(); } /// return the StandardWells object BlackoilWellModel& wellModel() { return well_model_; } const BlackoilWellModel& wellModel() const { return well_model_; } void beginReportStep() { simulator_.problem().beginEpisode(); } void endReportStep() { simulator_.problem().endEpisode(); } template void getMaxCoeff(const unsigned cell_idx, const IntensiveQuantities& intQuants, const FluidState& fs, const Residual& modelResid, const Scalar pvValue, std::vector& B_avg, std::vector& R_sum, std::vector& maxCoeff, std::vector& maxCoeffCell); //! \brief Returns const reference to model parameters. const ModelParameters& param() const { return param_; } //! \brief Returns const reference to component names. const ComponentName& compNames() const { return compNames_; } protected: // --------- Data members --------- Simulator& simulator_; const Grid& grid_; const PhaseUsage phaseUsage_; static constexpr bool has_solvent_ = getPropValue(); static constexpr bool has_extbo_ = getPropValue(); static constexpr bool has_polymer_ = getPropValue(); static constexpr bool has_polymermw_ = getPropValue(); static constexpr bool has_energy_ = getPropValue(); static constexpr bool has_foam_ = getPropValue(); static constexpr bool has_brine_ = getPropValue(); static constexpr bool has_micp_ = getPropValue(); ModelParameters param_; SimulatorReportSingle failureReport_; // Well Model BlackoilWellModel& well_model_; RSTConv rst_conv_; //!< Helper class for RPTRST CONV /// \brief Whether we print something to std::cout bool terminal_output_; /// \brief The number of cells of the global grid. long int global_nc_; std::vector> residual_norms_history_; Scalar current_relaxation_; BVector dx_old_; std::vector convergence_reports_; ComponentName compNames_{}; std::unique_ptr> nlddSolver_; //!< Non-linear DD solver BlackoilModelConvergenceMonitor conv_monitor_; private: Scalar dpMaxRel() const { return param_.dp_max_rel_; } Scalar dsMax() const { return param_.ds_max_; } Scalar drMaxRel() const { return param_.dr_max_rel_; } Scalar maxResidualAllowed() const { return param_.max_residual_allowed_; } double linear_solve_setup_time_; std::vector wasSwitched_; }; } // namespace Opm #include #endif // OPM_BLACKOILMODEL_HEADER_INCLUDED