Flow123d  release_2.2.0-41-g0958a8d
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/intersection.hh"
38 #include "mesh/partitioning.hh"
39 #include "la/distribution.hh"
40 #include "la/linsys.hh"
41 #include "la/linsys_PETSC.hh"
42 #include "la/linsys_BDDC.hh"
43 #include "la/schur.hh"
44 //#include "la/sparse_graph.hh"
46 
47 #include "flow/darcy_flow_mh.hh"
48 
50 
51 /*
52 #include "fem/mapping_p1.hh"
53 #include "fem/fe_p.hh"
54 #include "fem/fe_values.hh"
55 #include "fem/fe_rt.hh"
56 #include "quadrature/quadrature_lib.hh"
57 */
58 
59 #include "tools/time_governor.hh"
61 #include "fields/field.hh"
62 #include "fields/field_values.hh"
64 
65 #include "coupling/balance.hh"
66 
67 #include "fields/vec_seq_double.hh"
68 #include "darcy_flow_assembly.hh"
69 
70 
71 FLOW123D_FORCE_LINK_IN_CHILD(darcy_flow_mh);
72 
73 
74 
75 
76 namespace it = Input::Type;
77 
79  return it::Selection("MH_MortarMethod")
80  .add_value(NoMortar, "None", "No Mortar method is applied.")
81  .add_value(MortarP0, "P0", "Mortar space: P0 on elements of lower dimension.")
82  .add_value(MortarP1, "P1", "Mortar space: P1 on intersections, using non-conforming pressures.")
83  .close();
84 }
85 
86 
88  return it::Selection("Flow_Darcy_BC_Type")
89  .add_value(none, "none",
90  "Homogeneous Neumann boundary condition\n(zero normal flux over the boundary).")
91  .add_value(dirichlet, "dirichlet",
92  "Dirichlet boundary condition. "
93  "Specify the pressure head through the ``bc_pressure`` field "
94  "or the piezometric head through the ``bc_piezo_head`` field.")
95  .add_value(total_flux, "total_flux", "Flux boundary condition (combines Neumann and Robin type). "
96  "Water inflow equal to (($ \\delta_d(q_d^N + \\sigma_d (h_d^R - h_d) )$)). "
97  "Specify the water inflow by the ``bc_flux`` field, the transition coefficient by ``bc_robin_sigma`` "
98  "and the reference pressure head or pieozmetric head through ``bc_pressure`` or ``bc_piezo_head`` respectively.")
99  .add_value(seepage, "seepage",
100  "Seepage face boundary condition. Pressure and inflow bounded from above. Boundary with potential seepage flow "
101  "is described by the pair of inequalities: "
102  "(($h_d \\le h_d^D$)) and (($ -\\boldsymbol q_d\\cdot\\boldsymbol n \\le \\delta q_d^N$)), where the equality holds in at least one of them. "
103  "Caution: setting (($q_d^N$)) strictly negative "
104  "may lead to an ill posed problem since a positive outflow is enforced. "
105  "Parameters (($h_d^D$)) and (($q_d^N$)) are given by the fields ``bc_switch_pressure`` (or ``bc_switch_piezo_head``) and ``bc_flux`` respectively."
106  )
107  .add_value(river, "river",
108  "River boundary condition. For the water level above the bedrock, (($H_d > H_d^S$)), the Robin boundary condition is used with the inflow given by: "
109  "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d) )$)). For the water level under the bedrock, constant infiltration is used: "
110  "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d^S) )$)). Parameters: ``bc_pressure``, ``bc_switch_pressure``, "
111  " ``bc_sigma``, ``bc_flux``."
112  )
113  .close();
114 }
115 
117 
118  const it::Record &field_descriptor =
119  it::Record("Flow_Darcy_MH_Data",FieldCommon::field_descriptor_record_description("Flow_Darcy_MH_Data") )
120  .copy_keys( DarcyMH::EqData().make_field_descriptor_type("Flow_Darcy_MH_Data_aux") )
121  .declare_key("bc_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type_instance(),
122  "Boundary piezometric head for BC types: dirichlet, robin, and river." )
123  .declare_key("bc_switch_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type_instance(),
124  "Boundary switch piezometric head for BC types: seepage, river." )
125  .declare_key("init_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type_instance(),
126  "Initial condition for the pressure given as the piezometric head." )
127  .close();
128  return field_descriptor;
129 }
130 
132 
133  it::Record ns_rec = Input::Type::Record("NonlinearSolver", "Non-linear solver settings.")
134  .declare_key("linear_solver", LinSys::get_input_type(), it::Default("{}"),
135  "Linear solver for MH problem.")
136  .declare_key("tolerance", it::Double(0.0), it::Default("1E-6"),
137  "Residual tolerance.")
138  .declare_key("min_it", it::Integer(0), it::Default("1"),
139  "Minimum number of iterations (linear solutions) to use.\nThis is usefull if the convergence criteria "
140  "does not characterize your goal well enough so it converges prematurely, possibly even without a single linear solution."
141  "If greater then 'max_it' the value is set to 'max_it'.")
142  .declare_key("max_it", it::Integer(0), it::Default("100"),
143  "Maximum number of iterations (linear solutions) of the non-linear solver.")
144  .declare_key("converge_on_stagnation", it::Bool(), it::Default("false"),
145  "If a stagnation of the nonlinear solver is detected the solver stops. "
146  "A divergence is reported by default, forcing the end of the simulation. By setting this flag to 'true', the solver "
147  "ends with convergence success on stagnation, but it reports warning about it.")
148  .close();
149 
150  return it::Record("Flow_Darcy_MH", "Mixed-Hybrid solver for saturated Darcy flow.")
152  .declare_key("gravity", it::Array(it::Double(), 3,3), it::Default("[ 0, 0, -1]"),
153  "Vector of the gravity force. Dimensionless.")
155  "Input data for Darcy flow model.")
156  .declare_key("nonlinear_solver", ns_rec, it::Default("{}"),
157  "Non-linear solver for MH problem.")
158  .declare_key("output_stream", OutputTime::get_input_type(), it::Default("{}"),
159  "Output stream settings.\n Specify file format, precision etc.")
160 
161  .declare_key("output", DarcyFlowMHOutput::get_input_type(), IT::Default("{ \"fields\": [ \"pressure_p0\", \"velocity_p0\" ] }"),
162  "Specification of output fields and output times.")
164  "Output settings specific to Darcy flow model.\n"
165  "Includes raw output and some experimental functionality.")
166  .declare_key("balance", Balance::get_input_type(), it::Default("{}"),
167  "Settings for computing mass balance.")
169  "Time governor settings for the unsteady Darcy flow model.")
170  .declare_key("n_schurs", it::Integer(0,2), it::Default("2"),
171  "Number of Schur complements to perform when solving MH system.")
172  .declare_key("mortar_method", get_mh_mortar_selection(), it::Default("\"None\""),
173  "Method for coupling Darcy flow between dimensions on incompatible meshes. [Experimental]" )
174  .close();
175 }
176 
177 
178 const int DarcyMH::registrar =
179  Input::register_class< DarcyMH, Mesh &, const Input::Record >("Flow_Darcy_MH") +
181 
182 
183 
185 {
186  ADD_FIELD(anisotropy, "Anisotropy of the conductivity tensor.", "1.0" );
187  anisotropy.units( UnitSI::dimensionless() );
188 
189  ADD_FIELD(cross_section, "Complement dimension parameter (cross section for 1D, thickness for 2D).", "1.0" );
190  cross_section.units( UnitSI().m(3).md() );
191 
192  ADD_FIELD(conductivity, "Isotropic conductivity scalar.", "1.0" );
193  conductivity.units( UnitSI().m().s(-1) ).set_limits(0.0);
194 
195  ADD_FIELD(sigma, "Transition coefficient between dimensions.", "1.0");
196  sigma.units( UnitSI::dimensionless() );
197 
198  ADD_FIELD(water_source_density, "Water source density.", "0.0");
199  water_source_density.units( UnitSI().s(-1) );
200 
201  ADD_FIELD(bc_type,"Boundary condition type.", "\"none\"" );
202  // TODO: temporary solution, we should try to get rid of pointer to the selection after having generic types
203  bc_type.input_selection( get_bc_type_selection() );
204  bc_type.units( UnitSI::dimensionless() );
205 
206  ADD_FIELD(bc_pressure,"Prescribed pressure value on the boundary. Used for all values of ``bc_type`` except ``none`` and ``seepage``. "
207  "See documentation of ``bc_type`` for exact meaning of ``bc_pressure`` in individual boundary condition types.", "0.0");
208  bc_pressure.disable_where(bc_type, {none, seepage} );
209  bc_pressure.units( UnitSI().m() );
210 
211  ADD_FIELD(bc_flux,"Incoming water boundary flux. Used for bc_types : ``total_flux``, ``seepage``, ``river``.", "0.0");
212  bc_flux.disable_where(bc_type, {none, dirichlet} );
213  bc_flux.units( UnitSI().m(4).s(-1).md() );
214 
215  ADD_FIELD(bc_robin_sigma,"Conductivity coefficient in the ``total_flux`` or the ``river`` boundary condition type.", "0.0");
216  bc_robin_sigma.disable_where(bc_type, {none, dirichlet, seepage} );
217  bc_robin_sigma.units( UnitSI().m(3).s(-1).md() );
218 
219  ADD_FIELD(bc_switch_pressure,
220  "Critical switch pressure for ``seepage`` and ``river`` boundary conditions.", "0.0");
221  bc_switch_pressure.disable_where(bc_type, {none, dirichlet, total_flux} );
222  bc_switch_pressure.units( UnitSI().m() );
223 
224  //these are for unsteady
225  ADD_FIELD(init_pressure, "Initial condition for pressure in time dependent problems.", "0.0" );
226  init_pressure.units( UnitSI().m() );
227 
228  ADD_FIELD(storativity,"Storativity (in time dependent problems).", "0.0" );
229  storativity.units( UnitSI().m(-1) );
230 
231  //time_term_fields = this->subset({"storativity"});
232  //main_matrix_fields = this->subset({"anisotropy", "conductivity", "cross_section", "sigma", "bc_type", "bc_robin_sigma"});
233  //rhs_fields = this->subset({"water_source_density", "bc_pressure", "bc_flux"});
234 
235 }
236 
237 
238 
239 
240 
241 
242 //=============================================================================
243 // CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL
244 // - do it in parallel:
245 // - initial distribution of elements, edges
246 //
247 /*! @brief CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL
248  *
249  * Parameters {Solver,NSchurs} number of performed Schur
250  * complements (0,1,2) for water flow MH-system
251  *
252  */
253 //=============================================================================
254 DarcyMH::DarcyMH(Mesh &mesh_in, const Input::Record in_rec)
255 : DarcyFlowInterface(mesh_in, in_rec),
256  solution(nullptr),
257  schur0(nullptr),
258  data_changed_(false),
259  output_object(nullptr)
260 {
261 
262  is_linear_=true;
263 
264  START_TIMER("Darcy constructor");
265  {
266  auto time_record = input_record_.val<Input::Record>("time");
267  //if ( in_rec.opt_val("time", time_record) )
268  time_ = new TimeGovernor(time_record);
269  //else
270  // time_ = new TimeGovernor();
271  }
272 
273  data_ = make_shared<EqData>();
275 
276 
277  size = mesh_->n_elements() + mesh_->n_sides() + mesh_->n_edges();
278  n_schur_compls = in_rec.val<int>("n_schurs");
279  mortar_method_= in_rec.val<MortarMethod>("mortar_method");
280  if (mortar_method_ != NoMortar) {
282  }
283 
284 
285 
286  //side_ds->view( std::cout );
287  //el_ds->view( std::cout );
288  //edge_ds->view( std::cout );
289  //rows_ds->view( std::cout );
290 
291 }
292 
293 
294 
296 //connecting data fields with mesh
297 {
298 
299  START_TIMER("data init");
300  data_->mesh = mesh_;
301  data_->mh_dh = &mh_dh;
302  data_->set_mesh(*mesh_);
303 
304  auto gravity_array = input_record_.val<Input::Array>("gravity");
305  std::vector<double> gvec;
306  gravity_array.copy_to(gvec);
307  gvec.push_back(0.0); // zero pressure shift
308  data_->gravity_ = arma::vec(gvec);
309  data_->gravity_vec_ = data_->gravity_.subvec(0,2);
310 
311  data_->bc_pressure.add_factory(
312  std::make_shared<FieldAddPotential<3, FieldValue<3>::Scalar>::FieldFactory>
313  (data_->gravity_, "bc_piezo_head") );
314  data_->bc_switch_pressure.add_factory(
315  std::make_shared<FieldAddPotential<3, FieldValue<3>::Scalar>::FieldFactory>
316  (data_->gravity_, "bc_switch_piezo_head") );
317  data_->init_pressure.add_factory(
318  std::make_shared<FieldAddPotential<3, FieldValue<3>::Scalar>::FieldFactory>
319  (data_->gravity_, "init_piezo_head") );
320 
321 
322  data_->set_input_list( this->input_record_.val<Input::Array>("input_fields") );
323  // Check that the time step was set for the transient simulation.
324  if (! zero_time_term(true) && time_->is_default() ) {
325  //THROW(ExcAssertMsg());
326  //THROW(ExcMissingTimeGovernor() << input_record_.ei_address());
327  MessageOut() << "Missing the key 'time', obligatory for the transient problems." << endl;
328  ASSERT(false);
329  }
330 
331  data_->mark_input_times(*time_);
332 }
333 
334 
335 
337 
338  init_eq_data();
340 
341  mh_dh.reinit(mesh_);
342  // Initialize bc_switch_dirichlet to size of global boundary.
344 
345 
348  .val<Input::Record>("nonlinear_solver")
349  .val<Input::AbstractRecord>("linear_solver");
350 
351  // auxiliary set_time call since allocation assembly evaluates fields as well
353  data_->system_.local_matrix = std::make_shared<arma::mat>();
355 
356 
357 
358  // allocate time term vectors
359  VecDuplicate(schur0->get_solution(), &previous_solution);
360  VecCreateMPI(PETSC_COMM_WORLD, mh_dh.rows_ds->lsize(),PETSC_DETERMINE,&(steady_diagonal));
361  VecDuplicate(steady_diagonal,& new_diagonal);
362  VecZeroEntries(new_diagonal);
363  VecDuplicate(steady_diagonal, &steady_rhs);
364 
365 
366  // initialization of balance object
367  balance_ = std::make_shared<Balance>("water", mesh_);
368  balance_->init_from_input(input_record_.val<Input::Record>("balance"), time());
369  data_-> water_balance_idx_ = water_balance_idx_ = balance_->add_quantity("water_volume");
370  balance_->allocate(mh_dh.rows_ds->lsize(), 1);
371  balance_->units(UnitSI().m(3));
372 
373 
374  data_->system_.balance = balance_;
375  data_->system_.lin_sys = schur0;
376 
377 
379 }
380 
382 {}
383 
385 {
386 
387  /* TODO:
388  * - Allow solution reconstruction (pressure and velocity) from initial condition on user request.
389  * - Steady solution as an intitial condition may be forced by setting inti_time =-1, and set data for the steady solver in that time.
390  * Solver should be able to switch from and to steady case depending on the zero time term.
391  */
392 
394 
395  // zero_time_term means steady case
396  bool zero_time_term_from_right = zero_time_term();
397 
398 
399  if (zero_time_term_from_right) {
400  // steady case
401  VecZeroEntries(schur0->get_solution());
402  //read_initial_condition(); // Possible solution guess for steady case.
403  use_steady_assembly_ = true;
404  solve_nonlinear(); // with right limit data
405  } else {
406  VecZeroEntries(schur0->get_solution());
407  VecZeroEntries(previous_solution);
409  assembly_linear_system(); // in particular due to balance
410  // TODO: reconstruction of solution in zero time.
411  }
412  //solution_output(T,right_limit); // data for time T in any case
413  output_data();
414 }
415 
416 //=============================================================================
417 // COMPOSE and SOLVE WATER MH System possibly through Schur complements
418 //=============================================================================
420 {
421  START_TIMER("Solving MH system");
422 
423  time_->next_time();
424 
425  time_->view("DARCY"); //time governor information output
427  bool zero_time_term_from_left=zero_time_term();
428 
429  bool jump_time = data_->storativity.is_jump_time();
430  if (! zero_time_term_from_left) {
431  // time term not treated as zero
432  // Unsteady solution up to the T.
433 
434  // this flag is necesssary for switching BC to avoid setting zero neumann on the whole boundary in the steady case
435  use_steady_assembly_ = false;
436  prepare_new_time_step(); //SWAP
437 
438  solve_nonlinear(); // with left limit data
439  if (jump_time) {
440  WarningOut() << "Output of solution discontinuous in time not supported yet.\n";
441  //solution_output(T, left_limit); // output use time T- delta*dt
442  //output_data();
443  }
444  }
445 
446  if (time_->is_end()) {
447  // output for unsteady case, end_time should not be the jump time
448  // but rether check that
449  if (! zero_time_term_from_left && ! jump_time) output_data();
450  return;
451  }
452 
454  bool zero_time_term_from_right=zero_time_term();
455  if (zero_time_term_from_right) {
456  // this flag is necesssary for switching BC to avoid setting zero neumann on the whole boundary in the steady case
457  use_steady_assembly_ = true;
458  solve_nonlinear(); // with right limit data
459 
460  } else if (! zero_time_term_from_left && jump_time) {
461  WarningOut() << "Discontinuous time term not supported yet.\n";
462  //solution_transfer(); // internally call set_time(T, left) and set_time(T,right) again
463  //solve_nonlinear(); // with right limit data
464  }
465  //solution_output(T,right_limit); // data for time T in any case
466  output_data();
467 
468 }
469 
470 bool DarcyMH::zero_time_term(bool time_global) {
471  if (time_global) {
472  return (data_->storativity.input_list_size() == 0);
473  } else {
474  return data_->storativity.field_result(mesh_->region_db().get_region_set("BULK")) == result_zeros;
475  }
476 }
477 
478 
480 {
481 
483  double residual_norm = schur0->compute_residual();
484  unsigned int l_it=0;
486  MessageOut().fmt("[nonlin solver] norm of initial residual: {}\n", residual_norm);
487 
488  // Reduce is_linear flag.
489  int is_linear_common;
490  MPI_Allreduce(&is_linear_, &is_linear_common,1, MPI_INT ,MPI_MIN,PETSC_COMM_WORLD);
491 
492  Input::Record nl_solver_rec = input_record_.val<Input::Record>("nonlinear_solver");
493  this->tolerance_ = nl_solver_rec.val<double>("tolerance");
494  this->max_n_it_ = nl_solver_rec.val<unsigned int>("max_it");
495  this->min_n_it_ = nl_solver_rec.val<unsigned int>("min_it");
496  if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->max_n_it_;
497 
498  if (! is_linear_common) {
499  // set tolerances of the linear solver unless they are set by user.
500  schur0->set_tolerances(0.1*this->tolerance_, 0.01*this->tolerance_, 100);
501  }
502  vector<double> convergence_history;
503 
504  Vec save_solution;
505  VecDuplicate(schur0->get_solution(), &save_solution);
506  while (nonlinear_iteration_ < this->min_n_it_ ||
507  (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->max_n_it_ )) {
508  OLD_ASSERT_EQUAL( convergence_history.size(), nonlinear_iteration_ );
509  convergence_history.push_back(residual_norm);
510 
511  // stagnation test
512  if (convergence_history.size() >= 5 &&
513  convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
514  convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
515  // stagnation
516  if (input_record_.val<Input::Record>("nonlinear_solver").val<bool>("converge_on_stagnation")) {
517  WarningOut().fmt("Accept solution on stagnation. Its: {} Residual: {}\n", nonlinear_iteration_, residual_norm);
518  break;
519  } else {
520  THROW(ExcSolverDiverge() << EI_Reason("Stagnation."));
521  }
522  }
523 
524  if (! is_linear_common)
525  VecCopy( schur0->get_solution(), save_solution);
526  int convergedReason = schur0->solve();
528 
529  // hack to make BDDC work with empty compute_residual
530  if (is_linear_common) break;
531  data_changed_=true; // force reassembly for non-linear case
532 
533  double alpha = 1; // how much of new solution
534  VecAXPBY(schur0->get_solution(), (1-alpha), alpha, save_solution);
535 
536  /*
537  double * sol;
538  unsigned int sol_size;
539  get_solution_vector(sol, sol_size);
540  if (mh_dh.el_ds->myp() == 0)
541  VecView(sol_vec, PETSC_VIEWER_STDOUT_SELF);
542  */
543 
544  //LogOut().fmt("Linear solver ended with reason: {} \n", convergedReason );
545  //OLD_ASSERT( convergedReason >= 0, "Linear solver failed to converge. Convergence reason %d \n", convergedReason );
547 
548  residual_norm = schur0->compute_residual();
549  MessageOut().fmt("[nonlinear solver] it: {} lin. it:{} (reason: {}) residual: {}\n",
550  nonlinear_iteration_, l_it, convergedReason, residual_norm);
551  }
552  this -> postprocess();
553 
554  // adapt timestep
555  if (! this->zero_time_term()) {
556  double mult = 1.0;
557  if (nonlinear_iteration_ < 3) mult = 1.6;
558  if (nonlinear_iteration_ > 7) mult = 0.7;
559  int result = time_->set_upper_constraint(time_->dt() * mult, "Darcy adaptivity.");
560  //DebugOut().fmt("time adaptivity, res: {} it: {} m: {} dt: {} edt: {}\n", result, nonlinear_iteration_, mult, time_->dt(), time_->estimate_dt());
561  }
562 
564 
565 }
566 
567 
569 {
570  //VecSwap(previous_solution, schur0->get_solution());
571 }
572 
574 {
575  START_TIMER("postprocess");
576  //ElementFullIter ele = ELEMENT_FULL_ITER(mesh_, NULL);
577 
578  // modify side fluxes in parallel
579  // for every local edge take time term on digonal and add it to the corresponding flux
580  /*
581  for (unsigned int i_loc = 0; i_loc < el_ds->lsize(); i_loc++) {
582  ele = mesh_->element(el_4_loc[i_loc]);
583  FOR_ELEMENT_SIDES(ele,i) {
584  side_rows[i] = side_row_4_id[ mh_dh.side_dof( ele_ac.side(i) ) ];
585  values[i] = -1.0 * ele_ac.measure() *
586  data.cross_section.value(ele_ac.centre(), ele_ac.element_accessor()) *
587  data.water_source_density.value(ele_ac.centre(), ele_ac.element_accessor()) /
588  ele_ac.n_sides();
589  }
590  VecSetValues(schur0->get_solution(), ele_ac.n_sides(), side_rows, values, ADD_VALUES);
591  }
592  VecAssemblyBegin(schur0->get_solution());
593  VecAssemblyEnd(schur0->get_solution());
594  */
595 }
596 
597 
599  START_TIMER("Darcy output data");
600  //time_->view("DARCY"); //time governor information output
601  this->output_object->output();
602 
603 
604  START_TIMER("Darcy balance output");
605  balance_->calculate_cumulative(water_balance_idx_, schur0->get_solution());
606  balance_->calculate_instant(water_balance_idx_, schur0->get_solution());
607  balance_->output();
608 }
609 
610 
612 {
613  return schur0->get_solution_precision();
614 }
615 
616 
617 
618 void DarcyMH::get_solution_vector(double * &vec, unsigned int &vec_size)
619 {
620  // TODO: make class for vectors (wrapper for PETSC or other) derived from LazyDependency
621  // and use its mechanism to manage dependency between vectors
623 
624  // scatter solution to all procs
625  VecScatterBegin(par_to_all, schur0->get_solution(), sol_vec, INSERT_VALUES, SCATTER_FORWARD);
626  VecScatterEnd( par_to_all, schur0->get_solution(), sol_vec, INSERT_VALUES, SCATTER_FORWARD);
628  }
629 
630  vec = solution;
631  vec_size = this->size;
632  OLD_ASSERT(vec != NULL, "Requested solution is not allocated!\n");
633 }
634 
636 {
637  vec=schur0->get_solution();
638  OLD_ASSERT(vec != NULL, "Requested solution is not allocated!\n");
639 }
640 
641 
642 /*
643 void DarcyMH::local_assembly_specific() {
644 
645 }
646 */
647 // ===========================================================================================
648 //
649 // MATRIX ASSEMBLY - we use abstract assembly routine, where LS Mat/Vec SetValues
650 // are in fact pointers to allocating or filling functions - this is governed by Linsystem roitunes
651 //
652 // =======================================================================================
653 
655 {
656  START_TIMER("DarcyFlowMH_Steady::assembly_steady_mh_matrix");
657 
658  LinSys *ls = schur0;
659 
660  class Boundary *bcd;
661  class Neighbour *ngh;
662 
663  bool fill_matrix = assembler.size() > 0;
664  int side_row, edge_row, loc_b = 0;
665  int tmp_rows[100];
666  double local_vb[4]; // 2x2 matrix
667  int side_rows[4], edge_rows[4];
668 
669  // to make space for second schur complement, max. 10 neighbour edges of one el.
670  double zeros[1000];
671  for(int i=0; i<1000; i++) zeros[i]=0.0;
672 
673  double minus_ones[4] = { -1.0, -1.0, -1.0, -1.0 };
674  double * loc_side_rhs = data_->system_.loc_side_rhs;
675 
676  arma::mat &local_matrix = *(data_->system_.local_matrix);
677 
678 
679  if (fill_matrix)
680  balance_->start_flux_assembly(water_balance_idx_);
681 
682  for (unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++) {
683  auto ele_ac = mh_dh.accessor(i_loc);
684  unsigned int nsides = ele_ac.n_sides();
685  data_->system_.dirichlet_edge.resize(nsides);
686 
687 
688 
689  for (unsigned int i = 0; i < nsides; i++) {
690 
691 /* if (! side_ds->is_local(idx_side)) {
692  cout << el_ds->myp() << " : iside: " << ele.index() << " [" << el_ds->begin() << ", " << el_ds->end() << "]" << endl;
693  cout << el_ds->myp() << " : iside: " << idx_side << " [" << side_ds->begin() << ", " << side_ds->end() << "]" << endl;
694 
695  }*/
696 
697  side_rows[i] = side_row = ele_ac.side_row(i);
698  edge_rows[i] = edge_row = ele_ac.edge_row(i);
699  bcd=ele_ac.side(i)->cond();
700 
701  // gravity term on RHS
702  //
703  loc_side_rhs[i] = 0;
704 
705  // set block C and C': side-edge, edge-side
706  double c_val = 1.0;
707  data_->system_.dirichlet_edge[i] = 0;
708 
709  if (bcd) {
710  ElementAccessor<3> b_ele = bcd->element_accessor();
711  EqData::BC_Type type = (EqData::BC_Type)data_->bc_type.value(b_ele.centre(), b_ele);
712 
713  double cross_section = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
714 
715  if ( type == EqData::none) {
716  // homogeneous neumann
717  } else if ( type == EqData::dirichlet ) {
718  double bc_pressure = data_->bc_pressure.value(b_ele.centre(), b_ele);
719  c_val = 0.0;
720  loc_side_rhs[i] -= bc_pressure;
721  ls->rhs_set_value(edge_row, -bc_pressure);
722  ls->mat_set_value(edge_row, edge_row, -1.0);
723  data_->system_.dirichlet_edge[i] = 1;
724 
725  } else if ( type == EqData::total_flux) {
726 
727  // internally we work with outward flux
728  double bc_flux = -data_->bc_flux.value(b_ele.centre(), b_ele);
729  double bc_pressure = data_->bc_pressure.value(b_ele.centre(), b_ele);
730  double bc_sigma = data_->bc_robin_sigma.value(b_ele.centre(), b_ele);
731  //DebugOut().fmt("erow: {} flux: {} mesure: {} cs: {}", edge_row, bc_flux, bcd->element()->measure(), cross_section);
732  ls->mat_set_value(edge_row, edge_row, -bcd->element()->measure() * bc_sigma * cross_section );
733  ls->rhs_set_value(edge_row, (bc_flux - bc_sigma * bc_pressure) * bcd->element()->measure() * cross_section);
734 
735  } else if (type==EqData::seepage) {
736  is_linear_=false;
737  //unsigned int loc_edge_idx = edge_row - rows_ds->begin() - side_ds->lsize() - el_ds->lsize();
738  unsigned int loc_edge_idx = bcd->bc_ele_idx_;
739  char & switch_dirichlet = bc_switch_dirichlet[loc_edge_idx];
740  double bc_pressure = data_->bc_switch_pressure.value(b_ele.centre(), b_ele);
741  double bc_flux = -data_->bc_flux.value(b_ele.centre(), b_ele);
742  double side_flux=bc_flux * bcd->element()->measure() * cross_section;
743 
744  // ** Update BC type. **
745  if (switch_dirichlet) {
746  // check and possibly switch to flux BC
747  // The switch raise error on the corresponding edge row.
748  // Magnitude of the error is abs(solution_flux - side_flux).
749  ASSERT_DBG(mh_dh.rows_ds->is_local(side_row))(side_row);
750  unsigned int loc_side_row = ele_ac.side_local_row(i);
751  double & solution_flux = ls->get_solution_array()[loc_side_row];
752 
753  if ( solution_flux < side_flux) {
754  //DebugOut().fmt("x: {}, to neum, p: {} f: {} -> f: {}\n", b_ele.centre()[0], bc_pressure, solution_flux, side_flux);
755  solution_flux = side_flux;
756  switch_dirichlet=0;
757 
758  }
759  } else {
760  // check and possibly switch to pressure BC
761  // TODO: What is the appropriate DOF in not local?
762  // The switch raise error on the corresponding side row.
763  // Magnitude of the error is abs(solution_head - bc_pressure)
764  // Since usually K is very large, this error would be much
765  // higher then error caused by the inverse switch, this
766  // cause that a solution with the flux violating the
767  // flux inequality leading may be accepted, while the error
768  // in pressure inequality is always satisfied.
769  ASSERT_DBG(mh_dh.rows_ds->is_local(edge_row))(edge_row);
770  unsigned int loc_edge_row = ele_ac.edge_local_row(i);
771  double & solution_head = ls->get_solution_array()[loc_edge_row];
772 
773  if ( solution_head > bc_pressure) {
774  //DebugOut().fmt("x: {}, to dirich, p: {} -> p: {} f: {}\n",b_ele.centre()[0], solution_head, bc_pressure, bc_flux);
775  solution_head = bc_pressure;
776  switch_dirichlet=1;
777  }
778  }
779 
780  // ** Apply BCUpdate BC type. **
781  // Force Dirichlet type during the first iteration of the unsteady case.
782  if (switch_dirichlet || (use_steady_assembly_ && nonlinear_iteration_ == 0) ) {
783  //DebugOut().fmt("x: {}, dirich, bcp: {}\n", b_ele.centre()[0], bc_pressure);
784  c_val = 0.0;
785  loc_side_rhs[i] -= bc_pressure;
786  ls->rhs_set_value(edge_row, -bc_pressure);
787  ls->mat_set_value(edge_row, edge_row, -1.0);
788  data_->system_.dirichlet_edge[i] = 1;
789  } else {
790  //DebugOut()("x: {}, neuman, q: {} bcq: {}\n", b_ele.centre()[0], side_flux, bc_flux);
791  ls->rhs_set_value(edge_row, side_flux);
792  }
793 
794  } else if (type==EqData::river) {
795  is_linear_=false;
796  //unsigned int loc_edge_idx = edge_row - rows_ds->begin() - side_ds->lsize() - el_ds->lsize();
797  //unsigned int loc_edge_idx = bcd->bc_ele_idx_;
798  //char & switch_dirichlet = bc_switch_dirichlet[loc_edge_idx];
799 
800  double bc_pressure = data_->bc_pressure.value(b_ele.centre(), b_ele);
801  double bc_switch_pressure = data_->bc_switch_pressure.value(b_ele.centre(), b_ele);
802  double bc_flux = -data_->bc_flux.value(b_ele.centre(), b_ele);
803  double bc_sigma = data_->bc_robin_sigma.value(b_ele.centre(), b_ele);
804  ASSERT_DBG(mh_dh.rows_ds->is_local(edge_row))(edge_row);
805  unsigned int loc_edge_row = ele_ac.edge_local_row(i);
806  double & solution_head = ls->get_solution_array()[loc_edge_row];
807 
808 
809  // Force Robin type during the first iteration of the unsteady case.
810  if (solution_head > bc_switch_pressure || (use_steady_assembly_ && nonlinear_iteration_ ==0)) {
811  // Robin BC
812  //DebugOut().fmt("x: {}, robin, bcp: {}\n", b_ele.centre()[0], bc_pressure);
813  ls->rhs_set_value(edge_row, bcd->element()->measure() * cross_section * (bc_flux - bc_sigma * bc_pressure) );
814  ls->mat_set_value(edge_row, edge_row, -bcd->element()->measure() * bc_sigma * cross_section );
815  } else {
816  // Neumann BC
817  //DebugOut().fmt("x: {}, neuman, q: {} bcq: {}\n", b_ele.centre()[0], bc_switch_pressure, bc_pressure);
818  double bc_total_flux = bc_flux + bc_sigma*(bc_switch_pressure - bc_pressure);
819  ls->rhs_set_value(edge_row, bc_total_flux * bcd->element()->measure() * cross_section);
820  }
821  } else {
822  xprintf(UsrErr, "BC type not supported.\n");
823  }
824 
825  if (fill_matrix)
826  {
827  /*
828  DebugOut()("add_flux: {} {} {} {}\n",
829  mh_dh.el_ds->myp(),
830  ele_ac.ele_global_idx(),
831  loc_b,
832  side_row);*/
833  balance_->add_flux_matrix_values(water_balance_idx_, loc_b, {side_row}, {1});
834  }
835  ++loc_b;
836  }
837  ls->mat_set_value(side_row, edge_row, c_val);
838  ls->mat_set_value(edge_row, side_row, c_val);
839 
840  }
841 
842  if (fill_matrix) {
843  assembler[ele_ac.dim()-1]->assembly_local_matrix(ele_ac);
844 
845  // assemble matrix for weights in BDDCML
846  // approximation to diagonal of
847  // S = -C - B*inv(A)*B'
848  // as
849  // diag(S) ~ - diag(C) - 1./diag(A)
850  // the weights form a partition of unity to average a discontinuous solution from neighbouring subdomains
851  // to a continuous one
852  // it is important to scale the effect - if conductivity is low for one subdomain and high for the other,
853  // trust more the one with low conductivity - it will be closer to the truth than an arithmetic average
854  if ( typeid(*ls) == typeid(LinSys_BDDC) ) {
855  for(unsigned int i=0; i < nsides; i++) {
856  double val_side = local_matrix(i,i);
857  double val_edge = -1./local_matrix(i,i);
858 
859  static_cast<LinSys_BDDC*>(ls)->diagonal_weights_set_value( side_rows[i], val_side );
860  static_cast<LinSys_BDDC*>(ls)->diagonal_weights_set_value( edge_rows[i], val_edge );
861  }
862  }
863  }
864 
865  ls->rhs_set_values(nsides, side_rows, loc_side_rhs);
866 
867 
868  // set block A: side-side on one element - block diagonal matrix
869  ls->mat_set_values(nsides, side_rows, nsides, side_rows, local_matrix.memptr());
870  // set block B, B': element-side, side-element
871  int ele_row = ele_ac.ele_row();
872  ls->mat_set_values(1, &ele_row, nsides, side_rows, minus_ones);
873  ls->mat_set_values(nsides, side_rows, 1, &ele_row, minus_ones);
874 
875 
876  // D block: diagonal: element-element
877 
878  ls->mat_set_value(ele_row, ele_row, 0.0); // maybe this should be in virtual block for schur preallocation
879 
880  if ( typeid(*ls) == typeid(LinSys_BDDC) ) {
881  double val_ele = 1.;
882  static_cast<LinSys_BDDC*>(ls)->diagonal_weights_set_value( ele_row, val_ele );
883  }
884 
885  // D, E',E block: compatible connections: element-edge
886 
887  for (unsigned int i = 0; i < ele_ac.full_iter()->n_neighs_vb; i++) {
888  // every compatible connection adds a 2x2 matrix involving
889  // current element pressure and a connected edge pressure
890  ngh= ele_ac.full_iter()->neigh_vb[i];
891  tmp_rows[0]=ele_row;
892  tmp_rows[1]=mh_dh.row_4_edge[ ngh->edge_idx() ];
893 
894  if (fill_matrix)
895  assembler[ngh->side()->dim()]->assembly_local_vb(local_vb, ele_ac.full_iter(), ngh);
896 
897  ls->mat_set_values(2, tmp_rows, 2, tmp_rows, local_vb);
898 
899  // update matrix for weights in BDDCML
900  if ( typeid(*ls) == typeid(LinSys_BDDC) ) {
901  int ind = tmp_rows[1];
902  // there is -value on diagonal in block C!
903  double new_val = local_vb[0];
904  static_cast<LinSys_BDDC*>(ls)->diagonal_weights_set_value( ind, new_val );
905  }
906 
907  if (n_schur_compls == 2) {
908  // for 2. Schur: N dim edge is conected with N dim element =>
909  // there are nz between N dim edge and N-1 dim edges of the element
910 
911  ls->mat_set_values(nsides, edge_rows, 1, tmp_rows+1, zeros);
912  ls->mat_set_values(1, tmp_rows+1, nsides, edge_rows, zeros);
913 
914  // save all global edge indices to higher positions
915  tmp_rows[2+i] = tmp_rows[1];
916  }
917  }
918 
919 
920  // add virtual values for schur complement allocation
921  uint n_neigh;
922  switch (n_schur_compls) {
923  case 2:
924  n_neigh = ele_ac.full_iter()->n_neighs_vb;
925  // Connections between edges of N+1 dim. elements neighboring with actual N dim element 'ele'
926  OLD_ASSERT(n_neigh*n_neigh<1000, "Too many values in E block.");
927  ls->mat_set_values(ele_ac.full_iter()->n_neighs_vb, tmp_rows+2,
928  ele_ac.full_iter()->n_neighs_vb, tmp_rows+2, zeros);
929 
930  case 1: // included also for case 2
931  // -(C')*(A-)*B block and its transpose conect edge with its elements
932  ls->mat_set_values(1, &ele_row, ele_ac.n_sides(), edge_rows, zeros);
933  ls->mat_set_values(ele_ac.n_sides(), edge_rows, 1, &ele_row, zeros);
934  // -(C')*(A-)*C block conect all edges of every element
935  ls->mat_set_values(ele_ac.n_sides(), edge_rows, ele_ac.n_sides(), edge_rows, zeros);
936  }
937  }
938 
939  if (fill_matrix)
940  balance_->finish_flux_assembly(water_balance_idx_);
941 
942 
943 
944  if (mortar_method_ == MortarP0) {
945  P0_CouplingAssembler(*this).assembly(*ls);
946  } else if (mortar_method_ == MortarP1) {
947  P1_CouplingAssembler(*this).assembly(*ls);
948  }
949 }
950 
951 
953 {
954  START_TIMER("assembly source term");
955  balance_->start_source_assembly(water_balance_idx_);
956 
957  for (unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++) {
958  auto ele_ac = mh_dh.accessor(i_loc);
959 
960  double cs = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
961 
962  // set sources
963  double source = ele_ac.measure() * cs *
964  data_->water_source_density.value(ele_ac.centre(), ele_ac.element_accessor());
965  schur0->rhs_set_value(ele_ac.ele_row(), -1.0 * source );
966 
967  balance_->add_source_vec_values(water_balance_idx_, ele_ac.region().bulk_idx(), {(int) ele_ac.ele_row()}, {source});
968  }
969 
970  balance_->finish_source_assembly(water_balance_idx_);
971 }
972 
973 
975  vector<int> &dofs, unsigned int &ele_type, double &delta, arma::vec &dirichlet) {
976 
977  const Element *ele;
978 
979  if (i_ele == (int)(ml_it_->size()) ) { // master element .. 1D
980  ele_type = 0;
981  delta = -delta_0;
982  ele=master_;
983  } else {
984  ele_type = 1;
985  const Intersection &isect=intersections_[ (*ml_it_)[i_ele] ];
986  delta = isect.intersection_true_size();
987  ele = isect.slave_iter();
988  }
989 
990  dofs.resize(ele->n_sides());
991  dirichlet.resize(ele->n_sides());
992  dirichlet.zeros();
993 
994  for(unsigned int i_side=0; i_side < ele->n_sides(); i_side++ ) {
995  dofs[i_side]=darcy_.mh_dh.row_4_edge[ele->side(i_side)->edge_idx()];
996  Boundary * bcd = ele->side(i_side)->cond();
997  if (bcd) {
998  ElementAccessor<3> b_ele = bcd->element_accessor();
999  auto type = (DarcyMH::EqData::BC_Type)darcy_.data_->bc_type.value(b_ele.centre(), b_ele);
1000  //DebugOut().fmt("bcd id: {} sidx: {} type: {}\n", ele->id(), i_side, type);
1001  if (type == DarcyMH::EqData::dirichlet) {
1002  //DebugOut().fmt("Dirichlet: {}\n", ele->index());
1003  dofs[i_side] = -dofs[i_side];
1004  double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.centre(), b_ele);
1005  dirichlet[i_side] = bc_pressure;
1006  }
1007  }
1008  }
1009 
1010 }
1011 
1012 /**
1013  * Works well but there is large error next to the boundary.
1014  */
1016  double delta_i, delta_j;
1017  arma::mat product;
1018  arma::vec dirichlet_i, dirichlet_j;
1019  unsigned int ele_type_i, ele_type_j; // element type 0-master, 1-slave for row and col
1020 
1021  unsigned int i,j;
1022  vector<int> dofs_i,dofs_j;
1023 
1024  for(ml_it_ = master_list_.begin(); ml_it_ != master_list_.end(); ++ml_it_) {
1025 
1026  if (ml_it_->size() == 0) continue; // skip empty masters
1027 
1028 
1029  // on the intersection element we consider
1030  // * intersection dofs for master and slave
1031  // those are dofs of the space into which we interpolate
1032  // base functions from individual master and slave elements
1033  // For the master dofs both are usualy eqivalent.
1034  // * original dofs - for master same as intersection dofs, for slave
1035  // all dofs of slave elements
1036 
1037  // form list of intersection dofs, in this case pressures in barycenters
1038  // but we do not use those form MH system in order to allow second schur somplement. We rather map these
1039  // dofs to pressure traces, i.e. we use averages of traces as barycentric values.
1040 
1041 
1042  master_ = intersections_[ml_it_->front()].master_iter();
1043  delta_0 = master_->measure();
1044 
1045  double master_sigma=darcy_.data_->sigma.value( master_->centre(), master_->element_accessor());
1046 
1047  // rows
1048  double check_delta_sum=0;
1049  for(i = 0; i <= ml_it_->size(); ++i) {
1050  pressure_diff(i, dofs_i, ele_type_i, delta_i, dirichlet_i);
1051  check_delta_sum+=delta_i;
1052  //columns
1053  for (j = 0; j <= ml_it_->size(); ++j) {
1054  pressure_diff(j, dofs_j, ele_type_j, delta_j, dirichlet_j);
1055 
1056  double scale = -master_sigma * delta_i * delta_j / delta_0;
1057  product = scale * tensor_average[ele_type_i][ele_type_j];
1058 
1059  arma::vec rhs(dofs_i.size());
1060  rhs.zeros();
1061  ls.set_values( dofs_i, dofs_j, product, rhs, dirichlet_i, dirichlet_j);
1062  //auto dofs_i_cp=dofs_i;
1063  //auto dofs_j_cp=dofs_j;
1064  //ls.set_values( dofs_i_cp, dofs_j_cp, product, rhs, dirichlet_i, dirichlet_j);
1065  }
1066  }
1067  OLD_ASSERT(check_delta_sum < 1E-5*delta_0, "sum err %f > 0\n", check_delta_sum/delta_0);
1068  } // loop over master elements
1069 }
1070 
1071 
1072 
1073  void P1_CouplingAssembler::add_sides(const Element * ele, unsigned int shift, vector<int> &dofs, vector<double> &dirichlet)
1074  {
1075 
1076  for(unsigned int i_side=0; i_side < ele->n_sides(); i_side++ ) {
1077  dofs[shift+i_side] = darcy_.mh_dh.row_4_edge[ele->side(i_side)->edge_idx()];
1078  Boundary * bcd = ele->side(i_side)->cond();
1079 
1080  if (bcd) {
1081  ElementAccessor<3> b_ele = bcd->element_accessor();
1082  auto type = (DarcyMH::EqData::BC_Type)darcy_.data_->bc_type.value(b_ele.centre(), b_ele);
1083  //DebugOut().fmt("bcd id: {} sidx: {} type: {}\n", ele->id(), i_side, type);
1084  if (type == DarcyMH::EqData::dirichlet) {
1085  //DebugOut().fmt("Dirichlet: {}\n", ele->index());
1086  dofs[shift + i_side] = -dofs[shift + i_side];
1087  double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.centre(), b_ele);
1088  dirichlet[shift + i_side] = bc_pressure;
1089  }
1090  }
1091  }
1092  }
1093 
1094 
1095 /**
1096  * P1 connection of different dimensions
1097  *
1098  * - 20.11. 2014 - very poor convergence, big error in pressure even at internal part of the fracture
1099  */
1100 
1101 void P1_CouplingAssembler::assembly(LinSys &ls) {
1102 
1103  for (const Intersection &intersec : intersections_) {
1104  const Element * master = intersec.master_iter();
1105  const Element * slave = intersec.slave_iter();
1106 
1107  add_sides(slave, 0, dofs, dirichlet);
1108  add_sides(master, 3, dofs, dirichlet);
1109 
1110  double master_sigma=darcy_.data_->sigma.value( master->centre(), master->element_accessor());
1111 
1112 /*
1113  * Local coordinates on 1D
1114  * t0
1115  * node 0: 0.0
1116  * node 1: 1.0
1117  *
1118  * base fce points
1119  * t0 = 0.0 on side 0 node 0
1120  * t0 = 1.0 on side 1 node 1
1121  *
1122  * Local coordinates on 2D
1123  * t0 t1
1124  * node 0: 0.0 0.0
1125  * node 1: 1.0 0.0
1126  * node 2: 0.0 1.0
1127  *
1128  * base fce points
1129  * t0=0.5, t1=0.0 on side 0 nodes (0,1)
1130  * t0=0.5, t1=0.5 on side 1 nodes (1,2)
1131  * t0=0.0, t1=0.5 on side 2 nodes (2,0)
1132  */
1133 
1134 
1135 
1136  arma::vec point_Y(1);
1137  point_Y.fill(1.0);
1138  arma::vec point_2D_Y(intersec.map_to_slave(point_Y)); // local coordinates of Y on slave (1, t0, t1)
1139  arma::vec point_1D_Y(intersec.map_to_master(point_Y)); // local coordinates of Y on master (1, t0)
1140 
1141  arma::vec point_X(1);
1142  point_X.fill(0.0);
1143  arma::vec point_2D_X(intersec.map_to_slave(point_X)); // local coordinates of X on slave (1, t0, t1)
1144  arma::vec point_1D_X(intersec.map_to_master(point_X)); // local coordinates of X on master (1, t0)
1145 
1146  arma::mat base_2D(3, 3);
1147  // basis functions are numbered as sides
1148  // TODO:
1149  // Use RT finite element to evaluate following matrices.
1150 
1151  // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1152  // 2D RT_i(t0, t1) = a0 + a1*t0 + a2*t1
1153  // a0 a1 a2
1154  base_2D << 1.0 << 0.0 << -2.0 << arma::endr // RT for side 0
1155  << 1.0 << -2.0 << 0.0 << arma::endr // RT for side 1
1156  << -1.0 << 2.0 << 2.0 << arma::endr;// RT for side 2
1157 
1158 
1159  arma::mat base_1D(2, 2);
1160  // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1161  // 1D RT_i(t0) = a0 + a1 * t0
1162  // a0 a1
1163  base_1D << 1.0 << -1.0 << arma::endr // RT for side 0,
1164  << 0.0 << 1.0 << arma::endr; // RT for side 1,
1165 
1166 
1167 
1168  // Consider both 2D and 1D value are defined for the test function
1169  // related to the each of 5 DOFs involved in the intersection.
1170  // One of these values is always zero.
1171  // Compute difference of the 2D and 1D value for every DOF.
1172  // Compute value of this difference in both endpoints X,Y of the intersection.
1173 
1174  arma::vec difference_in_Y(5);
1175  arma::vec difference_in_X(5);
1176  // slave sides 0,1,2
1177  difference_in_Y.subvec(0, 2) = -base_2D * point_2D_Y;
1178  difference_in_X.subvec(0, 2) = -base_2D * point_2D_X;
1179  // master sides 3,4
1180  difference_in_Y.subvec(3, 4) = base_1D * point_1D_Y;
1181  difference_in_X.subvec(3, 4) = base_1D * point_1D_X;
1182 
1183  // applying the Simpson's rule
1184  // to the product of two linear functions f, g we get
1185  // (b-a)/6 * ( 3*f(a)*g(a) + 3*f(b)*g(b) + 2*f(a)*g(b) + 2*f(b)*g(a) )
1186  arma::mat A(5, 5);
1187  for (int i = 0; i < 5; ++i) {
1188  for (int j = 0; j < 5; ++j) {
1189  A(i, j) = -master_sigma * intersec.intersection_true_size() *
1190  ( difference_in_Y[i] * difference_in_Y[j]
1191  + difference_in_Y[i] * difference_in_X[j]/2
1192  + difference_in_X[i] * difference_in_Y[j]/2
1193  + difference_in_X[i] * difference_in_X[j]
1194  ) * (1.0 / 3.0);
1195 
1196  }
1197  }
1198  auto dofs_cp=dofs;
1199  ls.set_values( dofs_cp, dofs_cp, A, rhs, dirichlet, dirichlet);
1200 
1201  }
1202 }
1203 
1204 
1205 
1206 /*******************************************************************************
1207  * COMPOSE WATER MH MATRIX WITHOUT SCHUR COMPLEMENT
1208  ******************************************************************************/
1209 
1210 void DarcyMH::create_linear_system(Input::AbstractRecord in_rec) {
1211 
1212  START_TIMER("preallocation");
1213 
1214  if (schur0 == NULL) { // create Linear System for MH matrix
1215 
1216  if (in_rec.type() == LinSys_BDDC::get_input_type()) {
1217 #ifdef FLOW123D_HAVE_BDDCML
1218  WarningOut() << "For BDDC no Schur complements are used.";
1219  mh_dh.prepare_parallel_bddc();
1220  n_schur_compls = 0;
1221  LinSys_BDDC *ls = new LinSys_BDDC(mh_dh.global_row_4_sub_row->size(), &(*mh_dh.rows_ds),
1222  3, // 3 == la::BddcmlWrapper::SPD_VIA_SYMMETRICGENERAL
1223  1, // 1 == number of subdomains per process
1224  true); // swap signs of matrix and rhs to make the matrix SPD
1225  ls->set_from_input(in_rec);
1226  ls->set_solution( NULL );
1227  // possible initialization particular to BDDC
1228  START_TIMER("BDDC set mesh data");
1229  set_mesh_data_for_bddc(ls);
1230  schur0=ls;
1231  END_TIMER("BDDC set mesh data");
1232 #else
1233  xprintf(Err, "Flow123d was not build with BDDCML support.\n");
1234 #endif // FLOW123D_HAVE_BDDCML
1235  }
1236  else if (in_rec.type() == LinSys_PETSC::get_input_type()) {
1237  // use PETSC for serial case even when user wants BDDC
1238  if (n_schur_compls > 2) {
1239  WarningOut() << "Invalid number of Schur Complements. Using 2.";
1240  n_schur_compls = 2;
1241  }
1242 
1243  LinSys_PETSC *schur1, *schur2;
1244 
1245  if (n_schur_compls == 0) {
1246  LinSys_PETSC *ls = new LinSys_PETSC( &(*mh_dh.rows_ds) );
1247 
1248  // temporary solution; we have to set precision also for sequantial case of BDDC
1249  // final solution should be probably call of direct solver for oneproc case
1250  if (in_rec.type() != LinSys_BDDC::get_input_type()) ls->set_from_input(in_rec);
1251  else {
1252  ls->LinSys::set_from_input(in_rec); // get only common options
1253  }
1254 
1255  ls->set_solution( NULL );
1256  schur0=ls;
1257  } else {
1258  IS is;
1259  ISCreateStride(PETSC_COMM_WORLD, mh_dh.side_ds->lsize(), mh_dh.rows_ds->begin(), 1, &is);
1260  //OLD_ASSERT(err == 0,"Error in ISCreateStride.");
1261 
1262  SchurComplement *ls = new SchurComplement(is, &(*mh_dh.rows_ds));
1263 
1264  // make schur1
1265  Distribution *ds = ls->make_complement_distribution();
1266  if (n_schur_compls==1) {
1267  schur1 = new LinSys_PETSC(ds);
1268  schur1->set_positive_definite();
1269  } else {
1270  IS is;
1271  ISCreateStride(PETSC_COMM_WORLD, mh_dh.el_ds->lsize(), ls->get_distribution()->begin(), 1, &is);
1272  //OLD_ASSERT(err == 0,"Error in ISCreateStride.");
1273  SchurComplement *ls1 = new SchurComplement(is, ds); // is is deallocated by SchurComplement
1274  ls1->set_negative_definite();
1275 
1276  // make schur2
1277  schur2 = new LinSys_PETSC( ls1->make_complement_distribution() );
1278  schur2->set_positive_definite();
1279  ls1->set_complement( schur2 );
1280  schur1 = ls1;
1281  }
1282  ls->set_complement( schur1 );
1283  ls->set_from_input(in_rec);
1284  ls->set_solution( NULL );
1285  schur0=ls;
1286  }
1287 
1288  START_TIMER("PETSC PREALLOCATION");
1289  schur0->set_symmetric();
1290  schur0->start_allocation();
1291  assembly_mh_matrix(MultidimAssembler()); // preallocation
1292  VecZeroEntries(schur0->get_solution());
1293  END_TIMER("PETSC PREALLOCATION");
1294  }
1295  else {
1296  xprintf(Err, "Unknown solver type. Internal error.\n");
1297  }
1298 
1299  END_TIMER("preallocation");
1300  make_serial_scatter();
1301 
1302  }
1303 
1304 }
1305 
1306 
1307 
1308 
1309 void DarcyMH::assembly_linear_system() {
1310  START_TIMER("DarcyFlowMH_Steady::assembly_linear_system");
1311 
1312  is_linear_=true;
1313  bool is_steady = zero_time_term();
1314  //DebugOut() << "Assembly linear system\n";
1315  if (data_changed_) {
1316  data_changed_ = false;
1317  //DebugOut() << "Data changed\n";
1318  // currently we have no optimization for cases when just time term data or RHS data are changed
1319  START_TIMER("full assembly");
1320  if (typeid(*schur0) != typeid(LinSys_BDDC)) {
1321  schur0->start_add_assembly(); // finish allocation and create matrix
1322  }
1323 
1324  auto multidim_assembler = AssemblyBase::create< AssemblyMH >(data_);
1325 
1326  schur0->mat_zero_entries();
1327  schur0->rhs_zero_entries();
1328 
1329  assembly_source_term();
1330  assembly_mh_matrix( multidim_assembler ); // fill matrix
1331 
1332  schur0->finish_assembly();
1333  schur0->set_matrix_changed();
1334  //MatView( *const_cast<Mat*>(schur0->get_matrix()), PETSC_VIEWER_STDOUT_WORLD );
1335  //VecView( *const_cast<Vec*>(schur0->get_rhs()), PETSC_VIEWER_STDOUT_WORLD);
1336 
1337  if (! is_steady) {
1338  START_TIMER("fix time term");
1339  //DebugOut() << "setup time term\n";
1340  // assembly time term and rhs
1341  setup_time_term();
1342  modify_system();
1343  }
1344  else
1345  {
1346  balance_->start_mass_assembly(water_balance_idx_);
1347  balance_->finish_mass_assembly(water_balance_idx_);
1348  }
1349  END_TIMER("full assembly");
1350  } else {
1351  START_TIMER("modify system");
1352  if (! is_steady) {
1353  modify_system();
1354  } else {
1355  //xprintf(PrgErr, "Planned computation time for steady solver, but data are not changed.\n");
1356  }
1357  END_TIMER("modiffy system");
1358  }
1359 
1360 }
1361 
1362 
1363 
1364 void DarcyMH::set_mesh_data_for_bddc(LinSys_BDDC * bddc_ls) {
1365  START_TIMER("DarcyFlowMH_Steady::set_mesh_data_for_bddc");
1366  // prepare mesh for BDDCML
1367  // initialize arrays
1368  // auxiliary map for creating coordinates of local dofs and global-to-local numbering
1369  std::map<int,arma::vec3> localDofMap;
1370  // connectivity for the subdomain, i.e. global dof numbers on element, stored element-by-element
1371  // Indices of Nodes on Elements
1372  std::vector<int> inet;
1373  // number of degrees of freedom on elements - determines elementwise chunks of INET array
1374  // Number of Nodes on Elements
1375  std::vector<int> nnet;
1376  // Indices of Subdomain Elements in Global Numbering - for local elements, their global indices
1377  std::vector<int> isegn;
1378 
1379  // This array is currently not used in BDDCML, it was used as an interface scaling alternative to scaling
1380  // by diagonal. It corresponds to the rho-scaling.
1381  std::vector<double> element_permeability;
1382 
1383  // maximal and minimal dimension of elements
1384  uint elDimMax = 1;
1385  uint elDimMin = 3;
1386  for ( unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++ ) {
1387  auto ele_ac = mh_dh.accessor(i_loc);
1388  // for each element, create local numbering of dofs as fluxes (sides), pressure (element centre), Lagrange multipliers (edges), compatible connections
1389 
1390  elDimMax = std::max( elDimMax, ele_ac.dim() );
1391  elDimMin = std::min( elDimMin, ele_ac.dim() );
1392 
1393  isegn.push_back( ele_ac.ele_global_idx() );
1394  int nne = 0;
1395 
1396  FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) {
1397  // insert local side dof
1398  int side_row = ele_ac.side_row(si);
1399  arma::vec3 coord = ele_ac.side(si)->centre();
1400 
1401  localDofMap.insert( std::make_pair( side_row, coord ) );
1402  inet.push_back( side_row );
1403  nne++;
1404  }
1405 
1406  // insert local pressure dof
1407  int el_row = ele_ac.ele_row();
1408  arma::vec3 coord = ele_ac.centre();
1409  localDofMap.insert( std::make_pair( el_row, coord ) );
1410  inet.push_back( el_row );
1411  nne++;
1412 
1413  FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) {
1414  // insert local edge dof
1415  int edge_row = ele_ac.edge_row(si);
1416  arma::vec3 coord = ele_ac.side(si)->centre();
1417 
1418  localDofMap.insert( std::make_pair( edge_row, coord ) );
1419  inet.push_back( edge_row );
1420  nne++;
1421  }
1422 
1423  // insert dofs related to compatible connections
1424  for ( unsigned int i_neigh = 0; i_neigh < ele_ac.full_iter()->n_neighs_vb; i_neigh++) {
1425  int edge_row = mh_dh.row_4_edge[ ele_ac.full_iter()->neigh_vb[i_neigh]->edge_idx() ];
1426  arma::vec3 coord = ele_ac.full_iter()->neigh_vb[i_neigh]->edge()->side(0)->centre();
1427 
1428  localDofMap.insert( std::make_pair( edge_row, coord ) );
1429  inet.push_back( edge_row );
1430  nne++;
1431  }
1432 
1433  nnet.push_back( nne );
1434 
1435  // version for rho scaling
1436  // trace computation
1437  arma::vec3 centre = ele_ac.centre();
1438  double conduct = data_->conductivity.value( centre , ele_ac.element_accessor() );
1439  auto aniso = data_->anisotropy.value( centre, ele_ac.element_accessor() );
1440 
1441  // compute mean on the diagonal
1442  double coef = 0.;
1443  for ( int i = 0; i < 3; i++) {
1444  coef = coef + aniso.at(i,i);
1445  }
1446  // Maybe divide by cs
1447  coef = conduct*coef / 3;
1448 
1449  OLD_ASSERT( coef > 0.,
1450  "Zero coefficient of hydrodynamic resistance %f . \n ", coef );
1451  element_permeability.push_back( 1. / coef );
1452  }
1453  //convert set of dofs to vectors
1454  // number of nodes (= dofs) on the subdomain
1455  int numNodeSub = localDofMap.size();
1456  OLD_ASSERT_EQUAL( (unsigned int)numNodeSub, mh_dh.global_row_4_sub_row->size() );
1457  // Indices of Subdomain Nodes in Global Numbering - for local nodes, their global indices
1458  std::vector<int> isngn( numNodeSub );
1459  // pseudo-coordinates of local nodes (i.e. dofs)
1460  // they need not be exact, they are used just for some geometrical considerations in BDDCML,
1461  // such as selection of corners maximizing area of a triangle, bounding boxes fro subdomains to
1462  // find candidate neighbours etc.
1463  std::vector<double> xyz( numNodeSub * 3 ) ;
1464  int ind = 0;
1465  std::map<int,arma::vec3>::iterator itB = localDofMap.begin();
1466  for ( ; itB != localDofMap.end(); ++itB ) {
1467  isngn[ind] = itB -> first;
1468 
1469  arma::vec3 coord = itB -> second;
1470  for ( int j = 0; j < 3; j++ ) {
1471  xyz[ j*numNodeSub + ind ] = coord[j];
1472  }
1473 
1474  ind++;
1475  }
1476  localDofMap.clear();
1477 
1478  // Number of Nodal Degrees of Freedom
1479  // nndf is trivially one - dofs coincide with nodes
1480  std::vector<int> nndf( numNodeSub, 1 );
1481 
1482  // prepare auxiliary map for renumbering nodes
1483  typedef std::map<int,int> Global2LocalMap_; //! type for storage of global to local map
1484  Global2LocalMap_ global2LocalNodeMap;
1485  for ( unsigned ind = 0; ind < isngn.size(); ++ind ) {
1486  global2LocalNodeMap.insert( std::make_pair( static_cast<unsigned>( isngn[ind] ), ind ) );
1487  }
1488 
1489  // renumber nodes in the inet array to locals
1490  int indInet = 0;
1491  for ( unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) {
1492  int nne = nnet[ iEle ];
1493  for ( int ien = 0; ien < nne; ien++ ) {
1494 
1495  int indGlob = inet[indInet];
1496  // map it to local node
1497  Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob );
1498  OLD_ASSERT( pos != global2LocalNodeMap.end(),
1499  "Cannot remap node index %d to local indices. \n ", indGlob );
1500  int indLoc = static_cast<int> ( pos -> second );
1501 
1502  // store the node
1503  inet[ indInet++ ] = indLoc;
1504  }
1505  }
1506 
1507  int numNodes = size;
1508  int numDofsInt = size;
1509  int spaceDim = 3; // TODO: what is the proper value here?
1510  int meshDim = elDimMax;
1511 
1512  bddc_ls -> load_mesh( spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim );
1513 }
1514 
1515 
1516 
1517 
1518 //=============================================================================
1519 // DESTROY WATER MH SYSTEM STRUCTURE
1520 //=============================================================================
1521 DarcyMH::~DarcyMH() {
1522  if (schur0 != NULL) {
1523  delete schur0;
1524  VecScatterDestroy(&par_to_all);
1525  }
1526 
1527  if (solution != NULL) {
1528  chkerr(VecDestroy(&sol_vec));
1529  delete [] solution;
1530  }
1531 
1532  if (output_object) delete output_object;
1533 
1534 
1535 
1536 }
1537 
1538 
1539 // ================================================
1540 // PARALLLEL PART
1541 //
1542 
1543 
1544 void DarcyMH::make_serial_scatter() {
1545  START_TIMER("prepare scatter");
1546  // prepare Scatter form parallel to sequantial in original numbering
1547  {
1548  IS is_loc;
1549  int i, *loc_idx; //, si;
1550 
1551  // create local solution vector
1552  solution = new double[size];
1553  VecCreateSeqWithArray(PETSC_COMM_SELF,1, size, solution,
1554  &(sol_vec));
1555 
1556  // create seq. IS to scatter par solutin to seq. vec. in original order
1557  // use essentialy row_4_id arrays
1558  loc_idx = new int [size];
1559  i = 0;
1560  FOR_ELEMENTS(mesh_, ele) {
1561  FOR_ELEMENT_SIDES(ele,si) {
1562  loc_idx[i++] = mh_dh.side_row_4_id[ mh_dh.side_dof( ele->side(si) ) ];
1563  }
1564  }
1565  FOR_ELEMENTS(mesh_, ele) {
1566  loc_idx[i++] = mh_dh.row_4_el[ele.index()];
1567  }
1568  for(unsigned int i_edg=0; i_edg < mesh_->n_edges(); i_edg++) {
1569  loc_idx[i++] = mh_dh.row_4_edge[i_edg];
1570  }
1571  OLD_ASSERT( i==size,"Size of array does not match number of fills.\n");
1572  //DBGPRINT_INT("loc_idx",size,loc_idx);
1573  ISCreateGeneral(PETSC_COMM_SELF, size, loc_idx, PETSC_COPY_VALUES, &(is_loc));
1574  delete [] loc_idx;
1575  VecScatterCreate(schur0->get_solution(), is_loc, sol_vec,
1576  PETSC_NULL, &par_to_all);
1577  ISDestroy(&(is_loc));
1578  }
1579  solution_changed_for_scatter=true;
1580 
1581  END_TIMER("prepare scatter");
1582 
1583 }
1584 
1585 
1586 /*
1587 void mat_count_off_proc_values(Mat m, Vec v) {
1588  int n, first, last;
1589  const PetscInt *cols;
1590  Distribution distr(v);
1591 
1592  int n_off = 0;
1593  int n_on = 0;
1594  int n_off_rows = 0;
1595  MatGetOwnershipRange(m, &first, &last);
1596  for (int row = first; row < last; row++) {
1597  MatGetRow(m, row, &n, &cols, PETSC_NULL);
1598  bool exists_off = false;
1599  for (int i = 0; i < n; i++)
1600  if (distr.get_proc(cols[i]) != distr.myp())
1601  n_off++, exists_off = true;
1602  else
1603  n_on++;
1604  if (exists_off)
1605  n_off_rows++;
1606  MatRestoreRow(m, row, &n, &cols, PETSC_NULL);
1607  }
1608 }
1609 */
1610 
1611 
1612 
1613 
1614 
1615 
1616 
1617 
1618 
1619 
1620 
1621 
1622 void DarcyMH::read_initial_condition()
1623 {
1624  double *local_sol = schur0->get_solution_array();
1625 
1626  // cycle over local element rows
1627 
1628  DebugOut().fmt("Setup with dt: {}\n", time_->dt());
1629  for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) {
1630  auto ele_ac = mh_dh.accessor(i_loc_el);
1631  // set initial condition
1632  local_sol[ele_ac.ele_local_row()] = data_->init_pressure.value(ele_ac.centre(),ele_ac.element_accessor());
1633  }
1634 
1635  solution_changed_for_scatter=true;
1636 
1637 }
1638 
1639 void DarcyMH::setup_time_term() {
1640  // save diagonal of steady matrix
1641  MatGetDiagonal(*( schur0->get_matrix() ), steady_diagonal);
1642  // save RHS
1643  VecCopy(*( schur0->get_rhs()), steady_rhs);
1644 
1645 
1646  PetscScalar *local_diagonal;
1647  VecGetArray(new_diagonal,& local_diagonal);
1648 
1649  DebugOut().fmt("Setup with dt: {}\n", time_->dt());
1650 
1651  balance_->start_mass_assembly(water_balance_idx_);
1652 
1653  //DebugOut().fmt("time_term lsize: {} {}\n", mh_dh.el_ds->myp(), mh_dh.el_ds->lsize());
1654  for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) {
1655  auto ele_ac = mh_dh.accessor(i_loc_el);
1656 
1657  // set new diagonal
1658  double diagonal_coeff = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor())
1659  * data_->storativity.value(ele_ac.centre(), ele_ac.element_accessor())
1660  * ele_ac.measure();
1661  local_diagonal[ele_ac.ele_local_row()]= - diagonal_coeff / time_->dt();
1662 
1663  //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);
1664  balance_->add_mass_matrix_values(water_balance_idx_,
1665  ele_ac.region().bulk_idx(), { int(ele_ac.ele_row()) }, {diagonal_coeff});
1666  }
1667  VecRestoreArray(new_diagonal,& local_diagonal);
1668  MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES);
1669 
1670  solution_changed_for_scatter=true;
1671  schur0->set_matrix_changed();
1672 
1673  balance_->finish_mass_assembly(water_balance_idx_);
1674 }
1675 
1676 void DarcyMH::modify_system() {
1677  START_TIMER("modify system");
1678  if (time_->is_changed_dt() && time_->step().index()>0) {
1679  double scale_factor=time_->step(-2).length()/time_->step().length();
1680  if (scale_factor != 1.0) {
1681  // if time step has changed and setup_time_term not called
1682  MatDiagonalSet(*( schur0->get_matrix() ),steady_diagonal, INSERT_VALUES);
1683 
1684  VecScale(new_diagonal, time_->last_dt()/time_->dt());
1685  MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES);
1686  schur0->set_matrix_changed();
1687  }
1688  }
1689 
1690  // modify RHS - add previous solution
1691  //VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, previous_solution);
1692  VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, schur0->get_solution());
1693  VecAXPY(*( schur0->get_rhs()), 1.0, steady_rhs);
1694  schur0->set_rhs_changed();
1695 
1696  //VecSwap(previous_solution, schur0->get_solution());
1697 }
1698 
1699 
1700 //-----------------------------------------------------------------------------
1701 // vim: set cindent:
TimeGovernor & time()
Definition: equation.hh:148
FieldSet & data()
Definition: equation.hh:193
void get_solution_vector(double *&vec, unsigned int &vec_size) override
FieldSet * eq_data_
Definition: equation.hh:232
static const Input::Type::Record & get_input_type()
Main balance input record type.
Definition: balance.cc:44
void reinit(Mesh *mesh)
double measure() const
Definition: elements.cc:89
Output class for darcy_flow_mh model.
void assembly_mh_matrix(MultidimAssembler ma)
virtual void initialize_specific()
void get_parallel_solution_vector(Vec &vector) override
Accessor to input data conforming to declared Array.
Definition: accessors.hh:567
unsigned int uint
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:598
int is_linear_
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
void make_intersec_elements()
Definition: mesh.cc:630
void init_eq_data()
static const Input::Type::Record & get_input_type()
The specification of output stream.
Definition: output_time.cc:37
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:458
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:233
Boundary * cond() const
Definition: side_impl.hh:70
virtual void output_data() override
Write computed fields.
Wrappers for linear systems based on MPIAIJ and MATIS format.
virtual void rhs_set_values(int nrow, int *rows, double *vals)=0
bool is_end() const
Returns true if the actual time is greater than or equal to the end time.
void assembly(LinSys &ls)
void next_time()
Proceed to the next time according to current estimated time step.
static const int registrar
Registrar of class to factory.
unsigned int max_n_it_
VecScatter par_to_all
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
Vec steady_rhs
static const Input::Type::Selection & get_mh_mortar_selection()
Selection for enum MortarMethod.
void initialize() override
RegionSet get_region_set(const string &set_name) const
Definition: region.cc:328
Definition: mesh.h:97
std::vector< char > bc_switch_dirichlet
Idicator of dirichlet or neumann type of switch boundary conditions.
static const Input::Type::Record & type_field_descriptor()
Distribution * el_ds
virtual double get_solution_precision()=0
const RegionDB & region_db() const
Definition: mesh.h:155
void pressure_diff(int i_ele, vector< int > &dofs, unsigned int &ele_type, double &delta, arma::vec &dirichlet)
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
const TimeStep & step(int index=-1) const
static const std::string field_descriptor_record_description(const string &record_name)
Definition: field_common.cc:68
Class for declaration of the integral input data.
Definition: type_base.hh:489
#define ADD_FIELD(name,...)
Definition: field_set.hh:269
Basic time management functionality for unsteady (and steady) solvers (class Equation).
unsigned int n_sides()
Definition: mesh.cc:175
bool solution_changed_for_scatter
void solve_nonlinear()
Solve method common to zero_time_step and update solution.
std::shared_ptr< EqData > data_
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:303
Basic time management class.
virtual void set_tolerances(double r_tol, double a_tol, unsigned int max_it)=0
Class for declaration of inputs sequences.
Definition: type_base.hh:345
void view(const char *name="") const
MortarMethod mortar_method_
unsigned int min_n_it_
friend class P0_CouplingAssembler
unsigned int nonlinear_iteration_
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
void mat_set_value(int row, int col, double val)
Definition: linsys.hh:325
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:195
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:124
#define OLD_ASSERT(...)
Definition: global_defs.h:131
SideIter side()
Definition: boundaries.h:69
unsigned int n_elements() const
Definition: mesh.h:141
virtual void postprocess()
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:540
unsigned int dim() const
Definition: side_impl.hh:37
double * get_solution_array()
Definition: linsys.hh:281
Mesh & mesh()
Definition: equation.hh:176
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:257
SideIter side()
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
const Ret val(const string &key) const
unsigned int n_sides() const
#define xprintf(...)
Definition: system.hh:92
const Element * slave_iter() const
#define START_TIMER(tag)
Starts a timer with specified tag.
Mesh * mesh_
Definition: equation.hh:223
Element * element()
Definition: boundaries.cc:39
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
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:490
static Input::Type::Abstract & get_input_type()
ElementVector bc_elements
Definition: mesh.h:236
SideIter side(const unsigned int loc_index)
bool use_steady_assembly_
static const Input::Type::Record & get_input_type_specific()
static const Input::Type::Selection & get_bc_type_selection()
Return a Selection corresponding to enum BC_Type.
virtual void assembly_linear_system()
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:459
LinSys * schur0
unsigned int bc_ele_idx_
Definition: boundaries.h:76
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:215
DarcyMH(Mesh &mesh, const Input::Record in_rec)
CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL.
Definition: system.hh:64
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 set_values(int nrow, int *rows, int ncol, int *cols, PetscScalar *mat_vals, PetscScalar *rhs_vals)
Set values in the system matrix and values in the right-hand side vector on corresponding rows...
Definition: linsys.hh:342
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.
double intersection_true_size() const
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
#define ASSERT_DBG(expr)
Definition: asserts.hh:349
unsigned int water_balance_idx_
index of water balance within the Balance object.
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:236
BasicData Data
Definition: format.h:848
arma::vec::fixed< spacedim > centre() const
Definition: accessors.hh:91
#define OLD_ASSERT_EQUAL(a, b)
Definition: global_defs.h:133
EqData()
Creation of all fields.
mixed-hybrid model of linear Darcy flow, possibly unsteady.
void zero_time_step() override
virtual void read_initial_condition()
Record type proxy class.
Definition: type_record.hh:182
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:149
virtual void prepare_new_time_step()
postprocess velocity field (add sources)
Class for representation SI units of Fields.
Definition: unit_si.hh:40
Vec new_diagonal
virtual double solution_precision() const
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:55
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.
friend class P1_CouplingAssembler
virtual int solve()=0
ElementAccessor< 3 > element_accessor()
Definition: boundaries.cc:47
void rhs_set_value(int row, double val)
Definition: linsys.hh:337
double tolerance_
static const Input::Type::Record & get_input_type()
Solver based on Multilevel BDDC - using corresponding class of OpenFTL package.
TimeGovernor * time_
Definition: equation.hh:224
virtual bool zero_time_term(bool time_global=false)
void output()
Calculate values for output.
unsigned int lsize(int proc) const
get local size