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