240 throw std::runtime_error(
"Not support ROCKOMP hysteresis option ");
243 std::size_t numRocktabTables = rock_config.num_rock_tables();
244 bool waterCompaction = rock_config.water_compaction();
246 if (!waterCompaction) {
247 const auto& rocktabTables = eclState_.getTableManager().getRocktabTables();
248 if (rocktabTables.size() != numRocktabTables)
249 throw std::runtime_error(
"ROCKCOMP is activated." + std::to_string(numRocktabTables)
250 +
" ROCKTAB tables is expected, but " + std::to_string(rocktabTables.size()) +
" is provided");
252 rockCompPoroMult_.resize(numRocktabTables);
253 rockCompTransMult_.resize(numRocktabTables);
254 for (std::size_t regionIdx = 0; regionIdx < numRocktabTables; ++regionIdx) {
255 const auto& rocktabTable = rocktabTables.template getTable<RocktabTable>(regionIdx);
256 const auto& pressureColumn = rocktabTable.getPressureColumn();
257 const auto& poroColumn = rocktabTable.getPoreVolumeMultiplierColumn();
258 const auto& transColumn = rocktabTable.getTransmissibilityMultiplierColumn();
259 rockCompPoroMult_[regionIdx].setXYContainers(pressureColumn, poroColumn);
260 rockCompTransMult_[regionIdx].setXYContainers(pressureColumn, transColumn);
263 const auto& rock2dTables = eclState_.getTableManager().getRock2dTables();
264 const auto& rock2dtrTables = eclState_.getTableManager().getRock2dtrTables();
265 const auto& rockwnodTables = eclState_.getTableManager().getRockwnodTables();
266 maxWaterSaturation_.resize(numElem, 0.0);
268 if (rock2dTables.size() != numRocktabTables)
269 throw std::runtime_error(
"Water compation option is selected in ROCKCOMP." + std::to_string(numRocktabTables)
270 +
" ROCK2D tables is expected, but " + std::to_string(rock2dTables.size()) +
" is provided");
272 if (rockwnodTables.size() != numRocktabTables)
273 throw std::runtime_error(
"Water compation option is selected in ROCKCOMP." + std::to_string(numRocktabTables)
274 +
" ROCKWNOD tables is expected, but " + std::to_string(rockwnodTables.size()) +
" is provided");
276 rockCompPoroMultWc_.resize(numRocktabTables, TabulatedTwoDFunction(TabulatedTwoDFunction::InterpolationPolicy::Vertical));
277 for (std::size_t regionIdx = 0; regionIdx < numRocktabTables; ++regionIdx) {
278 const RockwnodTable& rockwnodTable = rockwnodTables.template getTable<RockwnodTable>(regionIdx);
279 const auto& rock2dTable = rock2dTables[regionIdx];
281 if (rockwnodTable.getSaturationColumn().size() != rock2dTable.sizeMultValues())
282 throw std::runtime_error(
"Number of entries in ROCKWNOD and ROCK2D needs to match.");
284 for (std::size_t xIdx = 0; xIdx < rock2dTable.size(); ++xIdx) {
285 rockCompPoroMultWc_[regionIdx].appendXPos(rock2dTable.getPressureValue(xIdx));
286 for (std::size_t yIdx = 0; yIdx < rockwnodTable.getSaturationColumn().size(); ++yIdx)
287 rockCompPoroMultWc_[regionIdx].appendSamplePoint(xIdx,
288 rockwnodTable.getSaturationColumn()[yIdx],
289 rock2dTable.getPvmultValue(xIdx, yIdx));
293 if (!rock2dtrTables.empty()) {
294 rockCompTransMultWc_.resize(numRocktabTables, TabulatedTwoDFunction(TabulatedTwoDFunction::InterpolationPolicy::Vertical));
295 for (std::size_t regionIdx = 0; regionIdx < numRocktabTables; ++regionIdx) {
296 const RockwnodTable& rockwnodTable = rockwnodTables.template getTable<RockwnodTable>(regionIdx);
297 const auto& rock2dtrTable = rock2dtrTables[regionIdx];
299 if (rockwnodTable.getSaturationColumn().size() != rock2dtrTable.sizeMultValues())
300 throw std::runtime_error(
"Number of entries in ROCKWNOD and ROCK2DTR needs to match.");
302 for (std::size_t xIdx = 0; xIdx < rock2dtrTable.size(); ++xIdx) {
303 rockCompTransMultWc_[regionIdx].appendXPos(rock2dtrTable.getPressureValue(xIdx));
304 for (std::size_t yIdx = 0; yIdx < rockwnodTable.getSaturationColumn().size(); ++yIdx)
305 rockCompTransMultWc_[regionIdx].appendSamplePoint(xIdx,
306 rockwnodTable.getSaturationColumn()[yIdx],
307 rock2dtrTable.getTransMultValue(xIdx, yIdx));
314template<
class Gr
idView,
class Flu
idSystem>
315typename FlowGenericProblem<GridView,FluidSystem>::Scalar
319 if (this->rockParams_.empty())
322 unsigned tableIdx = 0;
323 if (!this->rockTableIdx_.empty()) {
324 tableIdx = this->rockTableIdx_[globalSpaceIdx];
326 return this->rockParams_[tableIdx].compressibility;
329template<
class Gr
idView,
class Flu
idSystem>
330typename FlowGenericProblem<GridView,FluidSystem>::Scalar
332porosity(
unsigned globalSpaceIdx,
unsigned timeIdx)
const
334 return this->referencePorosity_[timeIdx][globalSpaceIdx];
337template<
class Gr
idView,
class Flu
idSystem>
338typename FlowGenericProblem<GridView,FluidSystem>::Scalar
340rockFraction(
unsigned elementIdx,
unsigned timeIdx)
const
350 const auto ntg = this->lookUpData_.fieldPropDouble(eclState_.fieldProps(),
"NTG", elementIdx);
351 const auto poro_eff = ntg * this->lookUpData_.fieldPropDouble(eclState_.fieldProps(),
"PORO", elementIdx);
352 return (1 - poro_eff) * referencePorosity(elementIdx, timeIdx) / poro_eff;
355template<
class Gr
idView,
class Flu
idSystem>
358updateNum(
const std::string& name, std::vector<T>& numbers, std::size_t num_regions)
360 if (!eclState_.fieldProps().has_int(name))
363 std::function<void(T,
int)> valueCheck = [num_regions,name](T fieldPropValue, [[maybe_unused]]
int fieldPropIdx) {
364 if ( fieldPropValue > (
int)num_regions) {
365 throw std::runtime_error(
"Values larger than maximum number of regions "
366 + std::to_string(num_regions) +
" provided in " + name);
368 if ( fieldPropValue <= 0) {
369 throw std::runtime_error(
"zero or negative values provided for region array: " + name);
373 numbers = this->lookUpData_.template assignFieldPropsIntOnLeaf<T>(eclState_.fieldProps(), name,
377template<
class Gr
idView,
class Flu
idSystem>
378void FlowGenericProblem<GridView,FluidSystem>::
381 const auto num_regions = eclState_.getTableManager().getTabdims().getNumPVTTables();
382 updateNum(
"PVTNUM", pvtnum_, num_regions);
385template<
class Gr
idView,
class Flu
idSystem>
386void FlowGenericProblem<GridView,FluidSystem>::
389 const auto num_regions = eclState_.getTableManager().getTabdims().getNumSatTables();
390 updateNum(
"SATNUM", satnum_, num_regions);
393template<
class Gr
idView,
class Flu
idSystem>
394void FlowGenericProblem<GridView,FluidSystem>::
397 const auto num_regions = 1;
398 updateNum(
"MISCNUM", miscnum_, num_regions);
401template<
class Gr
idView,
class Flu
idSystem>
402void FlowGenericProblem<GridView,FluidSystem>::
405 const auto num_regions = 1;
406 updateNum(
"PLMIXNUM", plmixnum_, num_regions);
409template<
class Gr
idView,
class Flu
idSystem>
410bool FlowGenericProblem<GridView,FluidSystem>::
411vapparsActive(
int episodeIdx)
const
413 const auto& oilVaporizationControl = schedule_[episodeIdx].oilvap();
414 return (oilVaporizationControl.getType() == OilVaporizationProperties::OilVaporization::VAPPARS);
417template<
class Gr
idView,
class Flu
idSystem>
418bool FlowGenericProblem<GridView,FluidSystem>::
419beginEpisode_(
bool enableExperiments,
422 if (enableExperiments && gridView_.comm().rank() == 0 && episodeIdx >= 0) {
425 std::ostringstream ss;
426 boost::posix_time::time_facet* facet =
new boost::posix_time::time_facet(
"%d-%b-%Y");
427 boost::posix_time::ptime curDateTime =
428 boost::posix_time::from_time_t(schedule_.simTime(episodeIdx));
429 ss.imbue(std::locale(std::locale::classic(), facet));
430 ss <<
"Report step " << episodeIdx + 1
431 <<
"/" << schedule_.size() - 1
432 <<
" at day " << schedule_.seconds(episodeIdx)/(24*3600)
433 <<
"/" << schedule_.seconds(schedule_.size() - 1)/(24*3600)
434 <<
", date = " << curDateTime.date()
436 OpmLog::info(ss.str());
439 const auto& events = schedule_[episodeIdx].events();
442 if (episodeIdx > 0 && enableTuning_ && events.hasEvent(ScheduleEvents::TUNING_CHANGE))
444 const auto& sched_state = schedule_[episodeIdx];
445 const auto& tuning = sched_state.tuning();
446 initialTimeStepSize_ = sched_state.max_next_tstep(enableTuning_);
447 maxTimeStepAfterWellEvent_ = tuning.TMAXWC;
454template<
class Gr
idView,
class Flu
idSystem>
455void FlowGenericProblem<GridView,FluidSystem>::
456beginTimeStep_(
bool enableExperiments,
464 if (enableExperiments && gridView_.comm().rank() == 0 && episodeIdx >= 0) {
465 std::ostringstream ss;
466 boost::posix_time::time_facet* facet =
new boost::posix_time::time_facet(
"%d-%b-%Y");
467 boost::posix_time::ptime date = boost::posix_time::from_time_t(startTime) + boost::posix_time::milliseconds(
static_cast<long long>(time / prefix::milli));
468 ss.imbue(std::locale(std::locale::classic(), facet));
469 ss <<
"\nTime step " << timeStepIndex <<
", stepsize "
470 << unit::convert::to(timeStepSize, unit::day) <<
" days,"
471 <<
" at day " << (double)unit::convert::to(time, unit::day)
472 <<
"/" << (double)unit::convert::to(endTime, unit::day)
473 <<
", date = " << date;
474 OpmLog::info(ss.str());
478template<
class Gr
idView,
class Flu
idSystem>
479void FlowGenericProblem<GridView,FluidSystem>::
482 FluidSystem::initFromState(eclState_, schedule_);
485template<
class Gr
idView,
class Flu
idSystem>
486void FlowGenericProblem<GridView,FluidSystem>::
487readBlackoilExtentionsInitialConditions_(std::size_t numDof,
490 bool enablePolymerMolarWeight,
491 bool enableBioeffects,
494 auto getArray = [](
const std::vector<double>& input)
496 if constexpr (std::is_same_v<Scalar,double>) {
499 return std::vector<Scalar>{input.begin(), input.end()};
504 if (eclState_.fieldProps().has_double(
"SSOL")) {
505 solventSaturation_ = getArray(eclState_.fieldProps().get_double(
"SSOL"));
507 solventSaturation_.resize(numDof, 0.0);
510 solventRsw_.resize(numDof, 0.0);
514 if (eclState_.fieldProps().has_double(
"SPOLY")) {
515 polymer_.concentration = getArray(eclState_.fieldProps().get_double(
"SPOLY"));
517 polymer_.concentration.resize(numDof, 0.0);
521 if (enablePolymerMolarWeight) {
522 if (eclState_.fieldProps().has_double(
"SPOLYMW")) {
523 polymer_.moleWeight = getArray(eclState_.fieldProps().get_double(
"SPOLYMW"));
525 polymer_.moleWeight.resize(numDof, 0.0);
529 if (enableBioeffects) {
530 if (eclState_.fieldProps().has_double(
"SMICR")) {
531 bioeffects_.microbialConcentration = getArray(eclState_.fieldProps().get_double(
"SMICR"));
533 bioeffects_.microbialConcentration.resize(numDof, 0.0);
535 if (eclState_.fieldProps().has_double(
"SBIOF")) {
536 bioeffects_.biofilmVolumeFraction = getArray(eclState_.fieldProps().get_double(
"SBIOF"));
538 bioeffects_.biofilmVolumeFraction.resize(numDof, 0.0);
541 if (eclState_.fieldProps().has_double(
"SOXYG")) {
542 bioeffects_.oxygenConcentration = getArray(eclState_.fieldProps().get_double(
"SOXYG"));
544 bioeffects_.oxygenConcentration.resize(numDof, 0.0);
546 if (eclState_.fieldProps().has_double(
"SUREA")) {
547 bioeffects_.ureaConcentration = getArray(eclState_.fieldProps().get_double(
"SUREA"));
549 bioeffects_.ureaConcentration.resize(numDof, 0.0);
551 if (eclState_.fieldProps().has_double(
"SCALC")) {
552 bioeffects_.calciteVolumeFraction = getArray(eclState_.fieldProps().get_double(
"SCALC"));
554 bioeffects_.calciteVolumeFraction.resize(numDof, 0.0);
560template<
class Gr
idView,
class Flu
idSystem>
561typename FlowGenericProblem<GridView,FluidSystem>::Scalar
565 if (maxWaterSaturation_.empty())
568 return maxWaterSaturation_[globalDofIdx];
571template<
class Gr
idView,
class Flu
idSystem>
572typename FlowGenericProblem<GridView,FluidSystem>::Scalar
576 if (minRefPressure_.empty())
579 return minRefPressure_[globalDofIdx];
582template<
class Gr
idView,
class Flu
idSystem>
583typename FlowGenericProblem<GridView,FluidSystem>::Scalar
587 if (overburdenPressure_.empty())
590 return overburdenPressure_[elementIdx];
593template<
class Gr
idView,
class Flu
idSystem>
594typename FlowGenericProblem<GridView,FluidSystem>::Scalar
598 if (solventSaturation_.empty())
601 return solventSaturation_[elemIdx];
604template<
class Gr
idView,
class Flu
idSystem>
605typename FlowGenericProblem<GridView,FluidSystem>::Scalar
609 if (solventRsw_.empty())
612 return solventRsw_[elemIdx];
617template<
class Gr
idView,
class Flu
idSystem>
618typename FlowGenericProblem<GridView,FluidSystem>::Scalar
622 if (polymer_.concentration.empty()) {
626 return polymer_.concentration[elemIdx];
629template<
class Gr
idView,
class Flu
idSystem>
630typename FlowGenericProblem<GridView,FluidSystem>::Scalar
634 if (polymer_.moleWeight.empty()) {
638 return polymer_.moleWeight[elemIdx];
641template<
class Gr
idView,
class Flu
idSystem>
642typename FlowGenericProblem<GridView,FluidSystem>::Scalar
646 if (bioeffects_.microbialConcentration.empty()) {
653template<
class Gr
idView,
class Flu
idSystem>
654typename FlowGenericProblem<GridView,FluidSystem>::Scalar
658 if (bioeffects_.oxygenConcentration.empty()) {
665template<
class Gr
idView,
class Flu
idSystem>
666typename FlowGenericProblem<GridView,FluidSystem>::Scalar
670 if (bioeffects_.ureaConcentration.empty()) {
677template<
class Gr
idView,
class Flu
idSystem>
678typename FlowGenericProblem<GridView,FluidSystem>::Scalar
682 if (bioeffects_.biofilmVolumeFraction.empty()) {
689template<
class Gr
idView,
class Flu
idSystem>
690typename FlowGenericProblem<GridView,FluidSystem>::Scalar
694 if (bioeffects_.calciteVolumeFraction.empty()) {
701template<
class Gr
idView,
class Flu
idSystem>
708 return pvtnum_[elemIdx];
711template<
class Gr
idView,
class Flu
idSystem>
718 return satnum_[elemIdx];
721template<
class Gr
idView,
class Flu
idSystem>
725 if (miscnum_.empty())
728 return miscnum_[elemIdx];
731template<
class Gr
idView,
class Flu
idSystem>
735 if (plmixnum_.empty())
738 return plmixnum_[elemIdx];
741template<
class Gr
idView,
class Flu
idSystem>
742typename FlowGenericProblem<GridView,FluidSystem>::Scalar
746 if (polymer_.maxAdsorption.empty()) {
750 return polymer_.maxAdsorption[elemIdx];
753template<
class Gr
idView,
class Flu
idSystem>
757 return this->maxWaterSaturation_ == rhs.maxWaterSaturation_ &&
758 this->minRefPressure_ == rhs.minRefPressure_ &&
759 this->overburdenPressure_ == rhs.overburdenPressure_ &&
760 this->solventSaturation_ == rhs.solventSaturation_ &&
761 this->solventRsw_ == rhs.solventRsw_ &&
762 this->polymer_ == rhs.polymer_ &&
763 this->bioeffects_ == rhs.bioeffects_;