My Project
FieldProps.hpp
1/*
2 Copyright 2019 Equinor ASA.
3
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify it under the terms
7 of the GNU General Public License as published by the Free Software
8 Foundation, either version 3 of the License, or (at your option) any later
9 version.
10
11 OPM is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along with
16 OPM. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#ifndef FIELDPROPS_HPP
20#define FIELDPROPS_HPP
21
22#include <limits>
23#include <optional>
24#include <string>
25#include <unordered_set>
26#include <vector>
27
28#include <opm/input/eclipse/Deck/value_status.hpp>
29#include <opm/input/eclipse/Deck/DeckSection.hpp>
30#include <opm/input/eclipse/Units/UnitSystem.hpp>
31#include <opm/input/eclipse/EclipseState/Grid/Box.hpp>
32#include <opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.hpp>
33#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
34#include <opm/input/eclipse/EclipseState/Runspec.hpp>
35#include <opm/input/eclipse/EclipseState/Grid/Keywords.hpp>
36#include <opm/input/eclipse/EclipseState/Grid/TranCalculator.hpp>
37#include <opm/input/eclipse/EclipseState/Grid/FieldData.hpp>
38
39namespace Opm {
40
41class Deck;
42class EclipseGrid;
43class NumericalAquifers;
44
45namespace Fieldprops
46{
47
48namespace keywords {
49
50/*
51 Regarding global keywords
52 =========================
53
54 It turns out that when the option 'ALL' is used for the PINCH keyword we
55 require the MULTZ keyword specified for all cells, also the inactive cells.
56 The premise for the FieldProps implementation has all the way been that only
57 the active cells should be stored.
58
59 In order to support the ALL option of the PINCH keyword we have bolted on a
60 limited support for global storage. By setting .global = true in the
61 keyword_info describing the keyword you get:
62
63 1. Normal deck assignment like
64
65 MULTZ
66 ..... /
67
68 2. Scalar operations like EQUALS and MULTIPLY.
69
70 These operations also support the full details of the BOX behavior.
71
72 The following operations do not work
73 ------------------------------------
74
75 1. Operations involving multiple keywords like
76
77 COPY
78 MULTX MULTZ /
79 /
80
81 this also includes the OPERATE which involves multiple keywords for some
82 of its operations.
83
84 2. All region operatins like EQUALREG and MULTREG.
85
86 The operations which are not properly implemented will be intercepted and a
87 std::logic_error() exception will be thrown.
88*/
89
90
91
92inline bool isFipxxx(const std::string& keyword) {
93 // FIPxxxx can be any keyword, e.g. FIPREG or FIPXYZ that has the pattern "FIP.+"
94 // However, it can not be FIPOWG as that is an actual keyword.
95 if (keyword.size() < 4 || keyword == "FIPOWG") {
96 return false;
97 }
98 return keyword[0] == 'F' && keyword[1] == 'I' && keyword[2] == 'P';
99}
100
101
102/*
103 The aliased_keywords map defines aliases for other keywords. The FieldProps
104 objects will translate those keywords before further processing. The aliases
105 will also be exposed by the FieldPropsManager object.
106
107 However, the following methods of FieldProps do not fully support aliases:
108 - FieldProps::keys() does not return the aliases.
109 - FieldProps::erase() and FieldProps::extract() do not support aliases. Using
110 them with an aliased keyword will also remove the alias.
111
112 Note that the aliases are also added to GRID::double_keywords.
113
114 The PERMR and PERMTHT keywords are aliases for PERMX and PERMY, respectively.
115*/
116namespace ALIAS {
117 static const std::unordered_map<std::string, std::string> aliased_keywords = {{"PERMR", "PERMX"},
118 {"PERMTHT", "PERMY"}};
119}
120
121
122namespace GRID {
123static const std::unordered_map<std::string, keyword_info<double>> double_keywords = {{"MULTPV", keyword_info<double>{}.init(1.0)},
124 {"NTG", keyword_info<double>{}.init(1.0)},
125 {"PORO", keyword_info<double>{}.distribute_top(true)},
126 {"PERMX", keyword_info<double>{}.unit_string("Permeability").distribute_top(true)},
127 {"PERMY", keyword_info<double>{}.unit_string("Permeability").distribute_top(true)},
128 {"PERMZ", keyword_info<double>{}.unit_string("Permeability").distribute_top(true)},
129 {"PERMR", keyword_info<double>{}.unit_string("Permeability").distribute_top(true)},
130 {"PERMTHT", keyword_info<double>{}.unit_string("Permeability").distribute_top(true)},
131 {"TEMPI", keyword_info<double>{}.unit_string("Temperature")},
132 {"THCONR", keyword_info<double>{}.unit_string("Energy/AbsoluteTemperature*Length*Time")},
133 {"THCONSF", keyword_info<double>{}},
134 {"THCROCK", keyword_info<double>{}.unit_string("Energy/AbsoluteTemperature*Length*Time")},
135 {"THCOIL", keyword_info<double>{}.unit_string("Energy/AbsoluteTemperature*Length*Time")},
136 {"THCGAS", keyword_info<double>{}.unit_string("Energy/AbsoluteTemperature*Length*Time")},
137 {"THCWATER",keyword_info<double>{}.unit_string("Energy/AbsoluteTemperature*Length*Time")},
138 {"MULTX", keyword_info<double>{}.init(1.0).mult(true)},
139 {"MULTX-", keyword_info<double>{}.init(1.0).mult(true)},
140 {"MULTY", keyword_info<double>{}.init(1.0).mult(true)},
141 {"MULTY-", keyword_info<double>{}.init(1.0).mult(true)},
142 {"MULTZ", keyword_info<double>{}.init(1.0).mult(true).global_kw(true)},
143 {"MULTZ-", keyword_info<double>{}.init(1.0).mult(true)}};
144
145static const std::unordered_map<std::string, keyword_info<int>> int_keywords = {{"ACTNUM", keyword_info<int>{}.init(1)},
146 {"FLUXNUM", keyword_info<int>{}},
147 {"ISOLNUM", keyword_info<int>{}.init(1)},
148 {"MULTNUM", keyword_info<int>{}.init(1)},
149 {"OPERNUM", keyword_info<int>{}},
150 {"ROCKNUM", keyword_info<int>{}}};
151
152}
153
154namespace EDIT {
155
156/*
157 The TRANX, TRANY and TRANZ properties are handled very differently from the
158 other properties. It is important that these fields are not entered into the
159 double_keywords list of the EDIT section, that way we risk silent failures
160 due to the special treatment of the TRAN fields.
161*/
162
163static const std::unordered_map<std::string, keyword_info<double>> double_keywords = {{"MULTPV", keyword_info<double>{}.init(1.0)},
164 {"PORV", keyword_info<double>{}.unit_string("ReservoirVolume")},
165 {"MULTX", keyword_info<double>{}.init(1.0).mult(true)},
166 {"MULTX-", keyword_info<double>{}.init(1.0).mult(true)},
167 {"MULTY", keyword_info<double>{}.init(1.0).mult(true)},
168 {"MULTY-", keyword_info<double>{}.init(1.0).mult(true)},
169 {"MULTZ", keyword_info<double>{}.init(1.0).mult(true).global_kw(true)},
170 {"MULTZ-", keyword_info<double>{}.init(1.0).mult(true)}};
171
172static const std::unordered_map<std::string, keyword_info<int>> int_keywords = {};
173}
174
175namespace PROPS {
176static const std::unordered_map<std::string, keyword_info<double>> double_keywords = {{"SWATINIT", keyword_info<double>{}}};
177static const std::unordered_map<std::string, keyword_info<int>> int_keywords = {};
178
179#define dirfunc(base) base, base "X", base "X-", base "Y", base "Y-", base "Z", base "Z-"
180
181static const std::set<std::string> satfunc = {"SWLPC", "ISWLPC", "SGLPC", "ISGLPC",
182 dirfunc("SGL"),
183 dirfunc("ISGL"),
184 dirfunc("SGU"),
185 dirfunc("ISGU"),
186 dirfunc("SWL"),
187 dirfunc("ISWL"),
188 dirfunc("SWU"),
189 dirfunc("ISWU"),
190 dirfunc("SGCR"),
191 dirfunc("ISGCR"),
192 dirfunc("SOWCR"),
193 dirfunc("ISOWCR"),
194 dirfunc("SOGCR"),
195 dirfunc("ISOGCR"),
196 dirfunc("SWCR"),
197 dirfunc("ISWCR"),
198 dirfunc("PCW"),
199 dirfunc("IPCW"),
200 dirfunc("PCG"),
201 dirfunc("IPCG"),
202 dirfunc("KRW"),
203 dirfunc("IKRW"),
204 dirfunc("KRWR"),
205 dirfunc("IKRWR"),
206 dirfunc("KRO"),
207 dirfunc("IKRO"),
208 dirfunc("KRORW"),
209 dirfunc("IKRORW"),
210 dirfunc("KRORG"),
211 dirfunc("IKRORG"),
212 dirfunc("KRG"),
213 dirfunc("IKRG"),
214 dirfunc("KRGR"),
215 dirfunc("IKRGR")};
216
217static const std::map<std::string,std::string> sogcr_shift = {{"SOGCR", "SWL"},
218 {"SOGCRX", "SWLX"},
219 {"SOGCRX-", "SWLX-"},
220 {"SOGCRY", "SWLY"},
221 {"SOGCRY-", "SWLY-"},
222 {"SOGCRZ", "SWLZ"},
223 {"SOGCRZ-", "SWLZ-"},
224 {"ISOGCR", "ISWL"},
225 {"ISOGCRX", "ISWLX"},
226 {"ISOGCRX-", "ISWLX-"},
227 {"ISOGCRY", "ISWLY"},
228 {"ISOGCRY-", "ISWLY-"},
229 {"ISOGCRZ", "ISWLZ"},
230 {"ISOGCRZ-", "ISWLZ-"}};
231
232}
233
234namespace REGIONS {
235
236static const std::unordered_map<std::string, keyword_info<int>> int_keywords = {{"ENDNUM", keyword_info<int>{}.init(1)},
237 {"EQLNUM", keyword_info<int>{}.init(1)},
238 {"FIPNUM", keyword_info<int>{}.init(1)},
239 {"IMBNUM", keyword_info<int>{}.init(1)},
240 {"OPERNUM", keyword_info<int>{}},
241 {"MISCNUM", keyword_info<int>{}},
242 {"MISCNUM", keyword_info<int>{}},
243 {"PVTNUM", keyword_info<int>{}.init(1)},
244 {"SATNUM", keyword_info<int>{}.init(1)},
245 {"LWSLTNUM", keyword_info<int>{}},
246 {"ROCKNUM", keyword_info<int>{}},
247 {"KRNUMX", keyword_info<int>{}},
248 {"KRNUMY", keyword_info<int>{}},
249 {"KRNUMZ", keyword_info<int>{}},
250 };
251}
252
253namespace SOLUTION {
254
255static const std::unordered_map<std::string, keyword_info<double>> double_keywords = {{"PRESSURE", keyword_info<double>{}.unit_string("Pressure")},
256 {"SPOLY", keyword_info<double>{}.unit_string("Density")},
257 {"SPOLYMW", keyword_info<double>{}},
258 {"SSOL", keyword_info<double>{}},
259 {"SWAT", keyword_info<double>{}},
260 {"SGAS", keyword_info<double>{}},
261 {"SMICR", keyword_info<double>{}.unit_string("Density")},
262 {"SOXYG", keyword_info<double>{}.unit_string("Density")},
263 {"SUREA", keyword_info<double>{}.unit_string("Density")},
264 {"SBIOF", keyword_info<double>{}},
265 {"SCALC", keyword_info<double>{}},
266 {"SALTP", keyword_info<double>{}},
267 {"SALT", keyword_info<double>{}.unit_string("Salinity")},
268 {"TEMPI", keyword_info<double>{}.unit_string("Temperature")},
269 {"RS", keyword_info<double>{}.unit_string("GasDissolutionFactor")},
270 {"RV", keyword_info<double>{}.unit_string("OilDissolutionFactor")},
271 {"RVW", keyword_info<double>{}.unit_string("OilDissolutionFactor")}
272 };
273
274}
275
276namespace SCHEDULE {
277
278static const std::unordered_map<std::string, keyword_info<double>> double_keywords = {{"MULTX", keyword_info<double>{}.init(1.0).mult(true)},
279 {"MULTX-", keyword_info<double>{}.init(1.0).mult(true)},
280 {"MULTY", keyword_info<double>{}.init(1.0).mult(true)},
281 {"MULTY-", keyword_info<double>{}.init(1.0).mult(true)},
282 {"MULTZ", keyword_info<double>{}.init(1.0).mult(true).global_kw(true)},
283 {"MULTZ-", keyword_info<double>{}.init(1.0).mult(true)}};
284
285static const std::unordered_map<std::string, keyword_info<int>> int_keywords = {{"ROCKNUM", keyword_info<int>{}}};
286
287}
288
289template <typename T>
290keyword_info<T> global_kw_info(const std::string& name, bool allow_unsupported = false);
291
292} // end namespace keywords
293
294} // end namespace FieldProps
295
297public:
298
299 using ScalarOperation = Fieldprops::ScalarOperation;
300
302 int region_value;
303 double multiplier;
304 std::string region_name;
305
306
307 MultregpRecord(int rv, double m, const std::string& rn) :
308 region_value(rv),
309 multiplier(m),
310 region_name(rn)
311 {}
312
313
314 bool operator==(const MultregpRecord& other) const {
315 return this->region_value == other.region_value &&
316 this->multiplier == other.multiplier &&
317 this->region_name == other.region_name;
318 }
319 };
320
321
322
323 enum class GetStatus {
324 OK = 1,
325 INVALID_DATA = 2, // std::runtime_error
326 MISSING_KEYWORD = 3, // std::out_of_range
327 NOT_SUPPPORTED_KEYWORD = 4 // std::logic_error
328 };
329
330
331
332 template<typename T>
334 const std::string& keyword;
335 GetStatus status;
337 const Data * data_ptr;
338
339 FieldDataManager(const std::string& k, GetStatus s, const Data * d) :
340 keyword(k),
341 status(s),
342 data_ptr(d)
343 { }
344
345
346 void verify_status() const {
347 switch (status) {
348 case FieldProps::GetStatus::OK:
349 return;
350 case FieldProps::GetStatus::INVALID_DATA:
351 throw std::runtime_error("The keyword: " + keyword + " has not been fully initialized");
352 case FieldProps::GetStatus::MISSING_KEYWORD:
353 throw std::out_of_range("No such keyword in deck: " + keyword);
354 case FieldProps::GetStatus::NOT_SUPPPORTED_KEYWORD:
355 throw std::logic_error("The keyword " + keyword + " is not supported");
356 }
357 }
358
359 const std::vector<T>* ptr() const {
360 if (this->data_ptr)
361 return std::addressof(this->data_ptr->data);
362 else
363 return nullptr;
364 }
365
366 const std::vector<T>& data() const {
367 this->verify_status();
368 return this->data_ptr->data;
369 }
370
371 const Data& field_data() const {
372 this->verify_status();
373 return *this->data_ptr;
374 }
375
376 bool valid() const {
377 return (this->status == GetStatus::OK);
378 }
379
380 };
381
382
383
385 FieldProps(const Deck& deck, const Phases& phases, const EclipseGrid& grid, const TableManager& table_arg);
387 FieldProps(const Deck& deck, const EclipseGrid& grid);
388
389 void reset_actnum(const std::vector<int>& actnum);
390
391 void apply_numerical_aquifers(const NumericalAquifers& numerical_aquifers);
392
393 const std::string& default_region() const;
394
395 std::vector<int> actnum();
396 const std::vector<int>& actnumRaw() const;
397
398 template <typename T>
399 static bool supported(const std::string& keyword);
400
401 template <typename T>
402 bool has(const std::string& keyword) const;
403
404 template <typename T>
405 std::vector<std::string> keys() const;
406
407
408 template <typename T>
409 FieldDataManager<T> try_get(const std::string& keyword,
410 bool allow_unsupported=false) {
411 if (!allow_unsupported && !FieldProps::supported<T>(keyword))
412 return FieldDataManager<T>(keyword, GetStatus::NOT_SUPPPORTED_KEYWORD, nullptr);
413
414 const Fieldprops::FieldData<T> * field_data;
415 bool has0 = this->has<T>(keyword);
416
417 field_data = std::addressof(this->init_get<T>(keyword,
418 std::is_same<T,double>::value && allow_unsupported));
419 if (field_data->valid() || allow_unsupported)
420 return FieldDataManager<T>(keyword, GetStatus::OK, field_data);
421
422 if (!has0) {
423 this->erase<T>(keyword);
424 return FieldDataManager<T>(keyword, GetStatus::MISSING_KEYWORD, nullptr);
425 }
426
427 return FieldDataManager<T>(keyword, GetStatus::INVALID_DATA, nullptr);
428 }
429
430
431 template <typename T>
432 const std::vector<T>& get(const std::string& keyword) {
433 const auto& data = this->try_get<T>(keyword);
434 return data.data();
435 }
436
437 template <typename T>
438 std::vector<T> get_global(const std::string& keyword) {
439 const auto& managed_field_data = this->try_get<T>(keyword);
440 const auto& field_data = managed_field_data.field_data();
441 const auto& kw_info = Fieldprops::keywords::global_kw_info<T>(keyword);
442 if (kw_info.global)
443 return *field_data.global_data;
444 else
445 return this->global_copy(field_data.data, kw_info.scalar_init);
446 }
447
448
449 template <typename T>
450 std::vector<T> get_copy(const std::string& keyword, bool global) {
451 bool has0 = this->has<T>(keyword);
452 const auto& field_data = this->try_get<T>(keyword).field_data();
453
454 if (has0) {
455 if (global)
456 return this->global_copy(field_data.data, field_data.kw_info.scalar_init);
457 else
458 return field_data.data;
459 } else {
460 if (global) {
461 const auto& kw_info = Fieldprops::keywords::global_kw_info<T>(keyword);
462 return this->global_copy(this->extract<T>(keyword), kw_info.scalar_init);
463 } else
464 return this->extract<T>(keyword);
465 }
466 }
467
468
469 template <typename T>
470 std::vector<bool> defaulted(const std::string& keyword) {
471 const auto& field = this->init_get<T>(keyword);
472 std::vector<bool> def(field.size());
473
474 for (std::size_t i=0; i < def.size(); i++)
475 def[i] = value::defaulted( field.value_status[i]);
476
477 return def;
478 }
479
480
481 template <typename T>
482 std::vector<T> global_copy(const std::vector<T>& data, const std::optional<T>& default_value) const {
483 T fill_value = default_value.has_value() ? *default_value : 0;
484 std::vector<T> global_data(this->global_size, fill_value);
485 std::size_t i = 0;
486 for (std::size_t g = 0; g < this->global_size; g++) {
487 if (this->m_actnum[g]) {
488 global_data[g] = data[i];
489 i++;
490 }
491 }
492 return global_data;
493 }
494
495 std::size_t active_size;
496 std::size_t global_size;
497
498 std::size_t num_int() const {
499 return this->int_data.size();
500 }
501
502 std::size_t num_double() const {
503 return this->double_data.size();
504 }
505
506 void handle_schedule_keywords(const std::vector<DeckKeyword>& keywords);
507 bool tran_active(const std::string& keyword) const;
508 void apply_tran(const std::string& keyword, std::vector<double>& data);
509 bool operator==(const FieldProps& other) const;
510 static bool rst_cmp(const FieldProps& full_arg, const FieldProps& rst_arg);
511
512 const Fieldprops::TranMap& getTran() const
513 {
514 return tran;
515 }
516
517private:
518 void scanGRIDSection(const GRIDSection& grid_section);
519 void scanGRIDSectionOnlyACTNUM(const GRIDSection& grid_section);
520 void scanEDITSection(const EDITSection& edit_section);
521 void scanPROPSSection(const PROPSSection& props_section);
522 void scanREGIONSSection(const REGIONSSection& regions_section);
523 void scanSOLUTIONSection(const SOLUTIONSection& solution_section);
524 double getSIValue(const std::string& keyword, double raw_value) const;
525 double getSIValue(ScalarOperation op, const std::string& keyword, double raw_value) const;
526 template <typename T>
527 void erase(const std::string& keyword);
528
529 template <typename T>
530 std::vector<T> extract(const std::string& keyword);
531
532 template <typename T>
533 void operate(const DeckRecord& record, Fieldprops::FieldData<T>& target_data, const Fieldprops::FieldData<T>& src_data, const std::vector<Box::cell_index>& index_list);
534
535 template <typename T>
536 static void apply(ScalarOperation op, std::vector<T>& data, std::vector<value::status>& value_status, T scalar_value, const std::vector<Box::cell_index>& index_list);
537
538 template <typename T>
539 Fieldprops::FieldData<T>& init_get(const std::string& keyword, bool allow_unsupported = false);
540
541 template <typename T>
542 Fieldprops::FieldData<T>& init_get(const std::string& keyword, const Fieldprops::keywords::keyword_info<T>& kw_info);
543
544 std::string region_name(const DeckItem& region_item);
545 std::vector<Box::cell_index> region_index( const std::string& region_name, int region_value );
546 void handle_OPERATE(const DeckKeyword& keyword, Box box);
547 void handle_operation(const DeckKeyword& keyword, Box box);
548 void handle_region_operation(const DeckKeyword& keyword);
549 void handle_COPY(const DeckKeyword& keyword, Box box, bool region);
550 void distribute_toplayer(Fieldprops::FieldData<double>& field_data, const std::vector<double>& deck_data, const Box& box);
551 double get_beta(const std::string& func_name, const std::string& target_array, double raw_beta);
552 double get_alpha(const std::string& func_name, const std::string& target_array, double raw_alpha);
553
554 void handle_keyword(const DeckKeyword& keyword, Box& box);
555 void handle_double_keyword(Section section, const Fieldprops::keywords::keyword_info<double>& kw_info, const DeckKeyword& keyword, const std::string& keyword_name, const Box& box);
556 void handle_double_keyword(Section section, const Fieldprops::keywords::keyword_info<double>& kw_info, const DeckKeyword& keyword, const Box& box);
557 void handle_int_keyword(const Fieldprops::keywords::keyword_info<int>& kw_info, const DeckKeyword& keyword, const Box& box);
558 void init_satfunc(const std::string& keyword, Fieldprops::FieldData<double>& satfunc);
559 void init_porv(Fieldprops::FieldData<double>& porv);
560 void init_tempi(Fieldprops::FieldData<double>& tempi);
561
562 const UnitSystem unit_system;
563 std::size_t nx,ny,nz;
564 Phases m_phases;
565 SatFuncControls m_satfuncctrl;
566 std::vector<int> m_actnum;
567 std::vector<double> cell_volume;
568 std::vector<double> cell_depth;
569 const std::string m_default_region;
570 const EclipseGrid * grid_ptr; // A bit undecided whether to properly use the grid or not ...
571 TableManager tables;
572 std::optional<satfunc::RawTableEndPoints> m_rtep;
573 std::vector<MultregpRecord> multregp;
574 std::unordered_map<std::string, Fieldprops::FieldData<int>> int_data;
575 std::unordered_map<std::string, Fieldprops::FieldData<double>> double_data;
576
577 Fieldprops::TranMap tran;
578};
579
580}
581#endif
Definition: Deck.hpp:63
About cell information and dimension: The actual grid information is held in a pointer to an ERT ecl_...
Definition: EclipseGrid.hpp:54
Definition: FieldProps.hpp:296
FieldProps(const Deck &deck, const EclipseGrid &grid)
Special case constructor used to process ACTNUM only.
FieldProps(const Deck &deck, const Phases &phases, const EclipseGrid &grid, const TableManager &table_arg)
Normal constructor for FieldProps.
Definition: NumericalAquifers.hpp:36
Definition: Runspec.hpp:57
Definition: TableManager.hpp:65
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:29
Definition: FieldProps.hpp:333
Definition: FieldProps.hpp:301
Definition: FieldData.hpp:55