static void solve(FluidState &fluidState, typename FluidSystem::template ParameterCache<typename FluidState::Scalar> ¶mCache, unsigned refPhaseIdx, bool setViscosity, bool setEnthalpy) { typedef MathToolbox<typename FluidState::Scalar> FsToolbox; // compute the density and enthalpy of the // reference phase paramCache.updatePhase(fluidState, refPhaseIdx); fluidState.setDensity(refPhaseIdx, FluidSystem::density(fluidState, paramCache, refPhaseIdx)); if (setEnthalpy) fluidState.setEnthalpy(refPhaseIdx, FluidSystem::enthalpy(fluidState, paramCache, refPhaseIdx)); if (setViscosity) fluidState.setViscosity(refPhaseIdx, FluidSystem::viscosity(fluidState, paramCache, refPhaseIdx)); // compute the fugacities of all components in the reference phase for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { fluidState.setFugacityCoefficient(refPhaseIdx, compIdx, FluidSystem::fugacityCoefficient(fluidState, paramCache, refPhaseIdx, compIdx)); } // compute all quantities for the non-reference phases for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { if (phaseIdx == refPhaseIdx) continue; // reference phase is already calculated ComponentVector fugVec; for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { const auto& fug = fluidState.fugacity(refPhaseIdx, compIdx); fugVec[compIdx] = FsToolbox::template decay<Evaluation>(fug); } CompositionFromFugacities::solve(fluidState, paramCache, phaseIdx, fugVec); if (setViscosity) fluidState.setViscosity(phaseIdx, FluidSystem::viscosity(fluidState, paramCache, phaseIdx)); if (setEnthalpy) fluidState.setEnthalpy(phaseIdx, FluidSystem::enthalpy(fluidState, paramCache, phaseIdx)); } }
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 (unsigned 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 (unsigned compIdx = 0; compIdx < numComponents; ++ compIdx) molarities[compIdx] = reservoirFluidState.molarity(oilPhaseIdx, compIdx); if (guessInitial) { // we start at a fluid state with reservoir oil. for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { for (unsigned 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::template ParameterCache<Scalar> 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) 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, matParams, paramCache, 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, matParams, paramCache, 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, matParams, paramCache, tmpMolarities); return alpha; }
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)); }