SteadyStateUpscalerManager.hpp
Go to the documentation of this file.
1 //===========================================================================
2 //
3 // File: SteadyStateUpscalerManager.hpp
4 //
5 // Created: Thu Apr 29 11:12:56 2010
6 //
7 // Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
8 // Jostein R Natvig <jostein.r.natvig@sintef.no>
9 //
10 // $Date$
11 //
12 // $Revision$
13 //
14 //===========================================================================
15 
16 /*
17  Copyright 2010 SINTEF ICT, Applied Mathematics.
18  Copyright 2010 Statoil ASA.
19 
20  This file is part of The Open Reservoir Simulator Project (OpenRS).
21 
22  OpenRS is free software: you can redistribute it and/or modify
23  it under the terms of the GNU General Public License as published by
24  the Free Software Foundation, either version 3 of the License, or
25  (at your option) any later version.
26 
27  OpenRS is distributed in the hope that it will be useful,
28  but WITHOUT ANY WARRANTY; without even the implied warranty of
29  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30  GNU General Public License for more details.
31 
32  You should have received a copy of the GNU General Public License
33  along with OpenRS. If not, see <http://www.gnu.org/licenses/>.
34 */
35 
36 #ifndef OPM_STEADYSTATEUPSCALERMANAGER_HEADER
37 #define OPM_STEADYSTATEUPSCALERMANAGER_HEADER
38 
39 
42 #include <opm/core/utility/Units.hpp>
43 #include <opm/core/utility/SparseTable.hpp>
44 #include <cmath>
45 #include <fstream>
46 #include <iostream>
47 
48 
49 namespace Opm
50 {
51 
52 
54  template <class Istream>
55  void readControl(Istream& is, std::vector<double>& saturations, Opm::SparseTable<double>& all_pdrops)
56  {
57  int num_sats;
58  is >> num_sats;
59  std::vector<double> sat(num_sats);
60  Opm::SparseTable<double> ap;
61  std::vector<double> tmp_pd;
62  for (int i = 0; i < num_sats; ++i) {
63  is >> sat[i];
64  int num_pdrops;
65  is >> num_pdrops;
66  tmp_pd.resize(num_pdrops);
67  for (int j = 0; j < num_pdrops; ++j) {
68  is >> tmp_pd[j];
69  }
70  ap.appendRow(tmp_pd.begin(), tmp_pd.end());
71  }
72  all_pdrops.swap(ap);
73  saturations.swap(sat);
74  }
75 
76 
77 
78 
80  template <class Ostream>
81  void writeControl(Ostream& os, const std::vector<double>& saturations, const Opm::SparseTable<double>& all_pdrops)
82  {
83  int num_sats = saturations.size();
84  os << num_sats << '\n';
85  for (int i = 0; i < num_sats; ++i) {
86  os << saturations[i] << '\n';
87  int num_pdrops = all_pdrops[i].size();
88  os << num_pdrops;
89  for (int j = 0; j < num_pdrops; ++j) {
90  os << ' ' << all_pdrops[i][j];
91  }
92  os << '\n';
93  }
94  }
95 
96 
97 
98 
99  template<class Ostream, class Tensor>
100  void writeRelPerm(Ostream& os, const Tensor& K, double sat, double pdrop)
101  {
102  /* const int num_rows = K.numRows(); */
103  /* const int num_cols = K.numCols(); */
104 
105  /* We write tensor output in Voigt notation,
106  (but we also output the remainding three terms)
107  http://en.wikipedia.org/wiki/Voigt_notation
108  */
109 
110  /*
111  TODO:
112  If fixed boundary condition, only output diagonal elements
113  If linear or periodic bc's, output all 9 elements (even though 6 is strictly necessary for periodic bc's)
114  Use the Tensor class to order output into Voigt notation, so that it works for more than 3x3 matrices
115  */
116 
117  os << pdrop << '\t';
118  os << sat << '\t';
119  os << K(0,0) << '\t'; /* xx */
120  os << K(1,1) << '\t'; /* yy */
121  os << K(2,2) << '\t'; /* zz */
122  os << K(1,2) << '\t'; /* yz */
123  os << K(0,2) << '\t'; /* xz */
124  os << K(0,1) << '\t'; /* xy */
125  os << K(2,1) << '\t'; /* zy */
126  os << K(2,0) << '\t'; /* zx */
127  os << K(1,2); /* yz */
128 
129 
130  os << std::endl;
131 
132  }
133 
134 
135 
136  template <class Traits>
138  {
139  public:
140  void upscale(const Opm::parameter::ParameterGroup& param)
141  {
142  // Control structure.
143  std::vector<double> saturations;
144  Opm::SparseTable<double> all_pdrops;
145  bool from_file = param.has("sat_pdrop_filename");
146  if (from_file) {
147  std::string filename = param.get<std::string>("sat_pdrop_filename");
148  std::ifstream file(filename.c_str());
149  if (!file) {
150  OPM_THROW(std::runtime_error, "Could not open file " << filename);
151  }
152  readControl(file, saturations, all_pdrops);
153  } else {
154  // Get a linear range of saturations.
155  int num_sats = param.getDefault("num_sats", 4);
156  double min_sat = param.getDefault("min_sat", 0.2);
157  double max_sat = param.getDefault("max_sat", 0.8);
158  saturations.resize(num_sats);
159  for (int i = 0; i < num_sats; ++i) {
160  double factor = num_sats == 1 ? 0 : double(i)/double(num_sats - 1);
161  saturations[i] = (1.0 - factor)*min_sat + factor*max_sat;
162  }
163  // Get a logarithmic range of pressure drops.
164  int num_pdrops = param.getDefault("num_pdrops", 5);
165  double log_min_pdrop = std::log(param.getDefault("min_pdrop", 1e2));
166  double log_max_pdrop = std::log(param.getDefault("max_pdrop", 1e6));
167  std::vector<double> pdrops;
168  pdrops.resize(num_pdrops);
169  for (int i = 0; i < num_pdrops; ++i) {
170  double factor = num_pdrops == 1 ? 0 : double(i)/double(num_pdrops - 1);
171  pdrops[i] = std::exp((1.0 - factor)*log_min_pdrop + factor*log_max_pdrop);
172  }
173  // Assign the same pressure drops to all saturations.
174  for (int i = 0; i < num_sats; ++i) {
175  all_pdrops.appendRow(pdrops.begin(), pdrops.end());
176  }
177  }
178  int flow_direction = param.getDefault("flow_direction", 0);
179 
180  // Print the saturations and pressure drops.
181  // writeControl(std::cout, saturations, all_pdrops);
182 
183  // Initialize upscaler.
184  typedef SteadyStateUpscaler<Traits> Upscaler;
185  typedef typename Upscaler::permtensor_t permtensor_t;
186  Upscaler upscaler;
187  upscaler.init(param);
188 
189  // First, compute an upscaled permeability.
190  permtensor_t upscaled_K = upscaler.upscaleSinglePhase();
191  permtensor_t upscaled_K_copy = upscaled_K;
192  upscaled_K_copy *= (1.0/(Opm::prefix::milli*Opm::unit::darcy));
193  std::cout.precision(15);
194  std::cout << "Upscaled K in millidarcy:\n" << upscaled_K_copy << std::endl;
195  std::cout << "Upscaled porosity: " << upscaler.upscalePorosity() << std::endl;
196 
197  // Create output streams for upscaled relative permeabilities
198  std::string kr_filename = param.getDefault<std::string>("kr_filename", "upscaled_relperm");
199  std::string krw_filename = kr_filename + "_water";
200  std::string kro_filename = kr_filename + "_oil";
201  std::ofstream krw_out(krw_filename.c_str());
202  std::ofstream kro_out(kro_filename.c_str());
203  krw_out << "# Result from steady state upscaling" << std::endl;
204  krw_out << "# Pressuredrop Sw Krxx Kryy Krzz" << std::endl;
205  kro_out << "# Result from steady state upscaling" << std::endl;
206  kro_out << "# Pressuredrop Sw Krxx Kryy Krzz" << std::endl;
207 
208 
209  krw_out.precision(15); krw_out.setf(std::ios::scientific | std::ios::showpoint);
210  kro_out.precision(15); kro_out.setf(std::ios::scientific | std::ios::showpoint);
211  //#endif
212 
213  // Then, compute some upscaled relative permeabilities.
214  int num_cells = upscaler.grid().size(0);
215  int num_sats = saturations.size();
216  for (int i = 0; i < num_sats; ++i) {
217  // Starting every computation with a trio of uniform profiles.
218  std::vector<double> init_sat(num_cells, saturations[i]);
219  const Opm::SparseTable<double>::row_type pdrops = all_pdrops[i];
220  int num_pdrops = pdrops.size();
221  for (int j = 0; j < num_pdrops; ++j) {
222  double pdrop = pdrops[j];
223  std::pair<permtensor_t, permtensor_t> lambda
224  = upscaler.upscaleSteadyState(flow_direction, init_sat, saturations[i], pdrop, upscaled_K);
225  double usat = upscaler.lastSaturationUpscaled();
226  std::cout << "\n\nTensor of upscaled relperms for initial saturation " << saturations[i]
227  << ", real steady-state saturation " << usat
228  << " and pressure drop " << pdrop
229  << ":\n\n[water]\n" << lambda.first
230  << "\n[oil]\n" << lambda.second << std::endl;
231  // Changing initial saturations for next pressure drop to equal the steady state of the last
232  init_sat = upscaler.lastSaturationState();
233 
234 
235  writeRelPerm(krw_out, lambda.first , usat, pdrop);
236  writeRelPerm(kro_out, lambda.second, usat, pdrop);
237 
238  }
239  }
240  }
241  };
242 
243 
244 
245 
246 
247 
248 } // namespace Opm
249 
250 #endif // OPM_STEADYSTATEUPSCALERMANAGER_HEADER
void upscale(const Opm::parameter::ParameterGroup &param)
Definition: SteadyStateUpscalerManager.hpp:140
Definition: applier.hpp:18
A class for doing steady state upscaling.
Definition: SteadyStateUpscaler.hpp:51
void writeControl(Ostream &os, const std::vector< double > &saturations, const Opm::SparseTable< double > &all_pdrops)
Writes saturation and pressure drop data to an output stream.
Definition: SteadyStateUpscalerManager.hpp:81
Definition: SteadyStateUpscalerManager.hpp:137
void init(const Opm::parameter::ParameterGroup &param)
Initializes the upscaler from parameters.
Definition: UpscalerBase_impl.hpp:64
void readControl(Istream &is, std::vector< double > &saturations, Opm::SparseTable< double > &all_pdrops)
Reads saturation and pressure drop data from an input stream.
Definition: SteadyStateUpscalerManager.hpp:55
void writeRelPerm(Ostream &os, const Tensor &K, double sat, double pdrop)
Definition: SteadyStateUpscalerManager.hpp:100
int j
Definition: elasticity_upscale_impl.hpp:658