My Project
BlackoilAquiferModel_impl.hpp
1/*
2 Copyright 2017 TNO - Heat Transfer & Fluid Dynamics, Modelling & Optimization of the Subsurface
3 Copyright 2017 Statoil ASA.
4
5 This file is part of the Open Porous Media project (OPM).
6
7 OPM is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 OPM is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with OPM. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <opm/simulators/aquifers/AquiferConstantFlux.hpp>
22
23#include <opm/common/ErrorMacros.hpp>
24
25#include <algorithm>
26#include <memory>
27#include <stdexcept>
28#include <string_view>
29
30namespace Opm
31{
32
33template <typename TypeTag>
34BlackoilAquiferModel<TypeTag>::BlackoilAquiferModel(Simulator& simulator)
35 : simulator_(simulator)
36{
37 // Grid needs to support Facetag
38 using Grid = std::remove_const_t<std::remove_reference_t<decltype(simulator.vanguard().grid())>>;
39 static_assert(SupportsFaceTag<Grid>::value, "Grid has to support assumptions about face tag.");
40
41 init();
42}
43
44template <typename TypeTag>
45void
46BlackoilAquiferModel<TypeTag>::initialSolutionApplied()
47{
48 for (auto& aquifer : aquifers)
49 aquifer->initialSolutionApplied();
50}
51
52template <typename TypeTag>
53void
54BlackoilAquiferModel<TypeTag>::initFromRestart(const data::Aquifers& aquiferSoln)
55{
56 for (auto& aquifer : this->aquifers)
57 aquifer->initFromRestart(aquiferSoln);
58}
59
60template <typename TypeTag>
61void
62BlackoilAquiferModel<TypeTag>::beginEpisode()
63{
64 // Probably function name beginReportStep() is more appropriate.
65 //
66 // Basically, we want to update the aquifer related information from
67 // SCHEDULE setup in this section it is the beginning of a report step
68
69 this->createDynamicAquifers(this->simulator_.episodeIndex());
70}
71
72template <typename TypeTag>
73void
74BlackoilAquiferModel<TypeTag>::beginIteration()
75{}
76
77template <typename TypeTag>
78void
79BlackoilAquiferModel<TypeTag>::beginTimeStep()
80{
81 for (auto& aquifer : aquifers)
82 aquifer->beginTimeStep();
83}
84
85template <typename TypeTag>
86template <class Context>
87void
88BlackoilAquiferModel<TypeTag>::addToSource(RateVector& rates,
89 const Context& context,
90 unsigned spaceIdx,
91 unsigned timeIdx) const
92{
93 for (auto& aquifer : aquifers)
94 aquifer->addToSource(rates, context, spaceIdx, timeIdx);
95}
96
97template <typename TypeTag>
98void
99BlackoilAquiferModel<TypeTag>::addToSource(RateVector& rates,
100 unsigned globalSpaceIdx,
101 unsigned timeIdx) const
102{
103 for (auto& aquifer : aquifers)
104 aquifer->addToSource(rates, globalSpaceIdx, timeIdx);
105}
106
107template <typename TypeTag>
108void
109BlackoilAquiferModel<TypeTag>::endIteration()
110{}
111
112template <typename TypeTag>
113void
114BlackoilAquiferModel<TypeTag>::endTimeStep()
115{
116 for (auto& aquifer : aquifers) {
117 aquifer->endTimeStep();
118 using NumAq = AquiferNumerical<TypeTag>;
119 NumAq* num = dynamic_cast<NumAq*>(aquifer.get());
120 if (num)
121 this->simulator_.vanguard().grid().comm().barrier();
122 }
123}
124
125template <typename TypeTag>
126void
127BlackoilAquiferModel<TypeTag>::endEpisode()
128{}
129
130template <typename TypeTag>
131template <class Restarter>
132void
133BlackoilAquiferModel<TypeTag>::serialize(Restarter& /* res */)
134{
135 // TODO (?)
136 throw std::logic_error("BlackoilAquiferModel::serialize() is not yet implemented");
137}
138
139template <typename TypeTag>
140template <class Restarter>
141void
142BlackoilAquiferModel<TypeTag>::deserialize(Restarter& /* res */)
143{
144 // TODO (?)
145 throw std::logic_error("BlackoilAquiferModel::deserialize() is not yet implemented");
146}
147
148// Initialize the aquifers in the deck
149template <typename TypeTag>
150void BlackoilAquiferModel<TypeTag>::init()
151{
152 if (this->simulator_.vanguard().eclState().aquifer().active()) {
153 this->initializeStaticAquifers();
154 }
155
156}
157
158template<typename TypeTag>
159data::Aquifers BlackoilAquiferModel<TypeTag>::aquiferData() const
160{
161 data::Aquifers data;
162 for (const auto& aqu : this->aquifers)
163 data.insert_or_assign(aqu->aquiferID(), aqu->aquiferData());
164
165 return data;
166}
167
168template<typename TypeTag>
169template<class Serializer>
170void BlackoilAquiferModel<TypeTag>::
171serializeOp(Serializer& serializer)
172{
173 for (auto& aiPtr : aquifers) {
174 auto* ct = dynamic_cast<AquiferCarterTracy<TypeTag>*>(aiPtr.get());
175 auto* fetp = dynamic_cast<AquiferFetkovich<TypeTag>*>(aiPtr.get());
176 auto* num = dynamic_cast<AquiferNumerical<TypeTag>*>(aiPtr.get());
177 auto* flux = dynamic_cast<AquiferConstantFlux<TypeTag>*>(aiPtr.get());
178 if (ct) {
179 serializer(*ct);
180 } else if (fetp) {
181 serializer(*fetp);
182 } else if (num) {
183 serializer(*num);
184 } else if (flux) {
185 serializer(*flux);
186 } else {
187 OPM_THROW(std::logic_error, "Error serializing BlackoilAquiferModel: unknown aquifer type");
188 }
189 }
190}
191
192template <typename TypeTag>
193void BlackoilAquiferModel<TypeTag>::initializeStaticAquifers()
194{
195 const auto& aquifer =
196 this->simulator_.vanguard().eclState().aquifer();
197
198 for (const auto& aquCT : aquifer.ct()) {
199 auto aquCTPtr = this->template createAnalyticAquiferPointer
200 <AquiferCarterTracy<TypeTag>>(aquCT, aquCT.aquiferID, "Carter-Tracy");
201
202 if (aquCTPtr != nullptr) {
203 this->aquifers.push_back(std::move(aquCTPtr));
204 }
205 }
206
207 for (const auto& aquFetp : aquifer.fetp()) {
208 auto aquFetpPtr = this->template createAnalyticAquiferPointer
209 <AquiferFetkovich<TypeTag>>(aquFetp, aquFetp.aquiferID, "Fetkovich");
210
211 if (aquFetpPtr != nullptr) {
212 this->aquifers.push_back(std::move(aquFetpPtr));
213 }
214 }
215
216 for (const auto& [id, aquFlux] : aquifer.aquflux()) {
217 // Make sure not dummy constant flux aquifers
218 if (! aquFlux.active) { continue; }
219
220 auto aquFluxPtr = this->template createAnalyticAquiferPointer
221 <AquiferConstantFlux<TypeTag>>(aquFlux, id, "Constant Flux");
222
223 if (aquFluxPtr != nullptr) {
224 this->aquifers.push_back(std::move(aquFluxPtr));
225 }
226 }
227
228 if (aquifer.hasNumericalAquifer()) {
229 for (const auto& aquNum : aquifer.numericalAquifers().aquifers()) {
230 auto aquNumPtr = std::make_unique<AquiferNumerical<TypeTag>>
231 (aquNum.second, this->simulator_);
232
233 this->aquifers.push_back(std::move(aquNumPtr));
234 }
235 }
236}
237
238template <typename TypeTag>
239template <typename AquiferType, typename AquiferData>
240std::unique_ptr<AquiferType>
241BlackoilAquiferModel<TypeTag>::
242createAnalyticAquiferPointer(const AquiferData& aqData,
243 const int aquiferID,
244 std::string_view aqType) const
245{
246 const auto& connections =
247 this->simulator_.vanguard().eclState().aquifer().connections();
248
249 if (! connections.hasAquiferConnections(aquiferID)) {
250 const auto msg = fmt::format("No valid connections for {} aquifer {}. "
251 "Aquifer {} will be ignored.",
252 aqType, aquiferID, aquiferID);
253 OpmLog::warning(msg);
254
255 return {};
256 }
257
258 return std::make_unique<AquiferType>
259 (connections.getConnections(aquiferID), this->simulator_, aqData);
260}
261
262template <typename TypeTag>
263void BlackoilAquiferModel<TypeTag>::createDynamicAquifers(const int episode_index)
264{
265 const auto& sched = this->simulator_.vanguard().schedule()[episode_index];
266
267 for (const auto& [id, aquFlux] : sched.aqufluxs) {
268 auto aquPos =
269 std::find_if(std::begin(this->aquifers),
270 std::end(this->aquifers),
271 [id = id](const auto& aquPtr)
272 {
273 return aquPtr->aquiferID() == id;
274 });
275
276 if (aquPos == std::end(this->aquifers)) {
277 // An aquifer with this 'id' does not yet exist in
278 // the collection managed by this object. Create it.
279 auto aquFluxPtr = this->template createAnalyticAquiferPointer
280 <AquiferConstantFlux<TypeTag>>(aquFlux, id, "Constant Flux");
281
282 if (aquFluxPtr != nullptr) {
283 this->aquifers.push_back(std::move(aquFluxPtr));
284 }
285 }
286 else {
287 auto aquFluxPtr = dynamic_cast<AquiferConstantFlux<TypeTag>*>(aquPos->get());
288 if (aquFluxPtr == nullptr) {
289 // If the aquifers can return types easily, we might be able
290 // to give a better message with type information.
291 const auto msg =
292 fmt::format("Aquifer {} is updated with constant flux "
293 "aquifer keyword AQUFLUX at report step {}, "
294 "while it might be specified to be a "
295 "different type of aquifer before this. "
296 "We do not support the conversion between "
297 "different types of aquifer.\n", id, episode_index);
298
299 OPM_THROW(std::runtime_error, msg);
300 }
301
302 aquFluxPtr->updateAquifer(aquFlux);
303 }
304 }
305}
306
307} // namespace Opm
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: BlackoilPhases.hpp:27