Merge branch 'master' into vapoilwat

This commit is contained in:
Paul Egberts
2022-05-11 11:55:54 +02:00
committed by GitHub
37 changed files with 753 additions and 252 deletions

View File

@@ -363,21 +363,19 @@ add_test_compareECLFiles(CASENAME spe1_metric_vfp1
REL_TOL ${rel_tol}
DIR vfpprod_spe1)
if(BUILD_FLOW_VARIANTS)
add_test_compareECLFiles(CASENAME spe1_water
FILENAME SPE1CASE1_WATER
SIMULATOR flow_onephase
ABS_TOL ${abs_tol}
REL_TOL ${rel_tol}
DIR spe1)
add_test_compareECLFiles(CASENAME spe1_water
FILENAME SPE1CASE1_WATER
SIMULATOR flow
ABS_TOL ${abs_tol}
REL_TOL ${rel_tol}
DIR spe1)
add_test_compareECLFiles(CASENAME spe1_thermal_onephase
FILENAME SPE1CASE2_THERMAL_ONEPHASE
SIMULATOR flow_onephase_energy
ABS_TOL ${abs_tol}
REL_TOL ${rel_tol}
DIR spe1)
endif()
add_test_compareECLFiles(CASENAME spe1_thermal_onephase
FILENAME SPE1CASE2_THERMAL_ONEPHASE
SIMULATOR flow
ABS_TOL ${abs_tol}
REL_TOL ${rel_tol}
DIR spe1)
add_test_compareECLFiles(CASENAME spe1_spider
FILENAME SPIDER_CAKESLICE
@@ -1431,10 +1429,9 @@ if(MPI_FOUND)
DIR spe1
TEST_ARGS --linear-solver-reduction=1e-7 --tolerance-cnv=5e-6 --tolerance-mb=1e-8)
if(BUILD_FLOW_VARIANTS)
add_test_compare_parallel_simulation(CASENAME spe1_thermal
FILENAME SPE1CASE2_THERMAL_ONEPHASE
SIMULATOR flow_onephase_energy
SIMULATOR flow
ABS_TOL ${abs_tol}
REL_TOL ${rel_tol}
DIR spe1
@@ -1442,12 +1439,11 @@ if(BUILD_FLOW_VARIANTS)
add_test_compare_parallel_simulation(CASENAME spe1_water
FILENAME SPE1CASE1_WATER
SIMULATOR flow_onephase
SIMULATOR flow
ABS_TOL ${abs_tol}
REL_TOL ${rel_tol}
DIR spe1
TEST_ARGS --linear-solver-reduction=1e-7 --tolerance-cnv=5e-6 --tolerance-mb=1e-8)
endif()
add_test_compare_parallel_simulation(CASENAME spe1_brine
FILENAME SPE1CASE1_BRINE

View File

@@ -681,6 +681,8 @@ assignToSolution(data::Solution& sol)
{"PPCW", UnitSystem::measure::pressure, data::TargetType::RESTART_SOLUTION, ppcw_},
{"PRESROCC", UnitSystem::measure::pressure, data::TargetType::RESTART_SOLUTION, minimumOilPressure_},
{"PRESSURE", UnitSystem::measure::pressure, data::TargetType::RESTART_SOLUTION, oilPressure_},
{"PCOW", UnitSystem::measure::pressure, data::TargetType::RESTART_SOLUTION, pcow_},
{"PCOG", UnitSystem::measure::pressure, data::TargetType::RESTART_SOLUTION, pcog_},
{"PRES_OVB", UnitSystem::measure::pressure, data::TargetType::RESTART_SOLUTION, overburdenPressure_},
{"RS", UnitSystem::measure::gas_oil_ratio, data::TargetType::RESTART_SOLUTION, rs_},
{"RSSAT", UnitSystem::measure::gas_oil_ratio, data::TargetType::RESTART_AUXILIARY, gasDissolutionFactor_},
@@ -1094,6 +1096,15 @@ doAllocBuffers(unsigned bufferSize,
relativePermeability_[gasPhaseIdx].resize(bufferSize, 0.0);
}
if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(waterPhaseIdx) && rstKeywords["PCOW"] > 0) {
rstKeywords["PCOW"] = 0;
pcow_.resize(bufferSize, 0.0);
}
if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(gasPhaseIdx) && rstKeywords["PCOG"] > 0) {
rstKeywords["PCOG"] = 0;
pcog_.resize(bufferSize, 0.0);
}
if (rstKeywords["PBPD"] > 0) {
rstKeywords["PBPD"] = 0;
bubblePointPressure_.resize(bufferSize, 0.0);

View File

@@ -450,6 +450,8 @@ protected:
ScalarBuffer cUrea_;
ScalarBuffer cBiofilm_;
ScalarBuffer cCalcite_;
ScalarBuffer pcow_;
ScalarBuffer pcog_;
std::array<ScalarBuffer, numPhases> saturation_;
std::array<ScalarBuffer, numPhases> invB_;

View File

@@ -281,6 +281,14 @@ public:
this->rv_[globalDofIdx] = getValue(fs.Rv());
Valgrind::CheckDefined(this->rv_[globalDofIdx]);
}
if (!this->pcow_.empty()) {
this->pcow_[globalDofIdx] = getValue(fs.pressure(oilPhaseIdx)) - getValue(fs.pressure(waterPhaseIdx));
Valgrind::CheckDefined(this->pcow_[globalDofIdx]);
}
if (!this->pcog_.empty()) {
this->pcog_[globalDofIdx] = getValue(fs.pressure(gasPhaseIdx)) - getValue(fs.pressure(oilPhaseIdx));
Valgrind::CheckDefined(this->pcog_[globalDofIdx]);
}
if (!this->rvw_.empty()) {
this->rvw_[globalDofIdx] = getValue(fs.Rvw());
@@ -571,6 +579,14 @@ public:
val.second = getValue(fs.viscosity(gasPhaseIdx));
else if (key.first == "BVOIL" || key.first == "BOVIS")
val.second = getValue(fs.viscosity(oilPhaseIdx));
else if (key.first == "BRPV")
val.second = elemCtx.simulator().model().dofTotalVolume(globalDofIdx)*getValue(intQuants.porosity());
else if (key.first == "BOPV")
val.second = getValue(fs.saturation(oilPhaseIdx))*elemCtx.simulator().model().dofTotalVolume(globalDofIdx)*getValue(intQuants.porosity());
else if (key.first == "BWPV")
val.second = getValue(fs.saturation(waterPhaseIdx))*elemCtx.simulator().model().dofTotalVolume(globalDofIdx)*getValue(intQuants.porosity());
else if (key.first == "BGPV")
val.second = getValue(fs.saturation(gasPhaseIdx))*elemCtx.simulator().model().dofTotalVolume(globalDofIdx)*getValue(intQuants.porosity());
else {
std::string logstring = "Keyword '";
logstring.append(key.first);

View File

@@ -2119,8 +2119,9 @@ private:
Scalar rssat = FluidSystem::oilPvt().saturatedGasDissolutionFactor(fs.pvtRegionIndex(),t,p);
Scalar saturatedInvB = FluidSystem::oilPvt().saturatedInverseFormationVolumeFactor(fs.pvtRegionIndex(),t,p);
Scalar rsZero = 0.0;
Scalar pureInvB = FluidSystem::oilPvt().inverseFormationVolumeFactor(fs.pvtRegionIndex(),t,p,rsZero);
Scalar deltaDensity = (saturatedInvB - pureInvB) * FluidSystem::oilPvt().oilReferenceDensity(fs.pvtRegionIndex());
Scalar pureDensity = FluidSystem::oilPvt().inverseFormationVolumeFactor(fs.pvtRegionIndex(),t,p,rsZero) * FluidSystem::oilPvt().oilReferenceDensity(fs.pvtRegionIndex());
Scalar saturatedDensity = saturatedInvB * (FluidSystem::oilPvt().oilReferenceDensity(fs.pvtRegionIndex()) + rssat * FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, fs.pvtRegionIndex()));
Scalar deltaDensity = saturatedDensity - pureDensity;
Scalar rs = getValue(fs.Rs());
Scalar visc = FluidSystem::oilPvt().viscosity(fs.pvtRegionIndex(),t,p,rs);
Scalar poro = getValue(iq.porosity());

View File

@@ -219,9 +219,12 @@ private:
density(const double depth,
const double press) const
{
double rs = rs_(depth, press, temp_);
double rs = 0.0;
if(FluidSystem::enableDissolvedGas())
rs = rs_(depth, press, temp_);
double bOil = 0.0;
if (!FluidSystem::enableDissolvedGas() || rs >= FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_, temp_, press)) {
if (rs >= FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_, temp_, press)) {
bOil = FluidSystem::oilPvt().saturatedInverseFormationVolumeFactor(pvtRegionIdx_, temp_, press);
}
else {
@@ -267,9 +270,12 @@ private:
density(const double depth,
const double press) const
{
double rv = rv_(depth, press, temp_);
double rv = 0.0;
if (FluidSystem::enableVaporizedOil())
rv = rv_(depth, press, temp_);
double bGas = 0.0;
if (!FluidSystem::enableVaporizedOil() || rv >= FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_, temp_, press)) {
if (rv >= FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_, temp_, press)) {
bGas = FluidSystem::gasPvt().saturatedInverseFormationVolumeFactor(pvtRegionIdx_, temp_, press);
}
else {

View File

@@ -27,13 +27,13 @@ namespace Opm {
namespace Properties {
namespace TTag {
struct EclFlowProblemSimple {
struct EclFlowProblemWaterOnly {
using InheritsFrom = std::tuple<EclFlowProblem>;
};
}
//! The indices required by the model
template<class TypeTag>
struct Indices<TypeTag, TTag::EclFlowProblemSimple>
struct Indices<TypeTag, TTag::EclFlowProblemWaterOnly>
{
private:
// it is unfortunately not possible to simply use 'TypeTag' here because this leads
@@ -57,9 +57,36 @@ public:
} // namespace Opm::Properties
int flowEbosOnephaseMain(int argc, char** argv)
void flowEbosWaterOnlySetDeck(double setupTime, std::shared_ptr<Deck> deck,
std::shared_ptr<EclipseState> eclState,
std::shared_ptr<Schedule> schedule,
std::shared_ptr<SummaryConfig> summaryConfig)
{
using TypeTag = Opm::Properties::TTag::EclFlowProblemSimple;
using TypeTag = Properties::TTag::EclFlowProblemWaterOnly;
using Vanguard = GetPropType<TypeTag, Properties::Vanguard>;
Vanguard::setExternalSetupTime(setupTime);
Vanguard::setExternalDeck(std::move(deck));
Vanguard::setExternalEclState(std::move(eclState));
Vanguard::setExternalSchedule(std::move(schedule));
Vanguard::setExternalSummaryConfig(std::move(summaryConfig));
}
// ----------------- Main program -----------------
int flowEbosWaterOnlyMain(int argc, char** argv, bool outputCout, bool outputFiles)
{
// we always want to use the default locale, and thus spare us the trouble
// with incorrect locale settings.
resetLocale();
FlowMainEbos<Properties::TTag::EclFlowProblemWaterOnly>
mainfunc {argc, argv, outputCout, outputFiles};
return mainfunc.execute();
}
int flowEbosWaterOnlyMainStandalone(int argc, char** argv)
{
using TypeTag = Opm::Properties::TTag::EclFlowProblemWaterOnly;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
}

View File

@@ -22,8 +22,27 @@
#ifndef FLOW_ONEPHASE_HPP
#define FLOW_ONEPHASE_HPP
#include <memory>
namespace Opm {
int flowEbosOnephaseMain(int argc, char** argv);
class Deck;
class EclipseState;
template<class TypeTag> class FlowMainEbos;
class Schedule;
class SummaryConfig;
class UDQState;
class WellTestState;
namespace Action {
class State;
}
void flowEbosWaterOnlySetDeck(double setupTime, std::shared_ptr<Deck> deck,
std::shared_ptr<EclipseState> eclState,
std::shared_ptr<Schedule> schedule,
std::shared_ptr<SummaryConfig> summaryConfig);
int flowEbosWaterOnlyMain(int argc, char** argv, bool outputCout, bool outputFiles);
int flowEbosWaterOnlyMainStandalone(int argc, char** argv);
}
#endif

View File

@@ -19,24 +19,28 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <flow/flow_ebos_onephase_energy.hpp>
#include <opm/simulators/flow/Main.hpp>
#include <opm/models/blackoil/blackoilonephaseindices.hh>
#include <opm/material/common/ResetLocale.hpp>
namespace Opm {
namespace Properties {
namespace TTag {
struct EclFlowProblemSimple {
struct EclFlowProblemWaterOnlyEnergy {
using InheritsFrom = std::tuple<EclFlowProblem>;
};
}
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::EclFlowProblemSimple> {
struct EnableEnergy<TypeTag, TTag::EclFlowProblemWaterOnlyEnergy> {
static constexpr bool value = true;
};
//! The indices required by the model
template<class TypeTag>
struct Indices<TypeTag, TTag::EclFlowProblemSimple>
struct Indices<TypeTag, TTag::EclFlowProblemWaterOnlyEnergy>
{
private:
// it is unfortunately not possible to simply use 'TypeTag' here because this leads
@@ -60,9 +64,36 @@ public:
} // namespace Opm::Properties
int flowEbosOnephaseEnergyMain(int argc, char** argv)
void flowEbosWaterOnlyEnergySetDeck(double setupTime, std::shared_ptr<Deck> deck,
std::shared_ptr<EclipseState> eclState,
std::shared_ptr<Schedule> schedule,
std::shared_ptr<SummaryConfig> summaryConfig)
{
using TypeTag = Opm::Properties::TTag::EclFlowProblemSimple;
using TypeTag = Properties::TTag::EclFlowProblemWaterOnlyEnergy;
using Vanguard = GetPropType<TypeTag, Properties::Vanguard>;
Vanguard::setExternalSetupTime(setupTime);
Vanguard::setExternalDeck(std::move(deck));
Vanguard::setExternalEclState(std::move(eclState));
Vanguard::setExternalSchedule(std::move(schedule));
Vanguard::setExternalSummaryConfig(std::move(summaryConfig));
}
// ----------------- Main program -----------------
int flowEbosWaterOnlyEnergyMain(int argc, char** argv, bool outputCout, bool outputFiles)
{
// we always want to use the default locale, and thus spare us the trouble
// with incorrect locale settings.
resetLocale();
FlowMainEbos<Properties::TTag::EclFlowProblemWaterOnlyEnergy>
mainfunc {argc, argv, outputCout, outputFiles};
return mainfunc.execute();
}
int flowEbosWaterOnlyEnergyMainStandalone(int argc, char** argv)
{
using TypeTag = Opm::Properties::TTag::EclFlowProblemWaterOnlyEnergy;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
}

View File

@@ -22,8 +22,27 @@
#ifndef FLOW_ONEPHASE_ENERGY_HPP
#define FLOW_ONEPHASE_ENERGY_HPP
#include <memory>
namespace Opm {
int flowEbosOnephaseEnergyMain(int argc, char** argv);
class Deck;
class EclipseState;
template<class TypeTag> class FlowMainEbos;
class Schedule;
class SummaryConfig;
class UDQState;
class WellTestState;
namespace Action {
class State;
}
void flowEbosWaterOnlyEnergySetDeck(double setupTime, std::shared_ptr<Deck> deck,
std::shared_ptr<EclipseState> eclState,
std::shared_ptr<Schedule> schedule,
std::shared_ptr<SummaryConfig> summaryConfig);
int flowEbosWaterOnlyEnergyMain(int argc, char** argv, bool outputCout, bool outputFiles);
int flowEbosWaterOnlyEnergyMainStandalone(int argc, char** argv);
}
#endif

View File

@@ -24,5 +24,5 @@
int main(int argc, char** argv)
{
return Opm::flowEbosOnephaseMain(argc, argv);
return Opm::flowEbosWaterOnlyMainStandalone(argc, argv);
}

View File

@@ -23,5 +23,5 @@
int main(int argc, char** argv)
{
return Opm::flowEbosOnephaseEnergyMain(argc,argv);
return Opm::flowEbosWaterOnlyEnergyMainStandalone(argc,argv);
}

View File

@@ -112,13 +112,16 @@ namespace Opm{
const TableContainer& sof2Tables = tableManager.getSof2Tables();
const TableContainer& sgwfnTables= tableManager.getSgwfnTables();
const SwofletTable& swofletTable = tableManager.getSwofletTable();
const SgofletTable& sgofletTable = tableManager.getSgofletTable();
// Family I test.
bool family1 = pu.phase_used[BlackoilPhases::Liquid];
if (pu.phase_used[BlackoilPhases::Aqua]) {
family1 = family1 && !swofTables.empty();
family1 = family1 && (!swofTables.empty() || !swofletTable.empty());
}
if (pu.phase_used[BlackoilPhases::Vapour]) {
family1 = family1 && (!sgofTables.empty() || !slgofTables.empty());
family1 = family1 && ((!sgofTables.empty() || !sgofletTable.empty()) || !slgofTables.empty());
}
// Family II test.
@@ -664,7 +667,9 @@ namespace Opm{
satfunc::getRawFunctionValues(tables, phases, rtep);
const TableContainer& swofTables = tables.getSwofTables();
const SwofletTable& swofletTables = tables.getSwofletTable();
const TableContainer& sgofTables = tables.getSgofTables();
const SgofletTable& sgofletTables = tables.getSgofletTable();
const TableContainer& slgofTables = tables.getSlgofTables();
const TableContainer& sof3Tables = tables.getSof3Tables();
@@ -693,14 +698,19 @@ namespace Opm{
if (!sgofTables.empty()) {
const auto& table = sgofTables.getTable<SgofTable>(satnumIdx);
krog_value = table.evaluate( "KROG" , unscaledEpsInfo_[satnumIdx].Sgl );
} else if (!sgofletTables.empty()) {
krog_value = sgofletTables[satnumIdx].krt2_relperm;
} else {
assert(!slgofTables.empty());
const auto& table = slgofTables.getTable<SlgofTable>(satnumIdx);
krog_value = table.evaluate( "KROG" , unscaledEpsInfo_[satnumIdx].Sgl );
}
{
if (!swofTables.empty()) {
const auto& table = swofTables.getTable<SwofTable>(satnumIdx);
krow_value = table.evaluate("KROW" , unscaledEpsInfo_[satnumIdx].Swl);
} else {
assert(!swofletTables.empty());
krow_value = swofletTables[satnumIdx].krt2_relperm;
}
}
if (satFamily_ == SaturationFunctionFamily::FamilyII) {

View File

@@ -267,7 +267,7 @@ struct MaxInnerIterWells<TypeTag, TTag::FlowModelParameters> {
};
template<class TypeTag>
struct ShutUnsolvableWells<TypeTag, TTag::FlowModelParameters> {
static constexpr bool value = false;
static constexpr bool value = true;
};
template<class TypeTag>
struct AlternativeWellRateInit<TypeTag, TTag::FlowModelParameters> {
@@ -275,7 +275,7 @@ struct AlternativeWellRateInit<TypeTag, TTag::FlowModelParameters> {
};
template<class TypeTag>
struct StrictOuterIterWells<TypeTag, TTag::FlowModelParameters> {
static constexpr int value = 99;
static constexpr int value = 6;
};
template<class TypeTag>
struct StrictInnerIterWells<TypeTag, TTag::FlowModelParameters> {
@@ -297,12 +297,12 @@ struct EnableWellOperabilityCheckIter<TypeTag, TTag::FlowModelParameters> {
template<class TypeTag>
struct RelaxedWellFlowTol<TypeTag, TTag::FlowModelParameters> {
using type = GetPropType<TypeTag, Scalar>;
static constexpr type value = 1;
static constexpr type value = 1e-3;
};
template<class TypeTag>
struct RelaxedPressureTolMsw<TypeTag, TTag::FlowModelParameters> {
using type = GetPropType<TypeTag, Scalar>;
static constexpr type value = 0.5e5;
static constexpr type value = 1.0e4;
};
template<class TypeTag>
struct MaximumNumberOfWellSwitches<TypeTag, TTag::FlowModelParameters> {

View File

@@ -36,6 +36,8 @@
#include <flow/flow_ebos_brine_saltprecipitation.hpp>
#include <flow/flow_ebos_gaswater_saltprec_vapwat.hpp>
#include <flow/flow_ebos_brine_precsalt_vapwat.hpp>
#include <flow/flow_ebos_onephase.hpp>
#include <flow/flow_ebos_onephase_energy.hpp>
#include <flow/flow_ebos_oilwater_brine.hpp>
#include <flow/flow_ebos_gaswater_brine.hpp>
#include <flow/flow_ebos_energy.hpp>
@@ -291,6 +293,16 @@ private:
return this->runMICP(phases);
}
// water-only case
else if(phases.size() == 1 && phases.active(Phase::WATER) && !eclipseState_->getSimulationConfig().isThermal()) {
return this->runWaterOnly(phases);
}
// water-only case with energy
else if(phases.size() == 2 && phases.active(Phase::WATER) && eclipseState_->getSimulationConfig().isThermal()) {
return this->runWaterOnlyEnergy(phases);
}
// Twophase cases
else if (phases.size() == 2 && !eclipseState_->getSimulationConfig().isThermal()) {
return this->runTwoPhase(phases);
@@ -653,6 +665,36 @@ private:
return flowEbosFoamMain(argc_, argv_, outputCout_, outputFiles_);
}
int runWaterOnly(const Phases& phases)
{
if (!phases.active(Phase::WATER) || phases.size() != 1) {
if (outputCout_)
std::cerr << "No valid configuration is found for water-only simulation, valid options include "
<< "water, water + thermal" << std::endl;
return EXIT_FAILURE;
}
flowEbosWaterOnlySetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosWaterOnlyMain(argc_, argv_, outputCout_, outputFiles_);
}
int runWaterOnlyEnergy(const Phases& phases)
{
if (!phases.active(Phase::WATER) || phases.size() != 2) {
if (outputCout_)
std::cerr << "No valid configuration is found for water-only simulation, valid options include "
<< "water, water + thermal" << std::endl;
return EXIT_FAILURE;
}
flowEbosWaterOnlyEnergySetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosWaterOnlyEnergyMain(argc_, argv_, outputCout_, outputFiles_);
}
int runBrine(const Phases& phases)
{
if (! phases.active(Phase::WATER) || phases.size() == 2) {

View File

@@ -64,7 +64,7 @@ namespace Opm
class WellFailure
{
public:
enum struct Type { Invalid, MassBalance, Pressure, ControlBHP, ControlTHP, ControlRate };
enum struct Type { Invalid, MassBalance, Pressure, ControlBHP, ControlTHP, ControlRate, Unsolvable };
WellFailure(Type t, Severity s, int phase, const std::string& well_name)
: type_(t), severity_(s), phase_(phase), well_name_(well_name)
{

View File

@@ -140,8 +140,10 @@ const KeywordValidation::UnsupportedKeywords& unsupportedKeywords()
{"DPGRID", {false, std::nullopt}},
{"DPKRMOD", {false, std::nullopt}},
{"DPNUM", {false, std::nullopt}},
{"DR", {false, std::string{"Use the DRV keyword instead"}}},
{"DRILPRI", {false, std::nullopt}},
{"DSPDEINT", {false, std::nullopt}},
{"DTHETA", {false, std::string{"Use the DTHETAV keyword instead"}}},
{"DUALPERM", {false, std::nullopt}},
{"DUALPORO", {false, std::nullopt}},
{"DUMPCUPL", {false, std::nullopt}},
@@ -430,6 +432,7 @@ const KeywordValidation::UnsupportedKeywords& unsupportedKeywords()
{"OLDTRAN", {false, std::nullopt}},
{"OLDTRANR", {false, std::nullopt}},
{"OPTIONS", {false, std::nullopt}},
{"OUTRAD", {false, std::string{"Use the DRV keyword instead"}}},
{"OUTSOL", {false, std::nullopt}},
{"PARAOPTS", {false, std::nullopt}},
{"PCG32D", {false, std::nullopt}},

View File

@@ -365,7 +365,7 @@ namespace {
if (status != MPI_SUCCESS) {
throw std::invalid_argument {
"Unable to establish cell geomtry validity across MPI ranks"
"Unable to establish cell geometry validity across MPI ranks"
};
}
#endif // HAVE_MPI

View File

@@ -2067,7 +2067,7 @@ forceShutWellByName(const std::string& wellname,
// process that owns it.
int well_was_shut = 0;
for (const auto& well : well_container_generic_) {
if (well->name() == wellname && !well->wellIsStopped()) {
if (well->name() == wellname) {
wellTestState().close_well(wellname, WellTestConfig::Reason::PHYSICAL, simulation_time);
well_was_shut = 1;
break;

View File

@@ -669,7 +669,6 @@ namespace Opm {
case Well::ProducerCMode::RESV:
zero_rate_control = is_zero(prod_controls.resv_rate);
break;
default:
// Might still have zero rate controls, but is pressure controlled.
zero_rate_control = false;
@@ -1223,8 +1222,13 @@ namespace Opm {
ConvergenceReport local_report;
const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations();
for (const auto& well : well_container_) {
if (well->isOperableAndSolvable() ) {
if (well->isOperableAndSolvable() || well->wellIsStopped()) {
local_report += well->getWellConvergence(this->wellState(), B_avg, local_deferredLogger, iterationIdx > param_.strict_outer_iter_wells_ );
} else {
ConvergenceReport report;
using CR = ConvergenceReport;
report.setWellFailed({CR::WellFailure::Type::Unsolvable, CR::Severity::Normal, -1, well->name()});
local_report += report;
}
}
@@ -1488,6 +1492,8 @@ namespace Opm {
auto& events = this->wellState().well(well->indexOfWell()).events;
if (events.hasEvent(WellState::event_mask)) {
well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger);
well->updatePrimaryVariables(this->wellState(), deferred_logger);
well->initPrimaryVariablesEvaluation();
// There is no new well control change input within a report step,
// so next time step, the well does not consider to have effective events anymore.
events.clearEvent(WellState::event_mask);

View File

@@ -294,19 +294,38 @@ checkThpControl_() const
return thp_control;
}
std::pair<std::optional<double>,double>
GasLiftSingleWellGeneric::
computeConvergedBhpAtThpLimitByMaybeIncreasingALQ_() const
{
auto alq = this->orig_alq_;
double new_alq = alq;
std::optional<double> bhp;
while (alq <= (this->max_alq_ + this->increment_)) {
if (bhp = computeBhpAtThpLimit_(alq); bhp) {
new_alq = alq;
break;
}
alq += this->increment_;
}
return {bhp, new_alq};
}
std::optional<GasLiftSingleWellGeneric::BasicRates>
std::pair<std::optional<GasLiftSingleWellGeneric::BasicRates>,double>
GasLiftSingleWellGeneric::
computeInitialWellRates_() const
{
std::optional<BasicRates> rates;
if (auto bhp = computeBhpAtThpLimit_(this->orig_alq_); bhp) {
double initial_alq = this->orig_alq_;
//auto alq = initial_alq;
//if (auto bhp = computeBhpAtThpLimit_(this->orig_alq_); bhp) {
if (auto [bhp, alq] = computeConvergedBhpAtThpLimitByMaybeIncreasingALQ_(); bhp) {
{
const std::string msg = fmt::format(
"computed initial bhp {} given thp limit and given alq {}",
*bhp, this->orig_alq_);
"computed initial bhp {} given thp limit and given alq {}", *bhp, alq);
displayDebugMessage_(msg);
}
initial_alq = alq;
auto [new_bhp, bhp_is_limited] = getBhpWithLimit_(*bhp);
rates = computeWellRates_(new_bhp, bhp_is_limited);
if (rates) {
@@ -320,7 +339,7 @@ computeInitialWellRates_() const
else {
displayDebugMessage_("Aborting optimization.");
}
return rates;
return {rates, initial_alq};
}
std::optional<GasLiftSingleWellGeneric::LimitedRates>
@@ -819,12 +838,13 @@ getRateWithGroupLimit_(
}
std::optional<GasLiftSingleWellGeneric::LimitedRates>
std::pair<std::optional<GasLiftSingleWellGeneric::LimitedRates>, double>
GasLiftSingleWellGeneric::
getInitialRatesWithLimit_() const
{
std::optional<LimitedRates> limited_rates;
if (auto rates = computeInitialWellRates_(); rates) {
double initial_alq = this->orig_alq_;
if (auto [rates, alq] = computeInitialWellRates_(); rates) {
if (this->debug) {
displayDebugMessage_(
"Maybe limiting initial rates before optimize loop..");
@@ -832,8 +852,9 @@ getInitialRatesWithLimit_() const
auto temp_rates = getLimitedRatesFromRates_(*rates);
BasicRates old_rates = getWellStateRates_();
limited_rates = updateRatesToGroupLimits_(old_rates, temp_rates);
initial_alq = alq;
}
return limited_rates;
return {limited_rates, initial_alq};
}
GasLiftSingleWellGeneric::LimitedRates
@@ -1166,18 +1187,17 @@ runOptimizeLoop_(bool increase)
{
if (this->debug) debugShowProducerControlMode();
std::unique_ptr<GasLiftWellState> ret_value; // nullptr initially
auto rates = getInitialRatesWithLimit_();
auto [rates, cur_alq] = getInitialRatesWithLimit_();
if (!rates) return ret_value;
// if (this->debug) debugShowBhpAlqTable_();
if (this->debug) debugShowAlqIncreaseDecreaseCounts_();
if (this->debug) debugShowTargets_();
bool success = false; // did we succeed to increase alq?
bool alq_is_limited = false;
auto cur_alq = this->orig_alq_;
LimitedRates new_rates = *rates;
auto [temp_rates2, new_alq] = maybeAdjustALQbeforeOptimizeLoop_(
*rates, cur_alq, increase);
if (checkInitialALQmodified_(new_alq, cur_alq)) {
if (checkInitialALQmodified_(new_alq, this->orig_alq_)) {
auto delta_alq = new_alq - cur_alq;
new_rates = temp_rates2;
cur_alq = new_alq;
@@ -1591,7 +1611,10 @@ checkAlqOutsideLimits(double alq, [[maybe_unused]] double oil_rate)
// NOTE: checking for an upper limit should not be necessary
// when decreasing alq.. so this is just to catch an
// illegal state at an early point.
if (alq >= this->parent.max_alq_) {
if (this->parent.checkALQequal_(alq, this->parent.max_alq_)) {
return false;
}
else if (alq > this->parent.max_alq_) {
warn_( "unexpected: alq above upper limit when trying to "
"decrease lift gas. aborting iteration.");
result = true;

View File

@@ -250,7 +250,8 @@ protected:
bool checkInitialALQmodified_(double alq, double initial_alq) const;
bool checkThpControl_() const;
virtual std::optional<double> computeBhpAtThpLimit_(double alq) const = 0;
std::optional<BasicRates> computeInitialWellRates_() const;
std::pair<std::optional<double>,double> computeConvergedBhpAtThpLimitByMaybeIncreasingALQ_() const;
std::pair<std::optional<BasicRates>,double> computeInitialWellRates_() const;
std::optional<LimitedRates> computeLimitedWellRatesWithALQ_(double alq) const;
virtual BasicRates computeWellRates_(double bhp, bool bhp_is_limited, bool debug_output = true) const = 0;
std::optional<BasicRates> computeWellRatesWithALQ_(double alq) const;
@@ -272,7 +273,7 @@ protected:
const BasicRates& rates) const;
std::pair<double, bool> getGasRateWithGroupLimit_(
double new_gas_rate, double gas_rate) const;
std::optional<LimitedRates> getInitialRatesWithLimit_() const;
std::pair<std::optional<LimitedRates>,double> getInitialRatesWithLimit_() const;
LimitedRates getLimitedRatesFromRates_(const BasicRates& rates) const;
std::tuple<double,double,bool,bool> getLiquidRateWithGroupLimit_(
const double new_oil_rate, const double oil_rate,

View File

@@ -162,6 +162,9 @@ namespace Opm
protected:
int number_segments_;
// regularize msw equation
bool regularize_;
// components of the pressure drop to be included
WellSegments::CompPressureDrop compPressureDrop() const;
// multi-phase flow model

View File

@@ -383,10 +383,10 @@ processFractions(const int seg) const
template<typename FluidSystem, typename Indices, typename Scalar>
void
MultisegmentWellEval<FluidSystem,Indices,Scalar>::
updateWellState(const BVectorWell& dwells,
const double relaxation_factor,
const double dFLimit,
const double max_pressure_change) const
updatePrimaryVariablesNewton(const BVectorWell& dwells,
const double relaxation_factor,
const double dFLimit,
const double max_pressure_change) const
{
const std::vector<std::array<double, numWellEq> > old_primary_variables = primary_variables_;
@@ -1622,10 +1622,10 @@ assemblePressureEq(const int seg,
}
template<typename FluidSystem, typename Indices, typename Scalar>
std::vector<Scalar>
std::pair<bool, std::vector<Scalar> >
MultisegmentWellEval<FluidSystem,Indices,Scalar>::
getWellResiduals(const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger) const
getFiniteWellResiduals(const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger) const
{
assert(int(B_avg.size() ) == baseif_.numComponents());
std::vector<Scalar> residuals(numWellEq + 1, 0.0);
@@ -1641,8 +1641,9 @@ getWellResiduals(const std::vector<Scalar>& B_avg,
}
}
if (std::isnan(residual) || std::isinf(residual)) {
OPM_DEFLOG_THROW(NumericalIssue, "nan or inf value for residal get for well " << baseif_.name()
<< " segment " << seg << " eq_idx " << eq_idx, deferred_logger);
deferred_logger.debug("nan or inf value for residal get for well " + baseif_.name()
+ " segment " + std::to_string(seg) + " eq_idx " + std::to_string(eq_idx));
return {false, residuals};
}
if (residual > residuals[eq_idx]) {
@@ -1655,12 +1656,13 @@ getWellResiduals(const std::vector<Scalar>& B_avg,
{
const double control_residual = std::abs(resWell_[0][numWellEq - 1]);
if (std::isnan(control_residual) || std::isinf(control_residual)) {
OPM_DEFLOG_THROW(NumericalIssue, "nan or inf value for control residal get for well " << baseif_.name(), deferred_logger);
deferred_logger.debug("nan or inf value for control residal get for well " + baseif_.name());
return {false, residuals};
}
residuals[numWellEq] = control_residual;
}
return residuals;
return {true, residuals};
}
template<typename FluidSystem, typename Indices, typename Scalar>

View File

@@ -173,10 +173,10 @@ protected:
void updateUpwindingSegments();
// updating the well_state based on well solution dwells
void updateWellState(const BVectorWell& dwells,
const double relaxation_factor,
const double DFLimit,
const double max_pressure_change) const;
void updatePrimaryVariablesNewton(const BVectorWell& dwells,
const double relaxation_factor,
const double DFLimit,
const double max_pressure_change) const;
void computeSegmentFluidProperties(const EvalWell& temperature,
const EvalWell& saltConcentration,
@@ -199,8 +199,9 @@ protected:
EvalWell getWQTotal() const;
std::vector<Scalar> getWellResiduals(const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger) const;
std::pair<bool, std::vector<Scalar> >
getFiniteWellResiduals(const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger) const;
double getControlTolerance(const WellState& well_state,
const double tolerance_wells,

View File

@@ -49,6 +49,7 @@ namespace Opm
const std::vector<PerforationData>& perf_data)
: Base(well, pw_info, time_step, param, rate_converter, pvtRegionIdx, num_components, num_phases, index_of_well, perf_data)
, MSWEval(static_cast<WellInterfaceIndices<FluidSystem,Indices,Scalar>&>(*this))
, regularize_(false)
, segment_fluid_initial_(this->numberOfSegments(), std::vector<double>(this->num_components_, 0.0))
{
// not handling solvent or polymer for now with multisegment well
@@ -316,11 +317,11 @@ namespace Opm
well_potentials[phase] *= sign;
total_potential += well_potentials[phase];
}
if (total_potential < 0.0) {
if (total_potential < 0.0 && this->param_.check_well_operability_) {
// wells with negative potentials are not operable
this->operability_status_.has_negative_potentials = true;
const std::string msg = std::string("well ") + this->name() + std::string(": has non negative potentials is not operable");
deferred_logger.info(msg);
deferred_logger.warning("NEGATIVE_POTENTIALS_INOPERABLE", msg);
}
}
@@ -611,10 +612,10 @@ namespace Opm
const double dFLimit = this->param_.dwell_fraction_max_;
const double max_pressure_change = this->param_.max_pressure_change_ms_wells_;
this->MSWEval::updateWellState(dwells,
relaxation_factor,
dFLimit,
max_pressure_change);
this->MSWEval::updatePrimaryVariablesNewton(dwells,
relaxation_factor,
dFLimit,
max_pressure_change);
this->updateWellStateFromPrimaryVariables(well_state, getRefDensity(), deferred_logger);
Base::calculateReservoirRates(well_state.well(this->index_of_well_));
@@ -1373,7 +1374,14 @@ namespace Opm
const int max_iter_number = this->param_.max_inner_iter_ms_wells_;
const WellState well_state0 = well_state;
const std::vector<Scalar> residuals0 = this->getWellResiduals(Base::B_avg_, deferred_logger);
{
// getWellFiniteResiduals returns false for nan/inf residuals
const auto& [isFinite, residuals] = this->getFiniteWellResiduals(Base::B_avg_, deferred_logger);
if(!isFinite)
return false;
}
std::vector<std::vector<Scalar> > residual_history;
std::vector<double> measure_history;
int it = 0;
@@ -1383,14 +1391,17 @@ namespace Opm
bool converged = false;
int stagnate_count = 0;
bool relax_convergence = false;
this->regularize_ = false;
for (; it < max_iter_number; ++it, ++debug_cost_counter_) {
assembleWellEqWithoutIteration(ebosSimulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger);
const BVectorWell dx_well = mswellhelpers::applyUMFPack(this->duneD_, this->duneDSolver_, this->resWell_);
if (it > this->param_.strict_inner_iter_wells_)
if (it > this->param_.strict_inner_iter_wells_) {
relax_convergence = true;
this->regularize_ = true;
}
const auto report = getWellConvergence(well_state, Base::B_avg_, deferred_logger, relax_convergence);
if (report.converged()) {
@@ -1398,12 +1409,20 @@ namespace Opm
break;
}
residual_history.push_back(this->getWellResiduals(Base::B_avg_, deferred_logger));
measure_history.push_back(this->getResidualMeasureValue(well_state,
{
// getFinteWellResiduals returns false for nan/inf residuals
const auto& [isFinite, residuals] = this->getFiniteWellResiduals(Base::B_avg_, deferred_logger);
if (!isFinite)
return false;
residual_history.push_back(residuals);
measure_history.push_back(this->getResidualMeasureValue(well_state,
residual_history[it],
this->param_.tolerance_wells_,
this->param_.tolerance_pressure_ms_wells_,
deferred_logger) );
}
bool is_oscillate = false;
bool is_stagnate = false;
@@ -1443,6 +1462,8 @@ namespace Opm
sstr << " well " << this->name() << " observes oscillation in inner iteration " << it << "\n";
}
sstr << " relaxation_factor is " << relaxation_factor << " now\n";
this->regularize_ = true;
deferred_logger.debug(sstr.str());
}
updateWellState(dx_well, well_state, deferred_logger, relaxation_factor);
@@ -1533,7 +1554,7 @@ namespace Opm
// Add a regularization_factor to increase the accumulation term
// This will make the system less stiff and help convergence for
// difficult cases
const Scalar regularization_factor = this->param_.regularization_factor_ms_wells_;
const Scalar regularization_factor = this->regularize_? this->param_.regularization_factor_ms_wells_ : 1.0;
// for each component
for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx) {
const EvalWell accumulation_term = regularization_factor * (segment_surface_volume * this->surfaceVolumeFraction(seg, comp_idx)

View File

@@ -17,6 +17,7 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <opm/simulators/wells/SingleWellState.hpp>
#include <opm/simulators/wells/PerforationData.hpp>
@@ -39,6 +40,7 @@ SingleWellState::SingleWellState(const std::string& name_,
, surface_rates(pu_.num_phases)
, reservoir_rates(pu_.num_phases)
, perf_data(perf_input.size(), pressure_first_connection, !is_producer, pu_.num_phases)
, trivial_target(false)
{
for (std::size_t perf = 0; perf < perf_input.size(); perf++) {
this->perf_data.cell_index[perf] = perf_input[perf].cell_index;

View File

@@ -62,6 +62,7 @@ public:
std::vector<double> surface_rates;
std::vector<double> reservoir_rates;
PerfData perf_data;
bool trivial_target;
SegmentState segments;
Events events;
Well::InjectorCMode injection_cmode{Well::InjectorCMode::CMODE_UNDEFINED};

View File

@@ -2016,11 +2016,11 @@ namespace Opm
well_potentials[phase] *= sign;
total_potential += well_potentials[phase];
}
if (total_potential < 0.0) {
if (total_potential < 0.0 && this->param_.check_well_operability_) {
// wells with negative potentials are not operable
this->operability_status_.has_negative_potentials = true;
const std::string msg = std::string("well ") + this->name() + std::string(": has negative potentials and is not operable");
deferred_logger.info(msg);
deferred_logger.warning("NEGATIVE_POTENTIALS_INOPERABLE", msg);
}
}
@@ -2476,6 +2476,7 @@ namespace Opm
// solution
std::vector<double> rates(3);
computeWellRatesWithBhpIterations(ebos_simulator, bhp, rates, deferred_logger);
this->adaptRatesForVFP(rates);
return rates;
};

View File

@@ -248,6 +248,10 @@ public:
void checkWellOperability(const Simulator& ebos_simulator, const WellState& well_state, DeferredLogger& deferred_logger);
void gliftBeginTimeStepWellTestUpdateALQ(const Simulator& ebos_simulator,
WellState& well_state,
DeferredLogger& deferred_logger);
// check whether the well is operable under the current reservoir condition
// mostly related to BHP limit and THP limit
void updateWellOperability(const Simulator& ebos_simulator,

View File

@@ -163,7 +163,7 @@ activeProductionConstraint(const SingleWellState& ws,
if (controls.hasControl(Well::ProducerCMode::THP) && currentControl != Well::ProducerCMode::THP) {
const auto& thp = getTHPConstraint(summaryState);
double current_thp = ws.thp;
if (thp > current_thp) {
if (thp > current_thp && !ws.trivial_target) {
// If WVFPEXP item 4 is set to YES1 or YES2
// switching to THP is prevented if the well will
// produce at a higher rate with THP control
@@ -1120,6 +1120,10 @@ getGroupProductionTargetRate(const Group& group,
const auto& rates = ws.surface_rates;
const auto current_rate = -tcalc.calcModeRateFromRates(rates); // Switch sign since 'rates' are negative for producers.
double scale = 1.0;
if (target_rate == 0.0) {
return 0.0;
}
if (current_rate > 1e-14)
scale = target_rate/current_rate;
return scale;

View File

@@ -565,9 +565,9 @@ bisectBracket(const std::function<double(const double)>& eq,
}
} else { // eq_low * eq_high > 0.0
// Still failed bracketing!
const double limit = 3.0 * unit::barsa;
const double limit = 0.1 * unit::barsa;
if (std::min(abs_low, abs_high) < limit) {
// Return the least bad solution if less off than 3 bar.
// Return the least bad solution if less off than 0.1 bar.
deferred_logger.warning("FAILED_ROBUST_BHP_THP_SOLVE_BRACKETING_FAILURE",
"Robust bhp(thp) not solved precisely for well " + this->name());
approximate_solution = abs_low < abs_high ? low : high;

View File

@@ -332,6 +332,9 @@ namespace Opm
return;
}
if (this->isProducer()) {
gliftBeginTimeStepWellTestUpdateALQ(simulator, well_state_copy, deferred_logger);
}
updateWellOperability(simulator, well_state_copy, deferred_logger);
if ( !this->isOperableAndSolvable() ) {
const auto msg = fmt::format("WTEST: Well {} is not operable (physical)", this->name());
@@ -446,7 +449,7 @@ namespace Opm
const GroupState& group_state,
DeferredLogger& deferred_logger)
{
if (!this->isOperableAndSolvable())
if (!this->isOperableAndSolvable() && !this->wellIsStopped())
return;
// keep a copy of the original well state
@@ -507,6 +510,7 @@ namespace Opm
}
this->changed_to_open_this_step_ = false;
const bool well_operable = this->operability_status_.isOperableAndSolvable();
if (!well_operable && old_well_operable) {
if (this->well_ecl_.getAutomaticShutIn()) {
deferred_logger.info(" well " + this->name() + " gets SHUT during iteration ");
@@ -536,6 +540,9 @@ namespace Opm
void
WellInterface<TypeTag>::addCellRates(RateVector& rates, int cellIdx) const
{
if(!this->isOperableAndSolvable() && !this->wellIsStopped())
return;
for (int perfIdx = 0; perfIdx < this->number_of_perforations_; ++perfIdx) {
if (this->cells()[perfIdx] == cellIdx) {
for (int i = 0; i < RateVector::dimension; ++i) {
@@ -582,7 +589,49 @@ namespace Opm
updateWellOperability(ebos_simulator, well_state, deferred_logger);
}
template<typename TypeTag>
void
WellInterface<TypeTag>::
gliftBeginTimeStepWellTestUpdateALQ(const Simulator& ebos_simulator,
WellState& well_state,
DeferredLogger& deferred_logger)
{
const auto& summary_state = ebos_simulator.vanguard().summaryState();
const auto& well_name = this->name();
if (!this->wellHasTHPConstraints(summary_state)) {
const std::string msg = fmt::format("GLIFT WTEST: Well {} does not have THP constraints", well_name);
deferred_logger.info(msg);
return;
}
const auto& well_ecl = this->wellEcl();
const auto& schedule = ebos_simulator.vanguard().schedule();
auto report_step_idx = ebos_simulator.episodeIndex();
const auto& glo = schedule.glo(report_step_idx);
if (!glo.has_well(well_name)) {
const std::string msg = fmt::format(
"GLIFT WTEST: Well {} : Gas Lift not activated: "
"WLIFTOPT is probably missing. Skipping.", well_name);
deferred_logger.info(msg);
return;
}
const auto& gl_well = glo.well(well_name);
auto& max_alq_optional = gl_well.max_rate();
double max_alq;
if (max_alq_optional) {
max_alq = *max_alq_optional;
}
else {
const auto& controls = well_ecl.productionControls(summary_state);
const auto& table = this->vfpProperties()->getProd()->getTable(controls.vfp_table_number);
const auto& alq_values = table.getALQAxis();
max_alq = alq_values.back();
}
well_state.setALQ(well_name, max_alq);
const std::string msg = fmt::format(
"GLIFT WTEST: Well {} : Setting ALQ to max value: {}",
well_name, max_alq);
deferred_logger.info(msg);
}
template<typename TypeTag>
void
@@ -933,6 +982,9 @@ namespace Opm
for (int p = 0; p<np; ++p) {
ws.surface_rates[p] *= scale;
}
ws.trivial_target = false;
} else {
ws.trivial_target = true;
}
break;
}
@@ -1004,8 +1056,9 @@ namespace Opm
// if more than one nonzero rate.
auto& ws = well_state.well(this->index_of_well_);
int nonzero_rate_index = -1;
const double floating_point_error_epsilon = 1e-14;
for (int p = 0; p < this->number_of_phases_; ++p) {
if (ws.surface_rates[p] != 0.0) {
if (std::abs(ws.surface_rates[p]) > floating_point_error_epsilon) {
if (nonzero_rate_index == -1) {
nonzero_rate_index = p;
} else {

View File

@@ -3,6 +3,11 @@
#
%define tag final
%define rtype release
%define toolset devtoolset-9
%define build_openmpi 1
%define build_openmpi3 1
%define build_mpich 1
Name: opm-simulators
Version: 2018.10
@@ -12,70 +17,89 @@ License: GPL-3.0
Group: Development/Libraries/C and C++
Url: http://www.opm-project.org/
Source0: https://github.com/OPM/%{name}/archive/release/%{version}/%{tag}.tar.gz#/%{name}-%{version}.tar.gz
BuildRequires: blas-devel lapack-devel
BuildRequires: dune-common-devel dune-geometry-devel dune-grid-devel dune-localfunctions-devel
BuildRequires: git suitesparse-devel doxygen bc
BuildRequires: opm-grid-devel opm-grid-openmpi-devel opm-grid-mpich-devel
BuildRequires: opm-models-devel opm-models-openmpi-devel opm-models-mpich-devel
BuildRequires: opm-material-devel opm-material-openmpi-devel opm-material-mpich-devel
BuildRequires: tinyxml-devel dune-istl-devel zlib-devel
BuildRequires: openmpi-devel trilinos-openmpi-devel ptscotch-openmpi-devel scotch-devel
BuildRequires: mpich-devel trilinos-mpich-devel ptscotch-mpich-devel
BuildRequires: opm-common-devel opm-common-openmpi-devel opm-common-mpich-devel
BuildRequires: blas-devel lapack-devel openblas-devel
BuildRequires: git suitesparse-devel doxygen bc graphviz
BuildRequires: tinyxml-devel zlib-devel
BuildRequires: zoltan-devel
BuildRequires: cmake3
%{?!el8:BuildRequires: devtoolset-8-toolchain}
BuildRequires: boost-devel
BuildRequires: %{toolset}-toolchain
BuildRequires: boost-devel python3-devel tbb-devel
BuildRequires: dune-common-devel
BuildRequires: dune-geometry-devel
BuildRequires: dune-uggrid-devel
BuildRequires: dune-grid-devel
BuildRequires: dune-localfunctions-devel
BuildRequires: dune-istl-devel
BuildRequires: opm-common-devel
BuildRequires: opm-material-devel
BuildRequires: opm-grid-devel
BuildRequires: opm-models-devel
%if %{build_openmpi}
BuildRequires: openmpi-devel
BuildRequires: zoltan-openmpi-devel
BuildRequires: dune-common-openmpi-devel
BuildRequires: dune-geometry-openmpi-devel
BuildRequires: dune-uggrid-openmpi-devel
BuildRequires: dune-grid-openmpi-devel
BuildRequires: dune-localfunctions-openmpi-devel
BuildRequires: dune-istl-openmpi-devel
BuildRequires: opm-common-openmpi-devel
BuildRequires: opm-material-openmpi-devel
BuildRequires: opm-grid-openmpi-devel
BuildRequires: opm-models-openmpi-devel
%endif
%if %{build_openmpi3}
BuildRequires: openmpi3-devel
BuildRequires: zoltan-openmpi3-devel
BuildRequires: dune-common-openmpi3-devel
BuildRequires: dune-geometry-openmpi3-devel
BuildRequires: dune-uggrid-openmpi3-devel
BuildRequires: dune-grid-openmpi3-devel
BuildRequires: dune-localfunctions-openmpi3-devel
BuildRequires: dune-istl-openmpi3-devel
BuildRequires: opm-common-openmpi3-devel
BuildRequires: opm-material-openmpi3-devel
BuildRequires: opm-grid-openmpi3-devel
BuildRequires: opm-models-openmpi3-devel
%endif
%if %{build_mpich}
BuildRequires: mpich-devel
BuildRequires: zoltan-mpich-devel
BuildRequires: dune-common-mpich-devel
BuildRequires: dune-geometry-mpich-devel
BuildRequires: dune-uggrid-mpich-devel
BuildRequires: dune-grid-mpich-devel
BuildRequires: dune-localfunctions-mpich-devel
BuildRequires: dune-istl-mpich-devel
BuildRequires: opm-common-mpich-devel
BuildRequires: opm-material-mpich-devel
BuildRequires: opm-grid-mpich-devel
BuildRequires: opm-models-mpich-devel
%endif
BuildRoot: %{_tmppath}/%{name}-%{version}-build
Requires: libopm-simulators1 = %{version}
%description
The Open Porous Media (OPM) initiative provides a set of open-source tools centered around the simulation of flow and transport of fluids in porous media. The goal of the initiative is to establish a sustainable environment for the development of an efficient and well-maintained software suite.
%package -n libopm-simulators1
%package -n libopm-simulators%{opm_package_version}
Summary: Open Porous Media - automatic differentiation library
Group: System/Libraries
%description -n libopm-simulators1
The Open Porous Media (OPM) initiative provides a set of open-source tools centered around the simulation of flow and transport of fluids in porous media. The goal of the initiative is to establish a sustainable environment for the development of an efficient and well-maintained software suite.
%package -n libopm-simulators1-openmpi
Summary: Open Porous Media - automatic differentiation library
Group: System/Libraries
%description -n libopm-simulators1-openmpi
The Open Porous Media (OPM) initiative provides a set of open-source tools centered around the simulation of flow and transport of fluids in porous media. The goal of the initiative is to establish a sustainable environment for the development of an efficient and well-maintained software suite.
%package -n libopm-simulators1-mpich
Summary: Open Porous Media - automatic differentiation library
Group: System/Libraries
%description -n libopm-simulators1-mpich
%description -n libopm-simulators%{opm_package_version}
The Open Porous Media (OPM) initiative provides a set of open-source tools centered around the simulation of flow and transport of fluids in porous media. The goal of the initiative is to establish a sustainable environment for the development of an efficient and well-maintained software suite.
%package devel
Summary: Development and header files for opm-simulators
Group: Development/Libraries/C and C++
Requires: libopm-simulators1 = %{version}
Requires: libopm-simulator%{opm_package_version}s = %{version}
%description devel
This package contains the development and header files for opm-simulators
%package openmpi-devel
Summary: Development and header files for opm-simulators
Group: Development/Libraries/C and C++
Requires: libopm-simulators1-openmpi = %{version}
%description openmpi-devel
This package contains the development and header files for opm-simulators
%package mpich-devel
Summary: Development and header files for opm-simulators
Group: Development/Libraries/C and C++
Requires: libopm-simulators1-mpich = %{version}
%description mpich-devel
This package contains the development and header files for opm-simulators
%package doc
Summary: Documentation files for opm-simulators
Group: Documentation
@@ -84,112 +108,185 @@ BuildArch: noarch
%description doc
This package contains the documentation files for opm-simulators
%package bin
%package bin%{opm_package_version}
Summary: Applications in opm-simulators
Group: Scientific
Requires: libopm-simulators1 = %{version}
%description bin
%description bin%{opm_package_version}
This package contains the applications for opm-simulators
%package openmpi-bin
%if %{build_openmpi}
%package -n libopm-simulators-openmpi%{opm_package_version}
Summary: Open Porous Media - automatic differentiation library
Group: System/Libraries
%description -n libopm-simulators-openmpi%{opm_package_version}
The Open Porous Media (OPM) initiative provides a set of open-source tools centered around the simulation of flow and transport of fluids in porous media. The goal of the initiative is to establish a sustainable environment for the development of an efficient and well-maintained software suite.
%package openmpi-devel
Summary: Development and header files for opm-simulators
Group: Development/Libraries/C and C++
Requires: libopm-simulators-openmpi%{opm_package_version} = %{version}
%description openmpi-devel
This package contains the development and header files for opm-simulators
%package openmpi-bin%{opm_package_version}
Summary: Applications in opm-simulators
Group: Scientific
Requires: libopm-simulators1-openmpi = %{version}
Requires: libopm-grid1-openmpi
Requires: libopm-common1-openmpi
Requires: trilinos-openmpi
Requires: ptscotch-openmpi
%description openmpi-bin
%description openmpi-bin%{opm_package_version}
This package contains the applications for opm-simulators
%endif
%package mpich-bin
%if %{build_openmpi3}
%package -n libopm-simulators-openmpi3%{opm_package_version}
Summary: Open Porous Media - automatic differentiation library
Group: System/Libraries
%description -n libopm-simulators-openmpi3%{opm_package_version}
The Open Porous Media (OPM) initiative provides a set of open-source tools centered around the simulation of flow and transport of fluids in porous media. The goal of the initiative is to establish a sustainable environment for the development of an efficient and well-maintained software suite.
%package openmpi3-devel
Summary: Development and header files for opm-simulators
Group: Development/Libraries/C and C++
Requires: libopm-simulators-openmpi3%{opm_package_version} = %{version}
%description openmpi3-devel
This package contains the development and header files for opm-simulators
%package openmpi3-bin%{opm_package_version}
Summary: Applications in opm-simulators
Group: Scientific
Requires: libopm-simulators1-mpich = %{version}
Requires: libopm-grid1-mpich
Requires: libopm-common1-mpich
Requires: trilinos-mpich
Requires: ptscotch-mpich
%description mpich-bin
%description openmpi3-bin%{opm_package_version}
This package contains the applications for opm-simulators
%endif
%if %{build_mpich}
%package -n libopm-simulators-mpich%{opm_package_version}
Summary: Open Porous Media - automatic differentiation library
Group: System/Libraries
%description -n libopm-simulators-mpich%{opm_package_version}
The Open Porous Media (OPM) initiative provides a set of open-source tools centered around the simulation of flow and transport of fluids in porous media. The goal of the initiative is to establish a sustainable environment for the development of an efficient and well-maintained software suite.
%package mpich-devel
Summary: Development and header files for opm-simulators
Group: Development/Libraries/C and C++
Requires: libopm-simulators-mpich%{opm_package_version} = %{version}
%description mpich-devel
This package contains the development and header files for opm-simulators
%package mpich-bin%{opm_package_version}
Summary: Applications in opm-simulators
Group: Scientific
%description mpich-bin%{opm_package_version}
This package contains the applications for opm-simulators
%endif
%global debug_package %{nil}
%prep
%setup -q -n %{name}-release-%{version}-%{tag}
%setup -q -n %{name}-%{rtype}-%{version}-%{tag}
%build
mkdir serial
cd serial
cmake3 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DUSE_QUADMATH=0 %{!?el8:-DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/gfortran} -DCMAKE_INSTALL_SYSCONFDIR=/etc ..
make %{?_smp_mflags}
#make test
cd ..
pushd serial
scl enable %{toolset} 'cmake3 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DUSE_QUADMATH=0 -DCMAKE_INSTALL_SYSCONFDIR=/etc .. '
scl enable %{toolset} 'make %{?_smp_mflags}'
scl enable %{toolset} 'make test'
popd
%if %{build_openmpi}
mkdir openmpi
cd openmpi
%{?el6:module load openmpi-x86_64}
%{?!el6:module load mpi/openmpi-x86_64}
cmake3 -DUSE_MPI=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%{_prefix}/lib64/openmpi -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DUSE_QUADMATH=0 %{!?el8:-DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/gfortran} -DZOLTAN_ROOT=/usr/lib64/openmpi -DCMAKE_CXX_FLAGS=-I/usr/include/openmpi-x86_64/trilinos -DZOLTAN_INCLUDE_DIRS=/usr/include/openmpi-x86_64/trilinos -DPTSCOTCH_ROOT=/usr/lib64/openmpi -DPTSCOTCH_INCLUDE_DIR=/usr/include/openmpi-x86_64 -DCMAKE_INSTALL_SYSCONFDIR=/etc ..
make %{?_smp_mflags}
#make test
cd ..
pushd openmpi
module load mpi/openmpi-x86_64
scl enable %{toolset} 'cmake3 -DUSE_MPI=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%{_prefix}/lib64/openmpi -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DUSE_QUADMATH=0 -DZOLTAN_INCLUDE_DIRS=/usr/include/openmpi-x86_64/zoltan -DCMAKE_INSTALL_SYSCONFDIR=/etc ..'
scl enable %{toolset} 'make %{?_smp_mflags}'
scl enable %{toolset} 'make test'
module unload mpi/openmpi-x86_64
popd
%endif
%if %{build_openmpi3}
mkdir openmpi3
pushd openmpi3
module load mpi/openmpi3-x86_64
scl enable %{toolset} 'cmake3 -DUSE_MPI=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%{_prefix}/lib64/openmpi3 -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DUSE_QUADMATH=0 -DZOLTAN_INCLUDE_DIRS=/usr/include/openmpi3-x86_64/zoltan -DCMAKE_INSTALL_SYSCONFDIR=/etc ..'
scl enable %{toolset} 'make %{?_smp_mflags}'
scl enable %{toolset} 'make test'
module unload mpi/openmpi3-x86_64
popd
%endif
%if %{build_mpich}
mkdir mpich
cd mpich
%{?el6:module rm openmpi-x86_64}
%{?el6:module load mpich-x86_64}
%{?!el6:module rm mpi/openmpi-x86_64}
%{?!el6:module load mpi/mpich-x86_64}
cmake3 -DUSE_MPI=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%{_prefix}/lib64/mpich -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DUSE_QUADMATH=0 %{!?el8:-DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/g++ -DCMAKE_C_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/gcc -DCMAKE_Fortran_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/gfortran} -DZOLTAN_ROOT=/usr/lib64/mpich -DCMAKE_CXX_FLAGS=-I/usr/include/mpich-x86_64/trilinos -DZOLTAN_INCLUDE_DIRS=/usr/include/mpich-x86_64/trilinos -DPTSCOTCH_ROOT=/usr/lib64/mpich -DPTSCOTCH_INCLUDE_DIR=/usr/include/mpich-x86_64 -DCMAKE_INSTALL_SYSCONFDIR=/etc ..
make %{?_smp_mflags}
#make test
pushd mpich
module load mpi/mpich-x86_64
scl enable %{toolset} 'cmake3 -DUSE_MPI=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%{_prefix}/lib64/mpich -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_DOCDIR=share/doc/%{name}-%{version} -DUSE_RUNPATH=OFF -DWITH_NATIVE=OFF -DUSE_QUADMATH=0 -DZOLTAN_INCLUDE_DIRS=/usr/include/mpich-x86_64/zoltan -DCMAKE_INSTALL_SYSCONFDIR=/etc ..'
scl enable %{toolset} 'make %{?_smp_mflags}'
scl enable %{toolset} 'make test'
module unload mpi/openmpi3-x86_64
popd
%endif
%install
cd serial
make install DESTDIR=${RPM_BUILD_ROOT}
make install-html DESTDIR=${RPM_BUILD_ROOT}
cd ..
scl enable %{toolset} 'make install DESTDIR=${RPM_BUILD_ROOT} -C serial'
scl enable %{toolset} 'make install-html DESTDIR=${RPM_BUILD_ROOT} -C serial'
mv ${RPM_BUILD_ROOT}/usr/bin/flow ${RPM_BUILD_ROOT}/usr/bin/flow%{opm_package_version}
cd openmpi
make install DESTDIR=${RPM_BUILD_ROOT}
%if %{build_openmpi}
scl enable %{toolset} 'make install DESTDIR=${RPM_BUILD_ROOT} -C openmpi'
mkdir -p ${RPM_BUILD_ROOT}/usr/include/openmpi-x86_64/
mv ${RPM_BUILD_ROOT}/usr/lib64/openmpi/include/* ${RPM_BUILD_ROOT}/usr/include/openmpi-x86_64/
cd ..
mv ${RPM_BUILD_ROOT}/usr/lib64/openmpi/bin/flow ${RPM_BUILD_ROOT}/usr/lib64/openmpi/bin/flow%{opm_package_version}
%endif
cd mpich
make install DESTDIR=${RPM_BUILD_ROOT}
%if %{build_openmpi3}
scl enable %{toolset} 'make install DESTDIR=${RPM_BUILD_ROOT} -C openmpi3'
mkdir -p ${RPM_BUILD_ROOT}/usr/include/openmpi3-x86_64/
mv ${RPM_BUILD_ROOT}/usr/lib64/openmpi3/include/* ${RPM_BUILD_ROOT}/usr/include/openmpi3-x86_64/
mv ${RPM_BUILD_ROOT}/usr/lib64/openmpi3/bin/flow ${RPM_BUILD_ROOT}/usr/lib64/openmpi3/bin/flow%{opm_package_version}
%endif
%if %{build_mpich}
scl enable %{toolset} 'make install DESTDIR=${RPM_BUILD_ROOT} -C mpich'
mkdir -p ${RPM_BUILD_ROOT}/usr/include/mpich-x86_64/
mv ${RPM_BUILD_ROOT}/usr/lib64/mpich/include/* ${RPM_BUILD_ROOT}/usr/include/mpich-x86_64/
mv ${RPM_BUILD_ROOT}/usr/lib64/mpich/bin/flow ${RPM_BUILD_ROOT}/usr/lib64/mpich/bin/flow%{opm_package_version}
%endif
%clean
rm -rf %{buildroot}
%post -n libopm-simulators1 -p /sbin/ldconfig
%post -n libopm-simulators1-openmpi -p /sbin/ldconfig
%post -n libopm-simulators1-mpich -p /sbin/ldconfig
%post -n libopm-simulators%{opm_package_version} -p /sbin/ldconfig
%postun -n libopm-simulators%{opm_package_version} -p /sbin/ldconfig
%postun -n libopm-simulators1 -p /sbin/ldconfig
%postun -n libopm-simulators1-openmpi -p /sbin/ldconfig
%postun -n libopm-simulators1-mpich -p /sbin/ldconfig
%if %{build_openmpi}
%post -n libopm-simulators-openmpi%{opm_package_version} -p /sbin/ldconfig
%postun -n libopm-simulators-openmpi%{opm_package_version} -p /sbin/ldconfig
%endif
%if %{build_openmpi3}
%post -n libopm-simulators-openmpi3%{opm_package_version} -p /sbin/ldconfig
%postun -n libopm-simulators-openmpi3%{opm_package_version} -p /sbin/ldconfig
%endif
%if %{build_mpich}
%post -n libopm-simulators-mpich%{opm_package_version} -p /sbin/ldconfig
%postun -n libopm-simulators-mpich%{opm_package_version} -p /sbin/ldconfig
%endif
%files doc
%{_docdir}/*
/etc/bash_completion.d/*
%files -n libopm-simulators1
%files -n libopm-simulators%{opm_package_version}
%defattr(-,root,root,-)
%{_libdir}/*.so.*
%files -n libopm-simulators1-openmpi
%defattr(-,root,root,-)
%{_libdir}/openmpi/lib/*.so.*
%files -n libopm-simulators1-mpich
%defattr(-,root,root,-)
%{_libdir}/mpich/lib/*.so.*
%files devel
%defattr(-,root,root,-)
%{_libdir}/*.so
@@ -199,6 +296,16 @@ rm -rf %{buildroot}
%{_datadir}/cmake/*
%{_datadir}/opm/cmake/Modules/*
%files bin%{opm_package_version}
%{_bindir}/*
/etc/bash_completion.d/*
%{_datadir}/man/*
%if %{build_openmpi}
%files -n libopm-simulators-openmpi%{opm_package_version}
%defattr(-,root,root,-)
%{_libdir}/openmpi/lib/*.so.*
%files openmpi-devel
%defattr(-,root,root,-)
%{_libdir}/openmpi/lib/*.so
@@ -208,6 +315,35 @@ rm -rf %{buildroot}
%{_libdir}/openmpi/share/cmake/*
%{_libdir}/openmpi/share/opm/cmake/Modules/*
%files openmpi-bin%{opm_package_version}
%{_libdir}/openmpi/bin/*
%{_libdir}/openmpi/share/man/*
%endif
%if %{build_openmpi3}
%files -n libopm-simulators-openmpi3%{opm_package_version}
%defattr(-,root,root,-)
%{_libdir}/openmpi3/lib/*.so.*
%files openmpi3-devel
%defattr(-,root,root,-)
%{_libdir}/openmpi3/lib/*.so
%{_libdir}/openmpi3/lib/dunecontrol/*
%{_libdir}/openmpi3/lib/pkgconfig/*
%{_includedir}/openmpi3-x86_64/*
%{_libdir}/openmpi3/share/cmake/*
%{_libdir}/openmpi3/share/opm/cmake/Modules/*
%files openmpi3-bin%{opm_package_version}
%{_libdir}/openmpi3/bin/*
%{_libdir}/openmpi3/share/man/*
%endif
%if %{build_mpich}
%files -n libopm-simulators-mpich%{opm_package_version}
%defattr(-,root,root,-)
%{_libdir}/mpich/lib/*.so.*
%files mpich-devel
%defattr(-,root,root,-)
%{_libdir}/mpich/lib/*.so
@@ -217,11 +353,7 @@ rm -rf %{buildroot}
%{_libdir}/mpich/share/cmake/*
%{_libdir}/mpich/share/opm/cmake/Modules/*
%files bin
%{_bindir}/*
%files openmpi-bin
%{_libdir}/openmpi/bin/*
%files mpich-bin
%files mpich-bin%{opm_package_version}
%{_libdir}/mpich/bin/*
%{_libdir}/mpich/share/man/*
%endif

View File

@@ -36,7 +36,8 @@
#include <dune/istl/bvector.hh>
#include <dune/istl/bcrsmatrix.hh>
#include <dune/istl/matrixmarket.hh>
#include <dune/istl/solver.hh>
#include <dune/istl/solvers.hh>
#include <dune/istl/preconditioners.hh>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
@@ -48,12 +49,13 @@ public:
};
template <int bz>
Dune::BlockVector<Dune::FieldVector<double, bz>>
testCusparseSolver(const boost::property_tree::ptree& prm, const std::string& matrix_filename, const std::string& rhs_filename)
using Matrix = Dune::BCRSMatrix<Dune::FieldMatrix<double, bz, bz>>;
template <int bz>
using Vector = Dune::BlockVector<Dune::FieldVector<double, bz>>;
template <int bz>
void readLinearSystem(const std::string& matrix_filename, const std::string& rhs_filename, Matrix<bz>& matrix, Vector<bz>& rhs)
{
using Matrix = Dune::BCRSMatrix<Dune::FieldMatrix<double, bz, bz>>;
using Vector = Dune::BlockVector<Dune::FieldVector<double, bz>>;
Matrix matrix;
{
std::ifstream mfile(matrix_filename);
if (!mfile) {
@@ -61,7 +63,6 @@ testCusparseSolver(const boost::property_tree::ptree& prm, const std::string& ma
}
readMatrixMarket(matrix, mfile);
}
Vector rhs;
{
std::ifstream rhsfile(rhs_filename);
if (!rhsfile) {
@@ -69,6 +70,32 @@ testCusparseSolver(const boost::property_tree::ptree& prm, const std::string& ma
}
readMatrixMarket(rhs, rhsfile);
}
}
template <int bz>
Dune::BlockVector<Dune::FieldVector<double, bz>>
getDuneSolution(Matrix<bz>& matrix, Vector<bz>& rhs)
{
Dune::InverseOperatorResult result;
Vector<bz> x(rhs.size());
typedef Dune::MatrixAdapter<Matrix<bz>,Vector<bz>,Vector<bz> > Operator;
Operator fop(matrix);
double relaxation = 0.9;
Dune::SeqILU<Matrix<bz>,Vector<bz>,Vector<bz> > prec(matrix, relaxation);
double reduction = 1e-2;
int maxit = 10;
int verbosity = 0;
Dune::BiCGSTABSolver<Vector<bz> > solver(fop, prec, reduction, maxit, verbosity);
solver.apply(x, rhs, result);
return x;
}
template <int bz>
Dune::BlockVector<Dune::FieldVector<double, bz>>
testCusparseSolver(const boost::property_tree::ptree& prm, Matrix<bz>& matrix, Vector<bz>& rhs)
{
const int linear_solver_verbosity = prm.get<int>("verbosity");
const int maxit = prm.get<int>("maxiter");
@@ -81,13 +108,15 @@ testCusparseSolver(const boost::property_tree::ptree& prm, const std::string& ma
const std::string linsolver("ilu0");
Dune::InverseOperatorResult result;
Vector x(rhs.size());
auto wellContribs = Opm::WellContributions::create("cusparse", false);
std::unique_ptr<Opm::BdaBridge<Matrix, Vector, bz> > bridge;
try {
bridge = std::make_unique<Opm::BdaBridge<Matrix, Vector, bz> >(accelerator_mode, fpga_bitstream, linear_solver_verbosity, maxit, tolerance, platformID, deviceID, opencl_ilu_reorder, linsolver);
Vector<bz> x(rhs.size());
bridge->solve_system(&matrix, rhs, *wellContribs, result);
auto wellContribs = Opm::WellContributions::create("cusparse", false);
std::unique_ptr<Opm::BdaBridge<Matrix<bz>, Vector<bz>, bz> > bridge;
try {
bridge = std::make_unique<Opm::BdaBridge<Matrix<bz>, Vector<bz>, bz> >(accelerator_mode, fpga_bitstream, linear_solver_verbosity, maxit, tolerance, platformID, deviceID, opencl_ilu_reorder, linsolver);
auto mat2 = matrix; // deep copy to make sure nnz values are in contiguous memory
// matrix created by readMatrixMarket() did not have contiguous memory
bridge->solve_system(&mat2, rhs, *wellContribs, result);
bridge->get_result(x);
return x;
@@ -105,14 +134,17 @@ namespace pt = boost::property_tree;
void test3(const pt::ptree& prm)
{
const int bz = 3;
auto sol = testCusparseSolver<bz>(prm, "matr33.txt", "rhs3.txt");
Dune::BlockVector<Dune::FieldVector<double, bz>> expected {{-0.0131626, -3.5826e-6, 1.138362e-9},
{-1.25425e-3, -1.4167e-4, -0.0029366},
{-4.54355e-4, 1.28682e-5, 4.7644e-6}};
BOOST_REQUIRE_EQUAL(sol.size(), expected.size());
Matrix<bz> matrix;
Vector<bz> rhs;
readLinearSystem("matr33.txt", "rhs3.txt", matrix, rhs);
Vector<bz> rhs2 = rhs; // deep copy, getDuneSolution() changes values in rhs vector
auto duneSolution = getDuneSolution<bz>(matrix, rhs);
auto sol = testCusparseSolver<bz>(prm, matrix, rhs2);
BOOST_REQUIRE_EQUAL(sol.size(), duneSolution.size());
for (size_t i = 0; i < sol.size(); ++i) {
for (int row = 0; row < bz; ++row) {
BOOST_CHECK_CLOSE(sol[i][row], expected[i][row], 1e-3);
BOOST_CHECK_CLOSE(sol[i][row], duneSolution[i][row], 1e-3);
}
}
}

View File

@@ -36,6 +36,8 @@
#include <dune/istl/bvector.hh>
#include <dune/istl/bcrsmatrix.hh>
#include <dune/istl/matrixmarket.hh>
#include <dune/istl/solvers.hh>
#include <dune/istl/preconditioners.hh>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
@@ -47,12 +49,13 @@ public:
};
template <int bz>
Dune::BlockVector<Dune::FieldVector<double, bz>>
testOpenclSolver(const boost::property_tree::ptree& prm, const std::string& matrix_filename, const std::string& rhs_filename)
using Matrix = Dune::BCRSMatrix<Dune::FieldMatrix<double, bz, bz>>;
template <int bz>
using Vector = Dune::BlockVector<Dune::FieldVector<double, bz>>;
template <int bz>
void readLinearSystem(const std::string& matrix_filename, const std::string& rhs_filename, Matrix<bz>& matrix, Vector<bz>& rhs)
{
using Matrix = Dune::BCRSMatrix<Dune::FieldMatrix<double, bz, bz>>;
using Vector = Dune::BlockVector<Dune::FieldVector<double, bz>>;
Matrix matrix;
{
std::ifstream mfile(matrix_filename);
if (!mfile) {
@@ -60,7 +63,6 @@ testOpenclSolver(const boost::property_tree::ptree& prm, const std::string& matr
}
readMatrixMarket(matrix, mfile);
}
Vector rhs;
{
std::ifstream rhsfile(rhs_filename);
if (!rhsfile) {
@@ -68,7 +70,32 @@ testOpenclSolver(const boost::property_tree::ptree& prm, const std::string& matr
}
readMatrixMarket(rhs, rhsfile);
}
}
template <int bz>
Dune::BlockVector<Dune::FieldVector<double, bz>>
getDuneSolution(Matrix<bz>& matrix, Vector<bz>& rhs)
{
Dune::InverseOperatorResult result;
Vector<bz> x(rhs.size());
typedef Dune::MatrixAdapter<Matrix<bz>,Vector<bz>,Vector<bz> > Operator;
Operator fop(matrix);
double relaxation = 0.9;
Dune::SeqILU<Matrix<bz>,Vector<bz>,Vector<bz> > prec(matrix, relaxation);
double reduction = 1e-2;
int maxit = 10;
int verbosity = 0;
Dune::BiCGSTABSolver<Vector<bz> > solver(fop, prec, reduction, maxit, verbosity);
solver.apply(x, rhs, result);
return x;
}
template <int bz>
Dune::BlockVector<Dune::FieldVector<double, bz>>
testOpenclSolver(const boost::property_tree::ptree& prm, Matrix<bz>& matrix, Vector<bz>& rhs)
{
const int linear_solver_verbosity = prm.get<int>("verbosity");
const int maxit = prm.get<int>("maxiter");
const double tolerance = prm.get<double>("tol");
@@ -80,16 +107,18 @@ testOpenclSolver(const boost::property_tree::ptree& prm, const std::string& matr
const std::string linsolver("ilu0");
Dune::InverseOperatorResult result;
Vector x(rhs.size());
Vector<bz> x(rhs.size());
auto wellContribs = Opm::WellContributions::create("opencl", false);
std::unique_ptr<Opm::BdaBridge<Matrix, Vector, bz> > bridge;
std::unique_ptr<Opm::BdaBridge<Matrix<bz>, Vector<bz>, bz> > bridge;
try {
bridge = std::make_unique<Opm::BdaBridge<Matrix, Vector, bz> >(accelerator_mode, fpga_bitstream, linear_solver_verbosity, maxit, tolerance, platformID, deviceID, opencl_ilu_reorder, linsolver);
bridge = std::make_unique<Opm::BdaBridge<Matrix<bz>, Vector<bz>, bz> >(accelerator_mode, fpga_bitstream, linear_solver_verbosity, maxit, tolerance, platformID, deviceID, opencl_ilu_reorder, linsolver);
} catch (const std::logic_error& error) {
BOOST_WARN_MESSAGE(true, error.what());
throw PlatformInitException(error.what());
}
bridge->solve_system(&matrix, rhs, *wellContribs, result);
auto mat2 = matrix; // deep copy to make sure nnz values are in contiguous memory
// matrix created by readMatrixMarket() did not have contiguous memory
bridge->solve_system(&mat2, rhs, *wellContribs, result);
bridge->get_result(x);
return x;
@@ -100,14 +129,17 @@ namespace pt = boost::property_tree;
void test3(const pt::ptree& prm)
{
const int bz = 3;
auto sol = testOpenclSolver<bz>(prm, "matr33.txt", "rhs3.txt");
Dune::BlockVector<Dune::FieldVector<double, bz>> expected {{-0.0131626, -3.58263e-6, 1.13836e-9},
{-1.25425e-3, -1.4167e-4, -0.0029366},
{-4.5436e-4, 1.28682e-5, 4.7644e-6}};
BOOST_REQUIRE_EQUAL(sol.size(), expected.size());
Matrix<bz> matrix;
Vector<bz> rhs;
readLinearSystem("matr33.txt", "rhs3.txt", matrix, rhs);
Vector<bz> rhs2 = rhs; // deep copy, getDuneSolution() changes values in rhs vector
auto duneSolution = getDuneSolution<bz>(matrix, rhs);
auto sol = testOpenclSolver<bz>(prm, matrix, rhs2);
BOOST_REQUIRE_EQUAL(sol.size(), duneSolution.size());
for (size_t i = 0; i < sol.size(); ++i) {
for (int row = 0; row < bz; ++row) {
BOOST_CHECK_CLOSE(sol[i][row], expected[i][row], 1e-3);
BOOST_CHECK_CLOSE(sol[i][row], duneSolution[i][row], 1e-3);
}
}
}

View File

@@ -66,13 +66,13 @@ tests[spe1_oilgas]="flow spe1 SPE1CASE2_OILGAS"
tests[spe1_gaswater]="flow spe1 SPE1CASE2_GASWATER"
tests[spe1_nowells]="flow spe1 SPE1CASE2_NOWELLS"
tests[spe1_thermal]="flow spe1 SPE1CASE2_THERMAL"
tests[spe1_thermal_onephase]="flow_onephase_energy spe1 SPE1CASE2_THERMAL_ONEPHASE"
tests[spe1_thermal_onephase]="flow spe1 SPE1CASE2_THERMAL_ONEPHASE"
tests[spe1_thermal_watvisc]="flow spe1 SPE1CASE2_THERMAL_WATVISC"
tests[spe1_rockcomp]="flow spe1 SPE1CASE2_ROCK2DTR"
tests[spe1_brine]="flow spe1_brine SPE1CASE1_BRINE"
tests[spe1_precsalt]="flow spe1_precsalt SPE1CASE1_PRECSALT"
tests[spe1_brine_gaswater]="flow spe1_brine SPE1CASE2_BRINE_GASWATER"
tests[spe1_water]="flow_onephase spe1 SPE1CASE1_WATER"
tests[spe1_water]="flow spe1 SPE1CASE1_WATER"
tests[spe1_spider]="flow radial_grid SPIDER_CAKESLICE"
tests[spe1_radial]="flow radial_grid RADIAL_CAKESLICE"
tests[spe1_import]="flow spe1 SPE1CASE1_IMPORT"