00001
00011 #ifndef BS_MAIN_LOOP_CALC_H_
00012 #define BS_MAIN_LOOP_CALC_H_
00013
00014 #include "data_storage_interface.h"
00015 #include "event_manager.h"
00016
00017 #include "well_rate_control.h"
00018
00019 #include "string_formater.h"
00020 #include "well_type_helper.h"
00021 #include "well_connection.h"
00022 #include "calc_well.h"
00023 #include "rr_rw_wr_saver.h"
00024
00025 #include "save_connection_data.h"
00026
00027 #include "fi_operator.h"
00028 #include "jacobian_impl.h"
00029 #include "well_results_storage.h"
00030 #include "fip_results_storage.h"
00031
00032 #include BS_FORCE_PLUGIN_IMPORT ()
00033 #include "scale_array_holder.h"
00034 #include "print_process_memory_info.h"
00035 #include "path_tools.h"
00036 #include BS_STOP_PLUGIN_IMPORT ()
00037
00038 #include "well_reporter.h"
00039
00040 namespace blue_sky
00041 {
00042
00043 template <typename strategy_t>
00050 struct main_loop_calc_base
00051 {
00052 typedef event_manager <strategy_t> event_manager_t;
00053 typedef typename event_manager_t::sp_event_base_list sp_event_base_list_t;
00054
00055 public:
00059 virtual ~main_loop_calc_base () {}
00060
00062 virtual void ready () = 0;
00064 virtual void go () = 0;
00066 virtual void end () = 0;
00067
00069
00073 virtual void
00074 apply_events (const sp_event_base_list_t &) = 0;
00075 };
00076
00081 template <typename strategy_t, bool is_w, bool is_g, bool is_o>
00082 struct main_loop_calc : public main_loop_calc_base <strategy_t>
00083 {
00084 typedef main_loop_calc_base <strategy_t> base_t;
00085 typedef main_loop_calc <strategy_t, is_w, is_g, is_o> this_t;
00086
00087 typedef typename strategy_t::item_t item_t;
00088 typedef typename strategy_t::index_t index_t;
00089 typedef typename strategy_t::item_array_t item_array_t;
00090
00091 typedef calc_model <strategy_t> calc_model_t;
00092 typedef event_manager <strategy_t> event_manager_t;
00093 typedef rock_grid <strategy_t> rock_grid_t;
00094 typedef reservoir <strategy_t> reservoir_t;
00095 typedef rs_mesh_iface <strategy_t> mesh_iface_t;
00096 typedef jacobian <strategy_t> jacobian_t;
00097 typedef reservoir_simulator <strategy_t> reservoir_simulator_t;
00098 typedef idata idata_t;
00099 typedef typename calc_model_t::scal_3p_t scal_3p_t;
00100 typedef jacobian_matrix <strategy_t> jmatrix_t;
00101
00102 typedef typename event_manager_t::sp_event_base_list sp_event_base_list_t;
00103 typedef trans_multipliers_calc <strategy_t> trans_multipliers_calc_t;
00104
00105 typedef smart_ptr <calc_model_t, true> sp_calc_model_t;
00106 typedef smart_ptr <event_manager_t, true> sp_event_manager_t;
00107 typedef smart_ptr <rock_grid_t, true> sp_rock_grid_t;
00108 typedef smart_ptr <reservoir_t, true> sp_reservoir_t;
00109 typedef smart_ptr <mesh_iface_t, true> sp_mesh_iface_t;
00110 typedef smart_ptr <jacobian_t, true> sp_jacobian_t;
00111 typedef smart_ptr <fi_params, true> sp_fi_params_t;
00112 typedef smart_ptr <data_storage_interface, true> sp_storage_t;
00113 typedef smart_ptr <reservoir_simulator_t, true> sp_rs_t;
00114 typedef smart_ptr <idata_t, true> sp_idata_t;
00115 typedef typename calc_model_t::sp_scal3p sp_scal3p_t;
00116 typedef smart_ptr <jmatrix_t, true> sp_jmatrix_t;
00117
00118 typedef boost::posix_time::ptime ptime;
00119
00120 public:
00126 main_loop_calc (const sp_rs_t &rs)
00127 : rs_ (rs)
00128 , calc_model_ (rs->cm)
00129 , event_manager_ (rs->em)
00130 , rock_grid_prop_ (calc_model_->rock_grid_prop)
00131 , facility_storage_ (rs->facility_storage_)
00132 , reservoir_ (rs->reservoir_)
00133 , mesh_ (rs->mesh)
00134 , jacobian_ (rs->jacobian_)
00135 , params_ (calc_model_->ts_params)
00136 , data_map_ (rs->dm->data)
00137 , height_ (0)
00138 , rho_ (0)
00139 {
00140 number_of_newtonian_iterations = 0;
00141 number_of_linear_iterations = 0;
00142 number_of_restarts = 0;
00143 number_of_max_iters_restarts = 0;
00144 number_of_fi_operator_restarts = 0;
00145 number_of_close_wells_restarts = 0;
00146
00147 large_time_step_length_ = 0;
00148 large_time_step_start_ = 0;
00149 large_time_step_end_ = 0;
00150
00151 num_last_newton_iters_ = 0;
00152 num_last_lin_iters_ = 0;
00153
00154 number_of_small_time_steps = 0;
00155 number_of_large_time_steps = 1;
00156
00157 height_ = 0;
00158 rho_ = 0;
00159 min_z_ = 0;
00160 max_z_ = 0;
00161 dt_ = 0;
00162 current_time_ = 0;
00163
00164 do_calc_prev_fluid_volume_ = true;
00165
00166 if (calc_model_->n_phases > 1)
00167 {
00168 if (calc_model_->phase_d[FI_PHASE_WATER] != calc_model_->sat_d[FI_PHASE_WATER])
00169 bs_throw_exception ((boost::format ("Phase index (%d) for water should be equal to saturation index (%d)") % calc_model_->phase_d[FI_PHASE_WATER] % calc_model_->sat_d[FI_PHASE_WATER]).str ());
00170
00171 if (calc_model_->phase_d[FI_PHASE_GAS] != calc_model_->sat_d[FI_PHASE_GAS])
00172 bs_throw_exception ((boost::format ("Phase index (%d) for gas should be equal to saturation index (%d)") % calc_model_->phase_d[FI_PHASE_GAS] % calc_model_->sat_d[FI_PHASE_GAS]).str ());
00173 }
00174 }
00175
00180 inline void
00181 fi_operator_cells (index_t i)
00182 {
00183 sp_jmatrix_t jmatrix = jacobian_->get_jmatrix ();
00184 fi_operator_impl <strategy_t, is_w, is_g, is_o> fi_operator_impl_ (calc_model_, reservoir_, mesh_, jacobian_, jmatrix);
00185 fi_operator_impl_.fi_operator_init (i, dt_);
00186 }
00187
00192 inline void
00193 apply_events (const sp_event_base_list_t &event_list)
00194 {
00195 typename sp_event_base_list_t::const_iterator it = event_list.begin ();
00196 typename sp_event_base_list_t::const_iterator e = event_list.end ();
00197
00198 for (; it != e; ++it)
00199 {
00200 (*it)->apply (reservoir_, mesh_, calc_model_);
00201 }
00202 }
00203
00207 inline void
00208 compute_jacobian ()
00209 {
00210 reservoir_->compute_jacobian (calc_model_);
00211 }
00212
00217 inline item_t
00218 get_dt () const
00219 {
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 if ((number_of_small_time_steps == 0 && !number_of_large_time_steps))
00238 {
00239 BOSOUT (section::app_info, level::debug) << "number_of_small_time_steps == 0 && !number_of_large_time_steps" << bs_end;
00240 return (std::min <item_t>) (1.0, (item_t)large_time_step_end_);
00241 }
00242 else
00243 {
00244 BOSOUT (section::main_loop, level::low) << "increase_ts" << bs_end;
00245 return increase_ts (dt_, large_time_step_end_ - current_time_, num_last_newton_iters_);
00246 }
00247 }
00248
00253 inline void
00254 init_custom_wells (const sp_calc_model_t &calc_model)
00255 {
00256 reservoir_->init_custom_wells (calc_model);
00257 }
00258
00262 inline void
00263 process_small_steps ()
00264 {
00265 setup_jacobian_solver_params ();
00266
00267 sp_jmatrix_t jmatrix = jacobian_->get_jmatrix ();
00268 fi_operator_impl <strategy_t, is_w, is_g, is_o> fi_operator (calc_model_, reservoir_, mesh_, jacobian_, jmatrix);
00269 jacobian_impl <strategy_t> jacobian_impl_ (jacobian_, jmatrix);
00270
00271 for (number_of_small_time_steps = 0; current_time_ < large_time_step_end_ - EPS_DIFF; ++number_of_small_time_steps)
00272 {
00273 do_calc_prev_fluid_volume_ = true;
00274 dt_ = get_dt ();
00275 save_base_vars ();
00276
00277 for (;;)
00278 {
00279
00280 calc_model_->approx_flag = false;
00281 if (get_clamp_pressure ())
00282 compute_solution_range ();
00283
00284 rs_->on_small_step_start ();
00285 index_t ret_code = compute_small_time_step (fi_operator, jacobian_impl_, num_last_newton_iters_, num_last_lin_iters_);
00286 if (ret_code >= 0 && ret_code <= get_newton_iters_num ())
00287 {
00288 if (!process_well_model ())
00289 break;
00290 else
00291 {
00292 do_calc_prev_fluid_volume_ = false;
00293 continue;
00294 }
00295 }
00296 else if (ret_code >= 0)
00297 {
00298 newton_iter_fail(ret_code);
00299 }
00300 }
00301
00302 newton_iter_success();
00303 }
00304 }
00305
00310 BS_FORCE_INLINE
00311 void
00312 newton_iter_fail (size_t ret_code)
00313 {
00314 restore_base_vars ();
00315 item_t old_dt = dt_;
00316 dt_ = decrease_ts (dt_, large_time_step_end_ - current_time_);
00317
00318 BOSOUT (section::main_loop, level::low) << "have to decrease dt " << old_dt << " -> " << (double)dt_ << bs_end;
00319 if (fabs (old_dt - dt_) < 1.0e-12)
00320 {
00321 throw bs_exception ("process_small_step", "Newton process failed");
00322 }
00323
00324 if (ret_code > get_newton_iters_num ())
00325 {
00326 update_number_of_fi_operator_restarts ();
00327 update_number_of_restarts ();
00328 }
00329 else if (ret_code == get_newton_iters_num ())
00330 {
00331 update_number_of_max_iters_restarts ();
00332 update_number_of_restarts ();
00333 }
00334
00335 do_calc_prev_fluid_volume_ = false;
00336 rs_->on_newton_iter_fail ();
00337 }
00341 BS_FORCE_INLINE
00342 void
00343 newton_iter_success ()
00344 {
00345 update_number_of_newtonian_iterations (num_last_newton_iters_);
00346 update_number_of_linear_iterations (num_last_lin_iters_);
00347 update_current_time (dt_);
00348
00349 fi_borates_total ();
00350
00351
00352
00353
00354
00355
00356
00357
00358 BOSOUT (section::main_loop, level::high)
00359 << (boost::format ("Info: Newtonian iteration [%d], linear interations [%d]") % (size_t)num_last_newton_iters_ % (size_t)num_last_lin_iters_).str () << "\n"
00360 << (boost::format (" dt: [%10.20lf] on time [%10.20lf]") % (double)dt_ % (double)current_time_).str () << bs_end;
00361
00362 rs_->on_newton_iter_success ();
00363 }
00364
00369 inline void
00370 save_newton_iter_info ()
00371 {
00372 static FILE *file = fopen ("newton_iter_info.bs.txt", "wt");
00373 if (!file)
00374 {
00375 throw bs_exception ("can't open file", "");
00376 }
00377
00378 fprintf (file, "newtonian iters: %d, linear iters: %d, dt = %.20e on time = %.20e\n", (int)num_last_newton_iters_, (int)num_last_lin_iters_, (double)dt_, (double)current_time_);
00379 fflush (file);
00380 }
00381
00386 void
00387 print_saturation ()
00388 {
00389 static size_t iter_counter = 0;
00390 ++iter_counter;
00391 tools::save_seq_vector (tools::string_formater ("nw_saturation.bs.%d.txt", iter_counter).str).save (calc_model_->saturation_3p);
00392 }
00397 void
00398 print_pressure ()
00399 {
00400 static size_t iter_counter = 0;
00401 ++iter_counter;
00402 tools::save_seq_vector (tools::string_formater ("nw_pressure.bs.%d.txt", iter_counter).str).save (calc_model_->pressure);
00403 }
00404
00409 void
00410 print_volume ()
00411 {
00412 static size_t iter_counter = 0;
00413 ++iter_counter;
00414 tools::save_seq_vector (tools::string_formater ("nw_volumes.bs.%d.txt", iter_counter).str).save (calc_model_->rock_grid_prop->volume);
00415 }
00416
00417 inline bool
00418 process_well_model ()
00419 {
00420 if (calc_model_->well_model_var_ == WELL_MODEL_1VAR)
00421 {
00422 return process_well_model_1var ();
00423 }
00424 if (calc_model_->well_model_var_ == WELL_MODEL_3VAR)
00425 {
00426 return process_well_model_3var ();
00427 }
00428
00429 return false;
00430 }
00431
00432 inline bool
00433 process_well_model_1var ()
00434 {
00435 int ret_code = fi_borates_check_well_consistensy ();
00436 if (ret_code < 0)
00437 {
00438 restore_base_vars ();
00439
00440
00441 update_number_of_restarts ();
00442 }
00443 else if (ret_code > 0)
00444 {
00445 restore_base_vars ();
00446
00447 item_t old_dt = dt_;
00448 dt_ = decrease_ts (dt_, large_time_step_end_ - current_time_);
00449
00450 if (fabs (old_dt - dt_) < 1.0e-12)
00451 {
00452 throw bs_exception ("process_well_model_1var", "Newton process failed");
00453 }
00454
00455 update_number_of_restarts ();
00456 }
00457
00458 return ret_code != 0;
00459 }
00460
00461 inline bool
00462 process_well_model_3var ()
00463 {
00464 if (false)
00465 {
00466 restore_base_vars ();
00467
00468
00469
00470 update_number_of_close_wells_restarts ();
00471 update_number_of_restarts ();
00472 return true;
00473 }
00474
00475 return false;
00476 }
00477
00478 inline void
00479 fi_borates_total ()
00480 {
00481
00482 compute_acc_rates ();
00483 }
00484
00485 inline index_t
00486 fi_borates_check_well_consistensy ()
00487 {
00488 BS_ASSERT (false && "NOT IMPL YET");
00489 return 0;
00490 }
00491
00492 inline void
00493 set_approx_solution ()
00494 {
00495 BS_ASSERT (false && "NOT IMPL YET. IN OLD CODE TOO.");
00496 }
00497
00503 inline item_t
00504 get_newton_iters_num () const
00505 {
00506 return params_->get_int (fi_params::NEWTON_ITERS_NUM);
00507 }
00508
00513 inline item_t
00514 get_clamp_pressure () const
00515 {
00516 return params_->get_bool (fi_params::CLAMP_PRESSURE);
00517 }
00518
00524 inline item_t
00525 get_max_tolerance () const
00526 {
00527 return params_->get_float (fi_params::MAX_ALLOWED_LIN_SOLV_RESID);
00528 }
00529
00535 inline item_t
00536 get_small_ts () const
00537 {
00538 return 10 * params_->get_float (fi_params::MIN_TS);
00539 }
00545 inline item_t
00546 get_first_ts () const
00547 {
00548 BOSOUT (section::main_loop, level::low) << "get_first_ts: " << params_->get_float (fi_params::FIRST_TS) << bs_end;
00549 return params_->get_float (fi_params::FIRST_TS);
00550
00551 }
00552
00558 inline index_t
00559 get_n_max_iters () const
00560 {
00561 if (calc_model_->approx_flag)
00562 return params_->get_int (fi_params::APPROX_STEPS);
00563 else
00564 return params_->get_int (fi_params::NEWTON_ITERS_NUM);
00565 }
00566 inline index_t
00567 get_istart () const
00568 {
00569 return 1;
00570 }
00571
00580 inline index_t
00581 compute_small_time_step (fi_operator_impl <strategy_t, is_w, is_g, is_o> &fi_operator,
00582 jacobian_impl <strategy_t> &jacobian_impl_,
00583 index_t &nniters, index_t &nliters)
00584 {
00585 index_t max_n_iters = get_n_max_iters ();
00586 index_t istart = get_istart ();
00587 nniters = 0;
00588 nliters = 0;
00589
00590 for (index_t i = 0; i < max_n_iters + 1; ++i, ++nniters)
00591 {
00592 int init = (i == 0) ? istart : 0;
00593
00594 if (do_calc_prev_fluid_volume_ && init)
00595 fi_operator.calc_prev_fluid_volume ();
00596
00597 if (istart && !number_of_small_time_steps)
00598 {
00599 set_approx_solution ();
00600 }
00601
00602 if (false)
00603 generate_numeric_jacobian (init);
00604
00605 rs_->on_before_fi_operator ();
00606 fi_operator_return_type finish_flag = fi_operator.fi_operator (dt_, init, init, number_of_small_time_steps, true, false);
00607 if (finish_flag == FI_OPERATOR_RETURN_RESTART || i == max_n_iters)
00608 {
00609 return max_n_iters + 1;
00610 }
00611 else if (finish_flag == FI_OPERATOR_RETURN_FAIL)
00612 {
00613 return i;
00614 }
00615
00616 rs_->on_before_jacobian_setup ();
00617 jacobian_impl_.setup_jacobian ();
00618
00619 rs_->on_before_jacobian_solve ();
00620 index_t n_current_liters = 0;
00621 item_t tolerance = jacobian_impl_.solve_jacobian (n_current_liters);
00622 if (tolerance > get_max_tolerance ())
00623 {
00624 return max_n_iters + 1;
00625 }
00626 nliters += n_current_liters;
00627
00628 rs_->on_before_restore_solution ();
00629 fi_operator.save_prev_niter_vars ();
00630 restore_solution_return_type ret_code = calc_model_->restore_solution (fi_operator.mesh_, fi_operator.jmatrix_);
00631 if (ret_code == SMALL_TIME_STEP_CHOP)
00632 {
00633 check_time_step ();
00634 }
00635 else if (ret_code == SMALL_TIME_STEP_FAIL)
00636 {
00637 return max_n_iters + 1;
00638 }
00639
00640 reservoir_->restore_wells_solution (dt_, fi_operator.sol_, fi_operator.jmatrix_->get_sec_solution (), calc_model_->n_phases);
00641 }
00642
00643 return max_n_iters + 1;
00644 }
00645
00646 void print_memory_at_the_end ()
00647 {
00648 #ifdef BS_BOS_CORE_DEBUG_MEMORY
00649 BOSOUT (section::app_info, level::debug) << "at the end" << bs_end;
00650 BS_KERNEL.get_memory_manager ().print_info (false);
00651 #endif
00652 }
00653 void print_memory_before_jacobian_solve ()
00654 {
00655 #ifdef BS_BOS_CORE_DEBUG_MEMORY
00656 BOSOUT (section::app_info, level::debug) << "before solve_jacobian" << bs_end;
00657 BS_KERNEL.get_memory_manager ().print_info (false);
00658 #endif
00659 }
00660 void print_memory_before_jacobian_setup ()
00661 {
00662 #ifdef BS_BOS_CORE_DEBUG_MEMORY
00663 BOSOUT (section::app_info, level::debug) << "before setup_jacobian" << bs_end;
00664 BS_KERNEL.get_memory_manager ().print_info (false);
00665 #endif
00666 }
00667 void print_memory_before_fi_operator ()
00668 {
00669 #ifdef BS_BOS_CORE_DEBUG_MEMORY
00670 BOSOUT (section::app_info, level::debug) << "before fi_operator" << bs_end;
00671 BS_KERNEL.get_memory_manager ().print_info (false);
00672 #endif
00673 }
00674
00680 inline void
00681 generate_numeric_jacobian (int init);
00682
00687 inline void
00688 compute_acc_rates ();
00689
00695 inline void
00696 check_time_step ()
00697 {
00698 if (dt_ < get_small_ts ())
00699 {
00700 throw bs_exception ("compute_small_step", "Non-Linear Equation Convergence Failure");
00701 }
00702 }
00703
00707 inline void
00708 compute_solution_range ()
00709 {
00710 get_min_max_z ();
00711
00712 height_ = max_z_ - min_z_;
00713 rho_ = calc_model_->get_initial_rho (height_);
00714
00715 BS_ASSERT (min_z_ <= max_z_) (min_z_) (max_z_);
00716 calc_model_->update_min_pressure_range (min_z_ - 10);
00717 calc_model_->update_max_pressure_range (max_z_ + 10);
00718 }
00719
00723 inline void
00724 setup_jacobian_solver_params ()
00725 {
00726 jacobian_->setup_solver_params (calc_model_->well_model_type_, calc_model_->n_phases, params_);
00727 }
00731 inline void
00732 setup_jacobian ()
00733 {
00734 if (jacobian_->setup ())
00735 {
00736 throw bs_exception ("compute_small_time_step", "return -1");
00737 }
00738 }
00742 inline item_t
00743 solve_jacobian (index_t &n)
00744 {
00745 return jacobian_->solve (n);
00746 }
00747
00748 inline void
00749 get_min_max_z ()
00750 {
00751 item_t foo;
00752 mesh_->get_dimensions_range (foo, foo, foo, foo, max_z_, min_z_);
00753 }
00754
00758 inline void
00759 save_data ()
00760 {
00761 reservoir_->save_data (facility_storage_);
00762 }
00763
00768 inline bool
00769 check_limits ()
00770 {
00771 return reservoir_->check_limits (params_);
00772 }
00773
00780 inline item_t
00781 decrease_ts (double old_ts, double max_ts) const
00782 {
00783 double new_ts = old_ts * params_->get_float (fi_params::TS_DEC_MULT);
00784 if (new_ts < params_->get_float (fi_params::MIN_TS))
00785 new_ts = params_->get_float (fi_params::MIN_TS);
00786 if (new_ts > params_->get_float (fi_params::MAX_TS))
00787 new_ts = params_->get_float (fi_params::MAX_TS);
00788
00789 if (new_ts * params_->get_float (fi_params::OVERDRAFT) > max_ts)
00790 new_ts = max_ts;
00791
00792 return new_ts;
00793 }
00794
00802 inline item_t
00803 increase_ts (item_t old_ts, item_t max_ts, index_t n_iters) const
00804 {
00805 item_t new_ts;
00806 index_t i, n;
00807 item_t dp = 0;
00808 item_t ds = 0;
00809 item_t drs = 0;
00810 item_t dp_max = 0;
00811 item_t ds_max = 0;
00812 item_t drs_max = 0;
00813 item_t user_dp;
00814 item_t user_ds;
00815 item_t user_drs;
00816 item_t user_omega;
00817 item_t alpha;
00818 item_t alpha2;
00819 index_t ds_w, ds_g;
00820 index_t flag = 0;
00821 index_t dp_i = 0, ds_i = 0, drs_i = 0;
00822 index_t n_left = 0, n_right = 0;
00823
00824 #ifdef _MPI
00825 item_t mpi_dp_max, mpi_ds_max, mpi_drs_max;
00826 #endif //_MPI
00827
00828 if (!params_->get_bool (fi_params::NEW_TS_SELECTION_ALGORITHM))
00829 {
00830 if (n_iters <= params_->get_int (fi_params::NEWTON_ITERS_NUM)
00831 - params_->get_int (fi_params::NEWTON_ITERS_INC))
00832 new_ts = old_ts * params_->get_float (fi_params::TS_INC_MULT);
00833 else
00834 new_ts = old_ts;
00835 }
00836 else
00837 {
00838 BS_ASSERT (mesh_);
00839
00840 user_dp = params_->get_float (fi_params::TS_DP);
00841 user_ds = params_->get_float (fi_params::TS_DS);
00842 user_drs = params_->get_float (fi_params::TS_DRS);
00843 user_omega = params_->get_float (fi_params::TS_OMEGA);
00844 ds_w = calc_model_->sat_d[FI_PHASE_WATER];
00845 ds_g = calc_model_->sat_d[FI_PHASE_GAS];
00846
00847 n = (int)mesh_->get_n_active_elements();
00848
00849 #ifdef _MPI
00850 n_left = 0;
00851 n_right = n;
00852 #else //_MPI
00853 n_left = 0;
00854 n_right = n;
00855 #endif //_MPI
00856
00857
00858 for (i = n_left; i < n_right; ++i)
00859 {
00860 dp = (calc_model_->pressure[i] - calc_model_->old_data_.pressure[i]);
00861 if (fabs (dp_max) < fabs(dp))
00862 {
00863 dp_max = dp;
00864 dp_i = i;
00865 }
00866 }
00867
00868 n_left *= (calc_model_->n_phases);
00869 n_right *= (calc_model_->n_phases);
00870
00871 if (calc_model_->n_phases > 1)
00872 for (i = n_left; i < n_right; ++i)
00873 {
00874 ds = (calc_model_->saturation_3p[i] - calc_model_->old_data_.saturation_3p[i]);
00875 if (fabs (ds_max) < fabs(ds))
00876 {
00877 ds_max = ds;
00878 ds_i = (int)(i / (calc_model_->n_phases));
00879 }
00880 }
00881
00882 if (FI_CHK_OIL_GAS (calc_model_->phases))
00883 {
00884 #ifdef _MPI
00885 n_left = 0;
00886 n_right = n;
00887 #else //_MPI
00888 n_left = 0;
00889 n_right = n;
00890 #endif //_MPI
00891 for (i = n_left; i < n_right; ++i)
00892 {
00893 drs = (calc_model_->old_data_.gas_oil_ratio[i] - calc_model_->gas_oil_ratio[i]);
00894 if (fabs(drs_max) < fabs(drs))
00895 {
00896 drs_max = drs;
00897 drs_i = i;
00898 }
00899
00900 }
00901 }
00902
00903 #ifdef _MPI
00904 BS_ASSERT(false&&"MPI: NOT IMPL YET");
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914 #endif //_MPI
00915
00916 dp = (1.0 + user_omega) * user_dp / (dp_max + user_omega * user_dp);
00917 if (calc_model_->n_phases > 1)
00918 ds = (1.0 + user_omega) * user_ds / (ds_max + user_omega * user_ds);
00919 drs = (1.0 + user_omega) * user_drs / (drs_max + user_omega * user_drs);
00920
00921 BOSOUT (section::main_loop, level::low)
00922 << "dp_max[ " << dp_i << "] = " << dp_max
00923 << ", ds_max[" << ds_i << "] = " << ds_max
00924 << ", drs_max[" << drs_i << "] = " << drs_max
00925 << bs_end;
00926
00927 alpha = dp;
00928
00929 if (calc_model_->n_phases > 1)
00930 if (ds < alpha)
00931 {
00932 alpha = ds;
00933 flag = 1;
00934 }
00935 if (drs < alpha)
00936 {
00937 alpha = drs;
00938 flag = 2;
00939 }
00940
00941 if (alpha < 1)
00942 alpha = 1;
00943 alpha2 = 1.0;
00944 if (n_iters <= params_->get_int (fi_params::NEWTON_ITERS_NUM) - params_->get_int (fi_params::NEWTON_ITERS_INC))
00945 alpha2 = params_->get_float (fi_params::TS_INC_MULT);
00946 if (alpha > alpha2)
00947 alpha = alpha2;
00948 new_ts = old_ts * alpha;
00949 }
00950
00951 if (new_ts < params_->get_float (fi_params::MIN_TS))
00952 new_ts = params_->get_float (fi_params::MIN_TS);
00953 if (new_ts > params_->get_float (fi_params::MAX_TS))
00954 new_ts = params_->get_float (fi_params::MAX_TS);
00955
00956
00957 if (new_ts * params_->get_float (fi_params::OVERDRAFT) > max_ts)
00958 new_ts = max_ts;
00959 else if (new_ts > max_ts)
00960 new_ts = max_ts;
00961 else if (max_ts - new_ts < new_ts)
00962 new_ts = max_ts * 0.5;
00963
00964 BOSOUT (section::main_loop, level::low) << "increase ts: " << old_ts << " -> " << new_ts << bs_end;
00965 return new_ts;
00966 }
00967
00972 inline void
00973 save_base_vars ()
00974 {
00975 calc_model_->old_data_.save (calc_model_);
00976 reservoir_->pre_small_step ();
00977 }
00982 inline void
00983 restore_base_vars ()
00984 {
00985 #ifdef _DEBUG
00986 BOSOUT (section::main_loop, level::debug) << "restore_base_vars" << bs_end;
00987 #endif
00988 calc_model_->old_data_.restore (calc_model_);
00989 reservoir_->restart_small_step ();
00990 }
00991
00996 inline void
00997 update_number_of_newtonian_iterations (index_t nniters)
00998 {
00999 number_of_newtonian_iterations += nniters;
01000 }
01005 inline void
01006 update_number_of_linear_iterations (index_t nliters)
01007 {
01008 number_of_linear_iterations += nliters;
01009 }
01014 inline void
01015 update_current_time (item_t step_)
01016 {
01017 current_time_ += step_;
01018 }
01022 inline void
01023 update_number_of_fi_operator_restarts ()
01024 {
01025 ++number_of_fi_operator_restarts;
01026 }
01030 inline void
01031 update_number_of_restarts ()
01032 {
01033 ++number_of_restarts;
01034 }
01035 inline void
01036 update_number_of_max_iters_restarts ()
01037 {
01038 ++number_of_max_iters_restarts;
01039 }
01040 inline void
01041 update_number_of_close_wells_restarts ()
01042 {
01043 ++number_of_close_wells_restarts;
01044 }
01045
01046
01053 BS_FORCE_INLINE bool
01054 update_large_time_step_length (const ptime ¤t_time, const ptime &next_time)
01055 {
01056 using namespace boost::posix_time;
01057
01058 time_period tp (current_time, next_time);
01059 time_duration td (tp.length ());
01060
01061 large_time_step_length_ = item_t (td.total_milliseconds ()) / item_t (24.0 * 60 * 60 * 1000);
01062
01063 if (large_time_step_length_ > 0)
01064 {
01065 large_time_step_start_ = large_time_step_end_;
01066 large_time_step_end_ = large_time_step_end_ + large_time_step_length_;
01067 return true;
01068 }
01069
01070 return false;
01071 }
01072
01076 inline void
01077 update_large_time_step_num ()
01078 {
01079 ++number_of_large_time_steps;
01080 }
01081
01085 void
01086 print_mesh_info ()
01087 {
01088 BOSOUT (section::mesh, level::medium) << "mesh cells: " << mesh_->get_n_active_elements () << bs_end;
01089 BOSOUT (section::mesh, level::medium) << "mesh connections: " << mesh_->get_n_connections () << bs_end;
01090 }
01091
01095 void
01096 print_pvt_info ()
01097 {
01098 for (size_t i = 0, cnt = calc_model_->pvt_water_array.size (); i < cnt; ++i)
01099 {
01100 calc_model_->pvt_water_array[i]->print ();
01101 }
01102 for (size_t i = 0, cnt = calc_model_->pvt_oil_array.size (); i < cnt; ++i)
01103 {
01104 calc_model_->pvt_oil_array[i]->print ();
01105 }
01106 for (size_t i = 0, cnt = calc_model_->pvt_gas_array.size (); i < cnt; ++i)
01107 {
01108 calc_model_->pvt_gas_array[i]->print ();
01109 }
01110 }
01111
01118 inline void
01119 iteration (const ptime ¤t_time, const ptime &next_time, const sp_event_base_list_t &event_list)
01120 {
01121 using namespace boost::posix_time;
01122 BOSOUT (section::main_loop, level::high) << "\nTIMESTEP " << boost::posix_time::to_simple_string (current_time) << "\n" << bs_end;
01123
01124 if (update_large_time_step_length (current_time, next_time))
01125 {
01126 rs_->pre_large_step (event_list);
01127
01128 rs_->on_large_step_start ();
01129
01130 process_small_steps ();
01131 well_data_printer <strategy_t>::print_prod (data_map_, reservoir_);
01132 well_data_printer <strategy_t>::print_inj (data_map_, reservoir_);
01133 well_data_printer <strategy_t>::print_total_prod (data_map_, reservoir_);
01134
01135 time_step_end ((int)event_list.size ());
01136 }
01137 }
01138
01143 inline void
01144 time_step_end (int total_number_of_time_steps)
01145 {
01146 save_data ();
01147
01148 check_limits ();
01149
01150 update_large_time_step_num ();
01151
01152 static size_t iter_counter = 0;
01153 iter_counter++;
01154
01155
01156 well_data.copy_well_data_to_storage (calc_model_, dt_, reservoir_->get_facility_list ()->wells_begin (), reservoir_->get_facility_list ()->wells_end (), iter_counter, current_time_);
01157
01158 #ifdef _HDF5
01159 reservoir_->write_step_to_hdf5 (calc_model_, mesh_, jacobian_->get_jmatrix (), number_of_large_time_steps, total_number_of_time_steps, current_time_);
01160 #endif
01161
01162 BOSOUT (section::main_loop, level::high) << "number_of_large_time_steps: " << number_of_large_time_steps << bs_end;
01163 BOSOUT (section::main_loop, level::high) << "number_of_small_time_steps: " << number_of_small_time_steps << bs_end;
01164
01165 BOSOUT (section::main_loop, level::high) << "number_of_newtonian_iterations: " << number_of_newtonian_iterations << bs_end;
01166 BOSOUT (section::main_loop, level::high) << "number_of_linear_iterations: " << number_of_linear_iterations << bs_end;
01167 BOSOUT (section::main_loop, level::high) << "number_of_restarts: " << number_of_restarts << bs_end;
01168 BOSOUT (section::main_loop, level::high) << "number_of_max_iters_restarts: " << number_of_max_iters_restarts << bs_end;
01169 BOSOUT (section::main_loop, level::high) << "number_of_fi_operator_restarts: " << number_of_fi_operator_restarts << bs_end;
01170 BOSOUT (section::main_loop, level::high) << "number_of_close_wells_restarts: " << number_of_close_wells_restarts << bs_end;
01171 }
01172
01176 inline void
01177 ready ()
01178 {
01179 print_mesh_info ();
01180 print_pvt_info ();
01181
01182 fi_operator_cells (0);
01183 trans_multipliers_.apply ();
01184
01185 dt_ = get_first_ts ();
01186 save_base_vars ();
01187
01188 #ifdef _HDF5
01189 reservoir_->open_hdf5_file (path::join (path::dirname (rs_->model_filename ()), "results.h5"));
01190 reservoir_->write_mesh_to_hdf5 (mesh_);
01191 boost::gregorian::date start_date = rs_->keyword_manager_->get_starting_date ().date ();
01192 boost::gregorian::date base_date (1900, 1, 1);
01193 double starting_date = (start_date - base_date).days () + 2;
01194 reservoir_->get_hdf5_file ()->write_array ("/initial_data", "starting_date", &starting_date, 1);
01195 #endif
01196 }
01197
01201 inline void
01202 go ()
01203 {
01204 typename event_manager <strategy_t> ::event_map::iterator it = event_manager_->event_list.begin ();
01205 typename event_manager <strategy_t> ::event_map::iterator e = event_manager_->event_list.end ();
01206
01207 rs_->on_simulation_start ();
01208 for (--e; it != e; ++it)
01209 {
01210 typename event_manager <strategy_t> ::event_map::iterator it2 = it;
01211 ++it2;
01212
01213 iteration (it->first, it2->first, it->second);
01214 }
01215 }
01216
01220 inline void
01221 end ()
01222 {
01223 #ifdef _HDF5
01224 reservoir_->close_hdf5_file ();
01225 #endif
01226
01227 BOSOUT (section::main_loop, level::high) << "TOTAL: " << bs_end;
01228 BOSOUT (section::main_loop, level::high) << "number_of_large_time_steps: " << number_of_large_time_steps << bs_end;
01229 BOSOUT (section::main_loop, level::high) << "number_of_small_time_steps: " << number_of_small_time_steps << bs_end;
01230
01231 BOSOUT (section::main_loop, level::high) << "number_of_newtonian_iterations: " << number_of_newtonian_iterations << bs_end;
01232 BOSOUT (section::main_loop, level::high) << "number_of_linear_iterations: " << number_of_linear_iterations << bs_end;
01233 BOSOUT (section::main_loop, level::high) << "number_of_restarts: " << number_of_restarts << bs_end;
01234 BOSOUT (section::main_loop, level::high) << "number_of_max_iters_restarts: " << number_of_max_iters_restarts << bs_end;
01235 BOSOUT (section::main_loop, level::high) << "number_of_fi_operator_restarts: " << number_of_fi_operator_restarts << bs_end;
01236 BOSOUT (section::main_loop, level::high) << "number_of_close_wells_restarts: " << number_of_close_wells_restarts << bs_end;
01237 }
01238
01242 inline void
01243 reset_init_approx ()
01244 {
01245 reservoir_->reset_init_approx ();
01246 }
01250 inline void
01251 reset_wells ()
01252 {
01253 reservoir_->reinit_wells (true);
01254 }
01255
01256 public:
01257
01258 sp_rs_t rs_;
01259 sp_calc_model_t calc_model_;
01260 sp_event_manager_t event_manager_;
01261 sp_rock_grid_t rock_grid_prop_;
01262 sp_storage_t facility_storage_;
01263 sp_reservoir_t reservoir_;
01264 sp_mesh_iface_t mesh_;
01265 sp_jacobian_t jacobian_;
01266 sp_fi_params_t params_;
01267 sp_idata_t data_map_;
01268 trans_multipliers_calc_t trans_multipliers_;
01269
01270 public:
01271 item_t height_;
01272 item_t rho_;
01273 item_t min_z_;
01274 item_t max_z_;
01275
01276 double dt_;
01277 double current_time_;
01278
01279 item_t large_time_step_length_;
01280 item_t large_time_step_start_;
01281 item_t large_time_step_end_;
01282
01283 index_t num_last_newton_iters_;
01284 index_t num_last_lin_iters_;
01285
01286 index_t number_of_small_time_steps;
01287 index_t number_of_large_time_steps;
01288
01289 index_t number_of_newtonian_iterations;
01290 index_t number_of_linear_iterations;
01291 index_t number_of_restarts;
01292 index_t number_of_max_iters_restarts;
01293 index_t number_of_fi_operator_restarts;
01294 index_t number_of_close_wells_restarts;
01295
01296 bool do_calc_prev_fluid_volume_;
01297
01298 save_connection_data <strategy_t> connection_data;
01299 save_well_data <strategy_t> well_data;
01300 };
01301
01302
01303 }
01304
01305 #include "generate_numeric_jacobian.h"
01306 #include "compute_acc_rates.h"
01307
01308 #endif // #ifndef BS_MAIN_LOOP_CALC_H_
01309