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