mirror of
				https://github.com/OPM/opm-simulators.git
				synced 2025-02-25 18:55:30 -06:00 
			
		
		
		
	Make WTEST more robust
Only open wells that are solvable, operable and economical
This commit is contained in:
		@@ -273,7 +273,7 @@ partiallySupported()
 | 
			
		||||
         {
 | 
			
		||||
            "WTEST",
 | 
			
		||||
            {
 | 
			
		||||
               {3,{false, allow_values<std::string> {"E", ""}, "WTEST(TEST): only the E (economic) option is currently supported – will continue"}}, // REASON
 | 
			
		||||
               {3,{false, allow_values<std::string> {"E", "P", ""}, "WTEST(TEST): only the E (economic) and P (physical) option is currently supported – will continue"}}, // REASON
 | 
			
		||||
            },
 | 
			
		||||
         },
 | 
			
		||||
   };
 | 
			
		||||
 
 | 
			
		||||
@@ -382,12 +382,10 @@ namespace Opm {
 | 
			
		||||
    {
 | 
			
		||||
        const auto& wtest_config = schedule()[timeStepIdx].wtest_config();
 | 
			
		||||
        if (wtest_config.size() != 0) { // there is a WTEST request
 | 
			
		||||
            const auto wellsForTesting = wellTestState()
 | 
			
		||||
            const std::vector<std::string> wellsForTesting = wellTestState()
 | 
			
		||||
                .updateWells(wtest_config, wells_ecl_, simulationTime);
 | 
			
		||||
 | 
			
		||||
            for (const auto& testWell : wellsForTesting) {
 | 
			
		||||
                const std::string& well_name = testWell.first;
 | 
			
		||||
 | 
			
		||||
            for (const std::string& well_name : wellsForTesting) {
 | 
			
		||||
                // this is the well we will test
 | 
			
		||||
                WellInterfacePtr well = createWellForWellTest(well_name, timeStepIdx, deferred_logger);
 | 
			
		||||
 | 
			
		||||
@@ -402,10 +400,7 @@ namespace Opm {
 | 
			
		||||
                well->setVFPProperties(vfp_properties_.get());
 | 
			
		||||
                well->setGuideRate(&guideRate_);
 | 
			
		||||
 | 
			
		||||
                const WellTestConfig::Reason testing_reason = testWell.second;
 | 
			
		||||
 | 
			
		||||
                well->wellTesting(ebosSimulator_, simulationTime, timeStepIdx,
 | 
			
		||||
                                  testing_reason, this->wellState(), this->groupState(), wellTestState(), deferred_logger);
 | 
			
		||||
                well->wellTesting(ebosSimulator_, simulationTime, this->wellState(), this->groupState(), wellTestState(), deferred_logger);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -234,8 +234,7 @@ public:
 | 
			
		||||
    // TODO: theoretically, it should be a const function
 | 
			
		||||
    // Simulator is not const is because that assembleWellEq is non-const Simulator
 | 
			
		||||
    void wellTesting(const Simulator& simulator,
 | 
			
		||||
                     const double simulation_time, const int report_step,
 | 
			
		||||
                     const WellTestConfig::Reason testing_reason,
 | 
			
		||||
                     const double simulation_time,
 | 
			
		||||
                     /* const */ WellState& well_state, const GroupState& group_state, WellTestState& welltest_state,
 | 
			
		||||
                     DeferredLogger& deferred_logger);
 | 
			
		||||
 | 
			
		||||
@@ -300,18 +299,6 @@ protected:
 | 
			
		||||
 | 
			
		||||
    virtual void updateIPR(const Simulator& ebos_simulator, DeferredLogger& deferred_logger) const=0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void wellTestingEconomic(const Simulator& simulator,
 | 
			
		||||
                             const double simulation_time, WellState& well_state, const GroupState& group_state,
 | 
			
		||||
                             WellTestState& welltest_state, DeferredLogger& deferred_logger);
 | 
			
		||||
 | 
			
		||||
    void wellTestingPhysical(const Simulator& simulator,
 | 
			
		||||
                             const double simulation_time, const int report_step,
 | 
			
		||||
                             WellState& well_state,
 | 
			
		||||
                             const GroupState& group_state,
 | 
			
		||||
                             WellTestState& welltest_state, DeferredLogger& deferred_logger);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    virtual void assembleWellEqWithoutIteration(const Simulator& ebosSimulator,
 | 
			
		||||
                                                const double dt,
 | 
			
		||||
                                                const Well::InjectionControls& inj_controls,
 | 
			
		||||
@@ -335,7 +322,7 @@ protected:
 | 
			
		||||
                              const GroupState& group_state,
 | 
			
		||||
                              DeferredLogger& deferred_logger);
 | 
			
		||||
 | 
			
		||||
    void solveWellForTesting(const Simulator& ebosSimulator, WellState& well_state, const GroupState& group_state,
 | 
			
		||||
    bool solveWellForTesting(const Simulator& ebosSimulator, WellState& well_state, const GroupState& group_state,
 | 
			
		||||
                             DeferredLogger& deferred_logger);
 | 
			
		||||
 | 
			
		||||
    bool shutUnsolvableWells() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -214,36 +214,13 @@ namespace Opm
 | 
			
		||||
    void
 | 
			
		||||
    WellInterface<TypeTag>::
 | 
			
		||||
    wellTesting(const Simulator& simulator,
 | 
			
		||||
                const double simulation_time, const int report_step,
 | 
			
		||||
                const WellTestConfig::Reason testing_reason,
 | 
			
		||||
                const double simulation_time,
 | 
			
		||||
                /* const */ WellState& well_state,
 | 
			
		||||
                const GroupState& group_state,
 | 
			
		||||
                WellTestState& well_test_state,
 | 
			
		||||
                DeferredLogger& deferred_logger)
 | 
			
		||||
    {
 | 
			
		||||
        if (testing_reason == WellTestConfig::Reason::PHYSICAL) {
 | 
			
		||||
            wellTestingPhysical(simulator, simulation_time, report_step,
 | 
			
		||||
                                well_state, group_state, well_test_state, deferred_logger);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (testing_reason == WellTestConfig::Reason::ECONOMIC) {
 | 
			
		||||
            wellTestingEconomic(simulator, simulation_time,
 | 
			
		||||
                                well_state, group_state, well_test_state, deferred_logger);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    template<typename TypeTag>
 | 
			
		||||
    void
 | 
			
		||||
    WellInterface<TypeTag>::
 | 
			
		||||
    wellTestingEconomic(const Simulator& simulator,
 | 
			
		||||
                        const double simulation_time, WellState& well_state, const GroupState& group_state,
 | 
			
		||||
                        WellTestState& welltest_state, DeferredLogger& deferred_logger)
 | 
			
		||||
    {
 | 
			
		||||
        deferred_logger.info(" well " + this->name() + " is being tested for economic limits");
 | 
			
		||||
        deferred_logger.info(" well " + this->name() + " is being tested");
 | 
			
		||||
 | 
			
		||||
        WellState well_state_copy = well_state;
 | 
			
		||||
        auto& ws = well_state_copy.well(this->indexOfWell());
 | 
			
		||||
@@ -261,13 +238,27 @@ namespace Opm
 | 
			
		||||
        // untill the number of closed completions do not increase anymore.
 | 
			
		||||
        while (testWell) {
 | 
			
		||||
            const size_t original_number_closed_completions = welltest_state_temp.sizeCompletions();
 | 
			
		||||
            solveWellForTesting(simulator, well_state_copy, group_state, deferred_logger);
 | 
			
		||||
            bool converged = solveWellForTesting(simulator, well_state_copy, group_state, deferred_logger);
 | 
			
		||||
            if (!converged) {
 | 
			
		||||
                const auto msg = fmt::format("WTEST: Well {} is not solvable (physical)", this->name());
 | 
			
		||||
                deferred_logger.debug(msg);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            updateWellOperability(simulator, well_state_copy, deferred_logger);
 | 
			
		||||
            if ( !this->isOperable() ) {
 | 
			
		||||
                const auto msg = fmt::format("WTEST: Well {} is not operable (physical)", this->name());
 | 
			
		||||
                deferred_logger.debug(msg);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            std::vector<double> potentials;
 | 
			
		||||
            try {
 | 
			
		||||
                computeWellPotentials(simulator, well_state_copy, potentials, deferred_logger);
 | 
			
		||||
            } catch (const std::exception& e) {
 | 
			
		||||
                const std::string msg = std::string("well ") + this->name() + std::string(": computeWellPotentials() failed during testing for re-opening: ") + e.what();
 | 
			
		||||
                deferred_logger.info(msg);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            const int np = well_state_copy.numPhases();
 | 
			
		||||
            for (int p = 0; p < np; ++p) {
 | 
			
		||||
@@ -287,15 +278,16 @@ namespace Opm
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // update wellTestState if the well test succeeds
 | 
			
		||||
        if (!welltest_state_temp.hasWellClosed(this->name(), WellTestConfig::Reason::ECONOMIC)) {
 | 
			
		||||
            welltest_state.openWell(this->name(), WellTestConfig::Reason::ECONOMIC);
 | 
			
		||||
            const std::string msg = std::string("well ") + this->name() + std::string(" is re-opened through ECONOMIC testing");
 | 
			
		||||
        if (!welltest_state_temp.hasWellClosed(this->name())) {
 | 
			
		||||
            well_test_state.openWell(this->name());
 | 
			
		||||
 | 
			
		||||
            std::string msg = std::string("well ") + this->name() + std::string(" is re-opened");
 | 
			
		||||
            deferred_logger.info(msg);
 | 
			
		||||
 | 
			
		||||
            // also reopen completions
 | 
			
		||||
            for (auto& completion : this->well_ecl_.getCompletions()) {
 | 
			
		||||
                if (!welltest_state_temp.hasCompletion(this->name(), completion.first)) {
 | 
			
		||||
                    welltest_state.dropCompletion(this->name(), completion.first);
 | 
			
		||||
                    well_test_state.dropCompletion(this->name(), completion.first);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // set the status of the well_state to open
 | 
			
		||||
@@ -306,6 +298,7 @@ namespace Opm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    template<typename TypeTag>
 | 
			
		||||
    bool
 | 
			
		||||
    WellInterface<TypeTag>::
 | 
			
		||||
@@ -324,7 +317,7 @@ namespace Opm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    template<typename TypeTag>
 | 
			
		||||
    void
 | 
			
		||||
    bool
 | 
			
		||||
    WellInterface<TypeTag>::
 | 
			
		||||
    solveWellForTesting(const Simulator& ebosSimulator, WellState& well_state, const GroupState& group_state,
 | 
			
		||||
                        DeferredLogger& deferred_logger)
 | 
			
		||||
@@ -335,13 +328,15 @@ namespace Opm
 | 
			
		||||
        const bool converged = iterateWellEquations(ebosSimulator, dt, well_state, group_state, deferred_logger);
 | 
			
		||||
        if (converged) {
 | 
			
		||||
            deferred_logger.debug("WellTest: Well equation for well " + this->name() +  " converged");
 | 
			
		||||
        } else {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        const int max_iter = param_.max_welleq_iter_;
 | 
			
		||||
        deferred_logger.debug("WellTest: Well equation for well " + this->name() + " failed converging in "
 | 
			
		||||
                              + std::to_string(max_iter) + " iterations");
 | 
			
		||||
        well_state = well_state0;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    template<typename TypeTag>
 | 
			
		||||
    void
 | 
			
		||||
@@ -449,82 +444,6 @@ namespace Opm
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    template<typename TypeTag>
 | 
			
		||||
    void
 | 
			
		||||
    WellInterface<TypeTag>::
 | 
			
		||||
    wellTestingPhysical(const Simulator& ebos_simulator,
 | 
			
		||||
                        const double /* simulation_time */, const int /* report_step */,
 | 
			
		||||
                        WellState& well_state,
 | 
			
		||||
                        const GroupState& group_state,
 | 
			
		||||
                        WellTestState& welltest_state,
 | 
			
		||||
                        DeferredLogger& deferred_logger)
 | 
			
		||||
    {
 | 
			
		||||
        deferred_logger.info(" well " + this->name() + " is being tested for physical limits");
 | 
			
		||||
 | 
			
		||||
        // some most difficult things are the explicit quantities, since there is no information
 | 
			
		||||
        // in the WellState to do a decent initialization
 | 
			
		||||
 | 
			
		||||
        // TODO: Let us assume that the simulator is updated
 | 
			
		||||
 | 
			
		||||
        // Let us try to do a normal simualtion running, to keep checking the operability status
 | 
			
		||||
        // If the well is not operable during any of the time. It means it does not pass the physical
 | 
			
		||||
        // limit test.
 | 
			
		||||
 | 
			
		||||
        // create a copy of the well_state to use. If the operability checking is sucessful, we use this one
 | 
			
		||||
        // to replace the original one
 | 
			
		||||
        WellState well_state_copy = well_state;
 | 
			
		||||
        auto& ws = well_state_copy.well(this->indexOfWell());
 | 
			
		||||
 | 
			
		||||
        // TODO: well state for this well is kind of all zero status
 | 
			
		||||
        // we should be able to provide a better initialization
 | 
			
		||||
        calculateExplicitQuantities(ebos_simulator, well_state_copy, deferred_logger);
 | 
			
		||||
 | 
			
		||||
        updateWellOperability(ebos_simulator, well_state_copy, deferred_logger);
 | 
			
		||||
 | 
			
		||||
        if ( !this->isOperable() ) {
 | 
			
		||||
            const std::string msg = " well " + this->name() + " is not operable during well testing for physical reason";
 | 
			
		||||
            deferred_logger.debug(msg);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        updateWellStateWithTarget(ebos_simulator, group_state, well_state_copy, deferred_logger);
 | 
			
		||||
 | 
			
		||||
        calculateExplicitQuantities(ebos_simulator, well_state_copy, deferred_logger);
 | 
			
		||||
 | 
			
		||||
        const double dt = ebos_simulator.timeStepSize();
 | 
			
		||||
        const bool converged = this->iterateWellEquations(ebos_simulator, dt, well_state_copy, group_state, deferred_logger);
 | 
			
		||||
 | 
			
		||||
        if (!converged) {
 | 
			
		||||
            const std::string msg = " well " + this->name() + " did not get converged during well testing for physical reason";
 | 
			
		||||
            deferred_logger.debug(msg);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this->isOperable() ) {
 | 
			
		||||
            welltest_state.openWell(this->name(), WellTestConfig::PHYSICAL );
 | 
			
		||||
            const std::string msg = " well " + this->name() + " is re-opened through well testing for physical reason";
 | 
			
		||||
            deferred_logger.info(msg);
 | 
			
		||||
            // we need to populate the new well with potentials
 | 
			
		||||
            std::vector<double> potentials;
 | 
			
		||||
            try {
 | 
			
		||||
                computeWellPotentials(ebos_simulator, well_state_copy, potentials, deferred_logger);
 | 
			
		||||
            } catch (const std::exception& e) {
 | 
			
		||||
                const std::string msg2 = std::string("well ") + this->name() + std::string(": computeWellPotentials() failed during testing for re-opening: ") + e.what();
 | 
			
		||||
                deferred_logger.info(msg2);
 | 
			
		||||
            }
 | 
			
		||||
            const int np = well_state_copy.numPhases();
 | 
			
		||||
            for (int p = 0; p < np; ++p) {
 | 
			
		||||
                ws.well_potentials[p] = std::abs(potentials[p]);
 | 
			
		||||
            }
 | 
			
		||||
            //set the status of the well_state to open
 | 
			
		||||
            ws.open();
 | 
			
		||||
            well_state = well_state_copy;
 | 
			
		||||
        } else {
 | 
			
		||||
            const std::string msg = " well " + this->name() + " is not operable during well testing for physical reason";
 | 
			
		||||
            deferred_logger.debug(msg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    template<typename TypeTag>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user