make all tests and ebos compile when selecting float or quad as Scalar

at least, they compile as far as eWoms is concerned. Some external
libraries (in particular everything which uses SuperLU) still have
issues.

Also, there seem to be issues with the precision that is achievable
by the Newton method when using float.
This commit is contained in:
Andreas Lauser 2016-01-17 21:15:21 +01:00
parent 99a59c021f
commit 879e8a613d
2 changed files with 55 additions and 19 deletions

View File

@ -72,12 +72,32 @@ class EclEquilInitializer
public: public:
template <class MaterialLawManager> template <class MaterialLawManager>
EclEquilInitializer(const Simulator& simulator, EclEquilInitializer(const Simulator& simulator,
std::shared_ptr<MaterialLawManager> materialLawManager) std::shared_ptr<MaterialLawManager> /*materialLawManager*/)
: simulator_(simulator) : simulator_(simulator)
{ {
const auto& gridManager = simulator.gridManager(); const auto& gridManager = simulator.gridManager();
const auto deck = gridManager.deck();
const auto eclState = gridManager.eclState();
const auto& equilGrid = gridManager.equilGrid(); const auto& equilGrid = gridManager.equilGrid();
typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
typedef Opm::ThreePhaseMaterialTraits<double,
/*wettingPhaseIdx=*/FluidSystem::waterPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::oilPhaseIdx,
/*gasPhaseIdx=*/FluidSystem::gasPhaseIdx> EquilTraits;
// create a separate instance of the material law manager just because opm-core
// only supports double as the type for scalars (but ebos may use float or quad)
unsigned numEquilElems = gridManager.equilGrid().size(0);
unsigned numCartesianElems = gridManager.cartesianSize();
std::vector<int> compressedToCartesianElemIdx(numEquilElems);
for (unsigned equilElemIdx = 0; equilElemIdx < numEquilElems; ++equilElemIdx)
compressedToCartesianElemIdx[equilElemIdx] = gridManager.equilCartesianIndex(equilElemIdx);
auto materialLawManager =
std::make_shared<Opm::EclMaterialLawManager<EquilTraits> >();
materialLawManager->initFromDeck(deck, eclState, compressedToCartesianElemIdx);
// create the data structures which are used by initStateEquil() // create the data structures which are used by initStateEquil()
Opm::parameter::ParameterGroup tmpParam; Opm::parameter::ParameterGroup tmpParam;
Opm::BlackoilPropertiesFromDeck opmBlackoilProps( Opm::BlackoilPropertiesFromDeck opmBlackoilProps(
@ -89,11 +109,10 @@ public:
Opm::UgGridHelpers::cartDims(equilGrid), Opm::UgGridHelpers::cartDims(equilGrid),
tmpParam); tmpParam);
const unsigned numElems = equilGrid.size(/*codim=*/0); assert( gridManager.grid().size(/*codim=*/0) == static_cast<int>(numEquilElems) );
assert( gridManager.grid().size(/*codim=*/0) == static_cast<int>(numElems) );
// initialize the boiler plate of opm-core the state structure. // initialize the boiler plate of opm-core the state structure.
Opm::BlackoilState opmBlackoilState; Opm::BlackoilState opmBlackoilState;
opmBlackoilState.init(numElems, opmBlackoilState.init(numEquilElems,
/*numFaces=*/0, // we don't care here /*numFaces=*/0, // we don't care here
numPhases); numPhases);
@ -106,16 +125,17 @@ public:
opmBlackoilState); opmBlackoilState);
// copy the result into the array of initial fluid states // copy the result into the array of initial fluid states
initialFluidStates_.resize(numElems); initialFluidStates_.resize(numCartesianElems);
for (unsigned elemIdx = 0; elemIdx < numElems; ++elemIdx) { for (unsigned equilElemIdx = 0; equilElemIdx < numEquilElems; ++equilElemIdx) {
auto &fluidState = initialFluidStates_[elemIdx]; unsigned cartesianElemIdx = gridManager.equilCartesianIndex(equilElemIdx);
auto &fluidState = initialFluidStates_[cartesianElemIdx];
// get the PVT region index of the current element // get the PVT region index of the current element
unsigned regionIdx = simulator_.problem().pvtRegionIndex(elemIdx); unsigned regionIdx = simulator_.problem().pvtRegionIndex(equilElemIdx);
// set the phase saturations // set the phase saturations
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
Scalar S = opmBlackoilState.saturation()[elemIdx*numPhases + phaseIdx]; Scalar S = opmBlackoilState.saturation()[equilElemIdx*numPhases + phaseIdx];
fluidState.setSaturation(phaseIdx, S); fluidState.setSaturation(phaseIdx, S);
} }
@ -123,16 +143,16 @@ public:
const auto& temperatureVector = opmBlackoilState.temperature(); const auto& temperatureVector = opmBlackoilState.temperature();
Scalar T = FluidSystem::surfaceTemperature; Scalar T = FluidSystem::surfaceTemperature;
if (!temperatureVector.empty()) if (!temperatureVector.empty())
T = temperatureVector[elemIdx]; T = temperatureVector[equilElemIdx];
fluidState.setTemperature(T); fluidState.setTemperature(T);
// set the phase pressures. the Opm::BlackoilState only provides the oil // set the phase pressures. the Opm::BlackoilState only provides the oil
// phase pressure, so we need to calculate the other phases' pressures // phase pressure, so we need to calculate the other phases' pressures
// ourselfs. // ourselfs.
Dune::FieldVector< Scalar, numPhases > pC( 0 ); Dune::FieldVector< Scalar, numPhases > pC( 0 );
const auto& matParams = simulator.problem().materialLawParams(elemIdx); const auto& matParams = simulator.problem().materialLawParams(equilElemIdx);
MaterialLaw::capillaryPressures(pC, matParams, fluidState); MaterialLaw::capillaryPressures(pC, matParams, fluidState);
Scalar po = opmBlackoilState.pressure()[elemIdx]; Scalar po = opmBlackoilState.pressure()[equilElemIdx];
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
fluidState.setPressure(phaseIdx, po + (pC[phaseIdx] - pC[oilPhaseIdx])); fluidState.setPressure(phaseIdx, po + (pC[phaseIdx] - pC[oilPhaseIdx]));
@ -148,7 +168,7 @@ public:
if (gridManager.deck()->hasKeyword("DISGAS")) { if (gridManager.deck()->hasKeyword("DISGAS")) {
// for gas and oil we have to translate surface volumes to mole fractions // for gas and oil we have to translate surface volumes to mole fractions
// before we can set the composition in the fluid state // before we can set the composition in the fluid state
Scalar Rs = opmBlackoilState.gasoilratio()[elemIdx]; Scalar Rs = opmBlackoilState.gasoilratio()[equilElemIdx];
Scalar RsSat = FluidSystem::saturatedDissolutionFactor(fluidState, oilPhaseIdx, regionIdx); Scalar RsSat = FluidSystem::saturatedDissolutionFactor(fluidState, oilPhaseIdx, regionIdx);
if (Rs > RsSat) if (Rs > RsSat)
@ -164,7 +184,7 @@ public:
// retrieve the surface volume of vaporized gas // retrieve the surface volume of vaporized gas
if (gridManager.deck()->hasKeyword("VAPOIL")) { if (gridManager.deck()->hasKeyword("VAPOIL")) {
Scalar Rv = opmBlackoilState.rv()[elemIdx]; Scalar Rv = opmBlackoilState.rv()[equilElemIdx];
Scalar RvSat = FluidSystem::saturatedDissolutionFactor(fluidState, gasPhaseIdx, regionIdx); Scalar RvSat = FluidSystem::saturatedDissolutionFactor(fluidState, gasPhaseIdx, regionIdx);
if (Rv > RvSat) if (Rv > RvSat)
@ -187,7 +207,12 @@ public:
* This is supposed to correspond to hydrostatic conditions. * This is supposed to correspond to hydrostatic conditions.
*/ */
const ScalarFluidState& initialFluidState(unsigned elemIdx) const const ScalarFluidState& initialFluidState(unsigned elemIdx) const
{ return initialFluidStates_[elemIdx]; } {
const auto& gridManager = simulator_.gridManager();
unsigned cartesianElemIdx = gridManager.cartesianIndex(elemIdx);
return initialFluidStates_[cartesianElemIdx];
}
protected: protected:
const Simulator& simulator_; const Simulator& simulator_;

View File

@ -359,7 +359,10 @@ public:
for (unsigned priVarIdx = 0; priVarIdx < numModelEq; ++priVarIdx) { for (unsigned priVarIdx = 0; priVarIdx < numModelEq; ++priVarIdx) {
// calculate the derivative of the well equation w.r.t. the current // calculate the derivative of the well equation w.r.t. the current
// primary variable using forward differences // primary variable using forward differences
Scalar eps = 1e-6*std::max<Scalar>(1.0, priVars[priVarIdx]); Scalar eps =
1e3
*std::numeric_limits<Scalar>::epsilon()
*std::max<Scalar>(1.0, priVars[priVarIdx]);
priVars[priVarIdx] += eps; priVars[priVarIdx] += eps;
elemCtx.updateIntensiveQuantities(priVars, dofVars.localDofIdx, /*timeIdx=*/0); elemCtx.updateIntensiveQuantities(priVars, dofVars.localDofIdx, /*timeIdx=*/0);
@ -387,7 +390,10 @@ public:
const auto& fluidState = elemCtx.intensiveQuantities(dofVars.localDofIdx, /*timeIdx=*/0).fluidState(); const auto& fluidState = elemCtx.intensiveQuantities(dofVars.localDofIdx, /*timeIdx=*/0).fluidState();
// first, we need the source term of the grid for the slightly disturbed well. // first, we need the source term of the grid for the slightly disturbed well.
Scalar eps = std::max<Scalar>(1e5, actualBottomHolePressure_)*1e-8; Scalar eps =
1e3
*std::numeric_limits<Scalar>::epsilon()
*std::max<Scalar>(1e5, actualBottomHolePressure_);
computeVolumetricDofRates_(resvRates, actualBottomHolePressure_ + eps, dofVariables_[gridDofIdx]); computeVolumetricDofRates_(resvRates, actualBottomHolePressure_ + eps, dofVariables_[gridDofIdx]);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
modelRate.setVolumetricRate(fluidState, phaseIdx, resvRates[phaseIdx]); modelRate.setVolumetricRate(fluidState, phaseIdx, resvRates[phaseIdx]);
@ -421,7 +427,10 @@ public:
} }
// effect of changing the well's bottom hole pressure on the well equation // effect of changing the well's bottom hole pressure on the well equation
Scalar eps = std::min<Scalar>(1e7, std::max<Scalar>(1e6, targetBottomHolePressure_))*1e-8; Scalar eps =
1e3
*std::numeric_limits<Scalar>::epsilon()
*std::max<Scalar>(1e7, targetBottomHolePressure_);
Scalar wellResidStar = wellResidual_(actualBottomHolePressure_ + eps); Scalar wellResidStar = wellResidual_(actualBottomHolePressure_ + eps);
diagBlock[0][0] = (wellResidStar - wellResid)/eps; diagBlock[0][0] = (wellResidStar - wellResid)/eps;
} }
@ -1356,7 +1365,9 @@ protected:
// Newton-Raphson method // Newton-Raphson method
for (int iterNum = 0; iterNum < 20; ++iterNum) { for (int iterNum = 0; iterNum < 20; ++iterNum) {
Scalar eps = 1e-9*std::abs(bhp); Scalar eps =
std::max<Scalar>(1e-8, std::numeric_limits<Scalar>::epsilon()*1e4)
*std::abs(bhp);
Scalar f = wellResidual_(bhp); Scalar f = wellResidual_(bhp);
Scalar fStar = wellResidual_(bhp + eps); Scalar fStar = wellResidual_(bhp + eps);