Flow123d  release_3.0.0-506-g34af125
darcy_flow_mh.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file darcy_flow_mh.cc
15  * @ingroup flow
16  * @brief Setup and solve linear system of mixed-hybrid discretization of the linear
17  * porous media flow with possible preferential flow in fractures and chanels.
18  */
19 
20 //#include <limits>
21 #include <vector>
22 //#include <iostream>
23 //#include <iterator>
24 //#include <algorithm>
25 #include <armadillo>
26 
27 #include "petscmat.h"
28 #include "petscviewer.h"
29 #include "petscerror.h"
30 #include "mpi.h"
31 
32 #include "system/system.hh"
33 #include "system/sys_profiler.hh"
34 #include "input/factory.hh"
35 
36 #include "mesh/side_impl.hh"
37 #include "mesh/long_idx.hh"
38 #include "mesh/mesh.h"
39 #include "mesh/partitioning.hh"
40 #include "mesh/accessors.hh"
41 #include "mesh/range_wrapper.hh"
42 #include "la/distribution.hh"
43 #include "la/linsys.hh"
44 #include "la/linsys_PETSC.hh"
45 #include "la/linsys_BDDC.hh"
46 #include "la/schur.hh"
47 //#include "la/sparse_graph.hh"
49 
50 #include "flow/darcy_flow_mh.hh"
51 
53 
54 
55 #include "tools/time_governor.hh"
57 #include "fields/field.hh"
58 #include "fields/field_values.hh"
60 
61 #include "coupling/balance.hh"
62 
63 #include "fields/vec_seq_double.hh"
64 
65 #include "darcy_flow_assembly.hh"
66 
69 
70 
71 FLOW123D_FORCE_LINK_IN_CHILD(darcy_flow_mh);
72 
73 
74 
75 
76 namespace it = Input::Type;
77 
79  return it::Selection("MH_MortarMethod")
80  .add_value(NoMortar, "None", "Mortar space: P0 on elements of lower dimension.")
81  .add_value(MortarP0, "P0", "Mortar space: P0 on elements of lower dimension.")
82  .add_value(MortarP1, "P1", "Mortar space: P1 on intersections, using non-conforming pressures.")
83  .close();
84 }
85 
86 
88  return it::Selection("Flow_Darcy_BC_Type")
89  .add_value(none, "none",
90  "Homogeneous Neumann boundary condition. Zero flux")
91  .add_value(dirichlet, "dirichlet",
92  "Dirichlet boundary condition. "
93  "Specify the pressure head through the ''bc_pressure'' field "
94  "or the piezometric head through the ''bc_piezo_head'' field.")
95  .add_value(total_flux, "total_flux", "Flux boundary condition (combines Neumann and Robin type). "
96  "Water inflow equal to (($ \\delta_d(q_d^N + \\sigma_d (h_d^R - h_d) )$)). "
97  "Specify the water inflow by the 'bc_flux' field, the transition coefficient by 'bc_robin_sigma' "
98  "and the reference pressure head or pieozmetric head through ''bc_pressure'' or ''bc_piezo_head'' respectively.")
99  .add_value(seepage, "seepage",
100  "Seepage face boundary condition. Pressure and inflow bounded from above. Boundary with potential seepage flow "
101  "is described by the pair of inequalities: "
102  "(($h_d \\le h_d^D$)) and (($ -\\boldsymbol q_d\\cdot\\boldsymbol n \\le \\delta q_d^N$)), where the equality holds in at least one of them. "
103  "Caution. Setting (($q_d^N$)) strictly negative "
104  "may lead to an ill posed problem since a positive outflow is enforced. "
105  "Parameters (($h_d^D$)) and (($q_d^N$)) are given by fields ``bc_switch_pressure`` (or ``bc_switch_piezo_head``) and ``bc_flux`` respectively."
106  )
107  .add_value(river, "river",
108  "River boundary condition. For the water level above the bedrock, (($H_d > H_d^S$)), the Robin boundary condition is used with the inflow given by: "
109  "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d) )$)). For the water level under the bedrock, constant infiltration is used: "
110  "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d^S) )$)). Parameters: ``bc_pressure``, ``bc_switch_pressure``, "
111  " ``bc_sigma, ``bc_flux``."
112  )
113  .close();
114 }
115 
117 
118  const it::Record &field_descriptor =
119  it::Record("Flow_Darcy_MH_Data",FieldCommon::field_descriptor_record_description("Flow_Darcy_MH_Data") )
120  .copy_keys( DarcyMH::EqData().make_field_descriptor_type("Flow_Darcy_MH_Data_aux") )
121  .declare_key("bc_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type_instance(),
122  "Boundary piezometric head for BC types: dirichlet, robin, and river." )
123  .declare_key("bc_switch_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type_instance(),
124  "Boundary switch piezometric head for BC types: seepage, river." )
125  .declare_key("init_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type_instance(),
126  "Initial condition for the pressure given as the piezometric head." )
127  .close();
128  return field_descriptor;
129 }
130 
132 
133  it::Record ns_rec = Input::Type::Record("NonlinearSolver", "Parameters to a non-linear solver.")
134  .declare_key("linear_solver", LinSys::get_input_type(), it::Default("{}"),
135  "Linear solver for MH problem.")
136  .declare_key("tolerance", it::Double(0.0), it::Default("1E-6"),
137  "Residual tolerance.")
138  .declare_key("min_it", it::Integer(0), it::Default("1"),
139  "Minimum number of iterations (linear solves) to use. This is usefull if the convergence criteria "
140  "does not characterize your goal well enough so it converges prematurely possibly without the single linear solve."
141  "If greater then 'max_it' the value is set to 'max_it'.")
142  .declare_key("max_it", it::Integer(0), it::Default("100"),
143  "Maximum number of iterations (linear solves) of the non-linear solver.")
144  .declare_key("converge_on_stagnation", it::Bool(), it::Default("false"),
145  "If a stagnation of the nonlinear solver is detected the solver stops. "
146  "A divergence is reported by default forcing the end of the simulation. Setting this flag to 'true', the solver"
147  "ends with convergence success on stagnation, but report warning about it.")
148  .close();
149 
150  return it::Record("Flow_Darcy_MH", "Mixed-Hybrid solver for STEADY saturated Darcy flow.")
152  .declare_key("gravity", it::Array(it::Double(), 3,3), it::Default("[ 0, 0, -1]"),
153  "Vector of the gravity force. Dimensionless.")
155  "Input data for Darcy flow model.")
156  .declare_key("nonlinear_solver", ns_rec, it::Default("{}"),
157  "Non-linear solver for MH problem.")
158  .declare_key("output_stream", OutputTime::get_input_type(), it::Default("{}"),
159  "Parameters of output stream.")
160 
161  .declare_key("output", DarcyFlowMHOutput::get_input_type(), IT::Default("{ \"fields\": [ \"pressure_p0\", \"velocity_p0\" ] }"),
162  "Parameters of output from MH module.")
164  "Parameters of output form MH module.")
165  .declare_key("balance", Balance::get_input_type(), it::Default("{}"),
166  "Settings for computing mass balance.")
168  "Time governor setting for the unsteady Darcy flow model.")
169  .declare_key("n_schurs", it::Integer(0,2), it::Default("2"),
170  "Number of Schur complements to perform when solving MH system.")
171  .declare_key("mortar_method", get_mh_mortar_selection(), it::Default("\"None\""),
172  "Method for coupling Darcy flow between dimensions." )
173  .close();
174 }
175 
176 
177 const int DarcyMH::registrar =
178  Input::register_class< DarcyMH, Mesh &, const Input::Record >("Flow_Darcy_MH") +
180 
181 
182 
184 {
185  mortar_method_=NoMortar;
186 
187  ADD_FIELD(anisotropy, "Anisotropy of the conductivity tensor.", "1.0" );
188  anisotropy.units( UnitSI::dimensionless() );
189 
190  ADD_FIELD(cross_section, "Complement dimension parameter (cross section for 1D, thickness for 2D).", "1.0" );
191  cross_section.units( UnitSI().m(3).md() );
192 
193  ADD_FIELD(conductivity, "Isotropic conductivity scalar.", "1.0" );
194  conductivity.units( UnitSI().m().s(-1) ).set_limits(0.0);
195 
196  ADD_FIELD(sigma, "Transition coefficient between dimensions.", "1.0");
197  sigma.units( UnitSI::dimensionless() );
198 
199  ADD_FIELD(water_source_density, "Water source density.", "0.0");
200  water_source_density.units( UnitSI().s(-1) );
201 
202  ADD_FIELD(bc_type,"Boundary condition type, possible values:", "\"none\"" );
203  // TODO: temporary solution, we should try to get rid of pointer to the selection after having generic types
204  bc_type.input_selection( get_bc_type_selection() );
205  bc_type.units( UnitSI::dimensionless() );
206 
207  ADD_FIELD(bc_pressure,"Prescribed pressure value on the boundary. Used for all values of 'bc_type' except for 'none' and 'seepage'. "
208  "See documentation of 'bc_type' for exact meaning of 'bc_pressure' in individual boundary condition types.", "0.0");
209  bc_pressure.disable_where(bc_type, {none, seepage} );
210  bc_pressure.units( UnitSI().m() );
211 
212  ADD_FIELD(bc_flux,"Incoming water boundary flux. Used for bc_types : 'total_flux', 'seepage', 'river'.", "0.0");
213  bc_flux.disable_where(bc_type, {none, dirichlet} );
214  bc_flux.units( UnitSI().m(4).s(-1).md() );
215 
216  ADD_FIELD(bc_robin_sigma,"Conductivity coefficient in the 'total_flux' or the 'river' boundary condition type.", "0.0");
217  bc_robin_sigma.disable_where(bc_type, {none, dirichlet, seepage} );
218  bc_robin_sigma.units( UnitSI().m(3).s(-1).md() );
219 
220  ADD_FIELD(bc_switch_pressure,
221  "Critical switch pressure for 'seepage' and 'river' boundary conditions.", "0.0");
222  bc_switch_pressure.disable_where(bc_type, {none, dirichlet, total_flux} );
223  bc_switch_pressure.units( UnitSI().m() );
224 
225  //these are for unsteady
226  ADD_FIELD(init_pressure, "Initial condition for pressure", "0.0" );
227  init_pressure.units( UnitSI().m() );
228 
229  ADD_FIELD(storativity,"Storativity.", "0.0" );
230  storativity.units( UnitSI().m(-1) );
231 
232  //time_term_fields = this->subset({"storativity"});
233  //main_matrix_fields = this->subset({"anisotropy", "conductivity", "cross_section", "sigma", "bc_type", "bc_robin_sigma"});
234  //rhs_fields = this->subset({"water_source_density", "bc_pressure", "bc_flux"});
235 
236 }
237 
238 
239 
240 
241 
242 
243 //=============================================================================
244 // CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL
245 // - do it in parallel:
246 // - initial distribution of elements, edges
247 //
248 /*! @brief CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL
249  *
250  * Parameters {Solver,NSchurs} number of performed Schur
251  * complements (0,1,2) for water flow MH-system
252  *
253  */
254 //=============================================================================
255 DarcyMH::DarcyMH(Mesh &mesh_in, const Input::Record in_rec)
256 : DarcyFlowInterface(mesh_in, in_rec),
257  output_object(nullptr),
258  solution(nullptr),
259  data_changed_(false),
260  schur0(nullptr),
261  steady_diagonal(nullptr),
262  steady_rhs(nullptr),
263  new_diagonal(nullptr),
264  previous_solution(nullptr)
265 {
266 
267  START_TIMER("Darcy constructor");
268  {
269  auto time_record = input_record_.val<Input::Record>("time");
270  //if ( in_rec.opt_val("time", time_record) )
271  time_ = new TimeGovernor(time_record);
272  //else
273  // time_ = new TimeGovernor();
274  }
275 
276  data_ = make_shared<EqData>();
278 
279  data_->is_linear=true;
280 
281  size = mesh_->n_elements() + mesh_->n_sides() + mesh_->n_edges();
282  n_schur_compls = in_rec.val<int>("n_schurs");
283  data_->mortar_method_= in_rec.val<MortarMethod>("mortar_method");
284  if (data_->mortar_method_ != NoMortar) {
286  }
287 
288 
289 
290  //side_ds->view( std::cout );
291  //el_ds->view( std::cout );
292  //edge_ds->view( std::cout );
293  //rows_ds->view( std::cout );
294 
295 }
296 
297 
298 
300 //connecting data fields with mesh
301 {
302 
303  START_TIMER("data init");
304  data_->mesh = mesh_;
305  data_->mh_dh = &mh_dh;
306  data_->set_mesh(*mesh_);
307 
308  auto gravity_array = input_record_.val<Input::Array>("gravity");
309  std::vector<double> gvec;
310  gravity_array.copy_to(gvec);
311  gvec.push_back(0.0); // zero pressure shift
312  data_->gravity_ = arma::vec(gvec);
313  data_->gravity_vec_ = data_->gravity_.subvec(0,2);
314 
315  data_->bc_pressure.add_factory(
316  std::make_shared<FieldAddPotential<3, FieldValue<3>::Scalar>::FieldFactory>
317  (data_->gravity_, "bc_piezo_head") );
318  data_->bc_switch_pressure.add_factory(
319  std::make_shared<FieldAddPotential<3, FieldValue<3>::Scalar>::FieldFactory>
320  (data_->gravity_, "bc_switch_piezo_head") );
321  data_->init_pressure.add_factory(
322  std::make_shared<FieldAddPotential<3, FieldValue<3>::Scalar>::FieldFactory>
323  (data_->gravity_, "init_piezo_head") );
324 
325 
326  data_->set_input_list( this->input_record_.val<Input::Array>("input_fields"), *time_ );
327  // Check that the time step was set for the transient simulation.
328  if (! zero_time_term(true) && time_->is_default() ) {
329  //THROW(ExcAssertMsg());
330  //THROW(ExcMissingTimeGovernor() << input_record_.ei_address());
331  MessageOut() << "Missing the key 'time', obligatory for the transient problems." << endl;
332  ASSERT(false);
333  }
334 
335  data_->mark_input_times(*time_);
336 }
337 
338 
339 
341 
342  init_eq_data();
344 
345  mh_dh.reinit(mesh_);
346  // Initialize bc_switch_dirichlet to size of global boundary.
347  data_->bc_switch_dirichlet.resize(mesh_->n_elements()+mesh_->n_elements(true), 1);
348 
349 
352  .val<Input::Record>("nonlinear_solver")
353  .val<Input::AbstractRecord>("linear_solver");
354 
355  // auxiliary set_time call since allocation assembly evaluates fields as well
358 
359 
360 
361  // allocate time term vectors
362  VecDuplicate(schur0->get_solution(), &previous_solution);
363  VecCreateMPI(PETSC_COMM_WORLD, mh_dh.rows_ds->lsize(),PETSC_DETERMINE,&(steady_diagonal));
364  VecDuplicate(steady_diagonal,& new_diagonal);
365  VecZeroEntries(new_diagonal);
366  VecDuplicate(steady_diagonal, &steady_rhs);
367 
368 
369  // initialization of balance object
370  balance_ = std::make_shared<Balance>("water", mesh_);
371  balance_->init_from_input(input_record_.val<Input::Record>("balance"), time());
372  data_->water_balance_idx = balance_->add_quantity("water_volume");
373  balance_->allocate(mh_dh.rows_ds->lsize(), 1);
374  balance_->units(UnitSI().m(3));
375 
376 
377  data_->balance = balance_;
378  data_->lin_sys = schur0;
379 
380 
382 }
383 
385 {}
386 
388 {
389 
390  /* TODO:
391  * - Allow solution reconstruction (pressure and velocity) from initial condition on user request.
392  * - Steady solution as an intitial condition may be forced by setting inti_time =-1, and set data for the steady solver in that time.
393  * Solver should be able to switch from and to steady case depending on the zero time term.
394  */
395 
397 
398  // zero_time_term means steady case
399  bool zero_time_term_from_right = zero_time_term();
400 
401 
402  if (zero_time_term_from_right) {
403  // steady case
404  VecZeroEntries(schur0->get_solution());
405  //read_initial_condition(); // Possible solution guess for steady case.
406  use_steady_assembly_ = true;
407  solve_nonlinear(); // with right limit data
408  } else {
409  VecZeroEntries(schur0->get_solution());
410  VecZeroEntries(previous_solution);
412  assembly_linear_system(); // in particular due to balance
413 // print_matlab_matrix("matrix_zero");
414  // TODO: reconstruction of solution in zero time.
415  }
416  //solution_output(T,right_limit); // data for time T in any case
417  output_data();
418 }
419 
420 //=============================================================================
421 // COMPOSE and SOLVE WATER MH System possibly through Schur complements
422 //=============================================================================
424 {
425  START_TIMER("Solving MH system");
426 
427  time_->next_time();
428 
429  time_->view("DARCY"); //time governor information output
431  bool zero_time_term_from_left=zero_time_term();
432 
433  bool jump_time = data_->storativity.is_jump_time();
434  if (! zero_time_term_from_left) {
435  // time term not treated as zero
436  // Unsteady solution up to the T.
437 
438  // this flag is necesssary for switching BC to avoid setting zero neumann on the whole boundary in the steady case
439  use_steady_assembly_ = false;
440  prepare_new_time_step(); //SWAP
441 
442  solve_nonlinear(); // with left limit data
443  if (jump_time) {
444  WarningOut() << "Output of solution discontinuous in time not supported yet.\n";
445  //solution_output(T, left_limit); // output use time T- delta*dt
446  //output_data();
447  }
448  }
449 
450  if (time_->is_end()) {
451  // output for unsteady case, end_time should not be the jump time
452  // but rether check that
453  if (! zero_time_term_from_left && ! jump_time) output_data();
454  return;
455  }
456 
458  bool zero_time_term_from_right=zero_time_term();
459  if (zero_time_term_from_right) {
460  // this flag is necesssary for switching BC to avoid setting zero neumann on the whole boundary in the steady case
461  use_steady_assembly_ = true;
462  solve_nonlinear(); // with right limit data
463 
464  } else if (! zero_time_term_from_left && jump_time) {
465  WarningOut() << "Discontinuous time term not supported yet.\n";
466  //solution_transfer(); // internally call set_time(T, left) and set_time(T,right) again
467  //solve_nonlinear(); // with right limit data
468  }
469  //solution_output(T,right_limit); // data for time T in any case
470  output_data();
471 
472 }
473 
474 bool DarcyMH::zero_time_term(bool time_global) {
475  if (time_global) {
476  return (data_->storativity.input_list_size() == 0);
477  } else {
478  return data_->storativity.field_result(mesh_->region_db().get_region_set("BULK")) == result_zeros;
479  }
480 }
481 
482 
484 {
485 
487  double residual_norm = schur0->compute_residual();
489  MessageOut().fmt("[nonlinear solver] norm of initial residual: {}\n", residual_norm);
490 
491  // Reduce is_linear flag.
492  int is_linear_common;
493  MPI_Allreduce(&(data_->is_linear), &is_linear_common,1, MPI_INT ,MPI_MIN,PETSC_COMM_WORLD);
494 
495  Input::Record nl_solver_rec = input_record_.val<Input::Record>("nonlinear_solver");
496  this->tolerance_ = nl_solver_rec.val<double>("tolerance");
497  this->max_n_it_ = nl_solver_rec.val<unsigned int>("max_it");
498  this->min_n_it_ = nl_solver_rec.val<unsigned int>("min_it");
499  if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->max_n_it_;
500 
501  if (! is_linear_common) {
502  // set tolerances of the linear solver unless they are set by user.
503  schur0->set_tolerances(0.1*this->tolerance_, 0.01*this->tolerance_, 100);
504  }
505  vector<double> convergence_history;
506 
507  Vec save_solution;
508  VecDuplicate(schur0->get_solution(), &save_solution);
509  while (nonlinear_iteration_ < this->min_n_it_ ||
510  (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->max_n_it_ )) {
511  OLD_ASSERT_EQUAL( convergence_history.size(), nonlinear_iteration_ );
512  convergence_history.push_back(residual_norm);
513 
514  // stagnation test
515  if (convergence_history.size() >= 5 &&
516  convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
517  convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
518  // stagnation
519  if (input_record_.val<Input::Record>("nonlinear_solver").val<bool>("converge_on_stagnation")) {
520  WarningOut().fmt("Accept solution on stagnation. Its: {} Residual: {}\n", nonlinear_iteration_, residual_norm);
521  break;
522  } else {
523  THROW(ExcSolverDiverge() << EI_Reason("Stagnation."));
524  }
525  }
526 
527  if (! is_linear_common)
528  VecCopy( schur0->get_solution(), save_solution);
531 
532  // hack to make BDDC work with empty compute_residual
533  if (is_linear_common){
534  // we want to print this info in linear (and steady) case
535  residual_norm = schur0->compute_residual();
536  MessageOut().fmt("[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
537  si.n_iterations, si.converged_reason, residual_norm);
538  break;
539  }
540  data_changed_=true; // force reassembly for non-linear case
541 
542  double alpha = 1; // how much of new solution
543  VecAXPBY(schur0->get_solution(), (1-alpha), alpha, save_solution);
544 
545  /*
546  double * sol;
547  unsigned int sol_size;
548  get_solution_vector(sol, sol_size);
549  if (mh_dh.el_ds->myp() == 0)
550  VecView(sol_vec, PETSC_VIEWER_STDOUT_SELF);
551  */
552 
553  //LogOut().fmt("Linear solver ended with reason: {} \n", si.converged_reason );
554  //OLD_ASSERT( si.converged_reason >= 0, "Linear solver failed to converge. Convergence reason %d \n", si.converged_reason );
556 
557  residual_norm = schur0->compute_residual();
558  MessageOut().fmt("[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
559  nonlinear_iteration_, si.n_iterations, si.converged_reason, residual_norm);
560  }
561  chkerr(VecDestroy(&save_solution));
562  this -> postprocess();
563 
564  // adapt timestep
565  if (! this->zero_time_term()) {
566  double mult = 1.0;
567  if (nonlinear_iteration_ < 3) mult = 1.6;
568  if (nonlinear_iteration_ > 7) mult = 0.7;
569  int result = time_->set_upper_constraint(time_->dt() * mult, "Darcy adaptivity.");
570  //DebugOut().fmt("time adaptivity, res: {} it: {} m: {} dt: {} edt: {}\n", result, nonlinear_iteration_, mult, time_->dt(), time_->estimate_dt());
571  }
572 
574 
575 }
576 
577 
579 {
580  //VecSwap(previous_solution, schur0->get_solution());
581 }
582 
584 {
585  START_TIMER("postprocess");
586 
587  //fix velocity when mortar method is used
588  if(data_->mortar_method_ != MortarMethod::NoMortar){
589  auto multidim_assembler = AssemblyBase::create< AssemblyMH >(data_);
590  for (unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++) {
591  auto ele_ac = mh_dh.accessor(i_loc);
592  unsigned int dim = ele_ac.dim();
593  multidim_assembler[dim-1]->fix_velocity(ele_ac);
594  }
595  }
596  //ElementAccessor<3> ele;
597 
598  // modify side fluxes in parallel
599  // for every local edge take time term on digonal and add it to the corresponding flux
600  /*
601  for (unsigned int i_loc = 0; i_loc < el_ds->lsize(); i_loc++) {
602  ele = mesh_->element_accessor(el_4_loc[i_loc]);
603  for (unsigned int i=0; i<ele->n_sides(); i++) {
604  side_rows[i] = side_row_4_id[ mh_dh.side_dof( ele_ac.side(i) ) ];
605  values[i] = -1.0 * ele_ac.measure() *
606  data.cross_section.value(ele_ac.centre(), ele_ac.element_accessor()) *
607  data.water_source_density.value(ele_ac.centre(), ele_ac.element_accessor()) /
608  ele_ac.n_sides();
609  }
610  VecSetValues(schur0->get_solution(), ele_ac.n_sides(), side_rows, values, ADD_VALUES);
611  }
612  VecAssemblyBegin(schur0->get_solution());
613  VecAssemblyEnd(schur0->get_solution());
614  */
615 }
616 
617 
619  START_TIMER("Darcy output data");
620  //time_->view("DARCY"); //time governor information output
621  this->output_object->output();
622 
623 
624  START_TIMER("Darcy balance output");
625  balance_->calculate_cumulative(data_->water_balance_idx, schur0->get_solution());
626  balance_->calculate_instant(data_->water_balance_idx, schur0->get_solution());
627  balance_->output();
628 }
629 
630 
632 {
633  return schur0->get_solution_precision();
634 }
635 
636 
637 
638 void DarcyMH::get_solution_vector(double * &vec, unsigned int &vec_size)
639 {
640  // TODO: make class for vectors (wrapper for PETSC or other) derived from LazyDependency
641  // and use its mechanism to manage dependency between vectors
643 
644  // scatter solution to all procs
645  VecScatterBegin(par_to_all, schur0->get_solution(), sol_vec, INSERT_VALUES, SCATTER_FORWARD);
646  VecScatterEnd( par_to_all, schur0->get_solution(), sol_vec, INSERT_VALUES, SCATTER_FORWARD);
648  }
649 
650  vec = solution;
651  vec_size = this->size;
652  OLD_ASSERT(vec != NULL, "Requested solution is not allocated!\n");
653 }
654 
656 {
657  vec=schur0->get_solution();
658  OLD_ASSERT(vec != NULL, "Requested solution is not allocated!\n");
659 }
660 
661 
662 // ===========================================================================================
663 //
664 // MATRIX ASSEMBLY - we use abstract assembly routine, where LS Mat/Vec SetValues
665 // are in fact pointers to allocating or filling functions - this is governed by Linsystem roitunes
666 //
667 // =======================================================================================
669 {
670  START_TIMER("DarcyFlowMH_Steady::assembly_steady_mh_matrix");
671 
672  // set auxiliary flag for switchting Dirichlet like BC
673  data_->force_bc_switch = use_steady_assembly_ && (nonlinear_iteration_ == 0);
674  data_->n_schur_compls = n_schur_compls;
675 
676 
677  balance_->start_flux_assembly(data_->water_balance_idx);
678 
679  // TODO: try to move this into balance, or have it in the generic assembler class, that should perform the cell loop
680  // including various pre- and post-actions
681  data_->local_boundary_index=0;
682  for (unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++) {
683  auto ele_ac = mh_dh.accessor(i_loc);
684  unsigned int dim = ele_ac.dim();
685  assembler[dim-1]->assemble(ele_ac);
686  }
687 
688 
689  balance_->finish_flux_assembly(data_->water_balance_idx);
690 
691 }
692 
693 
695 {
696  START_TIMER("DarcyFlowMH_Steady::allocate_mh_matrix");
697 
698  // set auxiliary flag for switchting Dirichlet like BC
699  data_->n_schur_compls = n_schur_compls;
700  LinSys *ls = schur0;
701 
702 
703 
704  int local_dofs[10];
705 
706  // to make space for second schur complement, max. 10 neighbour edges of one el.
707  double zeros[100000];
708  for(int i=0; i<100000; i++) zeros[i] = 0.0;
709 
710  std::vector<int> tmp_rows;
711  tmp_rows.reserve(200);
712 
713  unsigned int nsides, loc_size;
714 
715  for (unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++) {
716  auto ele_ac = mh_dh.accessor(i_loc);
717  nsides = ele_ac.n_sides();
718 
719  //allocate at once matrix [sides,ele,edges]x[sides,ele,edges]
720  loc_size = 1 + 2*nsides;
721  unsigned int i_side = 0;
722 
723  for (; i_side < nsides; i_side++) {
724  local_dofs[i_side] = ele_ac.side_row(i_side);
725  local_dofs[i_side+nsides] = ele_ac.edge_row(i_side);
726  }
727  local_dofs[i_side+nsides] = ele_ac.ele_row();
728  int * edge_rows = local_dofs + nsides;
729  //int ele_row = local_dofs[0];
730 
731  // whole local MH matrix
732  ls->mat_set_values(loc_size, local_dofs, loc_size, local_dofs, zeros);
733 
734 
735  // compatible neighborings rows
736  unsigned int n_neighs = ele_ac.element_accessor()->n_neighs_vb();
737  for (unsigned int i = 0; i < n_neighs; i++) {
738  // every compatible connection adds a 2x2 matrix involving
739  // current element pressure and a connected edge pressure
740  Neighbour *ngh = ele_ac.element_accessor()->neigh_vb[i];
741  int neigh_edge_row = mh_dh.row_4_edge[ ngh->edge_idx() ];
742  tmp_rows.push_back(neigh_edge_row);
743  //DebugOut() << "CC" << print_var(tmp_rows[i]);
744  }
745 
746  // allocate always also for schur 2
747  ls->mat_set_values(nsides+1, edge_rows, n_neighs, tmp_rows.data(), zeros); // (edges, ele) x (neigh edges)
748  ls->mat_set_values(n_neighs, tmp_rows.data(), nsides+1, edge_rows, zeros); // (neigh edges) x (edges, ele)
749  ls->mat_set_values(n_neighs, tmp_rows.data(), n_neighs, tmp_rows.data(), zeros); // (neigh edges) x (neigh edges)
750 
751  tmp_rows.clear();
752 
753  if (data_->mortar_method_ != NoMortar) {
754  auto &isec_list = mesh_->mixed_intersections().element_intersections_[ele_ac.ele_global_idx()];
755  for(auto &isec : isec_list ) {
756  IntersectionLocalBase *local = isec.second;
757  ElementAccessor<3> slave_ele = mesh_->element_accessor( local->bulk_ele_idx() );
758  //DebugOut().fmt("Alloc: {} {}", ele_ac.ele_global_idx(), local->bulk_ele_idx());
759  for(unsigned int i_side=0; i_side < slave_ele->n_sides(); i_side++) {
760  tmp_rows.push_back( mh_dh.row_4_edge[ slave_ele.side(i_side)->edge_idx() ] );
761  //DebugOut() << "aedge" << print_var(tmp_rows[i_rows-1]);
762  }
763  }
764  }
765  /*
766  for(unsigned int i_side=0; i_side < ele_ac.element_accessor()->n_sides(); i_side++) {
767  DebugOut() << "aedge:" << print_var(edge_rows[i_side]);
768  }*/
769 
770  ls->mat_set_values(nsides, edge_rows, tmp_rows.size(), tmp_rows.data(), zeros); // master edges x neigh edges
771  ls->mat_set_values(tmp_rows.size(), tmp_rows.data(), nsides, edge_rows, zeros); // neigh edges x master edges
772  ls->mat_set_values(tmp_rows.size(), tmp_rows.data(), tmp_rows.size(), tmp_rows.data(), zeros); // neigh edges x neigh edges
773 
774  }
775 /*
776  // alloc edge diagonal entries
777  if(rank == 0)
778  for( vector<Edge>::iterator edg = mesh_->edges.begin(); edg != mesh_->edges.end(); ++edg) {
779  int edg_idx = mh_dh.row_4_edge[edg->side(0)->edge_idx()];
780 
781 // for( vector<Edge>::iterator edg2 = mesh_->edges.begin(); edg2 != mesh_->edges.end(); ++edg2){
782 // int edg_idx2 = mh_dh.row_4_edge[edg2->side(0)->edge_idx()];
783 // if(edg_idx == edg_idx2){
784 // DBGCOUT(<< "P[ " << rank << " ] " << "edg alloc: " << edg_idx << " " << edg_idx2 << "\n");
785  ls->mat_set_value(edg_idx, edg_idx, 0.0);
786 // }
787 // }
788  }
789  */
790  /*
791  if (mortar_method_ == MortarP0) {
792  P0_CouplingAssembler(*this).assembly(*ls);
793  } else if (mortar_method_ == MortarP1) {
794  P1_CouplingAssembler(*this).assembly(*ls);
795  }*/
796 }
797 
799 {
800  START_TIMER("assembly source term");
801  balance_->start_source_assembly(data_->water_balance_idx);
802 
803  for (unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++) {
804  auto ele_ac = mh_dh.accessor(i_loc);
805 
806  double cs = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
807 
808  // set sources
809  double source = ele_ac.measure() * cs *
810  data_->water_source_density.value(ele_ac.centre(), ele_ac.element_accessor());
811  schur0->rhs_set_value(ele_ac.ele_row(), -1.0 * source );
812 
813  balance_->add_source_vec_values(data_->water_balance_idx, ele_ac.region().bulk_idx(), {(LongIdx) ele_ac.ele_row()}, {source});
814  }
815 
816  balance_->finish_source_assembly(data_->water_balance_idx);
817 }
818 
819 
820 
821 
822 /*******************************************************************************
823  * COMPOSE WATER MH MATRIX WITHOUT SCHUR COMPLEMENT
824  ******************************************************************************/
825 
827 
828  START_TIMER("preallocation");
829 
830  if (schur0 == NULL) { // create Linear System for MH matrix
831 
832  if (in_rec.type() == LinSys_BDDC::get_input_type()) {
833 #ifdef FLOW123D_HAVE_BDDCML
834  WarningOut() << "For BDDC no Schur complements are used.";
836  n_schur_compls = 0;
838  3, // 3 == la::BddcmlWrapper::SPD_VIA_SYMMETRICGENERAL
839  1, // 1 == number of subdomains per process
840  true); // swap signs of matrix and rhs to make the matrix SPD
841  ls->set_from_input(in_rec);
842  ls->set_solution( NULL );
843  // possible initialization particular to BDDC
844  START_TIMER("BDDC set mesh data");
846  schur0=ls;
847  END_TIMER("BDDC set mesh data");
848 #else
849  xprintf(Err, "Flow123d was not build with BDDCML support.\n");
850 #endif // FLOW123D_HAVE_BDDCML
851  }
852  else if (in_rec.type() == LinSys_PETSC::get_input_type()) {
853  // use PETSC for serial case even when user wants BDDC
854  if (n_schur_compls > 2) {
855  WarningOut() << "Invalid number of Schur Complements. Using 2.";
856  n_schur_compls = 2;
857  }
858 
859  LinSys_PETSC *schur1, *schur2;
860 
861  if (n_schur_compls == 0) {
862  LinSys_PETSC *ls = new LinSys_PETSC( &(*mh_dh.rows_ds) );
863 
864  // temporary solution; we have to set precision also for sequantial case of BDDC
865  // final solution should be probably call of direct solver for oneproc case
866  if (in_rec.type() != LinSys_BDDC::get_input_type()) ls->set_from_input(in_rec);
867  else {
868  ls->LinSys::set_from_input(in_rec); // get only common options
869  }
870 
871  ls->set_solution( NULL );
872  schur0=ls;
873  } else {
874  IS is;
875  ISCreateStride(PETSC_COMM_WORLD, mh_dh.side_ds->lsize(), mh_dh.rows_ds->begin(), 1, &is);
876  //OLD_ASSERT(err == 0,"Error in ISCreateStride.");
877 
878  SchurComplement *ls = new SchurComplement(is, &(*mh_dh.rows_ds));
879 
880  // make schur1
881  Distribution *ds = ls->make_complement_distribution();
882  if (n_schur_compls==1) {
883  schur1 = new LinSys_PETSC(ds);
884  schur1->set_positive_definite();
885  } else {
886  IS is;
887  ISCreateStride(PETSC_COMM_WORLD, mh_dh.el_ds->lsize(), ls->get_distribution()->begin(), 1, &is);
888  //OLD_ASSERT(err == 0,"Error in ISCreateStride.");
889  SchurComplement *ls1 = new SchurComplement(is, ds); // is is deallocated by SchurComplement
890  ls1->set_negative_definite();
891 
892  // make schur2
893  schur2 = new LinSys_PETSC( ls1->make_complement_distribution() );
894  schur2->set_positive_definite();
895  ls1->set_complement( schur2 );
896  schur1 = ls1;
897  }
898  ls->set_complement( schur1 );
899  ls->set_from_input(in_rec);
900  ls->set_solution( NULL );
901  schur0=ls;
902  }
903 
904  START_TIMER("PETSC PREALLOCATION");
907 
909 
910  VecZeroEntries(schur0->get_solution());
911  END_TIMER("PETSC PREALLOCATION");
912  }
913  else {
914  xprintf(Err, "Unknown solver type. Internal error.\n");
915  }
916 
917  END_TIMER("preallocation");
919 
920  }
921 
922 }
923 
924 
925 
926 
928  START_TIMER("DarcyFlowMH_Steady::assembly_linear_system");
929 
930  data_->is_linear=true;
931  bool is_steady = zero_time_term();
932  //DebugOut() << "Assembly linear system\n";
933  if (data_changed_) {
934  data_changed_ = false;
935  //DebugOut() << "Data changed\n";
936  // currently we have no optimization for cases when just time term data or RHS data are changed
937  START_TIMER("full assembly");
938  if (typeid(*schur0) != typeid(LinSys_BDDC)) {
939  schur0->start_add_assembly(); // finish allocation and create matrix
940  }
941 
944 
946 
947  auto multidim_assembler = AssemblyBase::create< AssemblyMH >(data_);
948  assembly_mh_matrix( multidim_assembler ); // fill matrix
949 
951 // print_matlab_matrix("matrix");
953  //MatView( *const_cast<Mat*>(schur0->get_matrix()), PETSC_VIEWER_STDOUT_WORLD );
954  //VecView( *const_cast<Vec*>(schur0->get_rhs()), PETSC_VIEWER_STDOUT_WORLD);
955 
956  if (! is_steady) {
957  START_TIMER("fix time term");
958  //DebugOut() << "setup time term\n";
959  // assembly time term and rhs
960  setup_time_term();
961  modify_system();
962  }
963  else
964  {
965  balance_->start_mass_assembly(data_->water_balance_idx);
966  balance_->finish_mass_assembly(data_->water_balance_idx);
967  }
968  END_TIMER("full assembly");
969  } else {
970  START_TIMER("modify system");
971  if (! is_steady) {
972  modify_system();
973  } else {
974  //xprintf(PrgErr, "Planned computation time for steady solver, but data are not changed.\n");
975  }
976  END_TIMER("modiffy system");
977  }
978 
979 }
980 
981 
982 void DarcyMH::print_matlab_matrix(std::string matlab_file)
983 {
984  std::string output_file;
985 
986  if ( typeid(*schur0) == typeid(LinSys_BDDC) ){
987 // WarningOut() << "Can output matrix only on a single processor.";
988 // output_file = FilePath(matlab_file + "_bddc.m", FilePath::output_file);
989 // ofstream os( output_file );
990 // auto bddc = static_cast<LinSys_BDDC*>(schur0);
991 // bddc->print_matrix(os);
992  }
993  else {//if ( typeid(*schur0) == typeid(LinSys_PETSC) ){
994  output_file = FilePath(matlab_file + ".m", FilePath::output_file);
995  PetscViewer viewer;
996  PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
997  PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
998  MatView( *const_cast<Mat*>(schur0->get_matrix()), viewer);
999  VecView( *const_cast<Vec*>(schur0->get_rhs()), viewer);
1000  }
1001 // else{
1002 // WarningOut() << "No matrix output available for the current solver.";
1003 // return;
1004 // }
1005 
1006  // compute h_min for different dimensions
1007  double d_max = std::numeric_limits<double>::max();
1008  double h1 = d_max, h2 = d_max, h3 = d_max;
1009  double he2 = d_max, he3 = d_max;
1010  for (auto ele : mesh_->elements_range()) {
1011  switch(ele->dim()){
1012  case 1: h1 = std::min(h1,ele.measure()); break;
1013  case 2: h2 = std::min(h2,ele.measure()); break;
1014  case 3: h3 = std::min(h3,ele.measure()); break;
1015  }
1016 
1017  for (unsigned int j=0; j<ele->n_sides(); j++) {
1018  switch(ele->dim()){
1019  case 2: he2 = std::min(he2, ele.side(j)->measure()); break;
1020  case 3: he3 = std::min(he3, ele.side(j)->measure()); break;
1021  }
1022  }
1023  }
1024  if(h1 == d_max) h1 = 0;
1025  if(h2 == d_max) h2 = 0;
1026  if(h3 == d_max) h3 = 0;
1027  if(he2 == d_max) he2 = 0;
1028  if(he3 == d_max) he3 = 0;
1029 
1030  FILE * file;
1031  file = fopen(output_file.c_str(),"a");
1032  fprintf(file, "nA = %d;\n", mh_dh.side_ds->size());
1033  fprintf(file, "nB = %d;\n", mh_dh.el_ds->size());
1034  fprintf(file, "nBF = %d;\n", mh_dh.edge_ds->size());
1035  fprintf(file, "h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1036  fprintf(file, "he2 = %e;\nhe3 = %e;\n", he2, he3);
1037  fclose(file);
1038 }
1039 
1040 
1042  START_TIMER("DarcyFlowMH_Steady::set_mesh_data_for_bddc");
1043  // prepare mesh for BDDCML
1044  // initialize arrays
1045  // auxiliary map for creating coordinates of local dofs and global-to-local numbering
1046  std::map<int,arma::vec3> localDofMap;
1047  // connectivity for the subdomain, i.e. global dof numbers on element, stored element-by-element
1048  // Indices of Nodes on Elements
1049  std::vector<int> inet;
1050  // number of degrees of freedom on elements - determines elementwise chunks of INET array
1051  // Number of Nodes on Elements
1052  std::vector<int> nnet;
1053  // Indices of Subdomain Elements in Global Numbering - for local elements, their global indices
1054  std::vector<int> isegn;
1055 
1056  // This array is currently not used in BDDCML, it was used as an interface scaling alternative to scaling
1057  // by diagonal. It corresponds to the rho-scaling.
1058  std::vector<double> element_permeability;
1059 
1060  // maximal and minimal dimension of elements
1061  uint elDimMax = 1;
1062  uint elDimMin = 3;
1063  for ( unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++ ) {
1064  auto ele_ac = mh_dh.accessor(i_loc);
1065  // for each element, create local numbering of dofs as fluxes (sides), pressure (element centre), Lagrange multipliers (edges), compatible connections
1066 
1067  elDimMax = std::max( elDimMax, ele_ac.dim() );
1068  elDimMin = std::min( elDimMin, ele_ac.dim() );
1069 
1070  isegn.push_back( ele_ac.ele_global_idx() );
1071  int nne = 0;
1072 
1073  for (unsigned int si=0; si<ele_ac.element_accessor()->n_sides(); si++) {
1074  // insert local side dof
1075  int side_row = ele_ac.side_row(si);
1076  arma::vec3 coord = ele_ac.side(si)->centre();
1077 
1078  localDofMap.insert( std::make_pair( side_row, coord ) );
1079  inet.push_back( side_row );
1080  nne++;
1081  }
1082 
1083  // insert local pressure dof
1084  int el_row = ele_ac.ele_row();
1085  arma::vec3 coord = ele_ac.centre();
1086  localDofMap.insert( std::make_pair( el_row, coord ) );
1087  inet.push_back( el_row );
1088  nne++;
1089 
1090  for (unsigned int si=0; si<ele_ac.element_accessor()->n_sides(); si++) {
1091  // insert local edge dof
1092  int edge_row = ele_ac.edge_row(si);
1093  arma::vec3 coord = ele_ac.side(si)->centre();
1094 
1095  localDofMap.insert( std::make_pair( edge_row, coord ) );
1096  inet.push_back( edge_row );
1097  nne++;
1098  }
1099 
1100  // insert dofs related to compatible connections
1101  for ( unsigned int i_neigh = 0; i_neigh < ele_ac.element_accessor()->n_neighs_vb(); i_neigh++) {
1102  int edge_row = mh_dh.row_4_edge[ ele_ac.element_accessor()->neigh_vb[i_neigh]->edge_idx() ];
1103  arma::vec3 coord = ele_ac.element_accessor()->neigh_vb[i_neigh]->edge()->side(0)->centre();
1104 
1105  localDofMap.insert( std::make_pair( edge_row, coord ) );
1106  inet.push_back( edge_row );
1107  nne++;
1108  }
1109 
1110  nnet.push_back( nne );
1111 
1112  // version for rho scaling
1113  // trace computation
1114  arma::vec3 centre = ele_ac.centre();
1115  double conduct = data_->conductivity.value( centre , ele_ac.element_accessor() );
1116  auto aniso = data_->anisotropy.value( centre, ele_ac.element_accessor() );
1117 
1118  // compute mean on the diagonal
1119  double coef = 0.;
1120  for ( int i = 0; i < 3; i++) {
1121  coef = coef + aniso.at(i,i);
1122  }
1123  // Maybe divide by cs
1124  coef = conduct*coef / 3;
1125 
1126  OLD_ASSERT( coef > 0.,
1127  "Zero coefficient of hydrodynamic resistance %f . \n ", coef );
1128  element_permeability.push_back( 1. / coef );
1129  }
1130  //convert set of dofs to vectors
1131  // number of nodes (= dofs) on the subdomain
1132  int numNodeSub = localDofMap.size();
1133  OLD_ASSERT_EQUAL( (unsigned int)numNodeSub, mh_dh.global_row_4_sub_row->size() );
1134  // Indices of Subdomain Nodes in Global Numbering - for local nodes, their global indices
1135  std::vector<int> isngn( numNodeSub );
1136  // pseudo-coordinates of local nodes (i.e. dofs)
1137  // they need not be exact, they are used just for some geometrical considerations in BDDCML,
1138  // such as selection of corners maximizing area of a triangle, bounding boxes fro subdomains to
1139  // find candidate neighbours etc.
1140  std::vector<double> xyz( numNodeSub * 3 ) ;
1141  int ind = 0;
1142  std::map<int,arma::vec3>::iterator itB = localDofMap.begin();
1143  for ( ; itB != localDofMap.end(); ++itB ) {
1144  isngn[ind] = itB -> first;
1145 
1146  arma::vec3 coord = itB -> second;
1147  for ( int j = 0; j < 3; j++ ) {
1148  xyz[ j*numNodeSub + ind ] = coord[j];
1149  }
1150 
1151  ind++;
1152  }
1153  localDofMap.clear();
1154 
1155  // Number of Nodal Degrees of Freedom
1156  // nndf is trivially one - dofs coincide with nodes
1157  std::vector<int> nndf( numNodeSub, 1 );
1158 
1159  // prepare auxiliary map for renumbering nodes
1160  typedef std::map<int,int> Global2LocalMap_; //! type for storage of global to local map
1161  Global2LocalMap_ global2LocalNodeMap;
1162  for ( unsigned ind = 0; ind < isngn.size(); ++ind ) {
1163  global2LocalNodeMap.insert( std::make_pair( static_cast<unsigned>( isngn[ind] ), ind ) );
1164  }
1165 
1166  // renumber nodes in the inet array to locals
1167  int indInet = 0;
1168  for ( unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) {
1169  int nne = nnet[ iEle ];
1170  for ( int ien = 0; ien < nne; ien++ ) {
1171 
1172  int indGlob = inet[indInet];
1173  // map it to local node
1174  Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob );
1175  OLD_ASSERT( pos != global2LocalNodeMap.end(),
1176  "Cannot remap node index %d to local indices. \n ", indGlob );
1177  int indLoc = static_cast<int> ( pos -> second );
1178 
1179  // store the node
1180  inet[ indInet++ ] = indLoc;
1181  }
1182  }
1183 
1184  int numNodes = size;
1185  int numDofsInt = size;
1186  int spaceDim = 3; // TODO: what is the proper value here?
1187  int meshDim = elDimMax;
1188 
1189  bddc_ls -> load_mesh( spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim );
1190 }
1191 
1192 
1193 
1194 
1195 //=============================================================================
1196 // DESTROY WATER MH SYSTEM STRUCTURE
1197 //=============================================================================
1199  if (previous_solution != nullptr) chkerr(VecDestroy(&previous_solution));
1200  if (steady_diagonal != nullptr) chkerr(VecDestroy(&steady_diagonal));
1201  if (new_diagonal != nullptr) chkerr(VecDestroy(&new_diagonal));
1202  if (steady_rhs != nullptr) chkerr(VecDestroy(&steady_rhs));
1203 
1204 
1205  if (schur0 != NULL) {
1206  delete schur0;
1207  chkerr(VecScatterDestroy(&par_to_all));
1208  }
1209 
1210  if (solution != NULL) {
1211  chkerr(VecDestroy(&sol_vec));
1212  delete [] solution;
1213  }
1214 
1215  if (output_object) delete output_object;
1216 
1217  if(time_ != nullptr)
1218  delete time_;
1219 
1220 }
1221 
1222 
1223 // ================================================
1224 // PARALLLEL PART
1225 //
1226 
1227 
1229  START_TIMER("prepare scatter");
1230  // prepare Scatter form parallel to sequantial in original numbering
1231  {
1232  IS is_loc;
1233  int i, *loc_idx; //, si;
1234 
1235  // create local solution vector
1236  solution = new double[size];
1237  VecCreateSeqWithArray(PETSC_COMM_SELF,1, size, solution,
1238  &(sol_vec));
1239 
1240  // create seq. IS to scatter par solutin to seq. vec. in original order
1241  // use essentialy row_4_id arrays
1242  loc_idx = new int [size];
1243  i = 0;
1244  for (auto ele : mesh_->elements_range()) {
1245  for (unsigned int si=0; si<ele->n_sides(); si++) {
1246  loc_idx[i++] = mh_dh.side_row_4_id[ mh_dh.side_dof( ele.side(si) ) ];
1247  }
1248  }
1249  for (auto ele : mesh_->elements_range()) {
1250  loc_idx[i++] = mh_dh.row_4_el[ ele.idx() ];
1251  }
1252  for(unsigned int i_edg=0; i_edg < mesh_->n_edges(); i_edg++) {
1253  loc_idx[i++] = mh_dh.row_4_edge[i_edg];
1254  }
1255  OLD_ASSERT( i==size,"Size of array does not match number of fills.\n");
1256  //DBGPRINT_INT("loc_idx",size,loc_idx);
1257  ISCreateGeneral(PETSC_COMM_SELF, size, loc_idx, PETSC_COPY_VALUES, &(is_loc));
1258  delete [] loc_idx;
1259  VecScatterCreate(schur0->get_solution(), is_loc, sol_vec,
1260  PETSC_NULL, &par_to_all);
1261  chkerr(ISDestroy(&(is_loc)));
1262  }
1264 
1265  END_TIMER("prepare scatter");
1266 
1267 }
1268 
1269 
1270 /*
1271 void mat_count_off_proc_values(Mat m, Vec v) {
1272  int n, first, last;
1273  const PetscInt *cols;
1274  Distribution distr(v);
1275 
1276  int n_off = 0;
1277  int n_on = 0;
1278  int n_off_rows = 0;
1279  MatGetOwnershipRange(m, &first, &last);
1280  for (int row = first; row < last; row++) {
1281  MatGetRow(m, row, &n, &cols, PETSC_NULL);
1282  bool exists_off = false;
1283  for (int i = 0; i < n; i++)
1284  if (distr.get_proc(cols[i]) != distr.myp())
1285  n_off++, exists_off = true;
1286  else
1287  n_on++;
1288  if (exists_off)
1289  n_off_rows++;
1290  MatRestoreRow(m, row, &n, &cols, PETSC_NULL);
1291  }
1292 }
1293 */
1294 
1295 
1296 
1297 
1298 
1299 
1300 
1301 
1302 
1303 
1304 
1305 
1307 {
1308  double *local_sol = schur0->get_solution_array();
1309 
1310  // cycle over local element rows
1311 
1312  DebugOut().fmt("Setup with dt: {}\n", time_->dt());
1313  for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) {
1314  auto ele_ac = mh_dh.accessor(i_loc_el);
1315  // set initial condition
1316  local_sol[ele_ac.ele_local_row()] = data_->init_pressure.value(ele_ac.centre(),ele_ac.element_accessor());
1317  }
1318 
1320 
1321 }
1322 
1324  // save diagonal of steady matrix
1325  MatGetDiagonal(*( schur0->get_matrix() ), steady_diagonal);
1326  // save RHS
1327  VecCopy(*( schur0->get_rhs()), steady_rhs);
1328 
1329 
1330  PetscScalar *local_diagonal;
1331  VecGetArray(new_diagonal,& local_diagonal);
1332 
1333  DebugOut().fmt("Setup with dt: {}\n", time_->dt());
1334 
1335  balance_->start_mass_assembly(data_->water_balance_idx);
1336 
1337  //DebugOut().fmt("time_term lsize: {} {}\n", mh_dh.el_ds->myp(), mh_dh.el_ds->lsize());
1338  for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) {
1339  auto ele_ac = mh_dh.accessor(i_loc_el);
1340 
1341  // set new diagonal
1342  double diagonal_coeff = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor())
1343  * data_->storativity.value(ele_ac.centre(), ele_ac.element_accessor())
1344  * ele_ac.measure();
1345  local_diagonal[ele_ac.ele_local_row()]= - diagonal_coeff / time_->dt();
1346 
1347  //DebugOut().fmt("time_term: {} {} {} {} {}\n", mh_dh.el_ds->myp(), ele_ac.ele_global_idx(), i_loc_row, i_loc_el + mh_dh.side_ds->lsize(), diagonal_coeff);
1348  balance_->add_mass_matrix_values(data_->water_balance_idx,
1349  ele_ac.region().bulk_idx(), { LongIdx(ele_ac.ele_row()) }, {diagonal_coeff});
1350  }
1351  VecRestoreArray(new_diagonal,& local_diagonal);
1352  MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES);
1353 
1356 
1357  balance_->finish_mass_assembly(data_->water_balance_idx);
1358 }
1359 
1361  START_TIMER("modify system");
1362  if (time_->is_changed_dt() && time_->step().index()>0) {
1363  double scale_factor=time_->step(-2).length()/time_->step().length();
1364  if (scale_factor != 1.0) {
1365  // if time step has changed and setup_time_term not called
1366  MatDiagonalSet(*( schur0->get_matrix() ),steady_diagonal, INSERT_VALUES);
1367 
1368  VecScale(new_diagonal, time_->last_dt()/time_->dt());
1369  MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES);
1371  }
1372  }
1373 
1374  // modify RHS - add previous solution
1375  //VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, previous_solution);
1376  VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, schur0->get_solution());
1377  VecAXPY(*( schur0->get_rhs()), 1.0, steady_rhs);
1379 
1380  //VecSwap(previous_solution, schur0->get_solution());
1381 }
1382 
1383 
1384 //-----------------------------------------------------------------------------
1385 // vim: set cindent:
TimeGovernor & time()
Definition: equation.hh:148
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: long_idx.hh:22
unsigned int size() const
get global size
void get_solution_vector(double *&vec, unsigned int &vec_size) override
void make_serial_scatter()
FieldSet * eq_data_
Definition: equation.hh:232
Distribution * side_ds
static const Input::Type::Record & get_input_type()
Main balance input record type.
Definition: balance.cc:48
void reinit(Mesh *mesh)
Output class for darcy_flow_mh model.
RegionSet get_region_set(const std::string &set_name) const
Definition: region.cc:329
virtual void initialize_specific()
void get_parallel_solution_vector(Vec &vector) override
Accessor to input data conforming to declared Array.
Definition: accessors.hh:567
SchurComplement SchurComplement
Definition: linsys.hh:92
void assembly_mh_matrix(MultidimAssembly &assembler)
void set_symmetric(bool flag=true)
Definition: linsys.hh:522
unsigned int uint
Classes with algorithms for computation of intersections of meshes.
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:598
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
void init_eq_data()
virtual ~DarcyMH() override
MixedMeshIntersections & mixed_intersections()
Definition: mesh.cc:702
static const Input::Type::Record & get_input_type()
The specification of output stream.
Definition: output_time.cc:38
Common base for intersection object.
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
Class for declaration of the input of type Bool.
Definition: type_base.hh:459
void set_from_input(const Input::Record in_rec) override
unsigned int edge_idx() const
Definition: side_impl.hh:62
virtual void assembly_source_term()
Source term is implemented differently in LMH version.
friend class DarcyFlowMHOutput
#define MessageOut()
Macro defining &#39;message&#39; record of log.
Definition: logger.hh:243
virtual void start_add_assembly()
Definition: linsys.hh:322
virtual void output_data() override
Write computed fields.
virtual PetscErrorCode mat_zero_entries()
Definition: linsys.hh:264
Wrappers for linear systems based on MPIAIJ and MATIS format.
bool is_end() const
Returns true if the actual time is greater than or equal to the end time.
void next_time()
Proceed to the next time according to current estimated time step.
void set_rhs_changed()
Definition: linsys.hh:218
static const int registrar
Registrar of class to factory.
unsigned int max_n_it_
VecScatter par_to_all
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
Vec steady_rhs
static const Input::Type::Selection & get_mh_mortar_selection()
Selection for enum MortarMethod.
void initialize() override
LongIdx * side_row_4_id
Definition: mesh.h:80
static const Input::Type::Record & type_field_descriptor()
virtual void start_allocation()
Definition: linsys.hh:314
Distribution * el_ds
void chkerr(unsigned int ierr)
Replacement of new/delete operator in the spirit of xmalloc.
Definition: system.hh:147
virtual void finish_assembly()=0
virtual double get_solution_precision()=0
std::vector< std::vector< ILpair > > element_intersections_
SideIter side(const unsigned int loc_index)
Definition: accessors.hh:137
const RegionDB & region_db() const
Definition: mesh.h:147
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
const TimeStep & step(int index=-1) const
static const std::string field_descriptor_record_description(const string &record_name)
Definition: field_common.cc:73
Class for declaration of the integral input data.
Definition: type_base.hh:490
#define ADD_FIELD(name,...)
Definition: field_set.hh:279
Basic time management functionality for unsteady (and steady) solvers (class Equation).
unsigned int bulk_ele_idx() const
Returns index of bulk element.
LongIdx * row_4_el
bool solution_changed_for_scatter
void solve_nonlinear()
Solve method common to zero_time_step and update solution.
static const Input::Type::Record & get_input_type()
Definition: linsys_BDDC.cc:37
std::shared_ptr< EqData > data_
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:303
Basic time management class.
virtual void set_tolerances(double r_tol, double a_tol, unsigned int max_it)=0
Class for declaration of inputs sequences.
Definition: type_base.hh:346
virtual ElementAccessor< 3 > element_accessor(unsigned int idx) const
Create and return ElementAccessor to element of given idx.
Definition: mesh.cc:719
void view(const char *name="") const
std::shared_ptr< LocalToGlobalMap > global_row_4_sub_row
Necessary only for BDDC solver.
unsigned int min_n_it_
void modify_system()
unsigned int nonlinear_iteration_
void set_mesh_data_for_bddc(LinSys_BDDC *bddc_ls)
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:195
void update_solution() override
static Default optional()
The factory function to make an empty default value which is optional.
Definition: type_record.hh:124
#define OLD_ASSERT(...)
Definition: global_defs.h:131
void set_from_input(const Input::Record in_rec) override
Definition: linsys_BDDC.cc:300
virtual void postprocess()
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:541
static const Input::Type::Instance & get_input_type_specific()
double * get_solution_array()
Definition: linsys.hh:306
std::shared_ptr< Balance > balance_
#define MPI_MIN
Definition: mpi.h:198
unsigned int edge_idx()
Definition: neighbours.h:153
FLOW123D_FORCE_LINK_IN_CHILD(darcy_flow_mh)
int n_schur_compls
const Vec & get_solution()
Definition: linsys.hh:282
Input::Type::Record type() const
Definition: accessors.cc:273
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args)
Definition: ostream.cc:56
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
const Ret val(const string &key) const
unsigned int n_sides() const
Definition: elements.h:135
#define xprintf(...)
Definition: system.hh:92
bool is_changed_dt() const
#define START_TIMER(tag)
Starts a timer with specified tag.
Distribution * edge_ds
Mesh * mesh_
Definition: equation.hh:223
Selection & add_value(const int value, const std::string &key, const std::string &description="", TypeBase::attribute_map attributes=TypeBase::attribute_map())
Adds one new value with name given by key to the Selection.
static const Input::Type::Instance & get_input_type()
bool data_changed_
double * solution
double length() const
unsigned int side_dof(const SideIter side) const
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:501
static Input::Type::Abstract & get_input_type()
virtual Range< ElementAccessor< 3 > > elements_range() const
Returns range of bulk elements.
Definition: mesh.cc:1033
bool use_steady_assembly_
unsigned int n_sides() const
Definition: mesh.cc:221
void allocate_mh_matrix()
static const Input::Type::Selection & get_bc_type_selection()
Return a Selection corresponding to enum BC_Type.
void set_solution(double *sol_array)
Definition: linsys.hh:290
virtual void assembly_linear_system()
virtual const Vec * get_rhs()
Definition: linsys.hh:203
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:459
LinSys * schur0
virtual PetscErrorCode rhs_zero_entries()
Definition: linsys.hh:273
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:215
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
DarcyMH(Mesh &mesh, const Input::Record in_rec)
CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL.
Support classes for parallel programing.
#define MPI_Allreduce(sendbuf, recvbuf, count, datatype, op, comm)
Definition: mpi.h:612
int set_upper_constraint(double upper, std::string message)
Sets upper constraint for the next time step estimating.
void create_linear_system(Input::AbstractRecord rec)
Initialize global_row_4_sub_row.
MH_DofHandler mh_dh
LongIdx * row_4_edge
virtual unsigned int n_elements(bool boundary=false) const
Returns count of boundary or bulk elements.
Definition: mesh.h:346
MortarMethod
Type of experimental Mortar-like method for non-compatible 1d-2d interaction.
const Selection & close() const
Close the Selection, no more values can be added.
Input::Record input_record_
Definition: equation.hh:225
#define MPI_INT
Definition: mpi.h:160
double dt() const
std::shared_ptr< Distribution > rows_ds
LocalElementAccessorBase< 3 > accessor(uint local_ele_idx)
Vec steady_diagonal
static const Input::Type::Record & get_input_type()
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:246
virtual SolveInfo solve()=0
#define END_TIMER(tag)
Ends a timer with specified tag.
#define OLD_ASSERT_EQUAL(a, b)
Definition: global_defs.h:133
EqData()
Creation of all fields.
Definition: system.hh:64
void set_matrix_changed()
Definition: linsys.hh:212
static const Input::Type::Record & get_input_type()
Definition: linsys_PETSC.cc:32
void print_matlab_matrix(string matlab_file)
Print darcy flow matrix in matlab format into a file.
mixed-hybrid model of linear Darcy flow, possibly unsteady.
unsigned int index() const
void zero_time_step() override
void set_positive_definite(bool flag=true)
Definition: linsys.hh:537
virtual void read_initial_condition()
Record type proxy class.
Definition: type_record.hh:182
void prepare_parallel_bddc()
static Input::Type::Abstract & get_input_type()
Definition: linsys.cc:29
virtual void mat_set_values(int nrow, int *rows, int ncol, int *cols, double *vals)=0
DarcyFlowMHOutput * output_object
unsigned int n_edges() const
Definition: mesh.h:141
virtual void prepare_new_time_step()
postprocess velocity field (add sources)
Class for representation SI units of Fields.
Definition: unit_si.hh:40
virtual const Mat * get_matrix()
Definition: linsys.hh:187
double last_dt() const
Vec new_diagonal
virtual double solution_precision() const
virtual void setup_time_term()
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:55
#define DebugOut()
Macro defining &#39;debug&#39; record of log.
Definition: logger.hh:252
virtual double compute_residual()=0
Vec previous_solution
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
Template for classes storing finite set of named values.
Implementation of range helper class.
void rhs_set_value(int row, double val)
Definition: linsys.hh:362
double tolerance_
static const Input::Type::Record & get_input_type()
Solver based on Multilevel BDDC - using corresponding class of OpenFTL package.
TimeGovernor * time_
Definition: equation.hh:224
virtual bool zero_time_term(bool time_global=false)
void output()
Calculate values for output.
unsigned int lsize(int proc) const
get local size