Flow123d  master-2fe7782
darcy_flow_lmh.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_lmh.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 "system/index_types.hh"
35 #include "input/factory.hh"
36 
37 #include "mesh/mesh.h"
38 #include "mesh/bc_mesh.hh"
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 #include "la/vector_mpi.hh"
50 
51 //#include "flow/assembly_lmh_old_.hh"
52 #include "flow/darcy_flow_lmh.hh"
54 #include "flow/assembly_lmh.hh"
55 #include "flow/assembly_models.hh"
56 
57 #include "tools/time_governor.hh"
59 #include "fields/field.hh"
60 #include "fields/field_values.hh"
62 #include "fields/field_fe.hh"
63 #include "fields/field_model.hh"
64 #include "fields/field_constant.hh"
65 
66 #include "coupling/balance.hh"
67 
70 
71 #include "fem/fe_p.hh"
72 
73 
74 FLOW123D_FORCE_LINK_IN_CHILD(darcy_flow_lmh)
75 
76 
77 
78 
79 namespace it = Input::Type;
80 
82  return it::Selection("MH_MortarMethod")
83  .add_value(NoMortar, "None", "No Mortar method is applied.")
84  .add_value(MortarP0, "P0", "Mortar space: P0 on elements of lower dimension.")
85  .add_value(MortarP1, "P1", "Mortar space: P1 on intersections, using non-conforming pressures.")
86  .close();
87 }
88 
90 
91  const it::Record &field_descriptor =
93  .copy_keys( DarcyLMH::EqFields().make_field_descriptor_type(equation_name() + "_Data_aux") )
94  .declare_key("bc_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type_instance(),
95  "Boundary piezometric head for BC types: dirichlet, robin, and river." )
96  .declare_key("bc_switch_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type_instance(),
97  "Boundary switch piezometric head for BC types: seepage, river." )
98  .declare_key("init_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type_instance(),
99  "Initial condition for the pressure given as the piezometric head." )
100  .close();
101  return field_descriptor;
102 }
103 
105  it::Record ns_rec = Input::Type::Record("NonlinearSolver", "Non-linear solver settings.")
106  .declare_key("linear_solver", LinSys::get_input_type(), it::Default("{}"),
107  "Linear solver for MH problem.")
108  .declare_key("tolerance", it::Double(0.0), it::Default("1E-6"),
109  "Residual tolerance.")
110  .declare_key("min_it", it::Integer(0), it::Default("1"),
111  "Minimum number of iterations (linear solutions) to use.\nThis is usefull if the convergence criteria "
112  "does not characterize your goal well enough so it converges prematurely, possibly even without a single linear solution."
113  "If greater then 'max_it' the value is set to 'max_it'.")
114  .declare_key("max_it", it::Integer(0), it::Default("100"),
115  "Maximum number of iterations (linear solutions) of the non-linear solver.")
116  .declare_key("converge_on_stagnation", it::Bool(), it::Default("false"),
117  "If a stagnation of the nonlinear solver is detected the solver stops. "
118  "A divergence is reported by default, forcing the end of the simulation. By setting this flag to 'true', the solver "
119  "ends with convergence success on stagnation, but it reports warning about it.")
120  .close();
121 
123 
124  return it::Record(equation_name(), "Lumped Mixed-Hybrid solver for saturated Darcy flow.")
128  .declare_key("gravity", it::Array(it::Double(), 3,3), it::Default("[ 0, 0, -1]"),
129  "Vector of the gravity force. Dimensionless.")
131  "Input data for Darcy flow model.")
132  .declare_key("nonlinear_solver", ns_rec, it::Default("{}"),
133  "Non-linear solver for MH problem.")
134  .declare_key("output_stream", OutputTime::get_input_type(), it::Default("{}"),
135  "Output stream settings.\n Specify file format, precision etc.")
136 
138  IT::Default("{ \"fields\": [ \"pressure_p0\", \"velocity_p0\" ] }"),
139  "Specification of output fields and output times.")
141  "Output settings specific to Darcy flow model.\n"
142  "Includes raw output and some experimental functionality.")
143  .declare_key("balance", Balance::get_input_type(), it::Default("{}"),
144  "Settings for computing mass balance.")
145  .declare_key("mortar_method", get_mh_mortar_selection(), it::Default("\"None\""),
146  "Method for coupling Darcy flow between dimensions on incompatible meshes. [Experimental]" )
147  .close();
148 }
149 
150 
151 const int DarcyLMH::registrar =
152  Input::register_class< DarcyLMH, Mesh &, const Input::Record >(equation_name()) +
154 
155 
156 
158 {
159  *this += field_ele_pressure.name("pressure_p0")
160  .units(UnitSI().m())
162  .description("Pressure solution - P0 interpolation.");
163 
164  *this += field_edge_pressure.name("pressure_edge")
165  .units(UnitSI().m())
167  .description("Pressure solution - Crouzeix-Raviart interpolation.");
168 
169  *this += field_ele_piezo_head.name("piezo_head_p0")
170  .units(UnitSI().m())
172  .description("Piezo head solution - P0 interpolation.");
173 
174  *this += field_ele_velocity.name("velocity_p0")
175  .units(UnitSI().m().s(-1))
177  .description("Velocity solution - P0 interpolation.");
178 
179  *this += flux.name("flux")
180  .units(UnitSI().m().s(-1))
182  .description("Darcy flow flux.");
183 
184  *this += anisotropy.name("anisotropy")
185  .description("Anisotropy of the conductivity tensor.")
186  .input_default("1.0")
188 
189  *this += cross_section.name("cross_section")
190  .description("Complement dimension parameter (cross section for 1D, thickness for 2D).")
191  .input_default("1.0")
192  .units( UnitSI().m(3).md() );
193 
194  *this += conductivity.name("conductivity")
195  .description("Isotropic conductivity scalar.")
196  .input_default("1.0")
197  .units( UnitSI().m().s(-1) )
198  .set_limits(0.0);
199 
200  *this += sigma.name("sigma")
201  .description("Transition coefficient between dimensions.")
202  .input_default("1.0")
204 
205  *this += water_source_density.name("water_source_density")
206  .description("Water source density.")
207  .input_default("0.0")
208  .units( UnitSI().s(-1) );
209 
210  *this += water_source_sigma.name("water_source_sigma")
211  .description("Water source transition coefficient.")
212  .input_default("0.0")
213  .units( UnitSI().m(-1).s(-1) );
214 
215  *this += water_source_ref_pressure.name("water_source_ref_pressure")
216  .description("Water source reference pressure.")
217  .input_default("0.0")
218  .units( UnitSI().m() );
219 
220  *this += bc_type.name("bc_type")
221  .description("Boundary condition type.")
223  .input_default("\"none\"")
225 
226  *this += bc_pressure
228  .name("bc_pressure")
229  .description("Prescribed pressure value on the boundary. Used for all values of ``bc_type`` except ``none`` and ``seepage``. "
230  "See documentation of ``bc_type`` for exact meaning of ``bc_pressure`` in individual boundary condition types.")
231  .input_default("0.0")
232  .units( UnitSI().m() );
233 
234  *this += bc_flux
236  .name("bc_flux")
237  .description("Incoming water boundary flux. Used for bc_types : ``total_flux``, ``seepage``, ``river``.")
238  .input_default("0.0")
239  .units( UnitSI().m().s(-1) );
240 
241  *this += bc_robin_sigma
243  .name("bc_robin_sigma")
244  .description("Conductivity coefficient in the ``total_flux`` or the ``river`` boundary condition type.")
245  .input_default("0.0")
246  .units( UnitSI().s(-1) );
247 
248  *this += bc_switch_pressure
250  .name("bc_switch_pressure")
251  .description("Critical switch pressure for ``seepage`` and ``river`` boundary conditions.")
252  .input_default("0.0")
253  .units( UnitSI().m() );
254 
255 
256  //these are for unsteady
257  *this += init_pressure.name("init_pressure")
258  .description("Initial condition for pressure in time dependent problems.")
259  .input_default("0.0")
260  .units( UnitSI().m() );
261 
262  *this += storativity.name("storativity")
263  .description("Storativity (in time dependent problems).")
264  .input_default("0.0")
265  .units( UnitSI().m(-1) );
266 
267  *this += extra_storativity.name("extra_storativity")
268  .description("Storativity added from upstream equation.")
269  .units( UnitSI().m(-1) )
270  .input_default("0.0")
271  .flags( input_copy );
272 
273  *this += extra_source.name("extra_water_source_density")
274  .description("Water source density added from upstream equation.")
275  .input_default("0.0")
276  .units( UnitSI().s(-1) )
277  .flags( input_copy );
278 
279  *this += gravity_field.name("gravity")
280  .description("Gravity vector.")
281  .input_default("0.0")
283 
284  *this += bc_gravity.name("bc_gravity")
285  .description("Boundary gravity vector.")
286  .input_default("0.0")
288 
289  *this += init_piezo_head.name("init_piezo_head")
290  .units(UnitSI().m())
291  .input_default("0.0")
292  .description("Init piezo head.");
293 
294  *this += bc_piezo_head.name("bc_piezo_head")
295  .units(UnitSI().m())
296  .input_default("0.0")
297  .description("Boundary piezo head.");
298 
299  *this += bc_switch_piezo_head.name("bc_switch_piezo_head")
300  .units(UnitSI().m())
301  .input_default("0.0")
302  .description("Boundary switch piezo head.");
303 
304  *this += ref_pressure.name("ref_pressure")
305  .units(UnitSI().m())
306  .input_default("0.0")
308  .description("Precomputed pressure of l2 difference output.");
309 
310  *this += ref_velocity.name("ref_velocity")
311  .units(UnitSI().m().s(-1))
312  .input_default("0.0")
314  .description("Precomputed velocity of l2 difference output.");
315 
316  *this += ref_divergence.name("ref_divergence")
317  .units(UnitSI().m())
318  .input_default("0.0")
320  .description("Precomputed divergence of l2 difference output.");
321 
322  this->set_default_fieldset();
323  //time_term_fields = this->subset({"storativity"});
324  //main_matrix_fields = this->subset({"anisotropy", "conductivity", "cross_section", "sigma", "bc_type", "bc_robin_sigma"});
325  //rhs_fields = this->subset({"water_source_density", "bc_pressure", "bc_flux"});
326 }
327 
328 
329 
331  return it::Selection("Flow_Darcy_BC_Type")
332  .add_value(none, "none",
333  "Homogeneous Neumann boundary condition\n(zero normal flux over the boundary).")
334  .add_value(dirichlet, "dirichlet",
335  "Dirichlet boundary condition. "
336  "Specify the pressure head through the ``bc_pressure`` field "
337  "or the piezometric head through the ``bc_piezo_head`` field.")
338  .add_value(total_flux, "total_flux", "Flux boundary condition (combines Neumann and Robin type). "
339  "Water inflow equal to (($ \\delta_d(q_d^N + \\sigma_d (h_d^R - h_d) )$)). "
340  "Specify the water inflow by the ``bc_flux`` field, the transition coefficient by ``bc_robin_sigma`` "
341  "and the reference pressure head or piezometric head through ``bc_pressure`` or ``bc_piezo_head`` respectively.")
342  .add_value(seepage, "seepage",
343  "Seepage face boundary condition. Pressure and inflow bounded from above. Boundary with potential seepage flow "
344  "is described by the pair of inequalities: "
345  "(($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. "
346  "Caution: setting (($q_d^N$)) strictly negative "
347  "may lead to an ill posed problem since a positive outflow is enforced. "
348  "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."
349  )
350  .add_value(river, "river",
351  "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: "
352  "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d) )$)). For the water level under the bedrock, constant infiltration is used: "
353  "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d^S) )$)). Parameters: ``bc_pressure``, ``bc_switch_pressure``, "
354  " ``bc_sigma``, ``bc_flux``."
355  )
356  .close();
357 }
358 
359 
360 
361 DarcyLMH::EqData::EqData(shared_ptr<EqFields> eq_fields)
364 }
365 
366 
368 {
369  auto size = dh_p_->get_local_to_global_map().size();
370  save_local_system_.resize(size);
371  bc_fluxes_reconstruted.resize(size);
372  loc_system_.resize(size);
373  postprocess_solution_.resize(size);
374 }
375 
376 
378 {
379  std::fill(save_local_system_.begin(), save_local_system_.end(), false);
380  std::fill(bc_fluxes_reconstruted.begin(), bc_fluxes_reconstruted.end(), false);
381 }
382 
383 
384 
385 
386 
387 
388 //=============================================================================
389 // CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL
390 // - do it in parallel:
391 // - initial distribution of elements, edges
392 //
393 /*! @brief CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL
394  *
395  * Parameters {Solver,NSchurs} number of performed Schur
396  * complements (0,1,2) for water flow MH-system
397  *
398  */
399 //=============================================================================
400 DarcyLMH::DarcyLMH(Mesh &mesh_in, const Input::Record in_rec, TimeGovernor *tm)
401 : DarcyFlowInterface(mesh_in, in_rec),
402  output_object(nullptr),
403  data_changed_(false),
404  read_init_cond_assembly_(nullptr),
405  mh_matrix_assembly_(nullptr),
407 {
408 
409  START_TIMER("Darcy constructor");
410  {
411  auto time_record = input_record_.val<Input::Record>("time");
412  if (tm == nullptr)
413  {
414  time_ = new TimeGovernor(time_record);
415  }
416  else
417  {
418  TimeGovernor tm_from_rec(time_record);
419  if (!tm_from_rec.is_default()) // is_default() == false when time record is present in input file
420  {
421  MessageOut() << "Duplicate key 'time', time in flow equation is already initialized from parent class!";
422  ASSERT_PERMANENT(false);
423  }
424  time_ = tm;
425  }
426  }
427 
428  eq_fields_ = make_shared<EqFields>();
429  eq_data_ = make_shared<EqData>(eq_fields_);
430  this->eq_fieldset_ = eq_fields_;
431 
432  eq_fields_->set_mesh(*mesh_);
433 
434  eq_data_->is_linear=true;
435 
436  size = mesh_->n_elements() + mesh_->n_sides() + mesh_->n_edges();
437  eq_data_->mortar_method_= in_rec.val<MortarMethod>("mortar_method");
438  if (eq_data_->mortar_method_ != NoMortar) {
440  }
441 
442 
443  //side_ds->view( std::cout );
444  //el_ds->view( std::cout );
445  //edge_ds->view( std::cout );
446  //rows_ds->view( std::cout );
447 
448 }
449 
451 {
452  // DebugOut() << "t = " << time_->t() << " step_end " << time_->step().end() << "\n";
453  if(eq_data_->use_steady_assembly_)
454  {
455  // In steady case, the solution is computed with the data present at time t,
456  // and the steady state solution is valid until another change in data,
457  // which should correspond to time (t+dt).
458  // "The data change appears immediatly."
459  double next_t = time_->t() + time_->estimate_dt();
460  // DebugOut() << "STEADY next_t = " << next_t << "\n";
461  return next_t * (1 - 2*std::numeric_limits<double>::epsilon());
462  }
463  else
464  {
465  // In unsteady case, the solution is computed with the data present at time t,
466  // and the solution is valid at the time t+dt.
467  // "The data change does not appear immediatly, it is integrated over time interval dt."
468  // DebugOut() << "UNSTEADY\n";
469  return time_->t();
470  }
471 }
472 
474 //connecting data fields with mesh
475 {
476 
477  START_TIMER("Darcy data init");
478  eq_data_->mesh = mesh_;
479 
480  auto gravity_array = input_record_.val<Input::Array>("gravity");
481  std::vector<double> gvec;
482  gravity_array.copy_to(gvec);
483  gvec.push_back(0.0); // zero pressure shift
484  eq_data_->gravity_ = arma::vec(gvec);
485  eq_data_->gravity_vec_ = eq_data_->gravity_.subvec(0,2);
486 
487  FieldValue<3>::VectorFixed gvalue(eq_data_->gravity_vec_);
488  auto field_algo=std::make_shared<FieldConstant<3, FieldValue<3>::VectorFixed>>();
489  field_algo->set_value(gvalue);
490  eq_fields_->gravity_field.set(field_algo, 0.0);
491  eq_fields_->bc_gravity.set(field_algo, 0.0);
492 
493  eq_fields_->bc_pressure.add_factory(
494  std::make_shared<AddPotentialFactory<3, FieldValue<3>::Scalar> >
495  (eq_fields_->bc_gravity, eq_fields_->X(), eq_fields_->bc_piezo_head) );
496  eq_fields_->bc_switch_pressure.add_factory(
497  std::make_shared<AddPotentialFactory<3, FieldValue<3>::Scalar> >
498  (eq_fields_->bc_gravity, eq_fields_->X(), eq_fields_->bc_switch_piezo_head) );
499  eq_fields_->init_pressure.add_factory(
500  std::make_shared<AddPotentialFactory<3, FieldValue<3>::Scalar> >
501  (eq_fields_->gravity_field, eq_fields_->X(), eq_fields_->init_piezo_head) );
502 
503 
504  eq_fields_->set_input_list( this->input_record_.val<Input::Array>("input_fields"), *time_ );
505 
506  // Check that the time step was set for the transient simulation.
507  if (! zero_time_term(true) && time_->is_default() ) {
508  //THROW(ExcAssertMsg());
509  //THROW(ExcMissingTimeGovernor() << input_record_.ei_address());
510  MessageOut() << "Missing the key 'time', obligatory for the transient problems." << endl;
511  ASSERT_PERMANENT(false);
512  }
513 
514  eq_fields_->mark_input_times(*time_);
515 }
516 
518 
519  { // init DOF handler for pressure fields
520 // std::shared_ptr< FiniteElement<0> > fe0_rt = std::make_shared<FE_RT0_disc<0>>();
521  std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
522  std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
523  std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
524  std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
525  std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
526  std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
527  std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
528  std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
529  std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
530  std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
531  std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
532 // static FiniteElement<0> fe0_sys = FE_P_disc<0>(0); //TODO fix and use solution with FESystem<0>( {fe0_rt, fe0_disc, fe0_cr} )
533  FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
534  FESystem<1> fe1_sys( {fe1_rt, fe1_disc, fe1_cr} );
535  FESystem<2> fe2_sys( {fe2_rt, fe2_disc, fe2_cr} );
536  FESystem<3> fe3_sys( {fe3_rt, fe3_disc, fe3_cr} );
537  MixedPtr<FESystem> fe_sys( std::make_shared<FESystem<0>>(fe0_sys), std::make_shared<FESystem<1>>(fe1_sys),
538  std::make_shared<FESystem<2>>(fe2_sys), std::make_shared<FESystem<3>>(fe3_sys) );
539  std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>( mesh_, fe_sys);
540  eq_data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*mesh_);
541  eq_data_->dh_->distribute_dofs(ds);
542  }
543 
544  init_eq_data();
546 
547  eq_fields_->add_coords_field();
548 
549  { // construct pressure, velocity and piezo head fields
550  uint rt_component = 0;
551  eq_data_->full_solution = eq_data_->dh_->create_vector();
552  auto ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(eq_data_->dh_, &eq_data_->full_solution, rt_component);
553  eq_fields_->flux.set(ele_flux_ptr, 0.0);
554 
555  eq_fields_->field_ele_velocity.set(Model<3, FieldValue<3>::VectorFixed>::create(fn_mh_velocity(), eq_fields_->flux, eq_fields_->cross_section), 0.0);
556 
557  uint p_ele_component = 1;
558  auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(eq_data_->dh_, &eq_data_->full_solution, p_ele_component);
559  eq_fields_->field_ele_pressure.set(ele_pressure_ptr, 0.0);
560 
561  uint p_edge_component = 2;
562  auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(eq_data_->dh_, &eq_data_->full_solution, p_edge_component);
563  eq_fields_->field_edge_pressure.set(edge_pressure_ptr, 0.0);
564 
565  eq_fields_->field_ele_piezo_head.set(
566  Model<3, FieldValue<3>::Scalar>::create(fn_mh_piezohead(), eq_fields_->gravity_field, eq_fields_->X(), eq_fields_->field_ele_pressure),
567  0.0
568  );
569  }
570 
571  { // init DOF handlers represents element pressure DOFs
572  uint p_element_component = 1;
573  eq_data_->dh_p_ = std::make_shared<SubDOFHandlerMultiDim>(eq_data_->dh_,p_element_component);
574  }
575 
576  { // init DOF handlers represents edge DOFs
577  uint p_edge_component = 2;
578  eq_data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(eq_data_->dh_,p_edge_component);
579  }
580 
581  { // init DOF handlers represents side DOFs
582  MixedPtr<FE_CR_disc> fe_cr_disc;
583  std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>( mesh_, fe_cr_disc);
584  eq_data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*mesh_);
585  eq_data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
586  }
587 
588  eq_data_->init();
589 
590  // create solution vector for 2. Schur complement linear system
591 // p_edge_solution = new VectorMPI(eq_data_->dh_cr_->distr()->lsize());
592 // full_solution = new VectorMPI(eq_data_->dh_->distr()->lsize());
593  // this creates mpi vector from DoFHandler, including ghost values
594  eq_data_->p_edge_solution = eq_data_->dh_cr_->create_vector();
595  eq_data_->p_edge_solution_previous = eq_data_->dh_cr_->create_vector();
596  eq_data_->p_edge_solution_previous_time = eq_data_->dh_cr_->create_vector();
597 
598  // Initialize bc_switch_dirichlet to size of global boundary.
599  eq_data_->bc_switch_dirichlet.resize(mesh_->n_elements()+mesh_->bc_mesh()->n_elements(), 1);
600 
601 
602  eq_data_->nonlinear_iteration_=0;
604  .val<Input::Record>("nonlinear_solver")
605  .val<Input::AbstractRecord>("linear_solver");
606 
608 
609  // auxiliary set_time call since allocation assembly evaluates fields as well
612 
613 
614  // initialization of balance object
615  balance_ = std::make_shared<Balance>("water", mesh_);
616  balance_->init_from_input(input_record_.val<Input::Record>("balance"), time());
617  eq_data_->water_balance_idx = balance_->add_quantity("water_volume");
618  balance_->allocate(eq_data_->dh_, 1);
619  balance_->units(UnitSI().m(3));
620 
621  eq_data_->balance_ = this->balance_;
622 
623  this->initialize_asm();
624 }
625 
627 {
628  //eq_data_->multidim_assembler = AssemblyFlowBase::create< AssemblyLMH >(eq_fields_, eq_data_);
629 }
630 
631 //void DarcyLMH::read_initial_condition()
632 //{
633 // DebugOut().fmt("Read initial condition\n");
634 //
635 // for ( DHCellAccessor dh_cell : eq_data_->dh_->own_range() ) {
636 //
637 // LocDofVec p_indices = dh_cell.cell_with_other_dh(eq_data_->dh_p_.get()).get_loc_dof_indices();
638 // ASSERT_DBG(p_indices.n_elem == 1);
639 // LocDofVec l_indices = dh_cell.cell_with_other_dh(eq_data_->dh_cr_.get()).get_loc_dof_indices();
640 // ElementAccessor<3> ele = dh_cell.elm();
641 //
642 // // set initial condition
643 // double init_value = eq_fields_->init_pressure.value(ele.centre(),ele);
644 // unsigned int p_idx = eq_data_->dh_p_->parent_indices()[p_indices[0]];
645 // eq_data_->full_solution.set(p_idx, init_value);
646 //
647 // for (unsigned int i=0; i<ele->n_sides(); i++) {
648 // uint n_sides_of_edge = ele.side(i)->edge().n_sides();
649 // unsigned int l_idx = eq_data_->dh_cr_->parent_indices()[l_indices[i]];
650 // eq_data_->full_solution.add(l_idx, init_value/n_sides_of_edge);
651 //
652 // eq_data_->p_edge_solution.add(l_indices[i], init_value/n_sides_of_edge);
653 // }
654 // }
655 //
656 // initial_condition_postprocess();
657 //
658 // eq_data_->full_solution.ghost_to_local_begin();
659 // eq_data_->full_solution.ghost_to_local_end();
660 //
661 // eq_data_->p_edge_solution.ghost_to_local_begin();
662 // eq_data_->p_edge_solution.ghost_to_local_end();
663 // eq_data_->p_edge_solution_previous_time.copy_from(eq_data_->p_edge_solution);
664 //}
665 //
666 //void DarcyLMH::initial_condition_postprocess()
667 //{}
668 
670 {
671  START_TIMER("Darcy zero time step");
672 
673  /* TODO:
674  * - Allow solution reconstruction (pressure and velocity) from initial condition on user request.
675  * - Steady solution as an intitial condition may be forced by setting inti_time =-1, and set data for the steady solver in that time.
676  * Solver should be able to switch from and to steady case depending on the zero time term.
677  */
678 
680 
681  // zero_time_term means steady case
682  eq_data_->use_steady_assembly_ = zero_time_term();
683 
684  eq_data_->p_edge_solution.zero_entries();
685 
686  if (eq_data_->use_steady_assembly_) { // steady case
687  MessageOut() << "Flow zero time step - steady case\n";
688  //read_initial_condition(); // Possible solution guess for steady case.
689  solve_nonlinear(); // with right limit data
690  } else {
691  MessageOut() << "Flow zero time step - unsteady case\n";
692  eq_data_->time_step_ = time_->dt();
694  this->read_init_cond_asm();
695  accept_time_step(); // accept zero time step, i.e. initial condition
696 
697 
698  // we reconstruct the initial solution here
699  // during the reconstruction assembly:
700  // - the balance objects are actually allocated
701  // - the full solution vector is computed
703  }
704  //solution_output(T,right_limit); // data for time T in any case
705  output_data();
706 
707  END_TIMER("Darcy zero time step");
708 }
709 
710 //=============================================================================
711 // COMPOSE and SOLVE WATER MH System possibly through Schur complements
712 //=============================================================================
714 {
715  START_TIMER("Darcy solve system");
716 
717  time_->next_time();
718 
719  time_->view("DARCY"); //time governor information output
720 
721  solve_time_step();
722 
723  eq_data_->full_solution.local_to_ghost_begin();
724  eq_data_->full_solution.local_to_ghost_end();
725 }
726 
727 void DarcyLMH::solve_time_step(bool output)
728 {
730  bool zero_time_term_from_left=zero_time_term();
731 
732  bool jump_time = eq_fields_->storativity.is_jump_time();
733  if (! zero_time_term_from_left) {
734  MessageOut() << "Flow time step - unsteady case\n";
735  // time term not treated as zero
736  // Unsteady solution up to the T.
737 
738  // this flag is necesssary for switching BC to avoid setting zero neumann on the whole boundary in the steady case
739  eq_data_->use_steady_assembly_ = false;
740 
741  solve_nonlinear(); // with left limit data
742  if(output)
744  if (jump_time) {
745  WarningOut() << "Output of solution discontinuous in time not supported yet.\n";
746  //solution_output(T, left_limit); // output use time T- delta*dt
747  //output_data();
748  }
749  }
750 
751  if (time_->is_end()) {
752  // output for unsteady case, end_time should not be the jump time
753  // but rether check that
754  if (! zero_time_term_from_left && ! jump_time && output)
755  output_data();
756  return;
757  }
758 
760  bool zero_time_term_from_right=zero_time_term();
761  if (zero_time_term_from_right) {
762  MessageOut() << "Flow time step - steady case\n";
763  // this flag is necesssary for switching BC to avoid setting zero neumann on the whole boundary in the steady case
764  eq_data_->use_steady_assembly_ = true;
765  solve_nonlinear(); // with right limit data
766  if(output)
768 
769  } else if (! zero_time_term_from_left && jump_time) {
770  WarningOut() << "Discontinuous time term not supported yet.\n";
771  //solution_transfer(); // internally call set_time(T, left) and set_time(T,right) again
772  //solve_nonlinear(); // with right limit data
773  }
774  //solution_output(T,right_limit); // data for time T in any case
775  if (output)
776  output_data();
777 }
778 
779 bool DarcyLMH::zero_time_term(bool time_global) {
780  if (time_global) {
781  return (eq_fields_->storativity.input_list_size() == 0);
782  } else {
783  return eq_fields_->storativity.field_result(mesh_->region_db().get_region_set("BULK")) == result_zeros;
784  }
785 }
786 
787 
789 {
790  START_TIMER("Darcy solve_nonlinear");
792  double residual_norm = lin_sys_schur().compute_residual();
793  eq_data_->nonlinear_iteration_ = 0;
794  MessageOut().fmt("[nonlinear solver] norm of initial residual: {}\n", residual_norm);
795 
796  // Reduce is_linear flag.
797  int is_linear_common;
798  MPI_Allreduce(&(eq_data_->is_linear), &is_linear_common,1, MPI_INT ,MPI_MIN,PETSC_COMM_WORLD);
799 
800  Input::Record nl_solver_rec = input_record_.val<Input::Record>("nonlinear_solver");
801  this->tolerance_ = nl_solver_rec.val<double>("tolerance");
802  this->max_n_it_ = nl_solver_rec.val<unsigned int>("max_it");
803  this->min_n_it_ = nl_solver_rec.val<unsigned int>("min_it");
804  if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->max_n_it_;
805 
806  if (! is_linear_common) {
807  // set tolerances of the linear solver unless they are set by user.
808  lin_sys_schur().set_tolerances(0.1*this->tolerance_, 0.01*this->tolerance_, 10000, 100);
809  }
810  vector<double> convergence_history;
811 
812  while (eq_data_->nonlinear_iteration_ < this->min_n_it_ ||
813  (residual_norm > this->tolerance_ && eq_data_->nonlinear_iteration_ < this->max_n_it_ )) {
814  ASSERT_EQ( convergence_history.size(), eq_data_->nonlinear_iteration_ );
815  convergence_history.push_back(residual_norm);
816 
817  // print_matlab_matrix("matrix_" + std::to_string(time_->step().index()) + "_it_" + std::to_string(nonlinear_iteration_));
818  // stagnation test
819  if (convergence_history.size() >= 5 &&
820  convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
821  convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
822  // stagnation
823  if (input_record_.val<Input::Record>("nonlinear_solver").val<bool>("converge_on_stagnation")) {
824  WarningOut().fmt("Accept solution on stagnation. Its: {} Residual: {}\n", eq_data_->nonlinear_iteration_, residual_norm);
825  break;
826  } else {
827  THROW(ExcSolverDiverge() << EI_Reason("Stagnation."));
828  }
829  }
830 
831  if (! is_linear_common){
832  eq_data_->p_edge_solution_previous.copy_from(eq_data_->p_edge_solution);
833  eq_data_->p_edge_solution_previous.local_to_ghost_begin();
834  eq_data_->p_edge_solution_previous.local_to_ghost_end();
835  }
836 
838  MessageOut().fmt("[schur solver] lin. it: {}, reason: {}, residual: {}\n",
839  si.n_iterations, si.converged_reason, lin_sys_schur().compute_residual());
840 
841  eq_data_->nonlinear_iteration_++;
842 
843  // hack to make BDDC work with empty compute_residual
844  if (is_linear_common){
845  // we want to print this info in linear (and steady) case
846  residual_norm = lin_sys_schur().compute_residual();
847  MessageOut().fmt("[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
848  si.n_iterations, si.converged_reason, residual_norm);
849  break;
850  }
851  data_changed_=true; // force reassembly for non-linear case
852 
853  double alpha = 1; // how much of new solution
854  VecAXPBY(eq_data_->p_edge_solution.petsc_vec(), (1-alpha), alpha, eq_data_->p_edge_solution_previous.petsc_vec());
855 
856  //LogOut().fmt("Linear solver ended with reason: {} \n", si.converged_reason );
857  //ASSERT_PERMANENT_GE( si.converged_reason, 0).error("Linear solver failed to converge.\n");
859 
860  residual_norm = lin_sys_schur().compute_residual();
861  MessageOut().fmt("[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
862  eq_data_->nonlinear_iteration_, si.n_iterations, si.converged_reason, residual_norm);
863  }
864 
865 // reconstruct_solution_from_schur(eq_data_->multidim_assembler);
867 
868  // adapt timestep
869  if (! this->zero_time_term()) {
870  double mult = 1.0;
871  if (eq_data_->nonlinear_iteration_ < 3) mult = 1.6;
872  if (eq_data_->nonlinear_iteration_ > 7) mult = 0.7;
873  time_->set_upper_constraint(time_->dt() * mult, "Darcy adaptivity.");
874  // int result = time_->set_upper_constraint(time_->dt() * mult, "Darcy adaptivity.");
875  //DebugOut().fmt("time adaptivity, res: {} it: {} m: {} dt: {} edt: {}\n", result, nonlinear_iteration_, mult, time_->dt(), time_->estimate_dt());
876  }
877 }
878 
879 
881 {
882  eq_data_->p_edge_solution_previous_time.copy_from(eq_data_->p_edge_solution);
883  eq_data_->p_edge_solution_previous_time.local_to_ghost_begin();
884  eq_data_->p_edge_solution_previous_time.local_to_ghost_end();
885 }
886 
887 
889  START_TIMER("Darcy output data");
890 
891  // print_matlab_matrix("matrix_" + std::to_string(time_->step().index()));
892 
893  //time_->view("DARCY"); //time governor information output
894  this->output_object->output();
895 
896 
897  START_TIMER("Darcy balance output");
898  balance_->calculate_cumulative(eq_data_->water_balance_idx, eq_data_->full_solution.petsc_vec());
899  balance_->calculate_instant(eq_data_->water_balance_idx, eq_data_->full_solution.petsc_vec());
900  balance_->output();
901 }
902 
903 
904 //double DarcyLMH::solution_precision() const
905 //{
906 // return eq_data_->lin_sys_schur->get_solution_precision();
907 //}
908 
909 
910 // ===========================================================================================
911 //
912 // MATRIX ASSEMBLY - we use abstract assembly routine, where LS Mat/Vec SetValues
913 // are in fact pointers to allocating or filling functions - this is governed by Linsystem roitunes
914 //
915 // =======================================================================================
916 //void DarcyLMH::assembly_mh_matrix(FMT_UNUSED MultidimAssembly& assembler)
917 //{
918 // START_TIMER("DarcyLMH::assembly_steady_mh_matrix");
919 //
920 // // DebugOut() << "assembly_mh_matrix \n";
921 // // set auxiliary flag for switchting Dirichlet like BC
922 // eq_data_->force_no_neumann_bc = eq_data_->use_steady_assembly_ && (eq_data_->nonlinear_iteration_ == 0);
923 //
924 // balance_->start_flux_assembly(eq_data_->water_balance_idx);
925 // balance_->start_source_assembly(eq_data_->water_balance_idx);
926 // balance_->start_mass_assembly(eq_data_->water_balance_idx);
927 //
928 // // TODO: try to move this into balance, or have it in the generic assembler class, that should perform the cell loop
929 // // including various pre- and post-actions
930 //// for ( DHCellAccessor dh_cell : eq_data_->dh_->own_range() ) {
931 //// unsigned int dim = dh_cell.dim();
932 //// assembler[dim-1]->assemble(dh_cell);
933 //// }
934 // this->mh_matrix_assembly_->assemble(eq_data_->dh_);
935 //
936 //
937 // balance_->finish_mass_assembly(eq_data_->water_balance_idx);
938 // balance_->finish_source_assembly(eq_data_->water_balance_idx);
939 // balance_->finish_flux_assembly(eq_data_->water_balance_idx);
940 //
941 //}
942 
943 
945 {
946  START_TIMER("Darcy allocate_mh_matrix");
947 
948  // to make space for second schur complement, max. 10 neighbour edges of one el.
949  double zeros[100000];
950  for(int i=0; i<100000; i++) zeros[i] = 0.0;
951 
952  std::vector<LongIdx> tmp_rows;
953  tmp_rows.reserve(200);
954 
955  std::vector<LongIdx> dofs, dofs_ngh;
956  dofs.reserve(eq_data_->dh_cr_->max_elem_dofs());
957  dofs_ngh.reserve(eq_data_->dh_cr_->max_elem_dofs());
958 
959  // DebugOut() << "Allocate new schur\n";
960  for ( DHCellAccessor dh_cell : eq_data_->dh_cr_->own_range() ) {
961  ElementAccessor<3> ele = dh_cell.elm();
962 
963  const uint ndofs = dh_cell.n_dofs();
964  dofs.resize(dh_cell.n_dofs());
965  dh_cell.get_dof_indices(dofs);
966 
967  int* dofs_ptr = dofs.data();
968  lin_sys_schur().mat_set_values(ndofs, dofs_ptr, ndofs, dofs_ptr, zeros);
969 
970  tmp_rows.clear();
971 
972  // compatible neighborings rows
973  unsigned int n_neighs = ele->n_neighs_vb();
974  for ( DHCellSide neighb_side : dh_cell.neighb_sides() ) {
975  // every compatible connection adds a 2x2 matrix involving
976  // current element pressure and a connected edge pressure
977 
978  // read neighbor dofs (dh_cr dofhandler)
979  // neighbor cell owning neighb_side
980  DHCellAccessor dh_neighb_cell = neighb_side.cell();
981 
982  const uint ndofs_ngh = dh_neighb_cell.n_dofs();
983  dofs_ngh.resize(ndofs_ngh);
984  dh_neighb_cell.get_dof_indices(dofs_ngh);
985 
986  // local index of pedge dof on neighboring cell
987  tmp_rows.push_back(dofs_ngh[neighb_side.side().side_idx()]);
988  }
989 
990  lin_sys_schur().mat_set_values(ndofs, dofs_ptr, n_neighs, tmp_rows.data(), zeros); // (edges) x (neigh edges)
991  lin_sys_schur().mat_set_values(n_neighs, tmp_rows.data(), ndofs, dofs_ptr, zeros); // (neigh edges) x (edges)
992  lin_sys_schur().mat_set_values(n_neighs, tmp_rows.data(), n_neighs, tmp_rows.data(), zeros); // (neigh edges) x (neigh edges)
993 
994  tmp_rows.clear();
995 // if (eq_data_->mortar_method_ != NoMortar) {
996 // auto &isec_list = mesh_->mixed_intersections().element_intersections_[ele.idx()];
997 // for(auto &isec : isec_list ) {
998 // IntersectionLocalBase *local = isec.second;
999 // DHCellAccessor dh_cell_slave = eq_data_->dh_cr_->cell_accessor_from_element(local->bulk_ele_idx());
1000 //
1001 // const uint ndofs_slave = dh_cell_slave.n_dofs();
1002 // dofs_ngh.resize(ndofs_slave);
1003 // dh_cell_slave.get_dof_indices(dofs_ngh);
1004 //
1005 // //DebugOut().fmt("Alloc: {} {}", ele.idx(), local->bulk_ele_idx());
1006 // for(unsigned int i_side=0; i_side < dh_cell_slave.elm()->n_sides(); i_side++) {
1007 // tmp_rows.push_back( dofs_ngh[i_side] );
1008 // //DebugOut() << "aedge" << print_var(tmp_rows[tmp_rows.size()-1]);
1009 // }
1010 // }
1011 // }
1012 
1013  lin_sys_schur().mat_set_values(ndofs, dofs_ptr, tmp_rows.size(), tmp_rows.data(), zeros); // master edges x slave edges
1014  lin_sys_schur().mat_set_values(tmp_rows.size(), tmp_rows.data(), ndofs, dofs_ptr, zeros); // slave edges x master edges
1015  lin_sys_schur().mat_set_values(tmp_rows.size(), tmp_rows.data(), tmp_rows.size(), tmp_rows.data(), zeros); // slave edges x slave edges
1016  }
1017  // DebugOut() << "end Allocate new schur\n";
1018 
1019  // int local_dofs[10];
1020  // unsigned int nsides;
1021  // for ( DHCellAccessor dh_cell : eq_data_->dh_->own_range() ) {
1022  // LocalElementAccessorBase<3> ele_ac(dh_cell);
1023  // nsides = ele_ac.n_sides();
1024 
1025  // //allocate at once matrix [sides,ele,edges]x[sides,ele,edges]
1026  // loc_size = 1 + 2*nsides;
1027  // unsigned int i_side = 0;
1028 
1029  // for (; i_side < nsides; i_side++) {
1030  // local_dofs[i_side] = ele_ac.side_row(i_side);
1031  // local_dofs[i_side+nsides] = ele_ac.edge_row(i_side);
1032  // }
1033  // local_dofs[i_side+nsides] = ele_ac.ele_row();
1034  // int * edge_rows = local_dofs + nsides;
1035  // //int ele_row = local_dofs[0];
1036 
1037  // // whole local MH matrix
1038  // ls->mat_set_values(loc_size, local_dofs, loc_size, local_dofs, zeros);
1039 
1040 
1041  // // compatible neighborings rows
1042  // unsigned int n_neighs = ele_ac.element_accessor()->n_neighs_vb();
1043  // unsigned int i=0;
1044  // for ( DHCellSide neighb_side : dh_cell.neighb_sides() ) {
1045  // //for (unsigned int i = 0; i < n_neighs; i++) {
1046  // // every compatible connection adds a 2x2 matrix involving
1047  // // current element pressure and a connected edge pressure
1048  // Neighbour *ngh = ele_ac.element_accessor()->neigh_vb[i];
1049  // DHCellAccessor cell_higher_dim = eq_data_->dh_->cell_accessor_from_element(neighb_side.elem_idx());
1050  // LocalElementAccessorBase<3> acc_higher_dim( cell_higher_dim );
1051  // for (unsigned int j = 0; j < neighb_side.element().dim()+1; j++)
1052  // if (neighb_side.element()->edge_idx(j) == ngh->edge_idx()) {
1053  // int neigh_edge_row = acc_higher_dim.edge_row(j);
1054  // tmp_rows.push_back(neigh_edge_row);
1055  // break;
1056  // }
1057  // //DebugOut() << "CC" << print_var(tmp_rows[i]);
1058  // ++i;
1059  // }
1060 
1061  // // allocate always also for schur 2
1062  // ls->mat_set_values(nsides+1, edge_rows, n_neighs, tmp_rows.data(), zeros); // (edges, ele) x (neigh edges)
1063  // ls->mat_set_values(n_neighs, tmp_rows.data(), nsides+1, edge_rows, zeros); // (neigh edges) x (edges, ele)
1064  // ls->mat_set_values(n_neighs, tmp_rows.data(), n_neighs, tmp_rows.data(), zeros); // (neigh edges) x (neigh edges)
1065 
1066  // tmp_rows.clear();
1067 
1068  // if (eq_data_->mortar_method_ != NoMortar) {
1069  // auto &isec_list = mesh_->mixed_intersections().element_intersections_[ele_ac.ele_global_idx()];
1070  // for(auto &isec : isec_list ) {
1071  // IntersectionLocalBase *local = isec.second;
1072  // LocalElementAccessorBase<3> slave_acc( eq_data_->dh_->cell_accessor_from_element(local->bulk_ele_idx()) );
1073  // //DebugOut().fmt("Alloc: {} {}", ele_ac.ele_global_idx(), local->bulk_ele_idx());
1074  // for(unsigned int i_side=0; i_side < slave_acc.dim()+1; i_side++) {
1075  // tmp_rows.push_back( slave_acc.edge_row(i_side) );
1076  // //DebugOut() << "aedge" << print_var(tmp_rows[tmp_rows.size()-1]);
1077  // }
1078  // }
1079  // }
1080  // /*
1081  // for(unsigned int i_side=0; i_side < ele_ac.element_accessor()->n_sides(); i_side++) {
1082  // DebugOut() << "aedge:" << print_var(edge_rows[i_side]);
1083  // }*/
1084 
1085  // ls->mat_set_values(nsides, edge_rows, tmp_rows.size(), tmp_rows.data(), zeros); // master edges x neigh edges
1086  // ls->mat_set_values(tmp_rows.size(), tmp_rows.data(), nsides, edge_rows, zeros); // neigh edges x master edges
1087  // ls->mat_set_values(tmp_rows.size(), tmp_rows.data(), tmp_rows.size(), tmp_rows.data(), zeros); // neigh edges x neigh edges
1088 
1089  // }
1090 /*
1091  // alloc edge diagonal entries
1092  if(rank == 0)
1093  for( vector<Edge>::iterator edg = mesh_->edges.begin(); edg != mesh_->edges.end(); ++edg) {
1094  int edg_idx = mh_dh.row_4_edge[edg->side(0)->edge_idx()];
1095 
1096 // for( vector<Edge>::iterator edg2 = mesh_->edges.begin(); edg2 != mesh_->edges.end(); ++edg2){
1097 // int edg_idx2 = mh_dh.row_4_edge[edg2->side(0)->edge_idx()];
1098 // if(edg_idx == edg_idx2){
1099 // DBGCOUT(<< "P[ " << rank << " ] " << "edg alloc: " << edg_idx << " " << edg_idx2 << "\n");
1100  ls->mat_set_value(edg_idx, edg_idx, 0.0);
1101 // }
1102 // }
1103  }
1104  */
1105  /*
1106  if (mortar_method_ == MortarP0) {
1107  P0_CouplingAssembler(*this).assembly(*ls);
1108  } else if (mortar_method_ == MortarP1) {
1109  P1_CouplingAssembler(*this).assembly(*ls);
1110  }*/
1111 }
1112 
1113 
1114 
1115 /*******************************************************************************
1116  * COMPOSE WATER MH MATRIX WITHOUT SCHUR COMPLEMENT
1117  ******************************************************************************/
1118 
1120 
1121  START_TIMER("Darcy preallocation");
1122 
1123  // if (schur0 == NULL) { // create Linear System for MH matrix
1124 
1125 // if (in_rec.type() == LinSys_BDDC::get_input_type()) {
1126 // #ifdef FLOW123D_HAVE_BDDCML
1127 // WarningOut() << "For BDDC no Schur complements are used.";
1128 // n_schur_compls = 0;
1129 // LinSys_BDDC *ls = new LinSys_BDDC(&(*eq_data_->dh_->distr()),
1130 // true); // swap signs of matrix and rhs to make the matrix SPD
1131 // ls->set_from_input(in_rec);
1132 // ls->set_solution( eq_data_->full_solution.petsc_vec() );
1133 // // possible initialization particular to BDDC
1134 // START_TIMER("BDDC set mesh data");
1135 // set_mesh_data_for_bddc(ls);
1136 // schur0=ls;
1137 // END_TIMER("BDDC set mesh data");
1138 // #else
1139 // Exception
1140 // THROW( ExcBddcmlNotSupported() );
1141 // #endif // FLOW123D_HAVE_BDDCML
1142 // }
1143 // else
1144  if (in_rec.type() == LinSys_PETSC::get_input_type()) {
1145  // use PETSC for serial case even when user wants BDDC
1146 
1147  eq_data_->lin_sys_schur = std::make_shared<LinSys_PETSC>( &(*eq_data_->dh_cr_->distr()) );
1148  lin_sys_schur().set_from_input(in_rec);
1150  lin_sys_schur().set_solution( eq_data_->p_edge_solution.petsc_vec() );
1152  ((LinSys_PETSC *)&lin_sys_schur())->set_initial_guess_nonzero(true);
1153 
1154 // LinSys_PETSC *schur1, *schur2;
1155 
1156 // if (n_schur_compls == 0) {
1157 // LinSys_PETSC *ls = new LinSys_PETSC( &(*eq_data_->dh_->distr()) );
1158 
1159 // // temporary solution; we have to set precision also for sequantial case of BDDC
1160 // // final solution should be probably call of direct solver for oneproc case
1161 // // if (in_rec.type() != LinSys_BDDC::get_input_type()) ls->set_from_input(in_rec);
1162 // // else {
1163 // // ls->LinSys::set_from_input(in_rec); // get only common options
1164 // // }
1165 // ls->set_from_input(in_rec);
1166 
1167 // // ls->set_solution( eq_data_->full_solution.petsc_vec() );
1168 // schur0=ls;
1169 // } else {
1170 // IS is;
1171 // auto side_dofs_vec = get_component_indices_vec(0);
1172 
1173 // ISCreateGeneral(PETSC_COMM_SELF, side_dofs_vec.size(), &(side_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1174 // //ISView(is, PETSC_VIEWER_STDOUT_SELF);
1175 // //ASSERT_PERMANENT(err == 0).error("Error in ISCreateStride.");
1176 
1177 // SchurComplement *ls = new SchurComplement(&(*eq_data_->dh_->distr()), is);
1178 
1179 // // make schur1
1180 // Distribution *ds = ls->make_complement_distribution();
1181 // if (n_schur_compls==1) {
1182 // schur1 = new LinSys_PETSC(ds);
1183 // schur1->set_positive_definite();
1184 // } else {
1185 // IS is;
1186 // auto elem_dofs_vec = get_component_indices_vec(1);
1187 
1188 // const PetscInt *b_indices;
1189 // ISGetIndices(ls->IsB, &b_indices);
1190 // uint b_size = ls->loc_size_B;
1191 // for(uint i_b=0, i_bb=0; i_b < b_size && i_bb < elem_dofs_vec.size(); i_b++) {
1192 // if (b_indices[i_b] == elem_dofs_vec[i_bb])
1193 // elem_dofs_vec[i_bb++] = i_b + ds->begin();
1194 // }
1195 // ISRestoreIndices(ls->IsB, &b_indices);
1196 
1197 
1198 // ISCreateGeneral(PETSC_COMM_SELF, elem_dofs_vec.size(), &(elem_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1199 // //ISView(is, PETSC_VIEWER_STDOUT_SELF);
1200 // //ASSERT_PERMANENT(err == 0).error("Error in ISCreateStride.");
1201 // SchurComplement *ls1 = new SchurComplement(ds, is); // is is deallocated by SchurComplement
1202 // ls1->set_negative_definite();
1203 
1204 // // make schur2
1205 // schur2 = new LinSys_PETSC( ls1->make_complement_distribution() );
1206 // schur2->set_positive_definite();
1207 // ls1->set_complement( schur2 );
1208 // schur1 = ls1;
1209 // }
1210 // ls->set_complement( schur1 );
1211 // ls->set_from_input(in_rec);
1212 // // ls->set_solution( eq_data_->full_solution.petsc_vec() );
1213 // schur0=ls;
1214  // }
1215 
1216  START_TIMER("PETSc preallocation");
1218 
1220 
1221  eq_data_->full_solution.zero_entries();
1222  eq_data_->p_edge_solution.zero_entries();
1223  END_TIMER("PETSc preallocation");
1224  }
1225  else {
1226  THROW( ExcUnknownSolver() );
1227  }
1228 
1229  END_TIMER("Darcy preallocation");
1230 }
1231 
1233 {}
1234 
1235 //void DarcyLMH::reconstruct_solution_from_schur(MultidimAssembly& assembler)
1236 //{
1237 // START_TIMER("DarcyFlowMH::reconstruct_solution_from_schur");
1238 //
1239 // eq_data_->full_solution.zero_entries();
1240 // eq_data_->p_edge_solution.local_to_ghost_begin();
1241 // eq_data_->p_edge_solution.local_to_ghost_end();
1242 //
1243 // balance_->start_flux_assembly(eq_data_->water_balance_idx);
1244 // balance_->start_source_assembly(eq_data_->water_balance_idx);
1245 // balance_->start_mass_assembly(eq_data_->water_balance_idx);
1246 //
1247 // for ( DHCellAccessor dh_cell : eq_data_->dh_->own_range() ) {
1248 // unsigned int dim = dh_cell.dim();
1249 // assembler[dim-1]->assemble_reconstruct(dh_cell);
1250 // }
1251 //
1252 // eq_data_->full_solution.local_to_ghost_begin();
1253 // eq_data_->full_solution.local_to_ghost_end();
1254 //
1255 // balance_->finish_mass_assembly(eq_data_->water_balance_idx);
1256 // balance_->finish_source_assembly(eq_data_->water_balance_idx);
1257 // balance_->finish_flux_assembly(eq_data_->water_balance_idx);
1258 //}
1259 
1261  START_TIMER("Darcy assembly_linear_system");
1262 // DebugOut() << "DarcyLMH::assembly_linear_system\n";
1263 
1264  eq_data_->p_edge_solution.local_to_ghost_begin();
1265  eq_data_->p_edge_solution.local_to_ghost_end();
1266 
1267  eq_data_->is_linear=true;
1268  //DebugOut() << "Assembly linear system\n";
1269 // if (data_changed_) {
1270 // data_changed_ = false;
1271  {
1272  //DebugOut() << "Data changed\n";
1273  // currently we have no optimization for cases when just time term data or RHS data are changed
1274 // if (typeid(*schur0) != typeid(LinSys_BDDC)) {
1275 // schur0->start_add_assembly(); // finish allocation and create matrix
1276 // schur_compl->start_add_assembly();
1277 // }
1278 
1280 
1283 
1284  eq_data_->time_step_ = time_->dt();
1285 
1286  this->mh_matrix_assembly_->assemble(eq_data_->dh_);; // fill matrix
1287 // assembly_mh_matrix( eq_data_->multidim_assembler ); // fill matrix
1288 
1291 
1292  // print_matlab_matrix("matrix");
1293  }
1294 }
1295 
1296 
1297 void DarcyLMH::print_matlab_matrix(std::string matlab_file)
1298 {
1299  std::string output_file;
1300 
1301  // compute h_min for different dimensions
1302  double d_max = std::numeric_limits<double>::max();
1303  double h1 = d_max, h2 = d_max, h3 = d_max;
1304  double he2 = d_max, he3 = d_max;
1305  for (auto ele : mesh_->elements_range()) {
1306  switch(ele->dim()){
1307  case 1: h1 = std::min(h1,ele.measure()); break;
1308  case 2: h2 = std::min(h2,ele.measure()); break;
1309  case 3: h3 = std::min(h3,ele.measure()); break;
1310  }
1311 
1312  for (unsigned int j=0; j<ele->n_sides(); j++) {
1313  switch(ele->dim()){
1314  case 2: he2 = std::min(he2, ele.side(j)->measure()); break;
1315  case 3: he3 = std::min(he3, ele.side(j)->measure()); break;
1316  }
1317  }
1318  }
1319  if(h1 == d_max) h1 = 0;
1320  if(h2 == d_max) h2 = 0;
1321  if(h3 == d_max) h3 = 0;
1322  if(he2 == d_max) he2 = 0;
1323  if(he3 == d_max) he3 = 0;
1324 
1325  FILE * file;
1326  file = fopen(output_file.c_str(),"a");
1327  fprintf(file, "nA = %d;\n", eq_data_->dh_cr_disc_->distr()->size());
1328  fprintf(file, "nB = %d;\n", eq_data_->dh_->mesh()->get_el_ds()->size());
1329  fprintf(file, "nBF = %d;\n", eq_data_->dh_cr_->distr()->size());
1330  fprintf(file, "h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1331  fprintf(file, "he2 = %e;\nhe3 = %e;\n", he2, he3);
1332  fclose(file);
1333 
1334  {
1335  output_file = FilePath(matlab_file + "_sch_new.m", FilePath::output_file);
1336  PetscViewer viewer;
1337  PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1338  PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1339  MatView( *const_cast<Mat*>(lin_sys_schur().get_matrix()), viewer);
1340  VecView( *const_cast<Vec*>(lin_sys_schur().get_rhs()), viewer);
1341  VecView( *const_cast<Vec*>(&(lin_sys_schur().get_solution())), viewer);
1342  VecView( *const_cast<Vec*>(&(eq_data_->full_solution.petsc_vec())), viewer);
1343  }
1344 }
1345 
1346 
1347 //template <int dim>
1348 //std::vector<arma::vec3> dof_points(DHCellAccessor cell, const Mapping<dim, 3> &mapping) {
1349 //
1350 //
1351 // vector<arma::vec::fixed<dim+1>> bary_dof_points = cell->fe()->dof_points();
1352 //
1353 // std::vector<arma::vec3> points(20);
1354 // points.resize(0);
1355 //
1356 //}
1357 //
1358 
1359 // void DarcyLMH::set_mesh_data_for_bddc(LinSys_BDDC * bddc_ls) {
1360 // START_TIMER("DarcyFlowMH_Steady::set_mesh_data_for_bddc");
1361 // // prepare mesh for BDDCML
1362 // // initialize arrays
1363 // // auxiliary map for creating coordinates of local dofs and global-to-local numbering
1364 // std::map<int, arma::vec3> localDofMap;
1365 // // connectivity for the subdomain, i.e. global dof numbers on element, stored element-by-element
1366 // // Indices of Nodes on Elements
1367 // std::vector<int> inet;
1368 // // number of degrees of freedom on elements - determines elementwise chunks of INET array
1369 // // Number of Nodes on Elements
1370 // std::vector<int> nnet;
1371 // // Indices of Subdomain Elements in Global Numbering - for local elements, their global indices
1372 // std::vector<int> isegn;
1373 //
1374 // // This array is currently not used in BDDCML, it was used as an interface scaling alternative to scaling
1375 // // by diagonal. It corresponds to the rho-scaling.
1376 // std::vector<double> element_permeability;
1377 //
1378 // // maximal and minimal dimension of elements
1379 // uint elDimMax = 1;
1380 // uint elDimMin = 3;
1381 // std::vector<LongIdx> cell_dofs_global(10);
1382 //
1383 //
1384 //
1385 // for ( DHCellAccessor dh_cell : eq_data_->dh_->own_range() ) {
1386 // // LocalElementAccessorBase<3> ele_ac(dh_cell);
1387 // // for each element, create local numbering of dofs as fluxes (sides), pressure (element centre), Lagrange multipliers (edges), compatible connections
1388 //
1389 // dh_cell.get_dof_indices(cell_dofs_global);
1390 //
1391 // inet.insert(inet.end(), cell_dofs_global.begin(), cell_dofs_global.end());
1392 // uint n_inet = cell_dofs_global.size();
1393 //
1394 //
1395 // uint dim = dh_cell.elm().dim();
1396 // elDimMax = std::max( elDimMax, dim );
1397 // elDimMin = std::min( elDimMin, dim );
1398 //
1399 // // TODO: this is consistent with previous implementation, but may be wrong as it use global element numbering
1400 // // used in sequential mesh, do global numbering of distributed elements.
1401 // isegn.push_back( dh_cell.elm_idx());
1402 //
1403 // // TODO: use FiniteElement::dof_points
1404 // for (unsigned int si=0; si<dh_cell.elm()->n_sides(); si++) {
1405 // arma::vec3 coord = dh_cell.elm().side(si)->centre();
1406 // // flux dof points
1407 // localDofMap.insert( std::make_pair( cell_dofs_global[si], coord ) );
1408 // // pressure trace dof points
1409 // localDofMap.insert( std::make_pair( cell_dofs_global[si+dim+2], coord ) );
1410 // }
1411 // // pressure dof points
1412 // arma::vec3 elm_centre = dh_cell.elm().centre();
1413 // localDofMap.insert( std::make_pair( cell_dofs_global[dim+1], elm_centre ) );
1414 //
1415 // // insert dofs related to compatible connections
1416 // //const Element *ele = dh_cell.elm().element();
1417 // for(DHCellSide side : dh_cell.neighb_sides()) {
1418 // uint neigh_dim = side.cell().elm().dim();
1419 // side.cell().get_dof_indices(cell_dofs_global);
1420 // int edge_row = cell_dofs_global[neigh_dim+2+side.side_idx()];
1421 // localDofMap.insert( std::make_pair( edge_row, side.centre() ) );
1422 // inet.push_back( edge_row );
1423 // n_inet++;
1424 // }
1425 // nnet.push_back(n_inet);
1426 //
1427 //
1428 // // version for rho scaling
1429 // // trace computation
1430 // double conduct = eq_fields_->conductivity.value( elm_centre , dh_cell.elm() );
1431 // auto aniso = eq_fields_->anisotropy.value( elm_centre , dh_cell.elm() );
1432 //
1433 // // compute mean on the diagonal
1434 // double coef = 0.;
1435 // for ( int i = 0; i < 3; i++) {
1436 // coef = coef + aniso.at(i,i);
1437 // }
1438 // // Maybe divide by cs
1439 // coef = conduct*coef / 3;
1440 //
1441 // ASSERT_PERMANENT_GT(coef, 0).error("Zero coefficient of hydrodynamic resistance.\n");
1442 // element_permeability.push_back( 1. / coef );
1443 // }
1444 // // uint i_inet = 0;
1445 // // for(int n_dofs : nnet) {
1446 // // DebugOut() << "nnet: " << n_dofs;
1447 // // for(int j=0; j < n_dofs; j++, i_inet++) {
1448 // // DebugOut() << "inet: " << inet[i_inet];
1449 // // }
1450 // // }
1451 //
1452 // auto distr = eq_data_->dh_->distr();
1453 // // for(auto pair : localDofMap) {
1454 // // DebugOut().every_proc() << "r: " << distr->myp() << " gi: " << pair.first << "xyz: " << pair.second[0];
1455 // //
1456 // // }
1457 //
1458 //
1459 // //convert set of dofs to vectors
1460 // // number of nodes (= dofs) on the subdomain
1461 // int numNodeSub = localDofMap.size();
1462 // //ASSERT_PERMANENT_EQ( (unsigned int)numNodeSub, eq_data_->dh_->lsize() );
1463 // // Indices of Subdomain Nodes in Global Numbering - for local nodes, their global indices
1464 // std::vector<int> isngn( numNodeSub );
1465 // // pseudo-coordinates of local nodes (i.e. dofs)
1466 // // they need not be exact, they are used just for some geometrical considerations in BDDCML,
1467 // // such as selection of corners maximizing area of a triangle, bounding boxes fro subdomains to
1468 // // find candidate neighbours etc.
1469 // std::vector<double> xyz( numNodeSub * 3 ) ;
1470 // int ind = 0;
1471 // std::map<int,arma::vec3>::iterator itB = localDofMap.begin();
1472 // for ( ; itB != localDofMap.end(); ++itB ) {
1473 // isngn[ind] = itB -> first;
1474 //
1475 // arma::vec3 coord = itB -> second;
1476 // for ( int j = 0; j < 3; j++ ) {
1477 // xyz[ j*numNodeSub + ind ] = coord[j];
1478 // }
1479 //
1480 // ind++;
1481 // }
1482 // localDofMap.clear();
1483 //
1484 // // Number of Nodal Degrees of Freedom
1485 // // nndf is trivially one - dofs coincide with nodes
1486 // std::vector<int> nndf( numNodeSub, 1 );
1487 //
1488 // // prepare auxiliary map for renumbering nodes
1489 // typedef std::map<int,int> Global2LocalMap_; //! type for storage of global to local map
1490 // Global2LocalMap_ global2LocalNodeMap;
1491 // for ( unsigned ind = 0; ind < isngn.size(); ++ind ) {
1492 // global2LocalNodeMap.insert( std::make_pair( static_cast<unsigned>( isngn[ind] ), ind ) );
1493 // }
1494 //
1495 // // renumber nodes in the inet array to locals
1496 // int indInet = 0;
1497 // for ( unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) {
1498 // int nne = nnet[ iEle ];
1499 // for ( int ien = 0; ien < nne; ien++ ) {
1500 //
1501 // int indGlob = inet[indInet];
1502 // // map it to local node
1503 // Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob );
1504 // ASSERT_PERMANENT( pos != global2LocalNodeMap.end())(indGlob).error("Cannot remap node index to local indices. \n " );
1505 // int indLoc = static_cast<int> ( pos -> second );
1506 //
1507 // // store the node
1508 // inet[ indInet++ ] = indLoc;
1509 // }
1510 // }
1511 //
1512 // int numNodes = size;
1513 // int numDofsInt = size;
1514 // int spaceDim = 3; // TODO: what is the proper value here?
1515 // int meshDim = elDimMax;
1516 //
1517 // /**
1518 // * We need:
1519 // * - local to global element map (possibly mesh->el_4_loc
1520 // * - inet, nnet - local dof numbers per element, local numbering of only those dofs that are on owned elements
1521 // * 1. collect DH local dof indices on elements, manage map from DH local indices to BDDC local dof indices
1522 // * 2. map collected DH indices to BDDC indices using the map
1523 // * - local BDDC dofs to global dofs, use DH to BDDC map with DH local to global map
1524 // * - XYZ - permuted, collect in main loop into array of size of all DH local dofs, compress and rearrange latter
1525 // * - element_permeability - in main loop
1526 // */
1527 // bddc_ls -> load_mesh( LinSys_BDDC::BDDCMatrixType::SPD_VIA_SYMMETRICGENERAL, spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim );
1528 // }
1529 
1530 
1531 
1532 
1533 //=============================================================================
1534 // DESTROY WATER MH SYSTEM STRUCTURE
1535 //=============================================================================
1537  if (output_object) delete output_object;
1538 
1539  if(time_ != nullptr)
1540  delete time_;
1541 
1542  if (read_init_cond_assembly_!=nullptr) {
1543  delete read_init_cond_assembly_;
1544  read_init_cond_assembly_ = nullptr;
1545  }
1546  if (mh_matrix_assembly_!=nullptr) {
1547  delete mh_matrix_assembly_;
1548  mh_matrix_assembly_ = nullptr;
1549  }
1550  if (reconstruct_schur_assembly_!=nullptr) {
1552  reconstruct_schur_assembly_ = nullptr;
1553  }
1554 }
1555 
1556 
1557 /// Helper method fills range (min and max) of given component
1558 void dofs_range(unsigned int n_dofs, unsigned int &min, unsigned int &max, unsigned int component) {
1559  if (component==0) {
1560  min = 0;
1561  max = n_dofs/2;
1562  } else if (component==1) {
1563  min = n_dofs/2;
1564  max = (n_dofs+1)/2;
1565  } else {
1566  min = (n_dofs+1)/2;
1567  max = n_dofs;
1568  }
1569 }
1570 
1571 
1573  ASSERT_LT(component, 3).error("Invalid component!");
1574  unsigned int i, n_dofs, min, max;
1575  std::vector<int> dof_vec;
1576  std::vector<LongIdx> dof_indices(eq_data_->dh_->max_elem_dofs());
1577  for ( DHCellAccessor dh_cell : eq_data_->dh_->own_range() ) {
1578  n_dofs = dh_cell.get_dof_indices(dof_indices);
1579  dofs_range(n_dofs, min, max, component);
1580  for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);
1581  }
1582  return dof_vec;
1583 }
1584 
1585 
1590 }
1591 
1592 
1594  this->read_init_cond_assembly_->assemble(eq_data_->dh_cr_);
1595 }
1596 
1597 
1598 //-----------------------------------------------------------------------------
1599 // vim: set cindent:
Functors of FieldModels used in Darcy flow module.
#define ASSERT_PERMANENT(expr)
Allow use shorter versions of macro names if these names is not used with external library.
Definition: asserts.hh:348
#define ASSERT_LT(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Definition: asserts.hh:301
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:333
static const Input::Type::Record & get_input_type()
Main balance input record type.
Definition: balance.cc:53
Cell accessor allow iterate over DOF handler cells.
unsigned int n_dofs() const
Return number of dofs on given cell.
unsigned int get_dof_indices(std::vector< LongIdx > &indices) const
Fill vector of the global indices of dofs associated to the cell.
Side accessor allows to iterate over sides of DOF handler cell.
static Input::Type::Abstract & get_input_type()
MortarMethod
Type of experimental Mortar-like method for non-compatible 1d-2d interaction.
static const Input::Type::Instance & get_input_type_specific()
void output()
Calculate values for output.
static const Input::Type::Instance & get_input_type(FieldSet &eq_data, const std::string &equation_name)
EqData(shared_ptr< EqFields > eq_fields)
void reset()
Reset data members.
MortarMethod mortar_method_
void init()
Initialize vectors, ...
Field< 3, FieldValue< 3 >::Scalar > water_source_density
Field< 3, FieldValue< 3 >::Scalar > ref_divergence
Field< 3, FieldValue< 3 >::Scalar > extra_storativity
Field< 3, FieldValue< 3 >::Scalar > field_ele_pressure
Externally added water source.
BCField< 3, FieldValue< 3 >::Enum > bc_type
Field< 3, FieldValue< 3 >::VectorFixed > gravity_field
Field< 3, FieldValue< 3 >::Scalar > sigma
Field< 3, FieldValue< 3 >::Scalar > init_pressure
Field< 3, FieldValue< 3 >::Scalar > storativity
BCField< 3, FieldValue< 3 >::Scalar > bc_pressure
BCField< 3, FieldValue< 3 >::Scalar > bc_flux
Field< 3, FieldValue< 3 >::TensorFixed > anisotropy
Field< 3, FieldValue< 3 >::Scalar > water_source_sigma
Field< 3, FieldValue< 3 >::Scalar > cross_section
Field< 3, FieldValue< 3 >::Scalar > conductivity
Field< 3, FieldValue< 3 >::VectorFixed > field_ele_velocity
Field< 3, FieldValue< 3 >::Scalar > field_edge_pressure
BCField< 3, FieldValue< 3 >::Scalar > bc_switch_piezo_head
Field< 3, FieldValue< 3 >::Scalar > field_ele_piezo_head
Field< 3, FieldValue< 3 >::Scalar > init_piezo_head
Same as previous but used in boundary fields.
Field< 3, FieldValue< 3 >::Scalar > water_source_ref_pressure
BCField< 3, FieldValue< 3 >::Scalar > bc_robin_sigma
static const Input::Type::Selection & get_bc_type_selection()
Return a Selection corresponding to enum BC_Type.
Field< 3, FieldValue< 3 >::Scalar > extra_source
Externally added storativity.
Field< 3, FieldValue< 3 >::VectorFixed > ref_velocity
Precompute l2 difference outputs.
Field< 3, FieldValue< 3 >::VectorFixed > flux
EqFields()
Creation of all fields.
BCField< 3, FieldValue< 3 >::Scalar > bc_switch_pressure
BCField< 3, FieldValue< 3 >::VectorFixed > bc_gravity
Holds gravity vector acceptable in FieldModel.
BCField< 3, FieldValue< 3 >::Scalar > bc_piezo_head
Field< 3, FieldValue< 3 >::Scalar > ref_pressure
GenericAssemblyBase * mh_matrix_assembly_
void initialize() override
void print_matlab_matrix(string matlab_file)
Print darcy flow matrix in matlab format into a file.
virtual double solved_time() override
void zero_time_step() override
virtual void postprocess()
EqFields & eq_fields()
void solve_nonlinear()
Solve method common to zero_time_step and update solution.
static std::string equation_name()
virtual void initialize_specific()
static const int registrar
Registrar of class to factory.
DarcyFlowMHOutput * output_object
std::shared_ptr< EqData > eq_data_
unsigned int max_n_it_
bool data_changed_
GenericAssemblyBase * reconstruct_schur_assembly_
double tolerance_
virtual void initialize_asm()
Create and initialize assembly objects.
void update_solution() override
void allocate_mh_matrix()
unsigned int min_n_it_
void solve_time_step(bool output=true)
Solve the problem without moving to next time and without output.
std::vector< int > get_component_indices_vec(unsigned int component) const
Get vector of all DOF indices of given component (0..side, 1..element, 2..edge)
static const Input::Type::Record & type_field_descriptor()
void create_linear_system(Input::AbstractRecord rec)
static const Input::Type::Record & get_input_type()
DarcyLMH(Mesh &mesh, const Input::Record in_rec, TimeGovernor *tm=nullptr)
CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL.
friend class DarcyFlowMHOutput
virtual bool zero_time_term(bool time_global=false)
std::shared_ptr< EqFields > eq_fields_
static const Input::Type::Selection & get_mh_mortar_selection()
Selection for enum MortarMethod.
std::shared_ptr< Balance > balance_
void init_eq_data()
virtual void accept_time_step()
postprocess velocity field (add sources)
virtual ~DarcyLMH() override
virtual void output_data() override
Write computed fields.
GenericAssembly< ReadInitCondAssemblyLMHDim > * read_init_cond_assembly_
general assembly objects, hold assembly objects of appropriate dimension
LinSys & lin_sys_schur()
Getter for the linear system of the 2. Schur complement.
virtual void assembly_linear_system()
virtual void read_init_cond_asm()
Call assemble of read_init_cond_assembly_.
unsigned int n_neighs_vb() const
Return number of neighbours.
Definition: elements.h:65
Input::Record input_record_
Definition: equation.hh:242
static Input::Type::Record & record_template()
Template Record with common keys for derived equations.
Definition: equation.cc:39
std::shared_ptr< FieldSet > eq_fieldset_
Definition: equation.hh:249
TimeGovernor * time_
Definition: equation.hh:241
static Input::Type::Record & user_fields_template(std::string equation_name)
Template Record with common key user_fields for derived equations.
Definition: equation.cc:46
Mesh * mesh_
Definition: equation.hh:240
TimeGovernor & time()
Definition: equation.hh:151
Compound finite element on dim dimensional simplex.
Definition: fe_system.hh:102
static const std::string field_descriptor_record_description(const string &record_name)
Definition: field_common.cc:72
FieldCommon & input_selection(Input::Type::Selection element_selection)
FieldCommon & description(const string &description)
FieldCommon & flags(FieldFlag::Flags::Mask mask)
FieldCommon & name(const string &name)
FieldCommon & set_limits(double min, double max=std::numeric_limits< double >::max())
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
FieldCommon & input_default(const string &input_default)
static constexpr Mask input_copy
Definition: field_flag.hh:44
static constexpr Mask equation_result
Match result fields. These are never given by input or copy of input.
Definition: field_flag.hh:55
void set_default_fieldset()
Definition: field_set.hh:410
auto disable_where(const Field< spacedim, typename FieldValue< spacedim >::Enum > &control_field, const vector< FieldEnum > &value_list) -> Field &
Definition: field.impl.hh:194
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
@ output_file
Definition: file_path.hh:69
virtual void assemble(std::shared_ptr< DOFHandlerMultiDim > dh)=0
Generic class of assemblation.
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:458
Input::Type::Record type() const
Definition: accessors.cc:273
Accessor to input data conforming to declared Array.
Definition: accessors.hh:566
Accessor to the data with type Type::Record.
Definition: accessors.hh:291
const Ret val(const string &key) const
Class for declaration of inputs sequences.
Definition: type_base.hh:339
Class for declaration of the input of type Bool.
Definition: type_base.hh:452
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
static Default optional()
The factory function to make an empty default value which is optional.
Definition: type_record.hh:124
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:534
Class for declaration of the integral input data.
Definition: type_base.hh:483
Record type proxy class.
Definition: type_record.hh:182
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:602
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:196
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:216
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
Template for classes storing finite set of named values.
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.
const Selection & close() const
Close the Selection, no more values can be added.
static const Input::Type::Record & get_input_type()
Definition: linsys_PETSC.cc:32
void set_solution(Vec sol_vec)
Definition: linsys.hh:290
void set_matrix_changed()
Definition: linsys.hh:212
virtual void set_from_input(const Input::Record in_rec)
Definition: linsys.hh:641
virtual void start_add_assembly()
Definition: linsys.hh:341
virtual void finish_assembly()=0
virtual void set_tolerances(double r_tol, double a_tol, double d_tol, unsigned int max_it)=0
virtual void mat_set_values(int nrow, int *rows, int ncol, int *cols, double *vals)=0
virtual double compute_residual()=0
void set_symmetric(bool flag=true)
Definition: linsys.hh:561
virtual PetscErrorCode rhs_zero_entries()
Definition: linsys.hh:273
virtual void start_allocation()
Definition: linsys.hh:333
virtual SolveInfo solve()=0
void set_positive_definite(bool flag=true)
Definition: linsys.hh:576
virtual PetscErrorCode mat_zero_entries()
Definition: linsys.hh:264
static Input::Type::Abstract & get_input_type()
Definition: linsys.cc:29
const RegionDB & region_db() const
Definition: mesh.h:175
unsigned int n_edges() const
Definition: mesh.h:114
unsigned int n_elements() const
Definition: mesh.h:111
Range< ElementAccessor< 3 > > elements_range() const
Returns range of mesh elements.
Definition: mesh.cc:1188
Definition: mesh.h:362
BCMesh * bc_mesh() const override
Implement MeshBase::bc_mesh(), getter of boundary mesh.
Definition: mesh.h:567
MixedMeshIntersections & mixed_intersections()
Definition: mesh.cc:863
unsigned int n_sides() const
Definition: mesh.cc:308
static const Input::Type::Record & get_input_type()
The specification of output stream.
Definition: output_time.cc:38
RegionSet get_region_set(const std::string &set_name) const
Definition: region.cc:328
Basic time management functionality for unsteady (and steady) solvers (class Equation).
double dt() const
double t() const
bool is_end() const
Returns true if the actual time is greater than or equal to the end time.
int set_upper_constraint(double upper, std::string message)
Sets upper constraint for the next time step estimating.
void view(const char *name="") const
double estimate_dt() const
Estimate choice of next time step according to actual setting of constraints.
const TimeStep & step(int index=-1) const
void next_time()
Proceed to the next time according to current estimated time step.
Class for representation SI units of Fields.
Definition: unit_si.hh:40
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:55
void dofs_range(unsigned int n_dofs, unsigned int &min, unsigned int &max, unsigned int component)
Helper method fills range (min and max) of given component.
Lumped mixed-hybrid model of linear Darcy flow, possibly unsteady.
Output class for darcy_flow_mh model.
Support classes for parallel programing.
Definitions of basic Lagrangean finite elements with polynomial shape functions.
@ result_zeros
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
Definition: global_defs.h:104
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
Classes with algorithms for computation of intersections of meshes.
Wrappers for linear systems based on MPIAIJ and MATIS format.
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
#define WarningOut()
Macro defining 'warning' record of log.
Definition: logger.hh:278
#define MessageOut()
Macro defining 'message' record of log.
Definition: logger.hh:275
unsigned int uint
#define MPI_INT
Definition: mpi.h:160
#define MPI_Allreduce(sendbuf, recvbuf, count, datatype, op, comm)
Definition: mpi.h:612
#define MPI_MIN
Definition: mpi.h:198
ArmaVec< double, N > vec
Definition: armor.hh:933
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args)
Definition: ostream.cc:56
double Scalar
Definition: op_accessors.hh:25
Implementation of range helper class.
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
int converged_reason
Definition: linsys.hh:108
#define END_TIMER(tag)
Ends a timer with specified tag.
#define START_TIMER(tag)
Starts a timer with specified tag.
Basic time management class.