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