void
    NonlinearSolver<PhysicalModel>::detectOscillations(const std::vector<std::vector<double>>& residual_history,
                                                       const int it,
                                                       bool& oscillate, bool& stagnate) const
    {
        // The detection of oscillation in two primary variable results in the report of the detection
        // of oscillation for the solver.
        // Only the saturations are used for oscillation detection for the black oil model.
        // Stagnate is not used for any treatment here.

        if ( it < 2 ) {
            oscillate = false;
            stagnate = false;
            return;
        }

        stagnate = true;
        int oscillatePhase = 0;
        const std::vector<double>& F0 = residual_history[it];
        const std::vector<double>& F1 = residual_history[it - 1];
        const std::vector<double>& F2 = residual_history[it - 2];
        for (int p= 0; p < model_->numPhases(); ++p){
            const double d1 = std::abs((F0[p] - F2[p]) / F0[p]);
            const double d2 = std::abs((F0[p] - F1[p]) / F0[p]);

            oscillatePhase += (d1 < relaxRelTol()) && (relaxRelTol() < d2);

            // Process is 'stagnate' unless at least one phase
            // exhibits significant residual change.
            stagnate = (stagnate && !(std::abs((F1[p] - F2[p]) / F2[p]) > 1.0e-3));
        }

        oscillate = (oscillatePhase > 1);
    }
예제 #2
0
    int
    NewtonSolver<PhysicalModel>::
    step(const double dt,
         ReservoirState& reservoir_state,
         WellState& well_state)
    {
        // Do model-specific once-per-step calculations.
        model_->prepareStep(dt, reservoir_state, well_state);

        // For each iteration we store in a vector the norms of the residual of
        // the mass balance for each active phase, the well flux and the well equations.
        std::vector<std::vector<double>> residual_norms_history;

        // Assemble residual and Jacobian, store residual norms.
        model_->assemble(reservoir_state, well_state, true);
        residual_norms_history.push_back(model_->computeResidualNorms());

        // Set up for main Newton loop.
        double omega = 1.0;
        int iteration = 0;
        bool converged = model_->getConvergence(dt, iteration);
        const int sizeNonLinear = model_->sizeNonLinear();
        V dxOld = V::Zero(sizeNonLinear);
        bool isOscillate = false;
        bool isStagnate = false;
        const enum RelaxType relaxtype = relaxType();
        int linearIterations = 0;

        // ----------  Main Newton loop  ----------
        while ( (!converged && (iteration < maxIter())) || (minIter() > iteration)) {
            // Compute the Newton update to the primary variables.
            V dx = model_->solveJacobianSystem();

            // Store number of linear iterations used.
            linearIterations += model_->linearIterationsLastSolve();

            // Stabilize the Newton update.
            detectNewtonOscillations(residual_norms_history, iteration, relaxRelTol(), isOscillate, isStagnate);
            if (isOscillate) {
                omega -= relaxIncrement();
                omega = std::max(omega, relaxMax());
                if (model_->terminalOutputEnabled()) {
                    std::cout << " Oscillating behavior detected: Relaxation set to " << omega << std::endl;
                }
            }
            stabilizeNewton(dx, dxOld, omega, relaxtype);

            // Apply the update, the model may apply model-dependent
            // limitations and chopping of the update.
            model_->updateState(dx, reservoir_state, well_state);

            // Assemble residual and Jacobian, store residual norms.
            model_->assemble(reservoir_state, well_state, false);
            residual_norms_history.push_back(model_->computeResidualNorms());

            // increase iteration counter
            ++iteration;

            converged = model_->getConvergence(dt, iteration);
        }

        if (!converged) {
            if (model_->terminalOutputEnabled()) {
                std::cerr << "WARNING: Failed to compute converged solution in " << iteration << " iterations." << std::endl;
            }
            return -1; // -1 indicates that the solver has to be restarted
        }

        linearIterations_ += linearIterations;
        newtonIterations_ += iteration;
        linearIterationsLast_ = linearIterations;
        newtonIterationsLast_ = iteration;

        // Do model-specific post-step actions.
        model_->afterStep(dt, reservoir_state, well_state);

        return linearIterations;
    }