コード例 #1
0
    inline void BlackoilPropertiesFromDeck::init(Opm::DeckConstPtr deck,
                                                 Opm::EclipseStateConstPtr eclState,
                                                 int number_of_cells,
                                                 const int* global_cell,
                                                 const int* cart_dims,
                                                 const CentroidIterator& begin_cell_centroids,
                                                 int dimension,
                                                 const parameter::ParameterGroup& param,
                                                 bool init_rock)
    {
        // retrieve the cell specific PVT table index from the deck
        // and using the grid...
        extractPvtTableIndex(cellPvtRegionIdx_, deck, number_of_cells, global_cell);

        if(init_rock){
            rock_.init(eclState, number_of_cells, global_cell, cart_dims);
        }

        const int pvt_samples = param.getDefault("pvt_tab_size", -1);
        pvt_.init(deck, pvt_samples);

        // Unfortunate lack of pointer smartness here...
        const int sat_samples = param.getDefault("sat_tab_size", -1);
        std::string threephase_model = param.getDefault<std::string>("threephase_model", "gwseg");
        if (deck->hasKeyword("ENDSCALE") && threephase_model != "gwseg") {
            OPM_THROW(std::runtime_error, "Sorry, end point scaling currently available for the 'gwseg' model only.");
        }
        if (sat_samples > 1) {
            if (threephase_model == "stone2") {
                SaturationPropsFromDeck<SatFuncStone2Uniform>* ptr
                    = new SaturationPropsFromDeck<SatFuncStone2Uniform>();
                satprops_.reset(ptr);
                ptr->init(deck, eclState, number_of_cells, global_cell, begin_cell_centroids,
                          dimension, sat_samples);
            } else if (threephase_model == "simple") {
                SaturationPropsFromDeck<SatFuncSimpleUniform>* ptr
                    = new SaturationPropsFromDeck<SatFuncSimpleUniform>();
                satprops_.reset(ptr);
                ptr->init(deck, eclState, number_of_cells, global_cell, begin_cell_centroids,
                          dimension, sat_samples);
            } else if (threephase_model == "gwseg") {
                SaturationPropsFromDeck<SatFuncGwsegUniform>* ptr
                    = new SaturationPropsFromDeck<SatFuncGwsegUniform>();
                satprops_.reset(ptr);
                ptr->init(deck, eclState, number_of_cells, global_cell, begin_cell_centroids,
                          dimension, sat_samples);
            } else {
                OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
            }
        } else {
            if (threephase_model == "stone2") {
                SaturationPropsFromDeck<SatFuncStone2Nonuniform>* ptr
                    = new SaturationPropsFromDeck<SatFuncStone2Nonuniform>();
                satprops_.reset(ptr);
                ptr->init(deck, eclState, number_of_cells, global_cell, begin_cell_centroids,
                          dimension, sat_samples);
            } else if (threephase_model == "simple") {
                SaturationPropsFromDeck<SatFuncSimpleNonuniform>* ptr
                    = new SaturationPropsFromDeck<SatFuncSimpleNonuniform>();
                satprops_.reset(ptr);
                ptr->init(deck, eclState, number_of_cells, global_cell, begin_cell_centroids,
                          dimension, sat_samples);
            } else if (threephase_model == "gwseg") {
                SaturationPropsFromDeck<SatFuncGwsegNonuniform>* ptr
                    = new SaturationPropsFromDeck<SatFuncGwsegNonuniform>();
                satprops_.reset(ptr);
                ptr->init(deck, eclState, number_of_cells, global_cell, begin_cell_centroids,
                          dimension, sat_samples);
            } else {
                OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
            }
        }

        if (pvt_.numPhases() != satprops_->numPhases()) {
            OPM_THROW(std::runtime_error, "BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
                  << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
        }
    }
コード例 #2
0
 static void saturations(ContainerT& /* values */,
                         const Params& /* params */,
                         const FluidState& /* fs */)
 {
     OPM_THROW(std::logic_error, "Not implemented: saturations()");
 }
コード例 #3
0
ファイル: test_spline.cpp プロジェクト: blattms/opm-material
void testCommon(const Spline &sp,
                const double *x,
                const double *y)
{
    static double eps = 1e-10;
    static double epsFD = 1e-7;

    size_t n = sp.numSamples();
    for (size_t i = 0; i < n; ++i) {
        // sure that we hit all sampling points
        double y0 = (i>0)?sp.eval(x[i]-eps):y[0];
        double y1 = sp.eval(x[i]);
        double y2 = (i<n-1)?sp.eval(x[i]+eps):y[n-1];

        if (std::abs(y0 - y[i]) > 100*eps || std::abs(y2 - y[i]) > 100*eps)
            OPM_THROW(std::runtime_error,
                       "Spline seems to be discontinuous at sampling point " << i << "!");
        if (std::abs(y1 - y[i]) > eps)
            OPM_THROW(std::runtime_error,
                       "Spline does not capture sampling point " << i << "!");

        // make sure the derivative is continuous (assuming that the
        // second derivative is smaller than 1000)
        double d1 = sp.evalDerivative(x[i]);
        double d0 = (i>0)?sp.evalDerivative(x[i]-eps):d1;
        double d2 = (i<n-1)?sp.evalDerivative(x[i]+eps):d1;

        if (std::abs(d1 - d0) > 1000*eps || std::abs(d2 - d0) > 1000*eps)
            OPM_THROW(std::runtime_error,
                      "Spline seems to exhibit a discontinuous derivative at sampling point " << i << "!");
    }

    // make sure the derivatives are consistent with the curve
    size_t np = 3*n;
    for (size_t i = 0; i < np; ++i) {
        double xval = sp.xMin() + (sp.xMax() - sp.xMin())*i/np;

        // first derivative
        double y1 = sp.eval(xval+epsFD);
        double y0 = sp.eval(xval);

        double mFD = (y1 - y0)/epsFD;
        double m = sp.evalDerivative(xval);

        if (std::abs( mFD - m ) > 1000*epsFD)
            OPM_THROW(std::runtime_error,
                      "Derivative of spline seems to be inconsistent with cuve"
                      " (" << mFD << " - " << m << " = " << mFD - m << ")!");

        // second derivative
        y1 = sp.evalDerivative(xval+epsFD);
        y0 = sp.evalDerivative(xval);

        mFD = (y1 - y0)/epsFD;
        m = sp.evalSecondDerivative(xval);

        if (std::abs( mFD - m ) > 1000*epsFD)
            OPM_THROW(std::runtime_error,
                      "Second derivative of spline seems to be inconsistent with cuve"
                      " (" << mFD << " - " << m << " = " << mFD - m << ")!");

        // Third derivative
        y1 = sp.evalSecondDerivative(xval+epsFD);
        y0 = sp.evalSecondDerivative(xval);

        mFD = (y1 - y0)/epsFD;
        m = sp.evalThirdDerivative(xval);

        if (std::abs( mFD - m ) > 1000*epsFD)
            OPM_THROW(std::runtime_error,
                      "Third derivative of spline seems to be inconsistent with cuve"
                      " (" << mFD << " - " << m << " = " << mFD - m << ")!");
    }
}
コード例 #4
0
ファイル: TofReorder.cpp プロジェクト: higgscc/opm-core
    /// Solve for time-of-flight and a number of tracers.
    /// \param[in]  darcyflux         Array of signed face fluxes.
    /// \param[in]  porevolume        Array of pore volumes.
    /// \param[in]  source            Source term. Sign convention is:
    ///                                 (+) inflow flux,
    ///                                 (-) outflow flux.
    /// \param[in]  tracerheads       Table containing one row per tracer, and each
    ///                               row contains the source cells for that tracer.
    /// \param[out] tof               Array of time-of-flight values (1 per cell).
    /// \param[out] tracer            Array of tracer values. N per cell, where N is
    ///                               equalt to tracerheads.size().
    void TofReorder::solveTofTracer(const double* darcyflux,
                                    const double* porevolume,
                                    const double* source,
                                    const SparseTable<int>& tracerheads,
                                    std::vector<double>& tof,
                                    std::vector<double>& tracer)
    {
        darcyflux_ = darcyflux;
        porevolume_ = porevolume;
        source_ = source;
        const int num_cells = grid_.number_of_cells;
#ifndef NDEBUG
        // Sanity check for sources.
        const double cum_src = std::accumulate(source, source + num_cells, 0.0);
        if (std::fabs(cum_src) > *std::max_element(source, source + num_cells)*1e-2) {
            OPM_THROW(std::runtime_error, "Sources do not sum to zero: " << cum_src);
        }
#endif
        tof.resize(num_cells);
        std::fill(tof.begin(), tof.end(), 0.0);
        tof_ = &tof[0];

        if (use_multidim_upwind_) {
            face_tof_.resize(grid_.number_of_faces);
            std::fill(face_tof_.begin(), face_tof_.end(), 0.0);
            face_part_tof_.resize(grid_.face_nodepos[grid_.number_of_faces]);
            std::fill(face_part_tof_.begin(), face_part_tof_.end(), 0.0);
        }

        // Execute solve for tof
        compute_tracer_ = false;
        executeSolve();

        // Find the tracer heads (injectors).
        const int num_tracers = tracerheads.size();
        tracer.resize(num_cells*num_tracers);
        std::fill(tracer.begin(), tracer.end(), 0.0);
        if (num_tracers > 0) {
            tracerhead_by_cell_.clear();
            tracerhead_by_cell_.resize(num_cells, NoTracerHead);
        }
        for (int tr = 0; tr < num_tracers; ++tr) {
            const unsigned int tracerheadsSize = tracerheads[tr].size();
            for (unsigned int i = 0; i < tracerheadsSize; ++i) {
                const int cell = tracerheads[tr][i];
                tracer[num_cells * tr + cell] = 1.0;
                tracerhead_by_cell_[cell] = tr;
            }
        }

        // Execute solve for tracers.
        std::vector<double> fake_pv(num_cells, 0.0);
        porevolume_ = fake_pv.data();
        for (int tr = 0; tr < num_tracers; ++tr) {
            tof_ = tracer.data() + tr * num_cells;
            compute_tracer_ = true;
            executeSolve();
        }

        // Write output tracer data (transposing the computed data).
        std::vector<double> computed = tracer;
        for (int cell = 0; cell < num_cells; ++cell) {
            for (int tr = 0; tr < num_tracers; ++tr) {
                tracer[num_tracers * cell + tr] = computed[num_cells * tr + cell];
            }
        }
    }
コード例 #5
0
 // dummy method that is not implemented for this class
 SolutionVector computeNewtonIncrement(const LinearisedBlackoilResidual&) const
 {
     OPM_THROW(std::logic_error,"This method is not implemented");
     return SolutionVector();
 }
コード例 #6
0
SimulatorCompressiblePolymer::Impl::Impl(const parameter::ParameterGroup& param,
        const UnstructuredGrid& grid,
        const BlackoilPropertiesInterface& props,
        const PolymerProperties& poly_props,
        const RockCompressibility* rock_comp_props,
        WellsManager& wells_manager,
        const PolymerInflowInterface& polymer_inflow,
        LinearSolverInterface& linsolver,
        const double* gravity)
    : grid_(grid),
      props_(props),
      poly_props_(poly_props),
      rock_comp_props_(rock_comp_props),
      wells_manager_(wells_manager),
      wells_(wells_manager.c_wells()),
      polymer_inflow_(polymer_inflow),
      gravity_(gravity),
      psolver_(grid, props, rock_comp_props, poly_props, linsolver,
               param.getDefault("nl_pressure_residual_tolerance", 0.0),
               param.getDefault("nl_pressure_change_tolerance", 1.0),
               param.getDefault("nl_pressure_maxiter", 10),
               gravity, wells_manager.c_wells()),
      tsolver_(grid, props, poly_props,
               TransportSolverTwophaseCompressiblePolymer::Bracketing,
               param.getDefault("nl_tolerance", 1e-9),
               param.getDefault("nl_maxiter", 30))
{
    // For output.
    output_ = param.getDefault("output", true);
    if (output_) {
        output_vtk_ = param.getDefault("output_vtk", true);
        output_dir_ = param.getDefault("output_dir", std::string("output"));
        // Ensure that output dir exists
        boost::filesystem::path fpath(output_dir_);
        try {
            create_directories(fpath);
        }
        catch (...) {
            OPM_THROW(std::runtime_error, "Creating directories failed: " << fpath);
        }
        output_interval_ = param.getDefault("output_interval", 1);
    }

    // Well control related init.
    check_well_controls_ = param.getDefault("check_well_controls", false);
    max_well_control_iterations_ = param.getDefault("max_well_control_iterations", 10);

    // Transport related init.
    TransportSolverTwophaseCompressiblePolymer::SingleCellMethod method;
    std::string method_string = param.getDefault("single_cell_method", std::string("Bracketing"));
    if (method_string == "Bracketing") {
        method = Opm::TransportSolverTwophaseCompressiblePolymer::Bracketing;
    } else if (method_string == "Newton") {
        method = Opm::TransportSolverTwophaseCompressiblePolymer::Newton;
    } else {
        OPM_THROW(std::runtime_error, "Unknown method: " << method_string);
    }
    tsolver_.setPreferredMethod(method);
    num_transport_substeps_ = param.getDefault("num_transport_substeps", 1);
    use_segregation_split_ = param.getDefault("use_segregation_split", false);
    if (gravity != 0 && use_segregation_split_) {
        tsolver_.initGravity(gravity);
        extractColumn(grid_, columns_);
    }

    // Misc init.
    const int num_cells = grid.number_of_cells;
    allcells_.resize(num_cells);
    for (int cell = 0; cell < num_cells; ++cell) {
        allcells_[cell] = cell;
    }
}
コード例 #7
0
ファイル: MinpvProcessor.hpp プロジェクト: babrodtk/opm-grid
    inline int MinpvProcessor::process(const std::vector<double>& pv,
                                        const double minpv,
                                        const std::vector<int>& actnum,
                                        const bool mergeMinPVCells,
                                        double* zcorn) const
    {
        // Algorithm:
        // 1. Process each column of cells (with same i and j
        //    coordinates) from top (low k) to bottom (high k).
        // 2. For each cell 'c' visited, check if its pore volume
        //    pv[c] is less than minpv.
        // 3. If below the minpv threshold, move the lower four
        //    zcorn associated with the cell c to coincide with
        //    the upper four (so it becomes degenerate). If mergeMinPVcells
        //    is true, the higher four zcorn associated with the cell below
        //    is moved to these values (so it gains the deleted volume).

        int cells_modified = 0;

        // Check for sane input sizes.
        const size_t log_size = dims_[0] * dims_[1] * dims_[2];
        if (pv.size() != log_size) {
            OPM_THROW(std::runtime_error, "Wrong size of PORV input, must have one element per logical cartesian cell.");
        }
        if (!actnum.empty() && actnum.size() != log_size) {
            OPM_THROW(std::runtime_error, "Wrong size of ACTNUM input, must have one element per logical cartesian cell.");
        }

        // Main loop.
        for (int kk = 0; kk < dims_[2]; ++kk) {
            for (int jj = 0; jj < dims_[1]; ++jj) {
                for (int ii = 0; ii < dims_[0]; ++ii) {
                    const int c = ii + dims_[0] * (jj + dims_[1] * kk);
                    if (pv[c] < minpv && (actnum.empty() || actnum[c])) {
                        // Move deeper (higher k) coordinates to lower k coordinates.
                        std::array<double, 8> cz = getCellZcorn(ii, jj, kk, zcorn);
                        for (int count = 0; count < 4; ++count) {
                            cz[count + 4] = cz[count];
                        }
                        setCellZcorn(ii, jj, kk, cz, zcorn);


                        // optionally add removed volume to the cell below.
                        if (mergeMinPVCells) {
                            // Check if there is a cell below.
                            if (pv[c] > 0.0 && kk < dims_[2] - 1) {
                                // Set lower k coordinates of cell below to upper cells's coordinates.
                                std::array<double, 8> cz_below = getCellZcorn(ii, jj, kk + 1, zcorn);
                                for (int count = 0; count < 4; ++count) {
                                    cz_below[count] = cz[count];
                                }
                                setCellZcorn(ii, jj, kk + 1, cz_below, zcorn);
                            }
                        }
                        ++cells_modified;
                    }
                }
            }
        }
        return cells_modified;
    }
コード例 #8
0
 static Evaluation liquidDiffCoeff(const Evaluation& /*temperature*/, const Evaluation& /*pressure*/)
 { OPM_THROW(std::runtime_error, "Not implemented: Binary liquid diffusion coefficients of air and mesitylene"); }
コード例 #9
0
void IntegrationTest::getIntegrationTest(){
    std::vector<double> timeVec1, timeVec2;
    setTimeVecs(timeVec1, timeVec2);  // Sets the time vectors, they are equal for all keywords (WPOR:PROD01 etc)
    setDataSets(timeVec1, timeVec2);

    int ivar = 0;
    if(!allowDifferentAmountOfKeywords){
        if(stringlist_get_size(keysShort) != stringlist_get_size(keysLong)){
            OPM_THROW(std::invalid_argument, "Different ammont of keywords in the two summary files.");
        }
    }
    if(printKeyword){
        printKeywords();
        return;
    }

    std::string keywordWithGreatestErrorRatio;
    double greatestRatio = 0;

    //Iterates over all keywords from the restricted file, use iterator "ivar". Searches for a  match in the file with more keywords, use the itarator "jvar".
    while(ivar < stringlist_get_size(keysShort)){
        const char* keyword = stringlist_iget(keysShort, ivar);

        if(oneOfTheMainVariables){
            std::string keywordString(keyword);
            std::string substr = keywordString.substr(0,4);
            if(substr!= mainVariable){
                ivar++;
                continue;
            }
        }
        for (int jvar = 0; jvar < stringlist_get_size(keysLong); jvar++){

            if (strcmp(keyword, stringlist_iget(keysLong, jvar)) == 0){ //When the keywords are equal, proceed in comparing summary files.
                /*	if(!checkUnits(keyword)){
                    OPM_THROW(std::runtime_error, "For keyword " << keyword << " the unit of the two files is not equal. Not possible to compare.");
                    } //Comparing the unit of the two vectors.*/
                checkForKeyword(timeVec1, timeVec2, keyword);
                if(findVectorWithGreatestErrorRatio){
                    WellProductionVolume volume = getSpecificWellVolume(timeVec1,timeVec2, keyword);
                    findGreatestErrorRatio(volume,greatestRatio, keyword, keywordWithGreatestErrorRatio);
                }
                break;
            }
            //will only enter here if no keyword match
            if(jvar == stringlist_get_size(keysLong)-1){
                if(!allowDifferentAmountOfKeywords){
                    OPM_THROW(std::invalid_argument, "No match on keyword");
                }
            }
        }
        ivar++;
    }
    if(findVectorWithGreatestErrorRatio){
        std::cout << "The keyword " << keywordWithGreatestErrorRatio << " had the greatest error ratio, which was " << greatestRatio << std::endl;
    }
    if((findVolumeError || oneOfTheMainVariables) && !findVectorWithGreatestErrorRatio){
        evaluateWellProductionVolume();
    }
    if(allowSpikes){
        std::cout << "checkWithSpikes succeeded." << std::endl;
    }
}
コード例 #10
0
 /*!
  * \brief The temperature of a fluid phase [-]
  */
 const Scalar& temperature(unsigned /* phaseIdx */) const
 { OPM_THROW(std::runtime_error, "Temperature is not provided by this fluid state"); }
コード例 #11
0
 static Evaluation henry(const Evaluation& /*temperature*/)
 { OPM_THROW(std::runtime_error, "Not implemented: Henry coefficient of air in mesitylene"); }
コード例 #12
0
    SimulatorReport SimulatorIncompTwophase::Impl::run(SimulatorTimer& timer,
                                                       TwophaseState& state,
                                                       WellState& well_state)
    {
        std::vector<double> transport_src;

        // Initialisation.
        std::vector<double> porevol;
        if (rock_comp_props_ && rock_comp_props_->isActive()) {
            computePorevolume(grid_, props_.porosity(), *rock_comp_props_, state.pressure(), porevol);
        } else {
            computePorevolume(grid_, props_.porosity(), porevol);
        }
        const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
        std::vector<double> initial_porevol = porevol;

        // Main simulation loop.
        Opm::time::StopWatch pressure_timer;
        double ptime = 0.0;
        Opm::time::StopWatch transport_timer;
        double ttime = 0.0;
        Opm::time::StopWatch callback_timer;
        double time_in_callbacks = 0.0;
        Opm::time::StopWatch step_timer;
        Opm::time::StopWatch total_timer;
        total_timer.start();
        double init_satvol[2] = { 0.0 };
        double satvol[2] = { 0.0 };
        double tot_injected[2] = { 0.0 };
        double tot_produced[2] = { 0.0 };
        Opm::computeSaturatedVol(porevol, state.saturation(), init_satvol);
        *log_ << "\nInitial saturations are    " << init_satvol[0]/tot_porevol_init
              << "    " << init_satvol[1]/tot_porevol_init << std::endl;
        Opm::Watercut watercut;
        watercut.push(0.0, 0.0, 0.0);
        Opm::WellReport wellreport;
        std::vector<double> fractional_flows;
        std::vector<double> well_resflows_phase;
        if (wells_) {
            well_resflows_phase.resize((wells_->number_of_phases)*(wells_->number_of_wells), 0.0);
            wellreport.push(props_, *wells_, state.saturation(), 0.0, well_state.bhp(), well_state.perfRates());
        }
        std::fstream tstep_os;
        if (output_) {
            std::string filename = output_dir_ + "/step_timing.param";
            tstep_os.open(filename.c_str(), std::fstream::out | std::fstream::app);
        }
        while (!timer.done()) {
            // Report timestep and (optionally) write state to disk.
            step_timer.start();
            timer.report(*log_);
            if (output_ && (timer.currentStepNum() % output_interval_ == 0)) {
                if (output_vtk_) {
#ifdef DISABLE_OUTPUT
                    outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
#endif
                }
#ifdef DISABLE_OUTPUT
                outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
#endif
                if (use_reorder_) {
                    // This use of dynamic_cast is not ideal, but should be safe.
                    outputVectorMatlab(std::string("reorder_it"),
                                       dynamic_cast<const TransportSolverTwophaseReorder&>(*tsolver_).getReorderIterations(),
                                       timer.currentStepNum(), output_dir_);
                }
            }

            SimulatorReport sreport;

            // Solve pressure equation.
            if (check_well_controls_) {
                computeFractionalFlow(props_, allcells_, state.saturation(), fractional_flows);
                wells_manager_.applyExplicitReinjectionControls(well_resflows_phase, well_resflows_phase);
            }
            bool well_control_passed = !check_well_controls_;
            int well_control_iteration = 0;
            do {
                // Run solver.
                pressure_timer.start();
                std::vector<double> initial_pressure = state.pressure();
                psolver_.solve(timer.currentStepLength(), state, well_state);

                // Renormalize pressure if rock is incompressible, and
                // there are no pressure conditions (bcs or wells).
                // It is deemed sufficient for now to renormalize
                // using geometric volume instead of pore volume.
                if ((rock_comp_props_ == NULL || !rock_comp_props_->isActive())
                    && allNeumannBCs(bcs_) && allRateWells(wells_)) {
                    // Compute average pressures of previous and last
                    // step, and total volume.
                    double av_prev_press = 0.0;
                    double av_press = 0.0;
                    double tot_vol = 0.0;
                    const int num_cells = grid_.number_of_cells;
                    for (int cell = 0; cell < num_cells; ++cell) {
                        av_prev_press += initial_pressure[cell]*grid_.cell_volumes[cell];
                        av_press      += state.pressure()[cell]*grid_.cell_volumes[cell];
                        tot_vol       += grid_.cell_volumes[cell];
                    }
                    // Renormalization constant
                    const double ren_const = (av_prev_press - av_press)/tot_vol;
                    for (int cell = 0; cell < num_cells; ++cell) {
                        state.pressure()[cell] += ren_const;
                    }
                    const int num_wells = (wells_ == NULL) ? 0 : wells_->number_of_wells;
                    for (int well = 0; well < num_wells; ++well) {
                        well_state.bhp()[well] += ren_const;
                    }
                }

                // Stop timer and report.
                pressure_timer.stop();
                double pt = pressure_timer.secsSinceStart();
                *log_ << "Pressure solver took:  " << pt << " seconds." << std::endl;
                ptime += pt;
                sreport.pressure_time = pt;

                // Optionally, check if well controls are satisfied.
                if (check_well_controls_) {
                    Opm::computePhaseFlowRatesPerWell(*wells_,
                                                      well_state.perfRates(),
                                                      fractional_flows,
                                                      well_resflows_phase);
                    *log_ << "Checking well conditions." << std::endl;
                    // For testing we set surface := reservoir
                    well_control_passed = wells_manager_.conditionsMet(well_state.bhp(), well_resflows_phase, well_resflows_phase);
                    ++well_control_iteration;
                    if (!well_control_passed && well_control_iteration > max_well_control_iterations_) {
                        OPM_THROW(std::runtime_error, "Could not satisfy well conditions in " << max_well_control_iterations_ << " tries.");
                    }
                    if (!well_control_passed) {
                        *log_ << "Well controls not passed, solving again." << std::endl;
                    } else {
                        *log_ << "Well conditions met." << std::endl;
                    }
                }
            } while (!well_control_passed);

            // Update pore volumes if rock is compressible.
            if (rock_comp_props_ && rock_comp_props_->isActive()) {
                initial_porevol = porevol;
                computePorevolume(grid_, props_.porosity(), *rock_comp_props_, state.pressure(), porevol);
            }

            // Process transport sources (to include bdy terms and well flows).
            Opm::computeTransportSource(grid_, src_, state.faceflux(), 1.0,
                                        wells_, well_state.perfRates(), transport_src);

            // Solve transport.
            transport_timer.start();
            double stepsize = timer.currentStepLength();
            if (num_transport_substeps_ != 1) {
                stepsize /= double(num_transport_substeps_);
                *log_ << "Making " << num_transport_substeps_ << " transport substeps." << std::endl;
            }
            double injected[2] = { 0.0 };
            double produced[2] = { 0.0 };
            for (int tr_substep = 0; tr_substep < num_transport_substeps_; ++tr_substep) {
                tsolver_->solve(&initial_porevol[0], &transport_src[0], stepsize, state);

                double substep_injected[2] = { 0.0 };
                double substep_produced[2] = { 0.0 };
                Opm::computeInjectedProduced(props_, state.saturation(), transport_src, stepsize,
                                             substep_injected, substep_produced);
                injected[0] += substep_injected[0];
                injected[1] += substep_injected[1];
                produced[0] += substep_produced[0];
                produced[1] += substep_produced[1];
                if (use_reorder_ && use_segregation_split_) {
                    // Again, unfortunate but safe use of dynamic_cast.
                    // Possible solution: refactor gravity solver to its own class.
                    dynamic_cast<TransportSolverTwophaseReorder&>(*tsolver_)
                        .solveGravity(&initial_porevol[0], stepsize, state);
                }
                watercut.push(timer.simulationTimeElapsed() + timer.currentStepLength(),
                              produced[0]/(produced[0] + produced[1]),
                              tot_produced[0]/tot_porevol_init);
                if (wells_) {
                    wellreport.push(props_, *wells_, state.saturation(),
                                    timer.simulationTimeElapsed() + timer.currentStepLength(),
                                    well_state.bhp(), well_state.perfRates());
                }
            }
            transport_timer.stop();
            double tt = transport_timer.secsSinceStart();
            sreport.transport_time = tt;
            *log_ << "Transport solver took: " << tt << " seconds." << std::endl;
            ttime += tt;
            // Report volume balances.
            Opm::computeSaturatedVol(porevol, state.saturation(), satvol);
            tot_injected[0] += injected[0];
            tot_injected[1] += injected[1];
            tot_produced[0] += produced[0];
            tot_produced[1] += produced[1];
            reportVolumes(*log_, satvol, tot_porevol_init,
                          tot_injected, tot_produced,
                          injected, produced,
                          init_satvol);
            sreport.total_time =  step_timer.secsSinceStart();
            if (output_) {
                sreport.reportParam(tstep_os);
            }

            // advance the timer to the end of the timestep *before* notifying
            // the client that the timestep is done
            ++timer;

            // notify all clients that we are done with the timestep
            callback_timer.start ();
            timestep_completed_.signal ();
            callback_timer.stop ();
            time_in_callbacks += callback_timer.secsSinceStart ();
        }

        if (output_) {
            if (output_vtk_) {
#ifdef DISABLE_OUTPUT
                outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
#endif
            }
#ifdef DISABLE_OUTPUT
            outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
#endif
            if (use_reorder_) {
                // This use of dynamic_cast is not ideal, but should be safe.
                outputVectorMatlab(std::string("reorder_it"),
                                   dynamic_cast<const TransportSolverTwophaseReorder&>(*tsolver_).getReorderIterations(),
                                   timer.currentStepNum(), output_dir_);
                }
            outputWaterCut(watercut, output_dir_);
            if (wells_) {
                outputWellReport(wellreport, output_dir_);
            }
            tstep_os.close();
        }

        total_timer.stop();

        SimulatorReport report;
        report.pressure_time = ptime;
        report.transport_time = ttime;
        report.total_time = total_timer.secsSinceStart() - time_in_callbacks;
        return report;
    }
コード例 #13
0
    SimulatorIncompTwophase::Impl::Impl(const parameter::ParameterGroup& param,
                                        const UnstructuredGrid& grid,
                                        const IncompPropertiesInterface& props,
                                        const RockCompressibility* rock_comp_props,
                                        WellsManager& wells_manager,
                                        const std::vector<double>& src,
                                        const FlowBoundaryConditions* bcs,
                                        LinearSolverInterface& linsolver,
                                        const double* gravity)
        : use_reorder_(param.getDefault("use_reorder", true)),
          use_segregation_split_(param.getDefault("use_segregation_split", false)),
          grid_(grid),
          props_(props),
          rock_comp_props_(rock_comp_props),
          wells_manager_(wells_manager),
          wells_(wells_manager.c_wells()),
          src_(src),
          bcs_(bcs),
          psolver_(grid, props, rock_comp_props, linsolver,
                   param.getDefault("nl_pressure_residual_tolerance", 0.0),
                   param.getDefault("nl_pressure_change_tolerance", 1.0),
                   param.getDefault("nl_pressure_maxiter", 10),
                   gravity, wells_manager.c_wells(), src, bcs)
    {
        // Initialize transport solver.
        if (use_reorder_) {
            tsolver_.reset(new Opm::TransportSolverTwophaseReorder(grid,
                                                                   props,
                                                                   use_segregation_split_ ? gravity : NULL,
                                                                   param.getDefault("nl_tolerance", 1e-9),
                                                                   param.getDefault("nl_maxiter", 30)));

        } else {
            if (rock_comp_props && rock_comp_props->isActive()) {
                OPM_THROW(std::runtime_error, "The implicit pressure solver cannot handle rock compressibility.");
            }
            if (use_segregation_split_) {
                OPM_THROW(std::runtime_error, "The implicit pressure solver is not set up to use segregation splitting.");
            }
            std::vector<double> porevol;
            computePorevolume(grid, props.porosity(), porevol);
            tsolver_.reset(new Opm::TransportSolverTwophaseImplicit(grid,
                                                                    props,
                                                                    porevol,
                                                                    gravity,
                                                                    psolver_.getHalfTrans(),
                                                                    param));
        }

        // For output.
        log_ = param.getDefault("quiet", false) ? &Opm::null_stream : &std::cout;
        output_ = param.getDefault("output", true);
        if (output_) {
            output_vtk_ = param.getDefault("output_vtk", true);
            output_dir_ = param.getDefault("output_dir", std::string("output"));
            // Ensure that output dir exists
            boost::filesystem::path fpath(output_dir_);
            try {
                create_directories(fpath);
            }
            catch (...) {
                OPM_THROW(std::runtime_error, "Creating directories failed: " << fpath);
            }
            output_interval_ = param.getDefault("output_interval", 1);
        }

        // Well control related init.
        check_well_controls_ = param.getDefault("check_well_controls", false);
        max_well_control_iterations_ = param.getDefault("max_well_control_iterations", 10);

        // Transport related init.
        num_transport_substeps_ = param.getDefault("num_transport_substeps", 1);

        // Misc init.
        const int num_cells = grid.number_of_cells;
        allcells_.resize(num_cells);
        for (int cell = 0; cell < num_cells; ++cell) {
            allcells_[cell] = cell;
        }
    }
コード例 #14
0
        void upscale(const Opm::parameter::ParameterGroup& param)
        {
            // Control structure.
            std::vector<double> saturations;
            Opm::SparseTable<double> all_pdrops;
            bool from_file = param.has("sat_pdrop_filename");
            if (from_file) {
                std::string filename = param.get<std::string>("sat_pdrop_filename");
                std::ifstream file(filename.c_str());
                if (!file) {
                    OPM_THROW(std::runtime_error, "Could not open file " << filename);
                }
                readControl(file, saturations, all_pdrops);
            } else {
                // Get a linear range of saturations.
                int num_sats = param.getDefault("num_sats", 4);
                double min_sat = param.getDefault("min_sat", 0.2);
                double max_sat = param.getDefault("max_sat", 0.8);
                saturations.resize(num_sats);
                for (int i = 0; i < num_sats; ++i) {
                    double factor = num_sats == 1 ? 0 : double(i)/double(num_sats - 1);
                    saturations[i] = (1.0 - factor)*min_sat + factor*max_sat;
                }
                // Get a logarithmic range of pressure drops.
                int num_pdrops = param.getDefault("num_pdrops", 5);
                double log_min_pdrop = std::log(param.getDefault("min_pdrop", 1e2));
                double log_max_pdrop = std::log(param.getDefault("max_pdrop", 1e6));
                std::vector<double> pdrops;
                pdrops.resize(num_pdrops);
                for (int i = 0; i < num_pdrops; ++i) {
                    double factor = num_pdrops == 1 ? 0 : double(i)/double(num_pdrops - 1);
                    pdrops[i] = std::exp((1.0 - factor)*log_min_pdrop + factor*log_max_pdrop);
                }
                // Assign the same pressure drops to all saturations.
                for (int i = 0; i < num_sats; ++i) {
                    all_pdrops.appendRow(pdrops.begin(), pdrops.end());
                }
            }
            int flow_direction = param.getDefault("flow_direction", 0);

            // Print the saturations and pressure drops.
            // writeControl(std::cout, saturations, all_pdrops);

            // Initialize upscaler.
            typedef SteadyStateUpscaler<Traits> Upscaler;
            typedef typename Upscaler::permtensor_t permtensor_t;
            Upscaler upscaler;
            upscaler.init(param);

            // First, compute an upscaled permeability.
            permtensor_t upscaled_K = upscaler.upscaleSinglePhase();
            permtensor_t upscaled_K_copy = upscaled_K;
            upscaled_K_copy *= (1.0/(Opm::prefix::milli*Opm::unit::darcy));
            std::cout.precision(15);
            std::cout << "Upscaled K in millidarcy:\n" << upscaled_K_copy << std::endl;
            std::cout << "Upscaled porosity: " << upscaler.upscalePorosity() << std::endl;

            // Create output streams for upscaled relative permeabilities
            std::string kr_filename = param.getDefault<std::string>("kr_filename", "upscaled_relperm");
            std::string krw_filename = kr_filename + "_water";
            std::string kro_filename = kr_filename + "_oil";
            std::ofstream krw_out(krw_filename.c_str());
            std::ofstream kro_out(kro_filename.c_str());
            krw_out << "# Result from steady state upscaling" << std::endl;
            krw_out << "# Pressuredrop  Sw  Krxx  Kryy  Krzz" << std::endl;
            kro_out << "# Result from steady state upscaling" << std::endl;
            kro_out << "# Pressuredrop  Sw  Krxx  Kryy  Krzz" << std::endl;


            krw_out.precision(15);  krw_out.setf(std::ios::scientific | std::ios::showpoint);
            kro_out.precision(15);  kro_out.setf(std::ios::scientific | std::ios::showpoint);
	    //#endif

            // Then, compute some upscaled relative permeabilities.
            int num_cells = upscaler.grid().size(0);
            int num_sats = saturations.size();
            for (int i = 0; i < num_sats; ++i) {
                // Starting every computation with a trio of uniform profiles.
                std::vector<double> init_sat(num_cells, saturations[i]);
                const Opm::SparseTable<double>::row_type pdrops = all_pdrops[i];
                int num_pdrops = pdrops.size();
                for (int j = 0; j < num_pdrops; ++j) {
                    double pdrop = pdrops[j];
                    std::pair<permtensor_t, permtensor_t> lambda
                        = upscaler.upscaleSteadyState(flow_direction, init_sat, saturations[i], pdrop, upscaled_K);
                    double usat = upscaler.lastSaturationUpscaled();
                    std::cout << "\n\nTensor of upscaled relperms for initial saturation " << saturations[i]
                              << ", real steady-state saturation " << usat
                              << " and pressure drop " << pdrop
                              << ":\n\n[water]\n" << lambda.first
                              << "\n[oil]\n" << lambda.second << std::endl;
                    // Changing initial saturations for next pressure drop to equal the steady state of the last
                    init_sat = upscaler.lastSaturationState();

		    
                    writeRelPerm(krw_out, lambda.first , usat, pdrop);
                    writeRelPerm(kro_out, lambda.second, usat, pdrop);
		    
                }
            }
        }
コード例 #15
0
ファイル: SimpleH2O.hpp プロジェクト: chflo/opm-material
 static Evaluation liquidPressure(const Evaluation& /*temperature*/, const Evaluation& /*density*/)
 {
     OPM_THROW(std::logic_error,
               "The liquid pressure is undefined for incompressible fluids");
 }
コード例 #16
0
double IntegrationTest::integrateError(const std::vector<double>& timeVec1,
                                       const std::vector<double>& dataVec1,
                                       const std::vector<double>& timeVec2,
                                       const std::vector<double>& dataVec2){
    // When the data corresponds to a rate the integration will become a Riemann
    // sum.  This function calculates the Riemann sum of the error.  The reason why
    // a Riemann sum is used is because of the way the data is written to file.
    // When a change occur (e.g. change of a rate), the data (value and time) is
    // written to file, THEN the change happens in the simulator, i.e., we will
    // notice the change at the next step.
    //
    // Keep in mind that the summary vector is NOT a continuous curve, only points
    // of data (time, value).  We have to guess what happens between the data
    // points, we do this by saying: "There are no change, the only change happens
    // at the data points."  As stated above, the value of this constant "height" of
    // the rectangle corresponds to the value of the last time step.  Thus we have
    // to use the "right hand side value of the rectangle as height
    //
    // someDataVector[ivar] instead of someDataVector[ivar-1]
    //
    // (which intuition is saying is the correct value to use).

    if(timeVec1.size() != dataVec1.size() || timeVec2.size() != dataVec2.size() ){
        OPM_THROW(std::runtime_error, "The size of the time vector does not match the size of the data vector.");
    }
    double errorSum = 0;
    double rightEdge, leftEdge, width;
    size_t i = 1;
    size_t j = 1;
    leftEdge = timeVec1[0];
    while(i < timeVec1.size()){
        if(j == timeVec2.size() ){
            break;
        }
        if(timeVec1[i] == timeVec2[j]){
            rightEdge = timeVec1[i];
            width = rightEdge - leftEdge;
            double dev = std::fabs(dataVec1[i] - dataVec2[j]);
            errorSum += getRectangleArea(dev, width);
            leftEdge = rightEdge;
            i++;
            j++;
            continue;
        }
        if(timeVec1[i] < timeVec2[j]){
            rightEdge = timeVec1[i];
            width = rightEdge - leftEdge;
            double value = unitStep(dataVec2[j]);
            double dev = std::fabs(dataVec1[i]-value);
            errorSum += getRectangleArea(dev, width);
            leftEdge = rightEdge;
            i++;
            continue;
        }
        if(timeVec2[j] < timeVec1[i]){
            rightEdge = timeVec2[j];
            width = rightEdge - leftEdge;
            double value = unitStep(dataVec1[i]);
            double dev = std::fabs(dataVec2[j]-value);
            errorSum += getRectangleArea(dev, width);
            leftEdge = rightEdge;
            j++;
            continue;
        }
    }
    return errorSum;
}
コード例 #17
0
    void SimulatorBase<Implementation>::computeRESV(const std::size_t               step,
                                                    const Wells*                    wells,
                                                    const BlackoilState&            x,
                                                    WellState& xw)
    {
        typedef SimFIBODetails::WellMap WellMap;

        const std::vector<WellConstPtr>& w_ecl = eclipse_state_->getSchedule()->getWells(step);
        const WellMap& wmap = SimFIBODetails::mapWells(w_ecl);

        const std::vector<int>& resv_wells = SimFIBODetails::resvWells(wells, step, wmap);

        const std::size_t number_resv_wells        = resv_wells.size();
        std::size_t       global_number_resv_wells = number_resv_wells;
#if HAVE_MPI
        if ( solver_.parallelInformation().type() == typeid(ParallelISTLInformation) )
        {
            const auto& info =
                boost::any_cast<const ParallelISTLInformation&>(solver_.parallelInformation());
            global_number_resv_wells = info.communicator().sum(global_number_resv_wells);
            if ( global_number_resv_wells )
            {
                // At least one process has resv wells. Therefore rate converter needs
                // to calculate averages over regions that might cross process
                // borders. This needs to be done by all processes and therefore
                // outside of the next if statement.
                rateConverter_.defineState(x, boost::any_cast<const ParallelISTLInformation&>(solver_.parallelInformation()));
            }
        }
        else
#endif
        {
            if ( global_number_resv_wells )
            {
                rateConverter_.defineState(x);
            }
        }

        if (! resv_wells.empty()) {
            const PhaseUsage&                    pu = props_.phaseUsage();
            const std::vector<double>::size_type np = props_.numPhases();

            std::vector<double> distr (np);
            std::vector<double> hrates(np);
            std::vector<double> prates(np);

            for (std::vector<int>::const_iterator
                     rp = resv_wells.begin(), e = resv_wells.end();
                 rp != e; ++rp)
            {
                WellControls* ctrl = wells->ctrls[*rp];
                const bool is_producer = wells->type[*rp] == PRODUCER;

                // RESV control mode, all wells
                {
                    const int rctrl = SimFIBODetails::resv_control(ctrl);

                    if (0 <= rctrl) {
                        const std::vector<double>::size_type off = (*rp) * np;

                        if (is_producer) {
                            // Convert to positive rates to avoid issues
                            // in coefficient calculations.
                            std::transform(xw.wellRates().begin() + (off + 0*np),
                                           xw.wellRates().begin() + (off + 1*np),
                                           prates.begin(), std::negate<double>());
                        } else {
                            std::copy(xw.wellRates().begin() + (off + 0*np),
                                      xw.wellRates().begin() + (off + 1*np),
                                      prates.begin());
                        }

                        const int fipreg = 0; // Hack.  Ignore FIP regions.
                        rateConverter_.calcCoeff(prates, fipreg, distr);

                        well_controls_iset_distr(ctrl, rctrl, & distr[0]);
                    }
                }

                // RESV control, WCONHIST wells.  A bit of duplicate
                // work, regrettably.
                if (is_producer && wells->name[*rp] != 0) {
                    WellMap::const_iterator i = wmap.find(wells->name[*rp]);

                    if (i != wmap.end()) {
                        WellConstPtr wp = i->second;

                        const WellProductionProperties& p =
                            wp->getProductionProperties(step);

                        if (! p.predictionMode) {
                            // History matching (WCONHIST/RESV)
                            SimFIBODetails::historyRates(pu, p, hrates);

                            const int fipreg = 0; // Hack.  Ignore FIP regions.
                            rateConverter_.calcCoeff(hrates, fipreg, distr);

                            // WCONHIST/RESV target is sum of all
                            // observed phase rates translated to
                            // reservoir conditions.  Recall sign
                            // convention: Negative for producers.
                            const double target =
                                - std::inner_product(distr.begin(), distr.end(),
                                                     hrates.begin(), 0.0);

                            well_controls_clear(ctrl);
                            well_controls_assert_number_of_phases(ctrl, int(np));

                            static const double invalid_alq = -std::numeric_limits<double>::max();
                            static const int invalid_vfp = -std::numeric_limits<int>::max();

                            const int ok_resv =
                                well_controls_add_new(RESERVOIR_RATE, target,
                                                      invalid_alq, invalid_vfp,
                                                      & distr[0], ctrl);

                            // For WCONHIST the BHP limit is set to 1 atm.
                            // or a value specified using WELTARG
                            double bhp_limit = (p.BHPLimit > 0) ? p.BHPLimit : unit::convert::from(1.0, unit::atm);
                            const int ok_bhp =
                                well_controls_add_new(BHP, bhp_limit,
                                                      invalid_alq, invalid_vfp,
                                                      NULL, ctrl);

                            if (ok_resv != 0 && ok_bhp != 0) {
                                xw.currentControls()[*rp] = 0;
                                well_controls_set_current(ctrl, 0);
                            }
                        }
                    }
                }
            }
        }

        if( wells )
        {
            for (int w = 0, nw = wells->number_of_wells; w < nw; ++w) {
                WellControls* ctrl = wells->ctrls[w];
                const bool is_producer = wells->type[w] == PRODUCER;
                if (!is_producer && wells->name[w] != 0) {
                    WellMap::const_iterator i = wmap.find(wells->name[w]);
                    if (i != wmap.end()) {
                        WellConstPtr wp = i->second;
                        const WellInjectionProperties& injector = wp->getInjectionProperties(step);
                        if (!injector.predictionMode) {
                            //History matching WCONINJEH
                            static const double invalid_alq = -std::numeric_limits<double>::max();
                            static const int invalid_vfp = -std::numeric_limits<int>::max();
                            // For WCONINJEH the BHP limit is set to a large number
                            // or a value specified using WELTARG
                            double bhp_limit = (injector.BHPLimit > 0) ? injector.BHPLimit : std::numeric_limits<double>::max();
                            const int ok_bhp =
                                well_controls_add_new(BHP, bhp_limit,
                                                      invalid_alq, invalid_vfp,
                                                      NULL, ctrl);
                            if (!ok_bhp) {
                                OPM_THROW(std::runtime_error, "Failed to add well control.");
                            }
                        }
                    }
                }
            }
        }
    }
コード例 #18
0
inline
void distributeGridAndData( Dune::CpGrid& grid,
                            Opm::DeckConstPtr deck,
                            EclipseStateConstPtr eclipseState,
                            BlackoilState& state,
                            BlackoilPropsAdFromDeck& properties,
                            DerivedGeology& geology,
                            std::shared_ptr<BlackoilPropsAdFromDeck::MaterialLawManager>& material_law_manager,
                            std::vector<double>& threshold_pressures,
                            boost::any& parallelInformation,
                            const bool useLocalPerm)
{
    Dune::CpGrid global_grid ( grid );
    global_grid.switchToGlobalView();

    // distribute the grid and switch to the distributed view
    grid.loadBalance(eclipseState, geology.transmissibility().data());
    grid.switchToDistributedView();
    std::vector<int> compressedToCartesianIdx;
    Opm::createGlobalCellArray(grid, compressedToCartesianIdx);
    typedef BlackoilPropsAdFromDeck::MaterialLawManager MaterialLawManager;
    auto distributed_material_law_manager = std::make_shared<MaterialLawManager>();
    distributed_material_law_manager->initFromDeck(deck, eclipseState, compressedToCartesianIdx);
    // copy the values from the global to the local MaterialLawManager
    // We should actually communicate these to be future proof. But that is
    // really, really cumbersome for the underlying vector<shared_ptr>
    // where the classes pointed to even have more shared_ptr stored in them.
    typedef Dune::CpGrid::ParallelIndexSet IndexSet;
    const IndexSet& local_indices  = grid.getCellIndexSet();
    for ( auto index : local_indices )
    {
        distributed_material_law_manager->materialLawParamsPointerReferenceHack(index.local()) =
            material_law_manager->materialLawParamsPointerReferenceHack(index.global());

        distributed_material_law_manager->oilWaterScaledEpsInfoDrainagePointerReferenceHack(index.local()) =
            material_law_manager->oilWaterScaledEpsInfoDrainagePointerReferenceHack(index.global());
    }
    BlackoilPropsAdFromDeck distributed_props(properties,
                                              distributed_material_law_manager,
                                              grid.numCells());
    BlackoilState distributed_state(grid.numCells(), grid.numFaces(), state.numPhases());
    BlackoilStateDataHandle state_handle(global_grid, grid,
                                         state, distributed_state);
    BlackoilPropsDataHandle props_handle(properties,
                                         distributed_props);
    grid.scatterData(state_handle);
    grid.scatterData(props_handle);
    // Create a distributed Geology. Some values will be updated using communication
    // below
    DerivedGeology distributed_geology(grid,
                                       distributed_props, eclipseState,
                                       useLocalPerm, geology.gravity());
    GeologyDataHandle geo_handle(global_grid, grid,
                                 geology, distributed_geology);
    grid.scatterData(geo_handle);

    std::vector<double> distributed_pressures;

    if( !threshold_pressures.empty() ) // Might be empty if not specified
    {
        if( threshold_pressures.size() !=
            static_cast<std::size_t>(UgGridHelpers::numFaces(global_grid)) )
        {
            OPM_THROW(std::runtime_error, "NNCs not yet supported for parallel runs. "
                      << UgGridHelpers::numFaces(grid) << " faces but " <<
                      threshold_pressures.size()<<" threshold pressure values");
        }
        distributed_pressures.resize(UgGridHelpers::numFaces(grid));
        ThresholdPressureDataHandle press_handle(global_grid, grid,
                                                 threshold_pressures,
                                                 distributed_pressures);
        grid.scatterData(press_handle);
    }

    // copy states
    properties           = distributed_props;
    geology              = distributed_geology;
    state                = distributed_state;
    material_law_manager = distributed_material_law_manager;
    threshold_pressures   = distributed_pressures;
    extractParallelGridInformationToISTL(grid, parallelInformation);
}
コード例 #19
0
SimulatorReport SimulatorCompressiblePolymer::Impl::run(SimulatorTimer& timer,
        PolymerBlackoilState& state,
        WellState& well_state)
{
    std::vector<double> transport_src(grid_.number_of_cells);
    std::vector<double> polymer_inflow_c(grid_.number_of_cells);

    // Initialisation.
    std::vector<double> initial_pressure;
    std::vector<double> porevol;
    if (rock_comp_props_ && rock_comp_props_->isActive()) {
        computePorevolume(grid_, props_.porosity(), *rock_comp_props_, state.pressure(), porevol);
    } else {
        computePorevolume(grid_, props_.porosity(), porevol);
    }
    const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
    std::vector<double> initial_porevol = porevol;

    // Main simulation loop.
    Opm::time::StopWatch pressure_timer;
    double ptime = 0.0;
    Opm::time::StopWatch transport_timer;
    double ttime = 0.0;
    Opm::time::StopWatch total_timer;
    total_timer.start();
    double init_surfvol[2] = { 0.0 };
    double inplace_surfvol[2] = { 0.0 };
    double polymass = computePolymerMass(porevol, state.saturation(), state.concentration(), poly_props_.deadPoreVol());
    double polymass_adsorbed = computePolymerAdsorbed(grid_, props_, poly_props_, state, rock_comp_props_);
    double init_polymass = polymass + polymass_adsorbed;
    double tot_injected[2] = { 0.0 };
    double tot_produced[2] = { 0.0 };
    double tot_polyinj = 0.0;
    double tot_polyprod = 0.0;
    Opm::computeSaturatedVol(porevol, state.surfacevol(), init_surfvol);
    Opm::Watercut watercut;
    watercut.push(0.0, 0.0, 0.0);
    Opm::WellReport wellreport;
    std::vector<double> fractional_flows;
    std::vector<double> well_resflows_phase;
    if (wells_) {
        well_resflows_phase.resize((wells_->number_of_phases)*(wells_->number_of_wells), 0.0);
        wellreport.push(props_, *wells_, state.pressure(), state.surfacevol(),
                        state.saturation(), 0.0, well_state.bhp(), well_state.perfRates());
    }
    // Report timestep and (optionally) write state to disk.
    timer.report(std::cout);
    if (output_ && (timer.currentStepNum() % output_interval_ == 0)) {
        if (output_vtk_) {
            outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
        }
        outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
    }

    initial_pressure = state.pressure();

    // Solve pressure equation.
    if (check_well_controls_) {
        computeFractionalFlow(props_, poly_props_, allcells_,
                              state.pressure(), state.temperature(), state.surfacevol(), state.saturation(),
                              state.concentration(), state.maxconcentration(),
                              fractional_flows);
        wells_manager_.applyExplicitReinjectionControls(well_resflows_phase, well_resflows_phase);
    }
    bool well_control_passed = !check_well_controls_;
    int well_control_iteration = 0;
    do {
        // Run solver
        pressure_timer.start();
        psolver_.solve(timer.currentStepLength(), state, well_state);

        // Renormalize pressure if both fluids and rock are
        // incompressible, and there are no pressure
        // conditions (bcs or wells).  It is deemed sufficient
        // for now to renormalize using geometric volume
        // instead of pore volume.
        if (psolver_.singularPressure()) {
            // Compute average pressures of previous and last
            // step, and total volume.
            double av_prev_press = 0.0;
            double av_press = 0.0;
            double tot_vol = 0.0;
            const int num_cells = grid_.number_of_cells;
            for (int cell = 0; cell < num_cells; ++cell) {
                av_prev_press += initial_pressure[cell]*grid_.cell_volumes[cell];
                av_press      += state.pressure()[cell]*grid_.cell_volumes[cell];
                tot_vol       += grid_.cell_volumes[cell];
            }
            // Renormalization constant
            const double ren_const = (av_prev_press - av_press)/tot_vol;
            for (int cell = 0; cell < num_cells; ++cell) {
                state.pressure()[cell] += ren_const;
            }
            const int num_wells = (wells_ == NULL) ? 0 : wells_->number_of_wells;
            for (int well = 0; well < num_wells; ++well) {
                well_state.bhp()[well] += ren_const;
            }
        }

        // Stop timer and report
        pressure_timer.stop();
        double pt = pressure_timer.secsSinceStart();
        std::cout << "Pressure solver took:  " << pt << " seconds." << std::endl;
        ptime += pt;

        // Optionally, check if well controls are satisfied.
        if (check_well_controls_) {
            Opm::computePhaseFlowRatesPerWell(*wells_,
                                              well_state.perfRates(),
                                              fractional_flows,
                                              well_resflows_phase);
            std::cout << "Checking well conditions." << std::endl;
            // For testing we set surface := reservoir
            well_control_passed = wells_manager_.conditionsMet(well_state.bhp(), well_resflows_phase, well_resflows_phase);
            ++well_control_iteration;
            if (!well_control_passed && well_control_iteration > max_well_control_iterations_) {
                OPM_THROW(std::runtime_error, "Could not satisfy well conditions in " << max_well_control_iterations_ << " tries.");
            }
            if (!well_control_passed) {
                std::cout << "Well controls not passed, solving again." << std::endl;
            } else {
                std::cout << "Well conditions met." << std::endl;
            }
        }
    } while (!well_control_passed);

    // Update pore volumes if rock is compressible.
    if (rock_comp_props_ && rock_comp_props_->isActive()) {
        initial_porevol = porevol;
        computePorevolume(grid_, props_.porosity(), *rock_comp_props_, state.pressure(), porevol);
    }

    // Process transport sources (to include bdy terms and well flows).
    Opm::computeTransportSource(props_, wells_, well_state, transport_src);

    // Find inflow rate.
    const double current_time = timer.simulationTimeElapsed();
    double stepsize = timer.currentStepLength();
    polymer_inflow_.getInflowValues(current_time, current_time + stepsize, polymer_inflow_c);


    // Solve transport.
    transport_timer.start();
    if (num_transport_substeps_ != 1) {
        stepsize /= double(num_transport_substeps_);
        std::cout << "Making " << num_transport_substeps_ << " transport substeps." << std::endl;
    }
    double injected[2] = { 0.0 };
    double produced[2] = { 0.0 };
    double polyinj = 0.0;
    double polyprod = 0.0;
    for (int tr_substep = 0; tr_substep < num_transport_substeps_; ++tr_substep) {
        tsolver_.solve(&state.faceflux()[0], initial_pressure,
                       state.pressure(), state.temperature(), &initial_porevol[0], &porevol[0],
                       &transport_src[0], &polymer_inflow_c[0], stepsize,
                       state.saturation(), state.surfacevol(),
                       state.concentration(), state.maxconcentration());
        double substep_injected[2] = { 0.0 };
        double substep_produced[2] = { 0.0 };
        double substep_polyinj = 0.0;
        double substep_polyprod = 0.0;
        Opm::computeInjectedProduced(props_, poly_props_,
                                     state,
                                     transport_src, polymer_inflow_c, stepsize,
                                     substep_injected, substep_produced,
                                     substep_polyinj, substep_polyprod);
        injected[0] += substep_injected[0];
        injected[1] += substep_injected[1];
        produced[0] += substep_produced[0];
        produced[1] += substep_produced[1];
        polyinj += substep_polyinj;
        polyprod += substep_polyprod;
        if (gravity_ != 0 && use_segregation_split_) {
            tsolver_.solveGravity(columns_, stepsize,
                                  state.saturation(), state.surfacevol(),
                                  state.concentration(), state.maxconcentration());
        }
    }
    transport_timer.stop();
    double tt = transport_timer.secsSinceStart();
    std::cout << "Transport solver took: " << tt << " seconds." << std::endl;
    ttime += tt;

    // Report volume balances.
    Opm::computeSaturatedVol(porevol, state.surfacevol(), inplace_surfvol);
    polymass = Opm::computePolymerMass(porevol, state.saturation(), state.concentration(), poly_props_.deadPoreVol());
    polymass_adsorbed = Opm::computePolymerAdsorbed(grid_, props_, poly_props_,
                        state, rock_comp_props_);
    tot_injected[0] += injected[0];
    tot_injected[1] += injected[1];
    tot_produced[0] += produced[0];
    tot_produced[1] += produced[1];
    tot_polyinj += polyinj;
    tot_polyprod += polyprod;
    std::cout.precision(5);
    const int width = 18;
    std::cout << "\nMass balance:        "
              "                   water(surfvol)      oil(surfvol)       polymer(kg)\n";
    std::cout << "    In-place:                       "
              << std::setw(width) << inplace_surfvol[0]
              << std::setw(width) << inplace_surfvol[1]
              << std::setw(width) << polymass << std::endl;
    std::cout << "    Adsorbed:                       "
              << std::setw(width) << 0.0
              << std::setw(width) << 0.0
              << std::setw(width) << polymass_adsorbed << std::endl;
    std::cout << "    Injected:                       "
              << std::setw(width) << injected[0]
              << std::setw(width) << injected[1]
              << std::setw(width) << polyinj << std::endl;
    std::cout << "    Produced:                       "
              << std::setw(width) << produced[0]
              << std::setw(width) << produced[1]
              << std::setw(width) << polyprod << std::endl;
    std::cout << "    Total inj:                      "
              << std::setw(width) << tot_injected[0]
              << std::setw(width) << tot_injected[1]
              << std::setw(width) << tot_polyinj << std::endl;
    std::cout << "    Total prod:                     "
              << std::setw(width) << tot_produced[0]
              << std::setw(width) << tot_produced[1]
              << std::setw(width) << tot_polyprod << std::endl;
    const double balance[3] = { init_surfvol[0] - inplace_surfvol[0] - tot_produced[0] + tot_injected[0],
                                init_surfvol[1] - inplace_surfvol[1] - tot_produced[1] + tot_injected[1],
                                init_polymass - polymass - tot_polyprod + tot_polyinj - polymass_adsorbed
                              };
    std::cout << "    Initial - inplace + inj - prod: "
              << std::setw(width) << balance[0]
              << std::setw(width) << balance[1]
              << std::setw(width) << balance[2]
              << std::endl;
    std::cout << "    Relative mass error:            "
              << std::setw(width) << balance[0]/(init_surfvol[0] + tot_injected[0])
              << std::setw(width) << balance[1]/(init_surfvol[1] + tot_injected[1])
              << std::setw(width) << balance[2]/(init_polymass + tot_polyinj)
              << std::endl;
    std::cout.precision(8);

    watercut.push(timer.simulationTimeElapsed() + timer.currentStepLength(),
                  produced[0]/(produced[0] + produced[1]),
                  tot_produced[0]/tot_porevol_init);
    if (wells_) {
        wellreport.push(props_, *wells_, state.pressure(), state.surfacevol(),
                        state.saturation(), timer.simulationTimeElapsed() + timer.currentStepLength(),
                        well_state.bhp(), well_state.perfRates());
    }

    if (output_) {
        if (output_vtk_) {
            outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
        }
        outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
        outputWaterCut(watercut, output_dir_);
        if (wells_) {
            outputWellReport(wellreport, output_dir_);
        }
    }

    total_timer.stop();

    SimulatorReport report;
    report.pressure_time = ptime;
    report.transport_time = ttime;
    report.total_time = total_timer.secsSinceStart();
    return report;
}
コード例 #20
0
    static void solve(FluidState &fluidState,
                      const typename MaterialLaw::Params &matParams,
                      typename FluidSystem::template ParameterCache<typename FluidState::Scalar>& paramCache,
                      const Dune::FieldVector<typename FluidState::Scalar, numComponents>& globalMolarities,
                      Scalar tolerance = -1)
    {
        typedef typename FluidState::Scalar InputEval;

        /////////////////////////
        // Check if all fluid phases are incompressible
        /////////////////////////
        bool allIncompressible = true;
        for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
            if (FluidSystem::isCompressible(phaseIdx)) {
                allIncompressible = false;
                break;
            }
        }

        if (allIncompressible) {
            // yes, all fluid phases are incompressible. in this case the flash solver
            // can only determine the saturations, not the pressures. (but this
            // determination is much simpler than a full flash calculation.)
            paramCache.updateAll(fluidState);
            solveAllIncompressible_(fluidState, paramCache, globalMolarities);
            return;
        }

        typedef Dune::FieldMatrix<InputEval, numEq, numEq> Matrix;
        typedef Dune::FieldVector<InputEval, numEq> Vector;

        typedef Opm::LocalAd::Evaluation<InputEval, numEq> FlashEval;
        typedef Dune::FieldVector<FlashEval, numEq> FlashDefectVector;
        typedef Opm::ImmiscibleFluidState<FlashEval, FluidSystem> FlashFluidState;

        Dune::FMatrixPrecision<InputEval>::set_singular_limit(1e-35);

        if (tolerance <= 0)
            tolerance = std::min<Scalar>(1e-5,
                                         1e8*std::numeric_limits<Scalar>::epsilon());

        typename FluidSystem::template ParameterCache<FlashEval> flashParamCache;
        flashParamCache.assignPersistentData(paramCache);

        /////////////////////////
        // Newton method
        /////////////////////////

        // Jacobian matrix
        Matrix J;
        // solution, i.e. phase composition
        Vector deltaX;
        // right hand side
        Vector b;

        Valgrind::SetUndefined(J);
        Valgrind::SetUndefined(deltaX);
        Valgrind::SetUndefined(b);

        FlashFluidState flashFluidState;
        assignFlashFluidState_<MaterialLaw>(fluidState, flashFluidState, matParams, flashParamCache);

        // copy the global molarities to a vector of evaluations. Remember that the
        // global molarities are constants. (but we need to copy them to a vector of
        // FlashEvals anyway in order to avoid getting into hell's kitchen.)
        Dune::FieldVector<FlashEval, numComponents> flashGlobalMolarities;
        for (unsigned compIdx = 0; compIdx < numComponents; ++ compIdx)
            flashGlobalMolarities[compIdx] = globalMolarities[compIdx];

        FlashDefectVector defect;
        const unsigned nMax = 50; // <- maximum number of newton iterations
        for (unsigned nIdx = 0; nIdx < nMax; ++nIdx) {
            // calculate Jacobian matrix and right hand side
            evalDefect_(defect, flashFluidState, flashGlobalMolarities);
            Valgrind::CheckDefined(defect);

            // create field matrices and vectors out of the evaluation vector to solve
            // the linear system of equations.
            for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
                for (unsigned pvIdx = 0; pvIdx < numEq; ++ pvIdx)
                    J[eqIdx][pvIdx] = defect[eqIdx].derivatives[pvIdx];

                b[eqIdx] = defect[eqIdx].value;
            }
            Valgrind::CheckDefined(J);
            Valgrind::CheckDefined(b);

            // Solve J*x = b
            deltaX = 0;

            try { J.solve(deltaX, b); }
            catch (Dune::FMatrixError e) {
                throw Opm::NumericalProblem(e.what());
            }
            Valgrind::CheckDefined(deltaX);

            // update the fluid quantities.
            Scalar relError = update_<MaterialLaw>(flashFluidState, flashParamCache, matParams, deltaX);

            if (relError < tolerance) {
                assignOutputFluidState_(flashFluidState, fluidState);
                return;
            }
        }

        OPM_THROW(Opm::NumericalProblem,
                  "ImmiscibleFlash solver failed: "
                  "{c_alpha^kappa} = {" << globalMolarities << "}, "
                  << "T = " << fluidState.temperature(/*phaseIdx=*/0));
    }
コード例 #21
0
        /// set the tables which specify the temperature dependence of the oil viscosity
        void initFromDeck(std::shared_ptr<const PvtInterface> isothermalPvt,
                          const Opm::Deck& deck,
                          const Opm::EclipseState& eclipseState)
        {
            isothermalPvt_ = isothermalPvt;

            int numRegions;
            auto tables = eclipseState->getTableManager();

            if (deck->hasKeyword("PVTO"))
                numRegions = tables->getPvtoTables().size();
            else if (deck->hasKeyword("PVDO"))
                numRegions = tables->getPvdoTables().size();
            else if (deck->hasKeyword("PVCDO"))
                numRegions = deck->getKeyword("PVCDO").size();
            else
                OPM_THROW(std::runtime_error, "Oil phase was not initialized using a known way");

            // viscosity
            if (deck->hasKeyword("VISCREF")) {
                oilvisctTables_ = &tables->getOilvisctTables();
                const auto& viscrefKeyword = deck->getKeyword("VISCREF");

                assert(int(oilvisctTables_->size()) == numRegions);
                assert(int(viscrefKeyword.size()) == numRegions);

                viscrefPress_.resize(numRegions);
                viscrefRs_.resize(numRegions);
                muRef_.resize(numRegions);
                for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                    const auto& viscrefRecord = viscrefKeyword.getRecord(regionIdx);
                    viscrefPress_[regionIdx] = viscrefRecord.getItem("REFERENCE_PRESSURE").getSIDouble(0);
                    viscrefRs_[regionIdx] = viscrefRecord.getItem("REFERENCE_RS").getSIDouble(0);

                    // temperature used to calculate the reference viscosity [K]. the
                    // value does not really matter if the underlying PVT object really
                    // is isothermal...
                    double Tref = 273.15 + 20;

                    // compute the reference viscosity using the isothermal PVT object.
                    double tmp1, tmp2;
                    isothermalPvt_->mu(1,
                                       &regionIdx,
                                       &viscrefPress_[regionIdx],
                                       &Tref,
                                       &viscrefRs_[regionIdx],
                                       &muRef_[regionIdx],
                                       &tmp1,
                                       &tmp2);
                }
            }

            // quantities required for density. note that we just always use the values
            // for the first EOS. (since EOS != PVT region.)
            tref_ = 0.0;
            if (deck->hasKeyword("THERMEX1")) {
                oilCompIdx_ = deck->getKeyword("OCOMPIDX").getRecord(0).getItem("OIL_COMPONENT_INDEX").get< int >(0) - 1;

                // always use the values of the first EOS
                tref_ = deck->getKeyword("TREF").getRecord(0).getItem("TEMPERATURE").getSIDouble(oilCompIdx_);
                pref_ = deck->getKeyword("PREF").getRecord(0).getItem("PRESSURE").getSIDouble(oilCompIdx_);
                cref_ = deck->getKeyword("CREF").getRecord(0).getItem("COMPRESSIBILITY").getSIDouble(oilCompIdx_);
                thermex1_ = deck->getKeyword("THERMEX1").getRecord(0).getItem("EXPANSION_COEFF").getSIDouble(oilCompIdx_);
            }
        }
コード例 #22
0
    void TransportSolverTwophaseReorder::solveMultiCell(const int num_cells, const int* cells)
    {
        // std::ofstream os("dump");
        // std::copy(cells, cells + num_cells, std::ostream_iterator<double>(os, "\n"));

        // Experiment: try a breath-first search to build a more suitable ordering.
        // Verdict: failed to improve #iterations.
        // {
        //     std::vector<int> pos(grid_.number_of_cells, -1);
        //     for (int i = 0; i < num_cells; ++i) {
        //      const int cell = cells[i];
        //      pos[cell] = i;
        //     }
        //     std::vector<int> done_pos(num_cells, 0);
        //     std::vector<int> upstream_pos;
        //     std::vector<int> new_pos;
        //     upstream_pos.push_back(0);
        //     done_pos[0] = 1;
        //     int current = 0;
        //     while (int(new_pos.size()) < num_cells) {
        //      const int i = upstream_pos[current++];
        //      new_pos.push_back(i);
        //      const int cell = cells[i];
        //      for (int j = ia_[cell]; j < ia_[cell+1]; ++j) {
        //          const int opos = pos[ja_[j]];
        //          if (!done_pos[opos]) {
        //              upstream_pos.push_back(opos);
        //              done_pos[opos] = 1;
        //          }
        //      }
        //     }
        //     std::reverse(new_pos.begin(), new_pos.end());
        //     std::copy(new_pos.begin(), new_pos.end(), const_cast<int*>(cells));
        // }

        // Experiment: try a random ordering.
        // Verdict: amazingly, reduced #iterations by approx. 25%!
        // int* c = const_cast<int*>(cells);
        // std::random_shuffle(c, c + num_cells);

        // Experiment: compute topological tof from first cell.
        // Verdict: maybe useful, not tried to exploit it yet.
        // std::vector<int> tof;
        // TofComputer comp(grid_.number_of_cells, &ia_[0], &ja_[0], cells[0], tof);
        // std::ofstream tofdump("tofdump");
        // std::copy(tof.begin(), tof.end(), std::ostream_iterator<double>(tofdump, "\n"));

        // Experiment: implement a metric measuring badness of ordering
        //             as average distance in (cyclic) ordering from
        //             upstream neighbours.
        // Verdict: does not seem to predict #iterations very well, if at all.
        // std::vector<int> pos(grid_.number_of_cells, -1);
        // for (int i = 0; i < num_cells; ++i) {
        //     const int cell = cells[i];
        //     pos[cell] = i;
        // }
        // double diffsum = 0;
        // for (int i = 0; i < num_cells; ++i) {
        //     const int cell = cells[i];
        //     int num_upstream = 0;
        //     int loc_diffsum = 0;
        //     for (int j = ia_[cell]; j < ia_[cell+1]; ++j) {
        //      const int opos = pos[ja_[j]];
        //      if (opos == -1) {
        //          std::cout << "Hmmm" << std::endl;
        //          continue;
        //      }
        //      ++num_upstream;
        //      const int diff = (i - opos + num_cells) % num_cells;
        //      loc_diffsum += diff;
        //     }
        //     diffsum += double(loc_diffsum)/double(num_upstream);
        // }
        // std::cout << "Average distance from upstream neighbours: " << diffsum/double(num_cells)
        //        << std::endl;

#ifdef EXPERIMENT_GAUSS_SEIDEL
        // Experiment: when a cell changes more than the tolerance,
        //             mark all downwind cells as needing updates. After
        //             computing a single update in each cell, use marks
        //             to guide further updating. Clear mark in cell when
        //             its solution gets updated.
        // Verdict: this is a good one! Approx. halved total time.
        std::vector<int> needs_update(num_cells, 1);
        // This one also needs the mapping from all cells to
        // the strongly connected subset to filter out connections
        std::vector<int> pos(grid_.number_of_cells, -1);
        for (int i = 0; i < num_cells; ++i) {
            const int cell = cells[i];
            pos[cell] = i;
        }

        // Note: partially copied from below.
        const double tol = 1e-9;
        const int max_iters = 300;
        // Must store s0 before we start.
        std::vector<double> s0(num_cells);
        // Must set initial fractional flows before we start.
        // Also, we compute the # of upstream neighbours.
        // std::vector<int> num_upstream(num_cells);
        for (int i = 0; i < num_cells; ++i) {
            const int cell = cells[i];
            fractionalflow_[cell] = fracFlow(saturation_[cell], cell);
            s0[i] = saturation_[cell];
            // num_upstream[i] = ia_upw_[cell + 1] - ia_upw_[cell];
        }
        // Solve once in each cell.
        // std::vector<int> fully_marked_stack;
        // fully_marked_stack.reserve(num_cells);
        int num_iters = 0;
        int update_count = 0; // Change name/meaning to cells_updated?
        do {
            update_count = 0; // Must reset count for every iteration.
            for (int i = 0; i < num_cells; ++i) {
                // while (!fully_marked_stack.empty()) {
                //     // std::cout << "# fully marked cells = " << fully_marked_stack.size() << std::endl;
                //     const int fully_marked_ci = fully_marked_stack.back();
                //     fully_marked_stack.pop_back();
                //     ++update_count;
                //     const int cell = cells[fully_marked_ci];
                //     const double old_s = saturation_[cell];
                //     saturation_[cell] = s0[fully_marked_ci];
                //     solveSingleCell(cell);
                //     const double s_change = std::fabs(saturation_[cell] - old_s);
                //     if (s_change > tol) {
                //      // Mark downwind cells.
                //      for (int j = ia_downw_[cell]; j < ia_downw_[cell+1]; ++j) {
                //          const int downwind_cell = ja_downw_[j];
                //          int ci = pos[downwind_cell];
                //          ++needs_update[ci];
                //          if (needs_update[ci] == num_upstream[ci]) {
                //              fully_marked_stack.push_back(ci);
                //          }
                //      }
                //     }
                //     // Unmark this cell.
                //     needs_update[fully_marked_ci] = 0;
                // }
                if (!needs_update[i]) {
                    continue;
                }
                ++update_count;
                const int cell = cells[i];
                const double old_s = saturation_[cell];
                saturation_[cell] = s0[i];
                solveSingleCell(cell);
                const double s_change = std::fabs(saturation_[cell] - old_s);
                if (s_change > tol) {
                    // Mark downwind cells.
                    for (int j = ia_downw_[cell]; j < ia_downw_[cell+1]; ++j) {
                        const int downwind_cell = ja_downw_[j];
                        int ci = pos[downwind_cell];
                        if (ci != -1) {
                            needs_update[ci] = 1;
                        }
                        // ++needs_update[ci];
                        // if (needs_update[ci] == num_upstream[ci]) {
                        //     fully_marked_stack.push_back(ci);
                        // }
                    }
                }
                // Unmark this cell.
                needs_update[i] = 0;
            }
            // std::cout << "Iter = " << num_iters << "    update_count = " << update_count
            //        << "    # marked cells = "
            //        << std::accumulate(needs_update.begin(), needs_update.end(), 0) << std::endl;
        } while (update_count > 0 && ++num_iters < max_iters);

        // Done with iterations, check if we succeeded.
        if (update_count > 0) {
            OPM_THROW(std::runtime_error, "In solveMultiCell(), we did not converge after "
                  << num_iters << " iterations. Remaining update count = " << update_count);
        }
        std::cout << "Solved " << num_cells << " cell multicell problem in "
                  << num_iters << " iterations." << std::endl;

#else
        double max_s_change = 0.0;
        const double tol = 1e-9;
        const int max_iters = 300;
        int num_iters = 0;
        // Must store s0 before we start.
        std::vector<double> s0(num_cells);
        // Must set initial fractional flows before we start.
        for (int i = 0; i < num_cells; ++i) {
            const int cell = cells[i];
            fractionalflow_[cell] = fracFlow(saturation_[cell], cell);
            s0[i] = saturation_[cell];
        }
        do {
            max_s_change = 0.0;
            for (int i = 0; i < num_cells; ++i) {
                const int cell = cells[i];
                const double old_s = saturation_[cell];
                saturation_[cell] = s0[i];
                solveSingleCell(cell);
                double s_change = std::fabs(saturation_[cell] - old_s);
                // std::cout << "cell = " << cell << "    delta s = " << s_change << std::endl;
                if (max_s_change < s_change) {
                    max_s_change = s_change;
                }
            }
            // std::cout << "Iter = " << num_iters << "    max_s_change = " << max_s_change
            //        << "    in cell " << max_change_cell << std::endl;
        } while (max_s_change > tol && ++num_iters < max_iters);
        if (max_s_change > tol) {
            OPM_THROW(std::runtime_error, "In solveMultiCell(), we did not converge after "
                  << num_iters << " iterations. Delta s = " << max_s_change);
        }
        std::cout << "Solved " << num_cells << " cell multicell problem in "
                  << num_iters << " iterations." << std::endl;
#endif // EXPERIMENT_GAUSS_SEIDEL
    }
コード例 #23
0
 static Scalar heatConductivity(const Params &params,
                                const FluidState &fluidState)
 {
     OPM_THROW(std::logic_error,
                "No heat conduction law specified!");
 }
コード例 #24
0
 /*!
  * \brief The molar density of a fluid phase [mol/m^3]
  */
 Scalar molarDensity(int /* phaseIdx */) const
 { OPM_THROW(std::logic_error, "Molar density is not provided by this fluid state"); }
コード例 #25
0
ファイル: H2O_CO2.hpp プロジェクト: GitPaean/opm-material
 static Evaluation liquidDiffCoeff(const Evaluation& temperature, const Evaluation& pressure)
 { OPM_THROW(std::runtime_error, "Not implemented: Binary liquid diffusion coefficients of CO2 and CH4"); }
コード例 #26
0
 /*!
  * \brief The molar volume of a fluid phase [m^3/mol]
  */
 Scalar molarVolume(int /* phaseIdx */) const
 { OPM_THROW(std::logic_error, "Molar volume is not provided by this fluid state"); }
コード例 #27
0
 static Evaluation Sg(const Params& /* params */,
                      const FluidState& /* fluidState */)
 {
     OPM_THROW(std::logic_error, "Not implemented: Sg()");
 }
コード例 #28
0
Scalar bringOilToSurface(FluidState &surfaceFluidState, Scalar alpha, const FluidState &reservoirFluidState, bool guessInitial)
{
    enum {
        numPhases = FluidSystem::numPhases,
        waterPhaseIdx = FluidSystem::waterPhaseIdx,
        gasPhaseIdx = FluidSystem::gasPhaseIdx,
        oilPhaseIdx = FluidSystem::oilPhaseIdx,

        numComponents = FluidSystem::numComponents
    };

    typedef Opm::NcpFlash<Scalar, FluidSystem> Flash;
    typedef Opm::ThreePhaseMaterialTraits<Scalar, waterPhaseIdx, oilPhaseIdx, gasPhaseIdx> MaterialTraits;
    typedef Opm::LinearMaterial<MaterialTraits> MaterialLaw;
    typedef typename MaterialLaw::Params MaterialLawParams;
    typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;

    const Scalar refPressure = 1.0135e5; // [Pa]

    // set the parameters for the capillary pressure law
    MaterialLawParams matParams;
    for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
        matParams.setPcMinSat(phaseIdx, 0.0);
        matParams.setPcMaxSat(phaseIdx, 0.0);
    }
    matParams.finalize();

    // retieve the global volumetric component molarities
    surfaceFluidState.setTemperature(273.15 + 20);

    ComponentVector molarities;
    for (int compIdx = 0; compIdx < numComponents; ++ compIdx)
        molarities[compIdx] = reservoirFluidState.molarity(oilPhaseIdx, compIdx);

    if (guessInitial) {
        // we start at a fluid state with reservoir oil.
        for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
            for (int compIdx = 0; compIdx < numComponents; ++ compIdx) {
                surfaceFluidState.setMoleFraction(phaseIdx,
                                                  compIdx,
                                                  reservoirFluidState.moleFraction(phaseIdx, compIdx));
            }
            surfaceFluidState.setDensity(phaseIdx, reservoirFluidState.density(phaseIdx));
            surfaceFluidState.setPressure(phaseIdx, reservoirFluidState.pressure(phaseIdx));
            surfaceFluidState.setSaturation(phaseIdx, 0.0);
        }
        surfaceFluidState.setSaturation(oilPhaseIdx, 1.0);
        surfaceFluidState.setSaturation(gasPhaseIdx, 1.0 - surfaceFluidState.saturation(oilPhaseIdx));
    }

    typename FluidSystem::ParameterCache paramCache;
    paramCache.updateAll(surfaceFluidState);

    // increase volume until we are at surface pressure. use the
    // newton method for this
    ComponentVector tmpMolarities;
    for (int i = 0;; ++i) {
        if (i >= 20)
            OPM_THROW(Opm::NumericalIssue,
                       "Newton method did not converge after 20 iterations");

        // calculate the deviation from the standard pressure
        tmpMolarities = molarities;
        tmpMolarities /= alpha;
        Flash::template solve<MaterialLaw>(surfaceFluidState, paramCache, matParams, tmpMolarities);
        Scalar f = surfaceFluidState.pressure(gasPhaseIdx) - refPressure;

        // calculate the derivative of the deviation from the standard
        // pressure
        Scalar eps = alpha*1e-10;
        tmpMolarities = molarities;
        tmpMolarities /= alpha + eps;
        Flash::template solve<MaterialLaw>(surfaceFluidState, paramCache, matParams, tmpMolarities);
        Scalar fStar = surfaceFluidState.pressure(gasPhaseIdx) - refPressure;
        Scalar fPrime = (fStar - f)/eps;

        // newton update
        Scalar delta = f/fPrime;
        alpha -= delta;
        if (std::abs(delta) < std::abs(alpha)*1e-9) {
            break;
        }
    }

    // calculate the final result
    tmpMolarities = molarities;
    tmpMolarities /= alpha;
    Flash::template solve<MaterialLaw>(surfaceFluidState, paramCache, matParams, tmpMolarities);
    return alpha;
}