Exemplo n.º 1
0
    inline typename UpscalerBase<Traits>::permtensor_t
    UpscalerBase<Traits>::upscaleEffectivePerm(const FluidInterface& fluid)
    {
	int num_cells = ginterf_.numberOfCells();
	// No source or sink.
	std::vector<double> src(num_cells, 0.0);
	// Just water.
	std::vector<double> sat(num_cells, 1.0);
	// Gravity.
	Dune::FieldVector<double, 3> gravity(0.0);
	// gravity[2] = -Dune::unit::gravity;

	permtensor_t upscaled_K(3, 3, (double*)0);
	for (int pdd = 0; pdd < Dimension; ++pdd) {
	    setupUpscalingConditions(ginterf_, bctype_, pdd, 1.0, 1.0, twodim_hack_, bcond_);
	    if (pdd == 0) {
		// Only on first iteration, since we do not change the
		// structure of the system, the way the flow solver is
		// implemented.
		flow_solver_.init(ginterf_, res_prop_, gravity, bcond_);
	    }

	    // Run pressure solver.
            bool same_matrix = (bctype_ != Fixed) && (pdd != 0);
	    flow_solver_.solve(fluid, sat, bcond_, src, residual_tolerance_,
                               linsolver_verbosity_, 
                               linsolver_type_, same_matrix,
                               linsolver_maxit_, linsolver_prolongate_factor_,
                               linsolver_smooth_steps_);
            double max_mod = flow_solver_.postProcessFluxes();
            std::cout << "Max mod = " << max_mod << std::endl;

	    // Compute upscaled K.
	    double Q[Dimension] =  { 0 };
	    switch (bctype_) {
	    case Fixed:
		Q[pdd] = computeAverageVelocity(flow_solver_.getSolution(), pdd, pdd);
		break;
	    case Linear:
	    case Periodic:
		for (int i = 0; i < Dimension; ++i) {
		    Q[i] = computeAverageVelocity(flow_solver_.getSolution(), i, pdd);
		}
		break;
	    default:
		OPM_THROW(std::runtime_error, "Unknown boundary type: " << bctype_);
	    }
	    double delta = computeDelta(pdd);
	    for (int i = 0; i < Dimension; ++i) {
		upscaled_K(i, pdd) = Q[i] * delta;
	    }
	}
	return upscaled_K;
    }
Exemplo n.º 2
0
    inline void setupBoundaryConditions(const Opm::parameter::ParameterGroup& param,
					const GridInterface& g,
					BCs& bcs)
    {
	if (param.getDefault("upscaling", false)) {
	    int bct = param.get<int>("boundary_condition_type");
	    int pddir = param.getDefault("pressure_drop_direction", 0);
	    double pdrop = param.getDefault("boundary_pressuredrop", 1.0e5);
	    double bdy_sat = param.getDefault("boundary_saturation", 1.0);
	    bool twodim_hack = param.getDefault("2d_hack", false);
	    setupUpscalingConditions(g, bct, pddir, pdrop, bdy_sat, twodim_hack, bcs);
	    return;
	}
        if (param.getDefault("region_based_bcs", false)) {
            setupRegionBasedConditions(param, g, bcs);
            return;
        }
	// Make flow equation boundary conditions.
	// Default is pressure 1.0e5 on the left, 0.0 on the right.
	// Recall that the boundary ids range from 1 to 6 for the cartesian edges,
	// and that boundary id 0 means interiour face/intersection.
	std::string flow_bc_type = param.getDefault<std::string>("flow_bc_type", "dirichlet");
	FlowBC::BCType bct = FlowBC::Dirichlet;
	double leftval = 1.0*Opm::unit::barsa;
	double rightval = 0.0;
	if (flow_bc_type == "neumann") {
	    bct = FlowBC::Neumann;
	    leftval = param.get<double>("left_flux");
	    rightval = param.getDefault<double>("right_flux", -leftval);
	} else if (flow_bc_type == "dirichlet") {
	    leftval = param.getDefault<double>("left_pressure", leftval);
	    rightval = param.getDefault<double>("right_pressure", rightval);
	} else if (flow_bc_type == "periodic") {
	    THROW("Periodic conditions not here yet.");
	} else {
	    THROW("Unknown flow boundary condition type " << flow_bc_type);
	}
	bcs.resize(7);
	bcs.flowCond(1) = FlowBC(bct, leftval);
	bcs.flowCond(2) = FlowBC(bct, rightval);

	// Default transport boundary conditions are used.
    }
inline std::pair<typename SteadyStateUpscaler<Traits>::permtensor_t,
       typename SteadyStateUpscaler<Traits>::permtensor_t>
       SteadyStateUpscaler<Traits>::
       upscaleSteadyState(const int flow_direction,
                          const std::vector<double>& initial_saturation,
                          const double boundary_saturation,
                          const double pressure_drop,
                          const permtensor_t& upscaled_perm)
{
    static int count = 0;
    ++count;
    int num_cells = this->ginterf_.numberOfCells();
    // No source or sink.
    std::vector<double> src(num_cells, 0.0);
    Opm::SparseVector<double> injection(num_cells);
    // Gravity.
    Dune::FieldVector<double, 3> gravity(0.0);
    if (use_gravity_) {
        gravity[2] = Opm::unit::gravity;
    }
    if (gravity.two_norm() > 0.0) {
        OPM_MESSAGE("Warning: Gravity is experimental for flow solver.");
    }

    // Set up initial saturation profile.
    std::vector<double> saturation = initial_saturation;

    // Set up boundary conditions.
    setupUpscalingConditions(this->ginterf_, this->bctype_, flow_direction,
                             pressure_drop, boundary_saturation, this->twodim_hack_, this->bcond_);

    // Set up solvers.
    if (flow_direction == 0) {
        this->flow_solver_.init(this->ginterf_, this->res_prop_, gravity, this->bcond_);
    }
    transport_solver_.initObj(this->ginterf_, this->res_prop_, this->bcond_);

    // Run pressure solver.
    this->flow_solver_.solve(this->res_prop_, saturation, this->bcond_, src,
                             this->residual_tolerance_, this->linsolver_verbosity_,
                             this->linsolver_type_, false,
                             this->linsolver_maxit_, this->linsolver_prolongate_factor_,
                             this->linsolver_smooth_steps_);
    double max_mod = this->flow_solver_.postProcessFluxes();
    std::cout << "Max mod = " << max_mod << std::endl;

    // Do a run till steady state. For now, we just do some pressure and transport steps...
    std::vector<double> saturation_old = saturation;
    for (int iter = 0; iter < simulation_steps_; ++iter) {
        // Run transport solver.
        transport_solver_.transportSolve(saturation, stepsize_, gravity, this->flow_solver_.getSolution(), injection);

        // Run pressure solver.
        this->flow_solver_.solve(this->res_prop_, saturation, this->bcond_, src,
                                 this->residual_tolerance_, this->linsolver_verbosity_,
                                 this->linsolver_type_, false,
                                 this->linsolver_maxit_, this->linsolver_prolongate_factor_,
                                 this->linsolver_smooth_steps_);
        max_mod = this->flow_solver_.postProcessFluxes();
        std::cout << "Max mod = " << max_mod << std::endl;

        // Print in-out flows if requested.
        if (print_inoutflows_) {
            std::pair<double, double> w_io, o_io;
            computeInOutFlows(w_io, o_io, this->flow_solver_.getSolution(), saturation);
            std::cout << "Pressure step " << iter
                      << "\nWater flow [in] " << w_io.first
                      << "  [out] " << w_io.second
                      << "\nOil flow   [in] " << o_io.first
                      << "  [out] " << o_io.second
                      << std::endl;
        }

        // Output.
        if (output_vtk_) {
            writeVtkOutput(this->ginterf_,
                           this->res_prop_,
                           this->flow_solver_.getSolution(),
                           saturation,
                           std::string("output-steadystate")
                           + '-' + boost::lexical_cast<std::string>(count)
                           + '-' + boost::lexical_cast<std::string>(flow_direction)
                           + '-' + boost::lexical_cast<std::string>(iter));
        }

        // Comparing old to new.
        int num_cells = saturation.size();
        double maxdiff = 0.0;
        for (int i = 0; i < num_cells; ++i) {
            maxdiff = std::max(maxdiff, std::fabs(saturation[i] - saturation_old[i]));
        }
#ifdef VERBOSE
        std::cout << "Maximum saturation change: " << maxdiff << std::endl;
#endif
        if (maxdiff < sat_change_threshold_) {
#ifdef VERBOSE
            std::cout << "Maximum saturation change is under steady state threshold." << std::endl;
#endif
            break;
        }

        // Copy to old.
        saturation_old = saturation;
    }

    // Compute phase mobilities.
    // First: compute maximal mobilities.
    typedef typename Super::ResProp::Mobility Mob;
    Mob m;
    double m1max = 0;
    double m2max = 0;
    for (int c = 0; c < num_cells; ++c) {
        this->res_prop_.phaseMobility(0, c, saturation[c], m.mob);
        m1max = maxMobility(m1max, m.mob);
        this->res_prop_.phaseMobility(1, c, saturation[c], m.mob);
        m2max = maxMobility(m2max, m.mob);
    }
    // Second: set thresholds.
    const double mob1_abs_thres = relperm_threshold_ / this->res_prop_.viscosityFirstPhase();
    const double mob1_rel_thres = m1max / maximum_mobility_contrast_;
    const double mob1_threshold = std::max(mob1_abs_thres, mob1_rel_thres);
    const double mob2_abs_thres = relperm_threshold_ / this->res_prop_.viscositySecondPhase();
    const double mob2_rel_thres = m2max / maximum_mobility_contrast_;
    const double mob2_threshold = std::max(mob2_abs_thres, mob2_rel_thres);
    // Third: extract and threshold.
    std::vector<Mob> mob1(num_cells);
    std::vector<Mob> mob2(num_cells);
    for (int c = 0; c < num_cells; ++c) {
        this->res_prop_.phaseMobility(0, c, saturation[c], mob1[c].mob);
        thresholdMobility(mob1[c].mob, mob1_threshold);
        this->res_prop_.phaseMobility(1, c, saturation[c], mob2[c].mob);
        thresholdMobility(mob2[c].mob, mob2_threshold);
    }

    // Compute upscaled relperm for each phase.
    ReservoirPropertyFixedMobility<Mob> fluid_first(mob1);
    permtensor_t eff_Kw = Super::upscaleEffectivePerm(fluid_first);
    ReservoirPropertyFixedMobility<Mob> fluid_second(mob2);
    permtensor_t eff_Ko = Super::upscaleEffectivePerm(fluid_second);

    // Set the steady state saturation fields for eventual outside access.
    last_saturation_state_.swap(saturation);

    // Compute the (anisotropic) upscaled mobilities.
    // eff_Kw := lambda_w*K
    //  =>  lambda_w = eff_Kw*inv(K);
    permtensor_t lambda_w(matprod(eff_Kw, inverse3x3(upscaled_perm)));
    permtensor_t lambda_o(matprod(eff_Ko, inverse3x3(upscaled_perm)));

    // Compute (anisotropic) upscaled relative permeabilities.
    // lambda = k_r/mu
    permtensor_t k_rw(lambda_w);
    k_rw *= this->res_prop_.viscosityFirstPhase();
    permtensor_t k_ro(lambda_o);
    k_ro *= this->res_prop_.viscositySecondPhase();
    return std::make_pair(k_rw, k_ro);
}