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