Exemplo n.º 1
0
 /// Relative permeabilities for all phases.
 /// \param[in]  sw     Array of n water saturation values.
 /// \param[in]  so     Array of n oil saturation values.
 /// \param[in]  sg     Array of n gas saturation values.
 /// \param[in]  cells  Array of n cell indices to be associated with the saturation values.
 /// \return            An std::vector with 3 elements, each an array of n relperm values,
 ///                    containing krw, kro, krg. Use PhaseIndex for indexing into the result.
 std::vector<V> BlackoilPropsAdFromDeck::relperm(const V& sw,
                                                 const V& so,
                                                 const V& sg,
                                                 const Cells& cells) const
 {
     const int n = cells.size();
     const int np = numPhases();
     Block s_all(n, np);
     if (phase_usage_.phase_used[Water]) {
         assert(sw.size() == n);
         s_all.col(phase_usage_.phase_pos[Water]) = sw;
     }
     if (phase_usage_.phase_used[Oil]) {
         assert(so.size() == n);
         s_all.col(phase_usage_.phase_pos[Oil]) = so;
     }
     if (phase_usage_.phase_used[Gas]) {
         assert(sg.size() == n);
         s_all.col(phase_usage_.phase_pos[Gas]) = sg;
     }
     Block kr(n, np);
     satprops_->relperm(n, s_all.data(), cells.data(), kr.data(), 0);
     std::vector<V> relperms;
     relperms.reserve(3);
     for (int phase = 0; phase < 3; ++phase) {
         if (phase_usage_.phase_used[phase]) {
             relperms.emplace_back(kr.col(phase_usage_.phase_pos[phase]));
         } else {
             relperms.emplace_back();
         }
     }
     return relperms;
 }
Exemplo n.º 2
0
 void init(const UnstructuredGrid& g, const PhaseUsage& usedPhases)
 {
     usedPhases_ = usedPhases;
     press_.resize(g.number_of_cells, 0.0);
     fpress_.resize(g.number_of_faces, 0.0);
     flux_.resize(g.number_of_faces, 0.0);
     sat_.resize(numPhases() * g.number_of_cells, 0.0);
     for (int cell = 0; cell < g.number_of_cells; ++cell) {
         // Defaulting the second saturation to 1.0.
         // This will usually be oil in a water-oil case,
         // gas in an oil-gas case.
         // For proper initialization, one should not rely on this,
         // but use available phase information instead.
         sat_[numPhases()*cell + 1] = 1.0;
     }
     gor_.resize(g.number_of_cells, 0.0);
 }
Exemplo n.º 3
0
    std::vector<ADB> BlackoilPropsAd::capPress(const ADB& sw,
                                               const ADB& so,
                                               const ADB& sg,
                                               const Cells& cells) const

    {
        const int numCells = cells.size();
        const int numActivePhases = numPhases();
        const int numBlocks = so.numBlocks();

        Block activeSat(numCells, numActivePhases);
        if (pu_.phase_used[Water]) {
            assert(sw.value().size() == numCells);
            activeSat.col(pu_.phase_pos[Water]) = sw.value();
        }
        if (pu_.phase_used[Oil]) {
            assert(so.value().size() == numCells);
            activeSat.col(pu_.phase_pos[Oil]) = so.value();
        } else {
            OPM_THROW(std::runtime_error, "BlackoilPropsAdFromDeck::relperm() assumes oil phase is active.");
        }
        if (pu_.phase_used[Gas]) {
            assert(sg.value().size() == numCells);
            activeSat.col(pu_.phase_pos[Gas]) = sg.value();
        }

        Block pc(numCells, numActivePhases);
        Block dpc(numCells, numActivePhases*numActivePhases);
        props_.capPress(numCells, activeSat.data(), cells.data(), pc.data(), dpc.data());

        std::vector<ADB> adbCapPressures;
        adbCapPressures.reserve(3);
        const ADB* s[3] = { &sw, &so, &sg };
        for (int phase1 = 0; phase1 < 3; ++phase1) {
            if (pu_.phase_used[phase1]) {
                const int phase1_pos = pu_.phase_pos[phase1];
                std::vector<ADB::M> jacs(numBlocks);
                for (int block = 0; block < numBlocks; ++block) {
                    jacs[block] = ADB::M(numCells, s[phase1]->derivative()[block].cols());
                }
                for (int phase2 = 0; phase2 < 3; ++phase2) {
                    if (!pu_.phase_used[phase2])
                        continue;
                    const int phase2_pos = pu_.phase_pos[phase2];
                    // Assemble dpc1/ds2.
                    const int column = phase1_pos + numActivePhases*phase2_pos; // Recall: Fortran ordering from props_.relperm()
                    ADB::M dpc1_ds2_diag = spdiag(dpc.col(column));
                    for (int block = 0; block < numBlocks; ++block) {
                        jacs[block] += dpc1_ds2_diag * s[phase2]->derivative()[block];
                    }
                }
                adbCapPressures.emplace_back(ADB::function(pc.col(phase1_pos), jacs));
            } else {
                adbCapPressures.emplace_back(ADB::null());
            }
        }
        return adbCapPressures;
    }
Exemplo n.º 4
0
 /// Relative permeabilities for all phases.
 /// \param[in]  sw     Array of n water saturation values.
 /// \param[in]  so     Array of n oil saturation values.
 /// \param[in]  sg     Array of n gas saturation values.
 /// \param[in]  cells  Array of n cell indices to be associated with the saturation values.
 /// \return            An std::vector with 3 elements, each an array of n relperm values,
 ///                    containing krw, kro, krg. Use PhaseIndex for indexing into the result.
 std::vector<ADB> BlackoilPropsAdFromDeck::relperm(const ADB& sw,
                                                   const ADB& so,
                                                   const ADB& sg,
                                                   const Cells& cells) const
 {
     const int n = cells.size();
     const int np = numPhases();
     Block s_all(n, np);
     if (phase_usage_.phase_used[Water]) {
         assert(sw.value().size() == n);
         s_all.col(phase_usage_.phase_pos[Water]) = sw.value();
     }
     if (phase_usage_.phase_used[Oil]) {
         assert(so.value().size() == n);
         s_all.col(phase_usage_.phase_pos[Oil]) = so.value();
     } else {
         OPM_THROW(std::runtime_error, "BlackoilPropsAdFromDeck::relperm() assumes oil phase is active.");
     }
     if (phase_usage_.phase_used[Gas]) {
         assert(sg.value().size() == n);
         s_all.col(phase_usage_.phase_pos[Gas]) = sg.value();
     }
     Block kr(n, np);
     Block dkr(n, np*np);
     satprops_->relperm(n, s_all.data(), cells.data(), kr.data(), dkr.data());
     const int num_blocks = so.numBlocks();
     std::vector<ADB> relperms;
     relperms.reserve(3);
     typedef const ADB* ADBPtr;
     ADBPtr s[3] = { &sw, &so, &sg };
     for (int phase1 = 0; phase1 < 3; ++phase1) {
         if (phase_usage_.phase_used[phase1]) {
             const int phase1_pos = phase_usage_.phase_pos[phase1];
             std::vector<ADB::M> jacs(num_blocks);
             for (int block = 0; block < num_blocks; ++block) {
                 jacs[block] = ADB::M(n, s[phase1]->derivative()[block].cols());
             }
             for (int phase2 = 0; phase2 < 3; ++phase2) {
                 if (!phase_usage_.phase_used[phase2]) {
                     continue;
                 }
                 const int phase2_pos = phase_usage_.phase_pos[phase2];
                 // Assemble dkr1/ds2.
                 const int column = phase1_pos + np*phase2_pos; // Recall: Fortran ordering from props_.relperm()
                 ADB::M dkr1_ds2_diag = spdiag(dkr.col(column));
                 for (int block = 0; block < num_blocks; ++block) {
                     jacs[block] += dkr1_ds2_diag * s[phase2]->derivative()[block];
                 }
             }
             relperms.emplace_back(ADB::function(kr.col(phase1_pos), jacs));
         } else {
             relperms.emplace_back(ADB::null());
         }
     }
     return relperms;
 }
Exemplo n.º 5
0
        bool equals(const BlackoilState& other, double epsilon = 1e-8) const {
            bool equal = (numPhases() == other.numPhases());

            for (int phaseIdx = 0; phaseIdx < BlackoilPhases::MaxNumPhases; ++ phaseIdx) {
                equal = equal && (usedPhases_.phase_used[phaseIdx] == other.usedPhases_.phase_used[phaseIdx]);
                if (usedPhases_.phase_used[phaseIdx])
                    equal = equal && (usedPhases_.phase_pos[phaseIdx] == other.usedPhases_.phase_pos[phaseIdx]);
            }

            equal = equal && (vectorApproxEqual( pressure() , other.pressure() , epsilon));
            equal = equal && (vectorApproxEqual( facepressure() , other.facepressure() , epsilon));
            equal = equal && (vectorApproxEqual( faceflux() , other.faceflux() , epsilon));
            equal = equal && (vectorApproxEqual( surfacevol() , other.surfacevol() , epsilon));
            equal = equal && (vectorApproxEqual( saturation() , other.saturation() , epsilon));
            equal = equal && (vectorApproxEqual( gasoilratio() , other.gasoilratio() , epsilon));

            return equal;
        }
    /// \param[in]  n      Number of data points.
    /// \param[in]  A      Array of nP^2 values, where the P^2 values for a cell give the
    ///                    matrix A = RB^{-1} which relates z to u by z = Au. The matrices
    ///                    are assumed to be in Fortran order, and are typically the result
    ///                    of a call to the method matrix().
    /// \param[in]  cells  The index of the grid cell of each data point.
    /// \param[out] rho    Array of nP density values, array must be valid before calling.
    void BlackoilPropertiesFromDeck::density(const int n,
                                             const double* A,
                                             const int* cells,
                                             double* rho) const
    {
        const int np = numPhases();
// #pragma omp parallel for
        for (int i = 0; i < n; ++i) {
            int cellIdx = cells?cells[i]:i;
            int pvtRegionIdx = getTableIndex_(cellPvtRegionIndex(), cellIdx);
            const double* sdens = pvt_.surfaceDensities(pvtRegionIdx);
            for (int phase = 0; phase < np; ++phase) {
                rho[np*i + phase] = 0.0;
                for (int comp = 0; comp < np; ++comp) {
                    rho[np*i + phase] += A[i*np*np + np*phase + comp]*sdens[comp];
                }
            }
        }
    }
 /// Construct from parameters.
 /// The following parameters are accepted (defaults):
 ///    num_phases         (2)         Must be 1 or 2.
 ///    relperm_func       ("Linear")  Must be "Constant", "Linear" or "Quadratic".
 ///    rho1 [rho2, rho3]  (1.0e3)     Density in kg/m^3
 ///    mu1 [mu2, mu3]     (1.0)       Viscosity in cP
 ///    porosity           (1.0)       Porosity
 ///    permeability       (100.0)     Permeability in mD
 IncompPropertiesDefaultPolymer(const Opm::parameter::ParameterGroup& param, int dim, int num_cells)
     : Opm::IncompPropertiesBasic(param, dim, num_cells)
 {
     assert(numPhases() == 2);
     sw_.resize(3);
     sw_[0] = 0.2;
     sw_[1] = 0.7;
     sw_[2] = 1.0;
     krw_.resize(3);
     krw_[0] = 0.0;
     krw_[1] = 0.7;
     krw_[2] = 1.0;
     so_.resize(2);
     so_[0] = 0.3;
     so_[1] = 0.8;
     kro_.resize(2);
     kro_[0] = 0.0;
     kro_[1] = 1.0;
 }
Exemplo n.º 8
0
 /// Set the first saturation to either its min or max value in
 /// the indicated cells. The second saturation value s2 is set
 /// to (1.0 - s1) for each cell. Any further saturation values
 /// are unchanged.
 void setFirstSat(const std::vector<int>& cells,
                  const Opm::BlackoilPropertiesInterface& props,
                  ExtremalSat es)
 {
     if (cells.empty()) {
         return;
     }
     const int n = cells.size();
     assert(n > 0);
     std::vector<double> smin(numPhases()*n);
     std::vector<double> smax(numPhases()*n);
     props.satRange(n, &cells[0], &smin[0], &smax[0]);
     const double* svals = (es == MinSat) ? &smin[0] : &smax[0];
     for (int ci = 0; ci < n; ++ci) {
         const int cell = cells[ci];
         sat_[numPhases()*cell] = svals[numPhases()*ci];
         sat_[numPhases()*cell + 1] = 1.0 - sat_[numPhases()*cell];
     }
 }
    /// \param[in]  n      Number of data points.
    /// \param[in]  p      Array of n pressure values.
    /// \param[in]  T      Array of n temperature values.
    /// \param[in]  z      Array of nP surface volume values.
    /// \param[in]  cells  Array of n cell indices to be associated with the p and z values.
    /// \param[out] A      Array of nP^2 values, array must be valid before calling.
    ///                    The P^2 values for a cell give the matrix A = RB^{-1} which
    ///                    relates z to u by z = Au. The matrices are output in Fortran order.
    /// \param[out] dAdp   If non-null: array of nP^2 matrix derivative values,
    ///                    array must be valid before calling. The matrices are output
    ///                    in Fortran order.
    void BlackoilPropertiesFromDeck::matrix(const int n,
                                            const double* p,
                                            const double* T,
                                            const double* z,
                                            const int* cells,
                                            double* A,
                                            double* dAdp) const
    {
        const int np = numPhases();

        const int *cellPvtTableIdx = cellPvtRegionIndex();
        std::vector<int> pvtTableIdx(n);
        for (int i = 0; i < n; ++ i)
            pvtTableIdx[i] = cellPvtTableIdx[cells[i]];

        B_.resize(n*np);
        R_.resize(n*np);
        if (dAdp) {
            dB_.resize(n*np);
            dR_.resize(n*np);
            pvt_.dBdp(n, &pvtTableIdx[0], p, T, z, &B_[0], &dB_[0]);
            pvt_.dRdp(n, &pvtTableIdx[0], p, z, &R_[0], &dR_[0]);
        } else {
            pvt_.B(n, &pvtTableIdx[0], p, T, z, &B_[0]);
            pvt_.R(n, &pvtTableIdx[0], p, z, &R_[0]);
        }
        const int* phase_pos = pvt_.phasePosition();
        bool oil_and_gas = pvt_.phaseUsed()[BlackoilPhases::Liquid] &&
            pvt_.phaseUsed()[BlackoilPhases::Vapour];
        const int o = phase_pos[BlackoilPhases::Liquid];
        const int g = phase_pos[BlackoilPhases::Vapour];

        // Compute A matrix
// #pragma omp parallel for
        for (int i = 0; i < n; ++i) {
            double* m = A + i*np*np;
            std::fill(m, m + np*np, 0.0);
            // Diagonal entries.
            for (int phase = 0; phase < np; ++phase) {
                m[phase + phase*np] = 1.0/B_[i*np + phase];
            }
            // Off-diagonal entries.
            if (oil_and_gas) {
                m[o + g*np] = R_[i*np + g]/B_[i*np + g];
                m[g + o*np] = R_[i*np + o]/B_[i*np + o];
            }
        }

        // Derivative of A matrix.
        // A     = R*inv(B) whence
        //
        // dA/dp = (dR/dp*inv(B) + R*d(inv(B))/dp)
        //       = (dR/dp*inv(B) - R*inv(B)*(dB/dp)*inv(B))
        //       = (dR/dp - A*(dB/dp)) * inv(B)
        //
        // The B matrix is diagonal and that fact is exploited in the
        // following implementation.
        if (dAdp) {
// #pragma omp parallel for
            // (1): dA/dp <- A
            std::copy(A, A + n*np*np, dAdp);

            for (int i = 0; i < n; ++i) {
                double*       m  = dAdp + i*np*np;

                // (2): dA/dp <- -dA/dp*(dB/dp) == -A*(dB/dp)
                const double* dB = & dB_[i * np];
                for (int col = 0; col < np; ++col) {
                    for (int row = 0; row < np; ++row) {
                        m[col*np + row] *= - dB[ col ]; // Note sign.
                    }
                }

                if (oil_and_gas) {
                    // (2b): dA/dp += dR/dp (== dR/dp - A*(dB/dp))
                    const double* dR = & dR_[i * np];

                    m[o*np + g] += dR[ o ];
                    m[g*np + o] += dR[ g ];
                }

                // (3): dA/dp *= inv(B) (== final result)
                const double* B = & B_[i * np];
                for (int col = 0; col < np; ++col) {
                    for (int row = 0; row < np; ++row) {
                        m[col*np + row] /= B[ col ];
                    }
                }
            }
        }
    }