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