30 #ifndef OPM_FLOW_PROBLEM_COMP_HPP 31 #define OPM_FLOW_PROBLEM_COMP_HPP 38 #include <opm/material/fluidstates/CompositionalFluidState.hpp> 40 #include <opm/material/thermal/EclThermalLawManager.hpp> 42 #include <opm/input/eclipse/EclipseState/Compositional/CompositionalConfig.hpp> 58 template <
class TypeTag>
64 using typename FlowProblemType::Scalar;
65 using typename FlowProblemType::Simulator;
66 using typename FlowProblemType::GridView;
67 using typename FlowProblemType::FluidSystem;
68 using typename FlowProblemType::Vanguard;
71 using FlowProblemType::dim;
72 using FlowProblemType::dimWorld;
74 using FlowProblemType::numPhases;
75 using FlowProblemType::numComponents;
77 using FlowProblemType::gasPhaseIdx;
78 using FlowProblemType::oilPhaseIdx;
79 using FlowProblemType::waterPhaseIdx;
81 using typename FlowProblemType::Indices;
82 using typename FlowProblemType::PrimaryVariables;
84 using typename FlowProblemType::Evaluation;
85 using typename FlowProblemType::MaterialLaw;
86 using typename FlowProblemType::RateVector;
88 using InitialFluidState = CompositionalFluidState<Scalar, FluidSystem>;
102 EclWriterType::registerParameters();
105 Parameters::SetDefault<Parameters::NewtonTolerance<Scalar>>(1e-7);
108 Opm::CompositionalConfig::EOSType getEosType()
const 110 auto& simulator = this->simulator();
111 const auto& eclState = simulator.vanguard().eclState();
112 return eclState.compositionalConfig().eosType(0);
120 , thresholdPressures_(simulator)
122 eclWriter_ = std::make_unique<EclWriterType>(simulator);
123 enableEclOutput_ = Parameters::Get<Parameters::EnableEclOutput>();
134 FlowProblemType::finishInit();
136 auto& simulator = this->simulator();
138 auto finishTransmissibilities = [updated =
false,
this]()
mutable {
142 this->transmissibilities_.finishInit(
143 [&vg = this->simulator().vanguard()](
const unsigned int it) {
return vg.gridIdxToEquilGridIdx(it); });
148 finishTransmissibilities();
150 if (enableEclOutput_) {
151 eclWriter_->setTransmissibilities(&simulator.problem().eclTransmissibilities());
152 std::function<unsigned int(unsigned int)> equilGridToGrid = [&simulator](
unsigned int i) {
153 return simulator.vanguard().gridEquilIdxToGridIdx(i);
155 eclWriter_->extractOutputTransAndNNC(equilGridToGrid);
158 const auto& eclState = simulator.vanguard().eclState();
159 const auto& schedule = simulator.vanguard().schedule();
162 simulator.setStartTime(schedule.getStartTime());
163 simulator.setEndTime(schedule.simTime(schedule.size() - 1));
169 simulator.setEpisodeIndex(-1);
170 simulator.setEpisodeLength(0.0);
175 this->gravity_ = 0.0;
176 if (Parameters::Get<Parameters::EnableGravity>())
177 this->gravity_[dim - 1] = 9.80665;
178 if (!eclState.getInitConfig().hasGravity())
179 this->gravity_[dim - 1] = 0.0;
181 if (this->enableTuning_) {
184 const auto& tuning = schedule[0].tuning();
185 this->initialTimeStepSize_ = tuning.TSINIT.has_value() ? tuning.TSINIT.value() : -1.0;
186 this->maxTimeStepAfterWellEvent_ = tuning.TMAXWC;
189 this->initFluidSystem_();
191 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)
192 && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
193 this->maxOilSaturation_.resize(this->model().numGridDof(), 0.0);
196 this->readRockParameters_(simulator.vanguard().cellCenterDepths(), [&simulator](
const unsigned idx) {
197 std::array<int, dim> coords;
198 simulator.vanguard().cartesianCoordinate(idx, coords);
199 std::ranges::transform(coords, coords.begin(),
200 [](
const auto c) {
return c + 1; });
203 FlowProblemType::readMaterialParameters_();
204 FlowProblemType::readThermalParameters_();
207 if (enableEclOutput_) {
208 eclWriter_->writeInit();
211 const auto& initconfig = eclState.getInitConfig();
212 if (initconfig.restartRequested())
213 readEclRestartSolution_();
215 this->readInitialCondition_();
217 FlowProblemType::updatePffDofData_();
219 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>()) {
220 const auto& vanguard = this->simulator().vanguard();
221 const auto& gridView = vanguard.gridView();
222 int numElements = gridView.size(0);
223 this->polymer_.maxAdsorption.resize(numElements, 0.0);
237 if (this->enableVtkOutput_() && eclState.getIOConfig().initOnly()) {
238 simulator.setTimeStepSize(0.0);
245 if (!initconfig.restartRequested()) {
246 simulator.startNextEpisode(schedule.seconds(1));
247 simulator.setEpisodeIndex(0);
248 simulator.setTimeStepIndex(0);
260 this->eclWriter_->mutableOutputModule().invalidateLocalData();
263 const auto& grid = this->simulator().vanguard().gridView().grid();
265 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
266 constexpr
bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
267 if (!isCpGrid || (grid.maxLevel() == 0)) {
273 if (enableEclOutput_){
274 eclWriter_->writeReports(timer);
286 if (! this->enableEclOutput_) {
292 if (!isSubStep || Parameters::Get<Parameters::EnableWriteAllSolutions>()) {
293 auto localCellData = data::Solution {};
295 this->eclWriter_->writeOutput(std::move(localCellData), isSubStep,
296 this->simulator().vanguard().schedule()
297 .exitStatus().has_value());
306 template <
class Context>
308 const Context& context,
312 OPM_TIMEBLOCK_LOCAL(eclProblemBoundary, Subsystem::Assembly);
313 if (!context.intersection(spaceIdx).boundary())
318 if (this->nonTrivialBoundaryConditions()) {
319 throw std::logic_error(
"boundary condition is not supported by compostional modeling yet");
329 template <
class Context>
330 void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx)
const 332 const unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
333 const auto& initial_fs = initialFluidStates_[globalDofIdx];
334 Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
335 for (
unsigned p = 0; p < numPhases; ++p) {
337 fs.setPressure(p, initial_fs.pressure(p));
340 fs.setSaturation(p, initial_fs.saturation(p));
343 fs.setTemperature(initial_fs.temperature(p));
347 if (!zmf_initialization_) {
348 for (
unsigned p = 0; p < numPhases; ++p) {
349 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
350 fs.setMoleFraction(p, compIdx, initial_fs.moleFraction(p, compIdx));
355 const auto& eos_type = getEosType();
356 typename FluidSystem::template ParameterCache<Scalar> paramCache(eos_type);
357 paramCache.updatePhase(fs, FluidSystem::oilPhaseIdx);
358 paramCache.updatePhase(fs, FluidSystem::gasPhaseIdx);
359 fs.setDensity(FluidSystem::oilPhaseIdx, FluidSystem::density(fs, paramCache, FluidSystem::oilPhaseIdx));
360 fs.setDensity(FluidSystem::gasPhaseIdx, FluidSystem::density(fs, paramCache, FluidSystem::gasPhaseIdx));
363 Dune::FieldVector<Scalar, numComponents> z(0.0);
364 Scalar sumMoles = 0.0;
365 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
366 if (Indices::waterEnabled && phaseIdx == static_cast<unsigned int>(waterPhaseIdx)){
369 const auto saturation = fs.saturation(phaseIdx);
370 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
371 Scalar tmp = fs.molarity(phaseIdx, compIdx) * saturation;
372 tmp = max(tmp, 1e-8);
378 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
379 fs.setMoleFraction(compIdx, z[compIdx]);
383 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
384 fs.setMoleFraction(compIdx, initial_fs.moleFraction(compIdx));
389 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
390 const auto& Ktmp = fs.wilsonK_(compIdx);
391 fs.setKvalue(compIdx, Ktmp);
394 const Scalar& Ltmp = -1.0;
397 values.assignNaive(fs);
400 void addToSourceDense(RateVector&,
unsigned,
unsigned)
const override 405 const InitialFluidState& initialFluidState(
unsigned globalDofIdx)
const 406 {
return initialFluidStates_[globalDofIdx]; }
408 std::vector<InitialFluidState>& initialFluidStates()
409 {
return initialFluidStates_; }
411 const std::vector<InitialFluidState>& initialFluidStates()
const 412 {
return initialFluidStates_; }
414 const FlowThresholdPressure<TypeTag>& thresholdPressure()
const 416 assert( !thresholdPressures_.enableThresholdPressure() &&
417 " Threshold Pressures are not supported by compostional simulation ");
418 return thresholdPressures_;
421 const EclWriterType& eclWriter()
const 422 {
return *eclWriter_; }
424 EclWriterType& eclWriter()
425 {
return *eclWriter_; }
427 void setSubStepReport(
const SimulatorReportSingle& report)
428 {
return eclWriter_->setSubStepReport(report); }
430 void setSimulationReport(
const SimulatorReport& report)
431 {
return eclWriter_->setSimulationReport(report); }
433 void finalizeOutput()
435 OPM_TIMEBLOCK(finalizeOutput);
440 template<
class Serializer>
441 void serializeOp(Serializer& serializer)
443 serializer(static_cast<FlowProblemType&>(*
this));
444 serializer(*eclWriter_);
448 void updateExplicitQuantities_(
int ,
int ,
bool )
override 453 void readEquilInitialCondition_()
override 455 throw std::logic_error(
"Equilibration is not supported by compositional modeling yet");
458 void readEclRestartSolution_()
460 throw std::logic_error(
"Restarting is not supported by compositional modeling yet");
463 void readExplicitInitialCondition_()
override 465 readExplicitInitialConditionCompositional_();
468 void readExplicitInitialConditionCompositional_()
470 const auto& simulator = this->simulator();
471 const auto& vanguard = simulator.vanguard();
472 const auto& eclState = vanguard.eclState();
473 const auto& fp = eclState.fieldProps();
474 const bool has_pressure = fp.has_double(
"PRESSURE");
476 throw std::runtime_error(
"The ECL input file requires the presence of the PRESSURE " 477 "keyword if the model is initialized explicitly");
479 const bool has_xmf = fp.has_double(
"XMF");
480 const bool has_ymf = fp.has_double(
"YMF");
481 const bool has_zmf = fp.has_double(
"ZMF");
482 if ( !has_zmf && !(has_xmf && has_ymf) ) {
483 throw std::runtime_error(
"The ECL input file requires the presence of ZMF or XMF and YMF " 484 "keyword if the model is initialized explicitly");
487 if (has_zmf && (has_xmf || has_ymf)) {
488 throw std::runtime_error(
"The ECL input file can not handle explicit initialization " 489 "with both ZMF and XMF or YMF");
492 if (has_xmf != has_ymf) {
493 throw std::runtime_error(
"The ECL input file needs XMF and YMF combined to do the explicit " 494 "initializtion when using XMF or YMF");
497 const bool has_temp = fp.has_double(
"TEMPI");
500 assert(fp.has_double(
"SGAS"));
502 std::size_t numDof = this->model().numGridDof();
504 initialFluidStates_.resize(numDof);
506 std::vector<double> waterSaturationData;
507 std::vector<double> gasSaturationData;
508 std::vector<double> soilData;
509 std::vector<double> pressureData;
510 std::vector<double> tempiData;
512 const bool water_active = FluidSystem::phaseIsActive(waterPhaseIdx);
513 const bool gas_active = FluidSystem::phaseIsActive(gasPhaseIdx);
514 const bool oil_active = FluidSystem::phaseIsActive(oilPhaseIdx);
516 if (water_active && Indices::numPhases > 2)
517 waterSaturationData = fp.get_double(
"SWAT");
519 waterSaturationData.resize(numDof);
521 pressureData = fp.get_double(
"PRESSURE");
524 tempiData = fp.get_double(
"TEMPI");
530 gasSaturationData = fp.get_double(
"SGAS");
532 gasSaturationData.resize(numDof);
534 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
535 auto& dofFluidState = initialFluidStates_[dofIdx];
538 Scalar temperatureLoc = tempiData[dofIdx];
539 assert(std::isfinite(temperatureLoc) && temperatureLoc > 0);
540 dofFluidState.setTemperature(temperatureLoc);
543 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
544 gasSaturationData[dofIdx]);
547 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx,
549 - waterSaturationData[dofIdx]
550 - gasSaturationData[dofIdx]);
553 dofFluidState.setSaturation(FluidSystem::waterPhaseIdx,
554 waterSaturationData[dofIdx]);
560 const Scalar pressure = pressureData[dofIdx];
563 const std::array<Scalar, numPhases> pc = {0};
564 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
565 if (!FluidSystem::phaseIsActive(phaseIdx))
568 if (Indices::oilEnabled)
569 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
570 else if (Indices::gasEnabled)
571 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
572 else if (Indices::waterEnabled)
574 dofFluidState.setPressure(phaseIdx, pressure);
577 if (has_xmf && has_ymf) {
578 const auto& xmfData = fp.get_double(
"XMF");
579 const auto& ymfData = fp.get_double(
"YMF");
580 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
581 const std::size_t data_idx = compIdx * numDof + dofIdx;
582 const Scalar xmf = xmfData[data_idx];
583 const Scalar ymf = ymfData[data_idx];
585 dofFluidState.setMoleFraction(FluidSystem::oilPhaseIdx, compIdx, xmf);
586 dofFluidState.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, ymf);
591 zmf_initialization_ =
true;
592 const auto& zmfData = fp.get_double(
"ZMF");
593 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
594 const std::size_t data_idx = compIdx * numDof + dofIdx;
595 const Scalar zmf = zmfData[data_idx];
596 dofFluidState.setMoleFraction(compIdx, zmf);
599 const auto ymf = (dofFluidState.saturation(FluidSystem::gasPhaseIdx) > 0.) ? zmf : Scalar{0};
600 dofFluidState.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, ymf);
603 const auto xmf = (dofFluidState.saturation(FluidSystem::oilPhaseIdx) > 0.) ? zmf : Scalar{0};
604 dofFluidState.setMoleFraction(FluidSystem::oilPhaseIdx, compIdx, xmf);
613 void handleSolventBC(
const BCProp::BCFace& , RateVector& )
const override 615 throw std::logic_error(
"solvent is disabled for compositional modeling and you're trying to add solvent to BC");
618 void handlePolymerBC(
const BCProp::BCFace& , RateVector& )
const override 620 throw std::logic_error(
"polymer is disabled for compositional modeling and you're trying to add polymer to BC");
623 void handleMicrBC(
const BCProp::BCFace& , RateVector& )
const override 625 throw std::logic_error(
"MICP is disabled for compositional modeling and you're trying to add microbes to BC");
628 void handleOxygBC(
const BCProp::BCFace& , RateVector& )
const override 630 throw std::logic_error(
"MICP is disabled for compositional modeling and you're trying to add oxygen to BC");
633 void handleUreaBC(
const BCProp::BCFace& , RateVector& )
const override 635 throw std::logic_error(
"MICP is disabled for compositional modeling and you're trying to add urea to BC");
638 FlowThresholdPressure<TypeTag> thresholdPressures_;
640 std::vector<InitialFluidState> initialFluidStates_;
642 bool zmf_initialization_ {
false};
644 bool enableEclOutput_{
false};
645 std::unique_ptr<EclWriterType> eclWriter_;
650 #endif // OPM_FLOW_PROBLEM_COMP_HPP This class calculates the threshold pressure for grid faces according to the Eclipse Reference Manual...
Output module for the results black oil model writing in ECL binary format.
void finishInit()
Called by the Opm::Simulator in order to initialize the problem.
Definition: FlowProblemComp.hpp:129
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(...))
Definition: propertysystem.hh:233
void endTimeStep() override
Called by the simulator after each time integration.
Definition: FlowProblemComp.hpp:255
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblem.hpp:92
unsigned pvtRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:901
virtual bool episodeWillBeOver() const
Whether or not the current episode will end at the end of the current time step.
Definition: FlowProblem.hpp:1886
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblemComp.hpp:59
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
void boundary(BoundaryRateVector &values, const Context &context, unsigned spaceIdx, unsigned) const
Evaluate the boundary conditions for a boundary segment.
Definition: FlowProblemComp.hpp:307
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:701
void initial(PrimaryVariables &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the initial value for a control volume.
Definition: FlowProblemComp.hpp:330
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblemComp.hpp:98
Collects necessary output values and pass it to opm-common's ECL output.
Definition: EclWriter.hpp:114
void writeOutput(bool verbose) override
Write the requested quantities of the current solution into the output files.
Definition: FlowProblemComp.hpp:282
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
virtual void endTimeStep()
Called by the simulator after each time integration.
Definition: FlowProblem.hpp:438
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblem.hpp:186
FlowProblemComp(Simulator &simulator)
Definition: FlowProblemComp.hpp:118
virtual void writeOutput(bool verbose)
Write the requested quantities of the current solution into the output files.
Definition: FlowProblem.hpp:518
Definition: SimulatorTimer.hpp:38