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