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