Flow123d  jenkins-Flow123d-windows32-release-multijob-51
darcy_flow_mh.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id$
21  * $Revision$
22  * $LastChangedBy$
23  * $LastChangedDate$
24  *
25  *
26  * @file
27  * @ingroup flow
28  * @brief Setup and solve linear system of mixed-hybrid discretization of the linear
29  * porous media flow with possible preferential flow in fractures and chanels.
30  *
31  */
32 
33 #include "petscmat.h"
34 #include "petscviewer.h"
35 #include "petscerror.h"
36 #include <armadillo>
37 #include <boost/foreach.hpp>
38 
39 
40 #include "system/system.hh"
41 
42 #include "mesh/mesh.h"
43 #include "mesh/intersection.hh"
44 #include "mesh/partitioning.hh"
45 #include "la/distribution.hh"
46 #include "la/linsys.hh"
47 #include "la/linsys_PETSC.hh"
48 #include "la/linsys_BDDC.hh"
49 #include "la/schur.hh"
50 #include "la/sparse_graph.hh"
52 
53 #include "system/file_path.hh"
54 #include "flow/mh_fe_values.hh"
55 #include "flow/darcy_flow_mh.hh"
56 
58 
59 #include "fem/mapping_p1.hh"
60 #include "fem/fe_p.hh"
61 #include "fem/fe_values.hh"
63 
64 #include <limits>
65 #include <set>
66 #include <vector>
67 #include <iostream>
68 #include <iterator>
69 #include <algorithm>
70 
72 
74 #include "fields/field.hh"
75 #include "fields/field_values.hh"
76 #include "system/sys_profiler.hh"
77 
78 
79 
80 
81 namespace it = Input::Type;
82 
84  = it::Selection("MH_MortarMethod")
85  .add_value(NoMortar, "None", "Mortar space: P0 on elements of lower dimension.")
86  .add_value(MortarP0, "P0", "Mortar space: P0 on elements of lower dimension.")
87  .add_value(MortarP1, "P1", "Mortar space: P1 on intersections, using non-conforming pressures.");
88 
89 
91  it::Selection("EqData_bc_Type")
92  .add_value(none, "none", "Homogeneous Neoumann BC.")
93  .add_value(dirichlet, "dirichlet")
94  .add_value(neumann, "neumann")
95  .add_value(robin, "robin")
96  .add_value(total_flux, "total_flux");
97 
98 //new input type with FIELDS
100  it::AbstractRecord("DarcyFlowMH", "Mixed-Hybrid solver for saturated Darcy flow.")
101  .declare_key("n_schurs", it::Integer(0,2), it::Default("2"),
102  "Number of Schur complements to perform when solving MH sytem.")
104  "Linear solver for MH problem.")
106  "Parameters of output form MH module.")
107  .declare_key("mortar_method", mh_mortar_selection, it::Default("None"),
108  "Method for coupling Darcy flow between dimensions." );
109 
110 
112  = it::Record("Steady_MH", "Mixed-Hybrid solver for STEADY saturated Darcy flow.")
113  .derive_from(DarcyFlowMH::input_type)
114  .declare_key("input_fields", it::Array(
115  DarcyFlowMH_Steady::EqData().make_field_descriptor_type("DarcyFlowMH")
116  .declare_key("bc_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type(), "Boundary condition for pressure as piezometric head." )
117  .declare_key("init_piezo_head", FieldAlgorithmBase< 3, FieldValue<3>::Scalar >::get_input_type(), "Initial condition for pressure as piezometric head." )
118  .declare_key(OldBcdInput::flow_old_bcd_file_key(), it::FileName::input(), "File with mesh dependent boundary conditions (obsolete).")
119  ), it::Default::obligatory(), "" );
120 
122  = it::Record("Unsteady_MH", "Mixed-Hybrid solver for unsteady saturated Darcy flow.")
123  .derive_from(DarcyFlowMH::input_type)
125  "Time governor setting for the unsteady Darcy flow model.")
126  .copy_keys(DarcyFlowMH_Steady::input_type);
127 
128 
130  = it::Record("Unsteady_LMH", "Lumped Mixed-Hybrid solver for unsteady saturated Darcy flow.")
131  .derive_from(DarcyFlowMH::input_type)
133  "Time governor setting for the unsteady Darcy flow model.")
134  .copy_keys(DarcyFlowMH_Steady::input_type);
135 
136 
137 
138 
139 // gravity vector + constant shift of values
140 arma::vec4 DarcyFlowMH::EqData::gravity_=arma::vec4("0 0 -1 0");
141 
142 
144 {
145  gravity_ = arma::vec4("0 0 -1 0");
146 
147  ADD_FIELD(anisotropy, "Anisotropy of the conductivity tensor.", "1.0" );
149 
150  ADD_FIELD(cross_section, "Complement dimension parameter (cross section for 1D, thickness for 2D).", "1.0" );
151  cross_section.units( UnitSI().m(3).md() );
152 
153  ADD_FIELD(conductivity, "Isotropic conductivity scalar.", "1.0" );
154  conductivity.units( UnitSI().m().s(-1) );
155 
156  ADD_FIELD(sigma, "Transition coefficient between dimensions.", "1.0");
158 
159  ADD_FIELD(water_source_density, "Water source density.", "0.0");
160  water_source_density.units( UnitSI().s(-1) );
161 
162  ADD_FIELD(bc_type,"Boundary condition type, possible values:", "\"none\"" );
166 
167  ADD_FIELD(bc_pressure,"Dirichlet BC condition value for pressure.");
170  bc_pressure.units( UnitSI().m() );
171 
172  ADD_FIELD(bc_flux,"Flux in Neumman or Robin boundary condition.");
175  bc_flux.units( UnitSI().m(4).s(-1).md() );
176 
177  ADD_FIELD(bc_robin_sigma,"Conductivity coefficient in Robin boundary condition.");
180  bc_robin_sigma.units( UnitSI().m(3).s(-1).md() );
181 
182  //these are for unsteady
183  ADD_FIELD(init_pressure, "Initial condition as pressure", "0.0" );
184  init_pressure.units( UnitSI().m() );
185 
186  ADD_FIELD(storativity,"Storativity.", "1.0" );
187  storativity.units( UnitSI().m(-1) );
188 
189  time_term_fields = this->subset({"storativity"});
190  main_matrix_fields = this->subset({"anisotropy", "conductivity", "cross_section", "sigma", "bc_type", "bc_robin_sigma"});
191  rhs_fields = this->subset({"water_source_density", "bc_pressure", "bc_flux"});
192 
193 }
194 
195 
196 
197 
198 //=============================================================================
199 // CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL
200 // - do it in parallel:
201 // - initial distribution of elements, edges
202 //
203 /*! @brief CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL
204  *
205  * Parameters {Solver,NSchurs} number of performed Schur
206  * complements (0,1,2) for water flow MH-system
207  *
208  */
209 //=============================================================================
210 DarcyFlowMH_Steady::DarcyFlowMH_Steady(Mesh &mesh_in, const Input::Record in_rec, bool make_tg )
211 : DarcyFlowMH(mesh_in, in_rec)
212 
213 {
214  using namespace Input;
215  START_TIMER("Darcy constructor");
216 
217  this->eq_data_ = &data_;
218 
219  //connecting data fields with mesh
220  START_TIMER("data init");
221  data_.set_mesh(mesh_in);
222  data_.set_input_list( in_rec.val<Input::Array>("input_fields") );
223 
224 
225 
226 
227  END_TIMER("data init");
228 
229 
230  size = mesh_->n_elements() + mesh_->n_sides() + mesh_->n_edges();
231  n_schur_compls = in_rec.val<int>("n_schurs");
232 
233  solution = NULL;
234  schur0 = NULL;
235 
236 
237  mortar_method_= in_rec.val<MortarMethod>("mortar_method");
238  if (mortar_method_ != NoMortar) {
240  }
241 
242  mh_dh.reinit(mesh_);
243 
244  prepare_parallel(in_rec.val<AbstractRecord>("solver"));
245 
246  //side_ds->view( std::cout );
247  //el_ds->view( std::cout );
248  //edge_ds->view( std::cout );
249  //rows_ds->view( std::cout );
250 
251 
252 
253 
254  if (make_tg) {
255  // steady time governor
256  time_ = new TimeGovernor();
259  data_.set_time(*time_);
260 
261  output_object = new DarcyFlowMHOutput(this, in_rec.val<Input::Record>("output"));
263  }
264 
265 
266 }
267 
268 
269 
270 
271 //=============================================================================
272 // COMPOSE and SOLVE WATER MH System possibly through Schur complements
273 //=============================================================================
275  START_TIMER("Solving MH system");
276 
277 
278  if (time_->is_end()) return;
279 
280  if (! time_->is_steady()) time_->next_time();
281 
282 
283 
285  int convergedReason = schur0->solve();
286 
287  xprintf(MsgLog, "Linear solver ended with reason: %d \n", convergedReason );
288  ASSERT( convergedReason >= 0, "Linear solver failed to converge. Convergence reason %d \n", convergedReason );
289 
290  this -> postprocess();
291 
293 
294  output_data();
295 
296  if (time_->is_steady()) time_->next_time();
297 }
298 
300 {
301  START_TIMER("postprocess");
302  //ElementFullIter ele = ELEMENT_FULL_ITER(mesh_, NULL);
303 
304  // modify side fluxes in parallel
305  // for every local edge take time term on digonal and add it to the corresponding flux
306  /*
307  for (unsigned int i_loc = 0; i_loc < el_ds->lsize(); i_loc++) {
308  ele = mesh_->element(el_4_loc[i_loc]);
309  FOR_ELEMENT_SIDES(ele,i) {
310  side_rows[i] = side_row_4_id[ mh_dh.side_dof( ele->side(i) ) ];
311  values[i] = -1.0 * ele->measure() *
312  data.cross_section.value(ele->centre(), ele->element_accessor()) *
313  data.water_source_density.value(ele->centre(), ele->element_accessor()) /
314  ele->n_sides();
315  }
316  VecSetValues(schur0->get_solution(), ele->n_sides(), side_rows, values, ADD_VALUES);
317  }
318  VecAssemblyBegin(schur0->get_solution());
319  VecAssemblyEnd(schur0->get_solution());
320  */
321 }
322 
323 
325  time_->view("DARCY"); //time governor information output
326  this->output_object->output();
327 }
328 
330 {
331  return schur0->get_solution_precision();
332 }
333 
334 
335 void DarcyFlowMH_Steady::get_solution_vector(double * &vec, unsigned int &vec_size)
336 {
337  // TODO: make class for vectors (wrapper for PETSC or other) derived from LazyDependency
338  // and use its mechanism to manage dependency between vectors
340 
341  // scatter solution to all procs
342  VecScatterBegin(par_to_all, schur0->get_solution(), sol_vec, INSERT_VALUES, SCATTER_FORWARD);
343  VecScatterEnd( par_to_all, schur0->get_solution(), sol_vec, INSERT_VALUES, SCATTER_FORWARD);
345  }
346 
347  vec = solution;
348  vec_size = this->size;
349  ASSERT(vec != NULL, "Requested solution is not allocated!\n");
350 }
351 
353 {
354  vec=schur0->get_solution();
355  ASSERT(vec != NULL, "Requested solution is not allocated!\n");
356 }
357 
358 
359 
360 // ===========================================================================================
361 //
362 // MATRIX ASSEMBLY - we use abstract assembly routine, where LS Mat/Vec SetValues
363 // are in fact pointers to allocating or filling functions - this is governed by Linsystem roitunes
364 //
365 // =======================================================================================
366 
367 
368 // ******************************************
369 // ABSTRACT ASSEMBLY OF MH matrix
370 // TODO: matice by se mela sestavovat zvlast pro kazdou dimenzi (objem, pukliny, pruseciky puklin)
371 // konekce by se mely sestavovat cyklem pres konekce, konekce by mely byt paralelizovany podle
372 // distribuce elementu nizssi dimenze
373 // k tomuto je treba nejdriv spojit s JK verzi, aby se vedelo co se deje v transportu a
374 // predelat mesh a neigbouring
375 // *****************************************
377  LinSys *ls = schur0;
379  MHFEValues fe_values;
380 
381  // We use FESideValues for calculating normal vectors.
382  // For initialization of FESideValues some auxiliary objects are needed.
383  MappingP1<1,3> map1;
384  MappingP1<2,3> map2;
385  MappingP1<3,3> map3;
386  QGauss<0> q0(1);
387  QGauss<1> q1(1);
388  QGauss<2> q2(1);
389  FE_P_disc<1,1,3> fe1;
390  FE_P_disc<0,2,3> fe2;
391  FE_P_disc<0,3,3> fe3;
392  FESideValues<1,3> fe_side_values1(map1, q0, fe1, update_normal_vectors);
393  FESideValues<2,3> fe_side_values2(map2, q1, fe2, update_normal_vectors);
394  FESideValues<3,3> fe_side_values3(map3, q2, fe3, update_normal_vectors);
395 
396  class Boundary *bcd;
397  class Neighbour *ngh;
398 
399  bool fill_matrix = schur0->is_preallocated();
400  int el_row, side_row, edge_row;
401  int tmp_rows[100];
402  int side_rows[4], edge_rows[4]; // rows for sides and edges of one element
403  double local_vb[4]; // 2x2 matrix
404 
405  // to make space for second schur complement, max. 10 neighbour edges of one el.
406  double zeros[1000];
407  for(int i=0; i<1000; i++) zeros[i]=0.0;
408 
409  double minus_ones[4] = { -1.0, -1.0, -1.0, -1.0 };
410  double loc_side_rhs[4];
411 
412 
413  for (unsigned int i_loc = 0; i_loc < el_ds->lsize(); i_loc++) {
414 
415  ele = mesh_->element(el_4_loc[i_loc]);
416  el_row = row_4_el[el_4_loc[i_loc]];
417  unsigned int nsides = ele->n_sides();
418  if (fill_matrix) fe_values.update(ele, data_.anisotropy, data_.cross_section, data_.conductivity);
419  double cross_section = data_.cross_section.value(ele->centre(), ele->element_accessor());
420 
421  for (unsigned int i = 0; i < nsides; i++) {
422  side_row = side_rows[i] = side_row_4_id[ mh_dh.side_dof( ele->side(i) ) ];
423  edge_row = edge_rows[i] = row_4_edge[ele->side(i)->edge_idx()];
424  bcd=ele->side(i)->cond();
425 
426  // gravity term on RHS
427  loc_side_rhs[i] = (ele->centre()[ 2 ] - ele->side(i)->centre()[ 2 ]);
428 
429  // set block C and C': side-edge, edge-side
430  double c_val = 1.0;
431 
432  if (bcd) {
433  ElementAccessor<3> b_ele = bcd->element_accessor();
434  EqData::BC_Type type = (EqData::BC_Type)data_.bc_type.value(b_ele.centre(), b_ele);
435  if ( type == EqData::none) {
436  // homogeneous neumann
437  } else if ( type == EqData::dirichlet ) {
438  c_val = 0.0;
439  double bc_pressure = data_.bc_pressure.value(b_ele.centre(), b_ele);
440  loc_side_rhs[i] -= bc_pressure;
441  ls->rhs_set_value(edge_row, -bc_pressure);
442  ls->mat_set_value(edge_row, edge_row, -1.0);
443 
444  } else if ( type == EqData::neumann) {
445  double bc_flux = data_.bc_flux.value(b_ele.centre(), b_ele);
446  ls->rhs_set_value(edge_row, bc_flux * bcd->element()->measure() * cross_section);
447 
448  } else if ( type == EqData::robin) {
449  double bc_pressure = data_.bc_pressure.value(b_ele.centre(), b_ele);
450  double bc_sigma = data_.bc_robin_sigma.value(b_ele.centre(), b_ele);
451  ls->rhs_set_value(edge_row, -bcd->element()->measure() * bc_sigma * bc_pressure * cross_section );
452  ls->mat_set_value(edge_row, edge_row, -bcd->element()->measure() * bc_sigma * cross_section );
453 
454  } else {
455  xprintf(UsrErr, "BC type not supported.\n");
456  }
457  }
458  ls->mat_set_value(side_row, edge_row, c_val);
459  ls->mat_set_value(edge_row, side_row, c_val);
460 
461  // assemble matrix for weights in BDDCML
462  // approximation to diagonal of
463  // S = -C - B*inv(A)*B'
464  // as
465  // diag(S) ~ - diag(C) - 1./diag(A)
466  // the weights form a partition of unity to average a discontinuous solution from neighbouring subdomains
467  // to a continuous one
468  // it is important to scale the effect - if conductivity is low for one subdomain and high for the other,
469  // trust more the one with low conductivity - it will be closer to the truth than an arithmetic average
470  if ( typeid(*ls) == typeid(LinSys_BDDC) ) {
471  double val_side = (fe_values.local_matrix())[i*nsides+i];
472  double val_edge = -1./ (fe_values.local_matrix())[i*nsides+i];
473 
474  static_cast<LinSys_BDDC*>(ls)->diagonal_weights_set_value( side_row, val_side );
475  static_cast<LinSys_BDDC*>(ls)->diagonal_weights_set_value( edge_row, val_edge );
476  }
477  }
478 
479  ls->rhs_set_values(nsides, side_rows, loc_side_rhs);
480 
481 
482  // set block A: side-side on one element - block diagonal matrix
483  ls->mat_set_values(nsides, side_rows, nsides, side_rows, fe_values.local_matrix() );
484  // set block B, B': element-side, side-element
485  ls->mat_set_values(1, &el_row, nsides, side_rows, minus_ones);
486  ls->mat_set_values(nsides, side_rows, 1, &el_row, minus_ones);
487 
488 
489  // set sources
490  ls->rhs_set_value(el_row, -1.0 * ele->measure() *
491  data_.cross_section.value(ele->centre(), ele->element_accessor()) *
492  data_.water_source_density.value(ele->centre(), ele->element_accessor()) );
493 
494 
495  // D block: non-compatible conections and diagonal: element-element
496 
497  ls->mat_set_value(el_row, el_row, 0.0); // maybe this should be in virtual block for schur preallocation
498 
499  if ( typeid(*ls) == typeid(LinSys_BDDC) ) {
500  double val_ele = 1.;
501  static_cast<LinSys_BDDC*>(ls)->diagonal_weights_set_value( el_row, val_ele );
502  }
503 
504  // D, E',E block: compatible connections: element-edge
505 
506  for (unsigned int i = 0; i < ele->n_neighs_vb; i++) {
507  // every compatible connection adds a 2x2 matrix involving
508  // current element pressure and a connected edge pressure
509  ngh= ele->neigh_vb[i];
510  tmp_rows[0]=el_row;
511  tmp_rows[1]=row_4_edge[ ngh->edge_idx() ];
512 
513  // compute normal vector to side
514  arma::vec3 nv;
515  ElementFullIter ele_higher = mesh_->element.full_iter(ngh->side()->element());
516  switch (ele_higher->dim()) {
517  case 1:
518  fe_side_values1.reinit(ele_higher, ngh->side()->el_idx());
519  nv = fe_side_values1.normal_vector(0);
520  break;
521  case 2:
522  fe_side_values2.reinit(ele_higher, ngh->side()->el_idx());
523  nv = fe_side_values2.normal_vector(0);
524  break;
525  case 3:
526  fe_side_values3.reinit(ele_higher, ngh->side()->el_idx());
527  nv = fe_side_values3.normal_vector(0);
528  break;
529  }
530 
531  double value = data_.sigma.value( ele->centre(), ele->element_accessor()) *
532  2*data_.conductivity.value( ele->centre(), ele->element_accessor()) *
533  arma::dot(data_.anisotropy.value( ele->centre(), ele->element_accessor())*nv, nv) *
534  data_.cross_section.value( ngh->side()->centre(), ele_higher->element_accessor() ) * // cross-section of higher dim. (2d)
535  data_.cross_section.value( ngh->side()->centre(), ele_higher->element_accessor() ) /
536  data_.cross_section.value( ele->centre(), ele->element_accessor() ) * // crossection of lower dim.
537  ngh->side()->measure();
538 
539 
540  local_vb[0] = -value; local_vb[1] = value;
541  local_vb[2] = value; local_vb[3] = -value;
542 
543  ls->mat_set_values(2, tmp_rows, 2, tmp_rows, local_vb);
544 
545  // update matrix for weights in BDDCML
546  if ( typeid(*ls) == typeid(LinSys_BDDC) ) {
547  int ind = tmp_rows[1];
548  // there is -value on diagonal in block C!
549  double new_val = - value;
550  static_cast<LinSys_BDDC*>(ls)->diagonal_weights_set_value( ind, new_val );
551  }
552 
553  if (n_schur_compls == 2) {
554  // for 2. Schur: N dim edge is conected with N dim element =>
555  // there are nz between N dim edge and N-1 dim edges of the element
556 
557  ls->mat_set_values(nsides, edge_rows, 1, tmp_rows+1, zeros);
558  ls->mat_set_values(1, tmp_rows+1, nsides, edge_rows, zeros);
559 
560  // save all global edge indices to higher positions
561  tmp_rows[2+i] = tmp_rows[1];
562  }
563  }
564 
565 
566  // add virtual values for schur complement allocation
567  switch (n_schur_compls) {
568  case 2:
569  // Connections between edges of N+1 dim. elements neighboring with actual N dim element 'ele'
570  ASSERT(ele->n_neighs_vb*ele->n_neighs_vb<1000, "Too many values in E block.");
571  ls->mat_set_values(ele->n_neighs_vb, tmp_rows+2,
572  ele->n_neighs_vb, tmp_rows+2, zeros);
573 
574  case 1: // included also for case 2
575  // -(C')*(A-)*B block and its transpose conect edge with its elements
576  ls->mat_set_values(1, &el_row, nsides, edge_rows, zeros);
577  ls->mat_set_values(nsides, edge_rows, 1, &el_row, zeros);
578  // -(C')*(A-)*C block conect all edges of every element
579  ls->mat_set_values(nsides, edge_rows, nsides, edge_rows, zeros);
580  }
581  }
582 
583 
584  if (mortar_method_ == MortarP0) {
585  P0_CouplingAssembler(*this).assembly(*ls);
586  } else if (mortar_method_ == MortarP1) {
587  P1_CouplingAssembler(*this).assembly(*ls);
588  }
589 }
590 
592  vector<int> &dofs, unsigned int &ele_type, double &delta, arma::vec &dirichlet) {
593 
594  const Element *ele;
595 
596  if (i_ele == (int)(ml_it_->size()) ) { // master element .. 1D
597  ele_type = 0;
598  delta = -delta_0;
599  ele=master_;
600  } else {
601  ele_type = 1;
602  const Intersection &isect=intersections_[ (*ml_it_)[i_ele] ];
603  delta = isect.intersection_true_size();
604  ele = isect.slave_iter();
605  }
606 
607  dofs.resize(ele->n_sides());
608 
609  for(unsigned int i_side=0; i_side < ele->n_sides(); i_side++ ) {
610  dofs[i_side]=darcy_.row_4_edge[ele->side(i_side)->edge_idx()];
611  Boundary * bcd = ele->side(i_side)->cond();
612  if (bcd) {
613  dirichlet.resize(ele->n_sides());
614  ElementAccessor<3> b_ele = bcd->element_accessor();
615  DarcyFlowMH::EqData::BC_Type type = (DarcyFlowMH::EqData::BC_Type)darcy_.data_.bc_type.value(b_ele.centre(), b_ele);
616  //DBGMSG("bcd id: %d sidx: %d type: %d\n", ele->id(), i_side, type);
617  if (type == DarcyFlowMH::EqData::dirichlet) {
618  //DBGMSG("Dirichlet: %d\n", ele->index());
619  dofs[i_side] = -dofs[i_side];
620  double bc_pressure = darcy_.data_.bc_pressure.value(b_ele.centre(), b_ele);
621  dirichlet[i_side] = bc_pressure;
622  }
623  }
624  }
625 
626 }
627 
628 /**
629  * Works well but there is large error next to the boundary.
630  */
632  double delta_i, delta_j;
633  arma::mat product;
634  arma::vec dirichlet_i, dirichlet_j;
635  unsigned int ele_type_i, ele_type_j;
636 
637  unsigned int i,j;
638  vector<int> dofs_i,dofs_j;
639 
640  for(ml_it_ = master_list_.begin(); ml_it_ != master_list_.end(); ++ml_it_) {
641 
642  if (ml_it_->size() == 0) continue; // skip empty masters
643 
644 
645  // on the intersection element we consider
646  // * intersection dofs for master and slave
647  // those are dofs of the space into which we interpolate
648  // base functions from individual master and slave elements
649  // For the master dofs both are usualy eqivalent.
650  // * original dofs - for master same as intersection dofs, for slave
651  // all dofs of slave elements
652 
653  // form list of intersection dofs, in this case pressures in barycenters
654  // but we do not use those form MH system in order to allow second schur somplement. We rather map these
655  // dofs to pressure traces, i.e. we use averages of traces as barycentric values.
656 
657 
658  master_ = intersections_[ml_it_->front()].master_iter();
659  delta_0 = master_->measure();
660 
661  double master_sigma=darcy_.data_.sigma.value( master_->centre(), master_->element_accessor());
662 
663  // rows
664  for(i = 0; i <= ml_it_->size(); ++i) {
665  pressure_diff(i, dofs_i, ele_type_i, delta_i, dirichlet_i);
666  //columns
667  for (j = 0; j <= ml_it_->size(); ++j) {
668  pressure_diff(j, dofs_j, ele_type_j, delta_j, dirichlet_j);
669 
670  double scale = -master_sigma * delta_i * delta_j / delta_0;
671  product = scale * tensor_average[ele_type_i][ele_type_j];
672 
673  arma::vec rhs(dofs_i.size());
674  rhs.zeros();
675  ls.set_values( dofs_i, dofs_j, product, rhs, dirichlet_i, dirichlet_j);
676  }
677  }
678  } // loop over master elements
679 }
680 
681 
682 
683  void P1_CouplingAssembler::add_sides(const Element * ele, unsigned int shift, vector<int> &dofs, vector<double> &dirichlet)
684  {
685 
686  for(unsigned int i_side=0; i_side < ele->n_sides(); i_side++ ) {
687  dofs[shift+i_side] = darcy_.row_4_edge[ele->side(i_side)->edge_idx()];
688  Boundary * bcd = ele->side(i_side)->cond();
689 
690  if (bcd) {
691  ElementAccessor<3> b_ele = bcd->element_accessor();
692  DarcyFlowMH::EqData::BC_Type type = (DarcyFlowMH::EqData::BC_Type)darcy_.data_.bc_type.value(b_ele.centre(), b_ele);
693  //DBGMSG("bcd id: %d sidx: %d type: %d\n", ele->id(), i_side, type);
694  if (type == DarcyFlowMH::EqData::dirichlet) {
695  //DBGMSG("Dirichlet: %d\n", ele->index());
696  dofs[shift + i_side] = -dofs[shift + i_side];
697  double bc_pressure = darcy_.data_.bc_pressure.value(b_ele.centre(), b_ele);
698  dirichlet[shift + i_side] = bc_pressure;
699  }
700  }
701  }
702  }
703 
704 
705 /**
706  * P1 coonection of different dimensions
707  * - demonstrated convergence, but still major open questions:
708  * ? in all test cases the error on the fracture is less on the left and greater on the right
709  * with incresing trend
710  * tried:
711  * - changed order of 1d elements (no change)
712  * - higher precision of ngh output and linear solver (no change)
713  * ? seems that there should be some factor 6.0 in the communication term
714  * ? in the case of infinite k2 -> simplest 1d-constant communication, the biggest difference on borders,
715  * numerical solution greater then analytical
716  *
717  * TODO:
718  * * full implementation of Dirichlet BC ( also for 2d sides)
719  */
720 
722 
723  for (const Intersection &intersec : intersections_) {
724  const Element * master = intersec.master_iter();
725  const Element * slave = intersec.slave_iter();
726 
727  add_sides(master, 0, dofs, dirichlet);
728  add_sides(slave, 2, dofs, dirichlet);
729  double master_sigma=darcy_.data_.sigma.value( master->centre(), master->element_accessor());
730 
731 /*
732  * Local coordinates on 1D
733  * t0
734  * node 0: 0.0
735  * node 1: 1.0
736  *
737  * base fce points
738  * t0 = 0.0 on side 0 node 0
739  * t0 = 1.0 on side 1 node 1
740  *
741  * Local coordinates on 2D
742  * t0 t1
743  * node 0: 0.0 0.0
744  * node 1: 1.0 0.0
745  * node 2: 0.0 1.0
746  *
747  * base fce points
748  * t0=0.5, t1=0.0 on side 0 nodes (0,1)
749  * t0=0.5, t1=0.5 on side 1 nodes (1,2)
750  * t0=0.0, t1=0.5 on side 2 nodes (2,0)
751  */
752 
753 
754 
755  arma::vec point_Y(1);
756  point_Y.fill(1.0);
757  arma::vec point_2D_Y(intersec.map_to_slave(point_Y)); // local coordinates of Y on slave
758  arma::vec point_1D_Y(intersec.map_to_master(point_Y)); // local coordinates of Y on master
759 
760  arma::vec point_X(1);
761  point_X.fill(0.0);
762  arma::vec point_2D_X(intersec.map_to_slave(point_X)); // local coordinates of X on slave
763  arma::vec point_1D_X(intersec.map_to_master(point_X)); // local coordinates of X on master
764 
765  arma::mat base_2D(3, 3);
766  // base fce = a0 + a1*t0 + a2*t1
767  // a0 a1 a2
768  base_2D << 1.0 << 0.0 << -2.0 << arma::endr //point on side 0
769  << -1.0 << 2.0 << 2.0 << arma::endr // point on side 1
770  << 1.0 << -2.0 << 0.0 << arma::endr;// point on side 2
771 
772  arma::mat base_1D(2, 2);
773  // base fce = a0 + a1 * t0
774  // a0 a1
775  base_1D << 1.0 << -1.0 << arma::endr // point on side 0,
776  << 0.0 << 1.0 << arma::endr; // point on side 1,
777 
778 
779  arma::vec difference_in_Y(5);
780  arma::vec difference_in_X(5);
781 
782  // slave sides 0,1,2
783  difference_in_Y.subvec(0, 2) = -base_2D * point_2D_Y;
784  difference_in_X.subvec(0, 2) = -base_2D * point_2D_X;
785  // master sides 3,4
786  difference_in_Y.subvec(3, 4) = base_1D * point_1D_Y;
787  difference_in_X.subvec(3, 4) = base_1D * point_1D_X;
788 
789  //prvky matice A[i,j]
790  arma::mat A(5, 5);
791  for (int i = 0; i < 5; ++i) {
792  for (int j = 0; j < 5; ++j) {
793  A(i, j) = -master_sigma * intersec.intersection_true_size() *
794  ( difference_in_Y[i] * difference_in_Y[j]
795  + difference_in_Y[i] * difference_in_X[j]/2
796  + difference_in_X[i] * difference_in_Y[j]/2
797  + difference_in_X[i] * difference_in_X[j]
798  ) * (1.0 / 3.0);
799 
800  }
801  }
802 
803  ls.set_values( dofs, dofs, A, rhs, dirichlet, dirichlet);
804 
805  }
806 }
807 
808 
809 
810 /*******************************************************************************
811  * COMPOSE WATER MH MATRIX WITHOUT SCHUR COMPLEMENT
812  ******************************************************************************/
813 
815 
816  START_TIMER("preallocation");
817 
818  auto in_rec = this->input_record_.val<Input::AbstractRecord>("solver");
819 
820  if (schur0 == NULL) { // create Linear System for MH matrix
821 
822  if (in_rec.type() == LinSys_BDDC::input_type) {
823 #ifdef HAVE_BDDCML
824  xprintf(Warn, "For BDDC is using no Schur complements.");
825  n_schur_compls = 0;
826  LinSys_BDDC *ls = new LinSys_BDDC(global_row_4_sub_row->size(), &(*rows_ds),
827  3, // 3 == la::BddcmlWrapper::SPD_VIA_SYMMETRICGENERAL
828  1, // 1 == number of subdomains per process
829  true); // swap signs of matrix and rhs to make the matrix SPD
830  ls->set_from_input(in_rec);
831  ls->set_solution( NULL );
832  // possible initialization particular to BDDC
833  START_TIMER("BDDC set mesh data");
835  schur0=ls;
836  END_TIMER("BDDC set mesh data");
837 #else
838  xprintf(Err, "Flow123d was not build with BDDCML support.\n");
839 #endif
840  }
841  else if (in_rec.type() == LinSys_PETSC::input_type) {
842  // use PETSC for serial case even when user wants BDDC
843  if (n_schur_compls > 2) {
844  xprintf(Warn, "Invalid number of Schur Complements. Using 2.");
845  n_schur_compls = 2;
846  }
847 
848  LinSys_PETSC *schur1, *schur2;
849 
850  if (n_schur_compls == 0) {
851  LinSys_PETSC *ls = new LinSys_PETSC( &(*rows_ds) );
852 
853  // temporary solution; we have to set precision also for sequantial case of BDDC
854  // final solution should be probably call of direct solver for oneproc case
855  if (in_rec.type() != LinSys_BDDC::input_type) ls->set_from_input(in_rec);
856  else {
857  ls->LinSys::set_from_input(in_rec); // get only common options
858  }
859 
860  ls->set_solution( NULL );
861  schur0=ls;
862  } else {
863  IS is;
864  ISCreateStride(PETSC_COMM_WORLD, side_ds->lsize(), rows_ds->begin(), 1, &is);
865  //ASSERT(err == 0,"Error in ISCreateStride.");
866 
867  SchurComplement *ls = new SchurComplement(is, &(*rows_ds));
868  ls->set_from_input(in_rec);
869  ls->set_solution( NULL );
870  ls->set_positive_definite();
871 
872  // make schur1
873  Distribution *ds = ls->make_complement_distribution();
874  if (n_schur_compls==1) {
875  schur1 = new LinSys_PETSC(ds);
876  } else {
877  IS is;
878  ISCreateStride(PETSC_COMM_WORLD, el_ds->lsize(), ls->get_distribution()->begin(), 1, &is);
879  //ASSERT(err == 0,"Error in ISCreateStride.");
880  SchurComplement *ls1 = new SchurComplement(is, ds); // is is deallocated by SchurComplement
881  ls1->set_negative_definite();
882 
883  // make schur2
884  schur2 = new LinSys_PETSC( ls1->make_complement_distribution() );
885  ls1->set_complement( schur2 );
886  schur1 = ls1;
887  }
888  ls->set_complement( schur1 );
889  schur0=ls;
890  }
891 
892  START_TIMER("PETSC PREALLOCATION");
895  assembly_steady_mh_matrix(); // preallocation
896  VecZeroEntries(schur0->get_solution());
897  END_TIMER("PETSC PREALLOCATION");
898  }
899  else {
900  xprintf(Err, "Unknown solver type. Internal error.\n");
901  }
902  }
903 
904 
905  END_TIMER("preallocation");
906 
908 
909 }
910 
911 
912 
913 
915 
916  data_.set_time(*time_);
917  DBGMSG("Assembly linear system\n");
918  if (data_.changed()) {
919  DBGMSG(" Data changed\n");
920  // currently we have no optimization for cases when just time term data or RHS data are changed
921  START_TIMER("full assembly");
922  if (typeid(*schur0) != typeid(LinSys_BDDC)) {
923  schur0->start_add_assembly(); // finish allocation and create matrix
924  }
927  assembly_steady_mh_matrix(); // fill matrix
930 
931  if (!time_->is_steady()) {
932  DBGMSG(" setup time term\n");
933  // assembly time term and rhs
934  setup_time_term();
935  modify_system();
936  }
937  END_TIMER("full assembly");
938  } else {
939  START_TIMER("modify system");
940  if (!time_->is_steady()) {
941  modify_system();
942  } else {
943  xprintf(PrgErr, "Planned computation time for steady solver, but data are not changed.\n");
944  }
945  END_TIMER("modiffy system");
946  }
947 
948 }
949 
950 
951 
953  // prepare mesh for BDDCML
954  // initialize arrays
955  // auxiliary map for creating coordinates of local dofs and global-to-local numbering
956  std::map<int,arma::vec3> localDofMap;
957  // connectivity for the subdomain, i.e. global dof numbers on element, stored element-by-element
958  // Indices of Nodes on Elements
959  std::vector<int> inet;
960  // number of degrees of freedom on elements - determines elementwise chunks of INET array
961  // Number of Nodes on Elements
962  std::vector<int> nnet;
963  // Indices of Subdomain Elements in Global Numbering - for local elements, their global indices
964  std::vector<int> isegn;
965 
966  // This array is currently not used in BDDCML, it was used as an interface scaling alternative to scaling
967  // by diagonal. It corresponds to the rho-scaling.
968  std::vector<double> element_permeability;
969 
970  // maximal and minimal dimension of elements
971  int elDimMax = 1;
972  int elDimMin = 3;
973  for ( unsigned int i_loc = 0; i_loc < el_ds->lsize(); i_loc++ ) {
974  // for each element, create local numbering of dofs as fluxes (sides), pressure (element centre), Lagrange multipliers (edges), compatible connections
975  ElementFullIter el = mesh_->element(el_4_loc[i_loc]);
976  int e_idx = el.index();
977 
978  int elDim = el->dim();
979  elDimMax = std::max( elDimMax, elDim );
980  elDimMin = std::min( elDimMin, elDim );
981 
982  isegn.push_back( e_idx );
983  int nne = 0;
984 
985  FOR_ELEMENT_SIDES(el,si) {
986  // insert local side dof
987  int side_row = side_row_4_id[ mh_dh.side_dof( el->side(si) ) ];
988  arma::vec3 coord = el->side(si)->centre();
989 
990  localDofMap.insert( std::make_pair( side_row, coord ) );
991  inet.push_back( side_row );
992  nne++;
993  }
994 
995  // insert local pressure dof
996  int el_row = row_4_el[ el_4_loc[i_loc] ];
997  arma::vec3 coord = el->centre();
998  localDofMap.insert( std::make_pair( el_row, coord ) );
999  inet.push_back( el_row );
1000  nne++;
1001 
1002  FOR_ELEMENT_SIDES(el,si) {
1003  // insert local edge dof
1004  int edge_row = row_4_edge[ el->side(si)->edge_idx() ];
1005  arma::vec3 coord = el->side(si)->centre();
1006 
1007  localDofMap.insert( std::make_pair( edge_row, coord ) );
1008  inet.push_back( edge_row );
1009  nne++;
1010  }
1011 
1012  // insert dofs related to compatible connections
1013  for ( unsigned int i_neigh = 0; i_neigh < el->n_neighs_vb; i_neigh++) {
1014  int edge_row = row_4_edge[ el->neigh_vb[i_neigh]->edge_idx() ];
1015  arma::vec3 coord = el->neigh_vb[i_neigh]->edge()->side(0)->centre();
1016 
1017  localDofMap.insert( std::make_pair( edge_row, coord ) );
1018  inet.push_back( edge_row );
1019  nne++;
1020  }
1021 
1022  nnet.push_back( nne );
1023 
1024  // version for rho scaling
1025  // trace computation
1026  arma::vec3 centre = el->centre();
1027  double conduct = data_.conductivity.value( centre , el->element_accessor() );
1028  arma::mat33 aniso = data_.anisotropy.value( centre, el->element_accessor() );
1029 
1030  // compute mean on the diagonal
1031  double coef = 0.;
1032  for ( int i = 0; i < 3; i++) {
1033  coef = coef + aniso.at(i,i);
1034  }
1035  // Maybe divide by cs
1036  coef = conduct*coef / 3;
1037 
1038  ASSERT( coef > 0.,
1039  "Zero coefficient of hydrodynamic resistance %f . \n ", coef );
1040  element_permeability.push_back( 1. / coef );
1041  }
1042  //convert set of dofs to vectors
1043  // number of nodes (= dofs) on the subdomain
1044  int numNodeSub = localDofMap.size();
1045  ASSERT_EQUAL( (unsigned int)numNodeSub, global_row_4_sub_row->size() );
1046  // Indices of Subdomain Nodes in Global Numbering - for local nodes, their global indices
1047  std::vector<int> isngn( numNodeSub );
1048  // pseudo-coordinates of local nodes (i.e. dofs)
1049  // they need not be exact, they are used just for some geometrical considerations in BDDCML,
1050  // such as selection of corners maximizing area of a triangle, bounding boxes fro subdomains to
1051  // find candidate neighbours etc.
1052  std::vector<double> xyz( numNodeSub * 3 ) ;
1053  int ind = 0;
1054  std::map<int,arma::vec3>::iterator itB = localDofMap.begin();
1055  for ( ; itB != localDofMap.end(); ++itB ) {
1056  isngn[ind] = itB -> first;
1057 
1058  arma::vec3 coord = itB -> second;
1059  for ( int j = 0; j < 3; j++ ) {
1060  xyz[ j*numNodeSub + ind ] = coord[j];
1061  }
1062 
1063  ind++;
1064  }
1065  localDofMap.clear();
1066 
1067  // Number of Nodal Degrees of Freedom
1068  // nndf is trivially one - dofs coincide with nodes
1069  std::vector<int> nndf( numNodeSub, 1 );
1070 
1071  // prepare auxiliary map for renumbering nodes
1072  typedef std::map<int,int> Global2LocalMap_; //! type for storage of global to local map
1073  Global2LocalMap_ global2LocalNodeMap;
1074  for ( unsigned ind = 0; ind < isngn.size(); ++ind ) {
1075  global2LocalNodeMap.insert( std::make_pair( static_cast<unsigned>( isngn[ind] ), ind ) );
1076  }
1077 
1078  // renumber nodes in the inet array to locals
1079  int indInet = 0;
1080  for ( unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) {
1081  int nne = nnet[ iEle ];
1082  for ( int ien = 0; ien < nne; ien++ ) {
1083 
1084  int indGlob = inet[indInet];
1085  // map it to local node
1086  Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob );
1087  ASSERT( pos != global2LocalNodeMap.end(),
1088  "Cannot remap node index %d to local indices. \n ", indGlob );
1089  int indLoc = static_cast<int> ( pos -> second );
1090 
1091  // store the node
1092  inet[ indInet++ ] = indLoc;
1093  }
1094  }
1095 
1096  int numNodes = size;
1097  int numDofsInt = size;
1098  int spaceDim = 3; // TODO: what is the proper value here?
1099  int meshDim = elDimMax;
1100 
1101  bddc_ls -> load_mesh( spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim );
1102 }
1103 
1104 
1105 
1106 
1107 //=============================================================================
1108 // DESTROY WATER MH SYSTEM STRUCTURE
1109 //=============================================================================
1111  if (schur0 != NULL) delete schur0;
1112 
1113  delete edge_ds;
1114  delete el_ds;
1115  delete side_ds;
1116 
1117  xfree(el_4_loc);
1118  xfree(row_4_el);
1121  xfree(edge_4_loc);
1122  xfree(row_4_edge);
1123 
1124  if (solution != NULL) {
1125  VecDestroy(&sol_vec);
1126  xfree(solution);
1127  }
1128 
1129  delete output_object;
1130 
1131  VecScatterDestroy(&par_to_all);
1132 }
1133 
1134 
1135 // ================================================
1136 // PARALLLEL PART
1137 //
1138 
1139 // ========================================================================
1140 // to finish row_4_id arrays we have to convert individual numberings of
1141 // sides/els/edges to whole numbering of rows. To this end we count shifts
1142 // for sides/els/edges on each proc and then we apply them on row_4_id
1143 // arrays.
1144 // we employ macros to avoid code redundancy
1145 // =======================================================================
1147  int i, shift;
1148  int np = edge_ds->np();
1149  int edge_shift[np], el_shift[np], side_shift[np];
1150  unsigned int rows_starts[np];
1151 
1152  int edge_n_id = mesh_->n_edges(),
1153  el_n_id = mesh_->element.size(),
1154  side_n_id = mesh_->n_sides();
1155 
1156  // compute shifts on every proc
1157  shift = 0; // in this var. we count new starts of arrays chunks
1158  for (i = 0; i < np; i++) {
1159  side_shift[i] = shift - (side_ds->begin(i)); // subtract actual start of the chunk
1160  shift += side_ds->lsize(i);
1161  el_shift[i] = shift - (el_ds->begin(i));
1162  shift += el_ds->lsize(i);
1163  edge_shift[i] = shift - (edge_ds->begin(i));
1164  shift += edge_ds->lsize(i);
1165  rows_starts[i] = shift;
1166  }
1167  // apply shifts
1168  for (i = 0; i < side_n_id; i++) {
1169  int &what = side_row_4_id[i];
1170  if (what >= 0)
1171  what += side_shift[side_ds->get_proc(what)];
1172  }
1173  for (i = 0; i < el_n_id; i++) {
1174  int &what = row_4_el[i];
1175  if (what >= 0)
1176  what += el_shift[el_ds->get_proc(what)];
1177 
1178  }
1179  for (i = 0; i < edge_n_id; i++) {
1180  int &what = row_4_edge[i];
1181  if (what >= 0)
1182  what += edge_shift[edge_ds->get_proc(what)];
1183  }
1184  // make distribution of rows
1185  for (i = np - 1; i > 0; i--)
1186  rows_starts[i] -= rows_starts[i - 1];
1187 
1188  rows_ds = boost::make_shared<Distribution>(&(rows_starts[0]), PETSC_COMM_WORLD);
1189 }
1190 
1192  START_TIMER("prepare scatter");
1193  // prepare Scatter form parallel to sequantial in original numbering
1194  {
1195  IS is_loc;
1196  int i, *loc_idx; //, si;
1197 
1198  // create local solution vector
1199  solution = (double *) xmalloc(size * sizeof(double));
1200  VecCreateSeqWithArray(PETSC_COMM_SELF,1, size, solution,
1201  &(sol_vec));
1202 
1203  // create seq. IS to scatter par solutin to seq. vec. in original order
1204  // use essentialy row_4_id arrays
1205  loc_idx = (int *) xmalloc(size * sizeof(int));
1206  i = 0;
1207  FOR_ELEMENTS(mesh_, ele) {
1208  FOR_ELEMENT_SIDES(ele,si) {
1209  loc_idx[i++] = side_row_4_id[ mh_dh.side_dof( ele->side(si) ) ];
1210  }
1211  }
1212  FOR_ELEMENTS(mesh_, ele) {
1213  loc_idx[i++] = row_4_el[ele.index()];
1214  }
1215  for(unsigned int i_edg=0; i_edg < mesh_->n_edges(); i_edg++) {
1216  loc_idx[i++] = row_4_edge[i_edg];
1217  }
1218  ASSERT( i==size,"Size of array does not match number of fills.\n");
1219  //DBGPRINT_INT("loc_idx",size,loc_idx);
1220  ISCreateGeneral(PETSC_COMM_SELF, size, loc_idx, PETSC_COPY_VALUES, &(is_loc));
1221  xfree(loc_idx);
1222  VecScatterCreate(schur0->get_solution(), is_loc, sol_vec,
1223  PETSC_NULL, &par_to_all);
1224  ISDestroy(&(is_loc));
1225  }
1227 
1228  END_TIMER("prepare scatter");
1229 
1230 }
1231 
1232 // ====================================================================================
1233 // - compute optimal edge partitioning
1234 // - compute appropriate partitioning of elements and sides
1235 // - make arrays: *_id_4_loc and *_row_4_id to allow parallel assembly of the MH matrix
1236 // ====================================================================================
1238 
1239  START_TIMER("prepare parallel");
1240 
1241  int *loc_part; // optimal (edge,el) partitioning (local chunk)
1242  int *id_4_old; // map from old idx to ids (edge,el)
1243  int i, loc_i;
1244 
1245  int e_idx;
1246 
1247 
1248  //ierr = MPI_Barrier(PETSC_COMM_WORLD);
1249  //ASSERT(ierr == 0, "Error in MPI_Barrier.");
1250 
1251  id_4_old = new int[mesh_->n_elements()];
1252  i = 0;
1253  FOR_ELEMENTS(mesh_, el) id_4_old[i++] = el.index();
1254 
1255  mesh_->get_part()->id_maps(mesh_->element.size(), id_4_old, el_ds, el_4_loc, row_4_el);
1256  delete[] id_4_old;
1257 
1258  //optimal element part; loc. els. id-> new el. numbering
1259  Distribution init_edge_ds(DistributionLocalized(), mesh_->n_edges(), PETSC_COMM_WORLD);
1260  // partitioning of edges, edge belongs to the proc of his first element
1261  // this is not optimal but simple
1262  loc_part = new int[init_edge_ds.lsize()];
1263  id_4_old = new int[mesh_->n_edges()];
1264  {
1265  loc_i = 0;
1266  FOR_EDGES(mesh_, edg ) {
1267  unsigned int i_edg = edg - mesh_->edges.begin();
1268  // partition
1269  e_idx = mesh_->element.index(edg->side(0)->element());
1270  if (init_edge_ds.is_local(i_edg)) {
1271  // find (new) proc of the first element of the edge
1272  loc_part[loc_i++] = el_ds->get_proc(row_4_el[e_idx]);
1273  }
1274  // id array
1275  id_4_old[i_edg] = i_edg;
1276  }
1277  }
1278 
1279  Partitioning::id_maps(mesh_->n_edges(), id_4_old, init_edge_ds, loc_part, edge_ds, edge_4_loc, row_4_edge);
1280  delete[] loc_part;
1281  delete[] id_4_old;
1282 
1283  //optimal side part; loc. sides; id-> new side numbering
1284  Distribution init_side_ds(DistributionBlock(), mesh_->n_sides(), PETSC_COMM_WORLD);
1285  // partitioning of sides follows elements
1286  loc_part = new int[init_side_ds.lsize()];
1287  id_4_old = new int[mesh_->n_sides()];
1288  {
1289  int is = 0;
1290  loc_i = 0;
1291  FOR_SIDES(mesh_, side ) {
1292  // partition
1293  if (init_side_ds.is_local(is)) {
1294  // find (new) proc of the element of the side
1295  loc_part[loc_i++] = el_ds->get_proc(
1297  }
1298  // id array
1299  id_4_old[is++] = mh_dh.side_dof( side );
1300  }
1301  }
1302 
1303  Partitioning::id_maps(mesh_->n_sides(), id_4_old, init_side_ds, loc_part, side_ds,
1305  delete [] loc_part;
1306  delete [] id_4_old;
1307 
1308  // convert row_4_id arrays from separate numberings to global numbering of rows
1310 
1311  // prepare global_row_4_sub_row
1312 
1313 #ifdef HAVE_BDDCML
1314  if (in_rec.type() == LinSys_BDDC::input_type) {
1315  // auxiliary
1316  Element *el;
1317  int side_row, edge_row;
1318 
1319  global_row_4_sub_row = boost::make_shared<LocalToGlobalMap>(rows_ds);
1320 
1321  //
1322  // ordering of dofs
1323  // for each subdomain:
1324  // | velocities (at sides) | pressures (at elements) | L. mult. (at edges) |
1325  for (unsigned int i_loc = 0; i_loc < el_ds->lsize(); i_loc++) {
1326  el = mesh_->element(el_4_loc[i_loc]);
1327  int el_row = row_4_el[el_4_loc[i_loc]];
1328 
1329  global_row_4_sub_row->insert( el_row );
1330 
1331  unsigned int nsides = el->n_sides();
1332  for (unsigned int i = 0; i < nsides; i++) {
1333  side_row = side_row_4_id[ mh_dh.side_dof( el->side(i) ) ];
1334  edge_row = row_4_edge[el->side(i)->edge_idx()];
1335 
1336  global_row_4_sub_row->insert( side_row );
1337  global_row_4_sub_row->insert( edge_row );
1338  }
1339 
1340  for (unsigned int i_neigh = 0; i_neigh < el->n_neighs_vb; i_neigh++) {
1341  // mark this edge
1342  edge_row = row_4_edge[el->neigh_vb[i_neigh]->edge_idx() ];
1343  global_row_4_sub_row->insert( edge_row );
1344  }
1345  }
1346  global_row_4_sub_row->finalize();
1347  }
1348 #endif // HAVE_BDDCML
1349 
1350 }
1351 
1352 
1353 
1354 void mat_count_off_proc_values(Mat m, Vec v) {
1355  int n, first, last;
1356  const PetscInt *cols;
1357  Distribution distr(v);
1358 
1359  int n_off = 0;
1360  int n_on = 0;
1361  int n_off_rows = 0;
1362  MatGetOwnershipRange(m, &first, &last);
1363  for (int row = first; row < last; row++) {
1364  MatGetRow(m, row, &n, &cols, PETSC_NULL);
1365  bool exists_off = false;
1366  for (int i = 0; i < n; i++)
1367  if (distr.get_proc(cols[i]) != distr.myp())
1368  n_off++, exists_off = true;
1369  else
1370  n_on++;
1371  if (exists_off)
1372  n_off_rows++;
1373  MatRestoreRow(m, row, &n, &cols, PETSC_NULL);
1374  }
1375 }
1376 
1377 
1378 
1379 
1380 
1381 
1382 
1383 
1384 
1385 
1386 
1387 
1388 // ========================
1389 // unsteady
1390 
1392  : DarcyFlowMH_Steady(mesh_in, in_rec, false)
1393 {
1394  time_ = new TimeGovernor(in_rec.val<Input::Record>("time"));
1395  data_.mark_input_times(this->mark_type());
1397  data_.set_time(*time_);
1398 
1399  output_object = new DarcyFlowMHOutput(this, in_rec.val<Input::Record>("output"));
1400 
1403 
1404  VecDuplicate(schur0->get_solution(), &previous_solution);
1405  VecCreateMPI(PETSC_COMM_WORLD,rows_ds->lsize(),PETSC_DETERMINE,&(steady_diagonal));
1406  VecDuplicate(steady_diagonal,& new_diagonal);
1407  VecZeroEntries(new_diagonal);
1408  VecDuplicate(*( schur0->get_rhs()), &steady_rhs);
1409 
1412 
1413  output_data();
1414 }
1415 
1417 {
1418 
1419  // read inital condition
1420  VecZeroEntries(schur0->get_solution());
1421 
1422  double *local_sol = schur0->get_solution_array();
1423 
1424  // cycle over local element rows
1426 
1427  DBGMSG("Setup with dt: %f\n",time_->dt());
1428  for (unsigned int i_loc_el = 0; i_loc_el < el_ds->lsize(); i_loc_el++) {
1429  ele = mesh_->element(el_4_loc[i_loc_el]);
1430  int i_loc_row = i_loc_el + side_ds->lsize();
1431 
1432  // set initial condition
1433  local_sol[i_loc_row] = data_.init_pressure.value(ele->centre(),ele->element_accessor());
1434  }
1435 
1437 
1438 }
1439 
1441  // save diagonal of steady matrix
1442  MatGetDiagonal(*( schur0->get_matrix() ), steady_diagonal);
1443  // save RHS
1444  VecCopy(*( schur0->get_rhs()), steady_rhs);
1445 
1446 
1447  PetscScalar *local_diagonal;
1448  VecGetArray(new_diagonal,& local_diagonal);
1449 
1451  DBGMSG("Setup with dt: %f\n",time_->dt());
1452  for (unsigned int i_loc_el = 0; i_loc_el < el_ds->lsize(); i_loc_el++) {
1453  ele = mesh_->element(el_4_loc[i_loc_el]);
1454  int i_loc_row = i_loc_el + side_ds->lsize();
1455 
1456  // set new diagonal
1457  local_diagonal[i_loc_row]= - data_.storativity.value(ele->centre(), ele->element_accessor()) *
1458  ele->measure() / time_->dt();
1459  }
1460  VecRestoreArray(new_diagonal,& local_diagonal);
1461  MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES);
1462 
1465 }
1466 
1468  START_TIMER("modify system");
1469  if (time_->is_changed_dt() && !schur0->is_matrix_changed()) {
1470  // if time step has changed and setup_time_term not called
1471  MatDiagonalSet(*( schur0->get_matrix() ),steady_diagonal, INSERT_VALUES);
1472 
1473  VecScale(new_diagonal, time_->last_dt()/time_->dt());
1474  MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES);
1476  }
1477 
1478  // modify RHS - add previous solution
1479  VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, schur0->get_solution());
1480  VecAXPY(*( schur0->get_rhs()), 1.0, steady_rhs);
1482 
1483  // swap solutions
1484  VecSwap(previous_solution, schur0->get_solution());
1485 }
1486 
1487 // ========================
1488 // unsteady
1489 
1491  : DarcyFlowMH_Steady(mesh_in, in_rec,false)
1492 {
1493  time_ = new TimeGovernor(in_rec.val<Input::Record>("time"));
1494  data_.mark_input_times(this->mark_type());
1495 
1496 
1498  data_.set_time(*time_);
1499 
1500  output_object = new DarcyFlowMHOutput(this, in_rec.val<Input::Record>("output"));
1501 
1504  VecDuplicate(schur0->get_solution(), &previous_solution);
1505  VecCreateMPI(PETSC_COMM_WORLD,rows_ds->lsize(),PETSC_DETERMINE,&(steady_diagonal));
1506  VecDuplicate(steady_diagonal,& new_diagonal);
1507  VecDuplicate(*( schur0->get_rhs()), &steady_rhs);
1508 
1511  output_data();
1512 }
1513 
1515 {
1516  VecZeroEntries(schur0->get_solution());
1517 
1518  // apply initial condition
1519  // cycle over local element rows
1520 
1522  double init_value;
1523 
1524  for (unsigned int i_loc_el = 0; i_loc_el < el_ds->lsize(); i_loc_el++) {
1525  ele = mesh_->element(el_4_loc[i_loc_el]);
1526 
1527  init_value = data_.init_pressure.value(ele->centre(), ele->element_accessor());
1528 
1529  FOR_ELEMENT_SIDES(ele,i) {
1530  int edge_row = row_4_edge[ele->side(i)->edge_idx()];
1531  VecSetValue(schur0->get_solution(),edge_row,init_value/ele->n_sides(),ADD_VALUES);
1532  }
1533  }
1534  VecAssemblyBegin(schur0->get_solution());
1535  VecAssemblyEnd(schur0->get_solution());
1536 
1538 }
1539 
1540 
1541 
1543 {
1544  // save diagonal of steady matrix
1545  MatGetDiagonal(*( schur0->get_matrix() ), steady_diagonal);
1546  // save RHS
1547  VecCopy(*( schur0->get_rhs()),steady_rhs);
1548 
1549  VecZeroEntries(new_diagonal);
1550 
1551  // modify matrix diagonal
1552  // cycle over local element rows
1554 
1555  for (unsigned int i_loc_el = 0; i_loc_el < el_ds->lsize(); i_loc_el++) {
1556  ele = mesh_->element(el_4_loc[i_loc_el]);
1557 
1558  data_.init_pressure.value(ele->centre(), ele->element_accessor());
1559 
1560  FOR_ELEMENT_SIDES(ele,i) {
1561  int edge_row = row_4_edge[ele->side(i)->edge_idx()];
1562  // set new diagonal
1563  VecSetValue(new_diagonal,edge_row, - ele->measure() *
1564  data_.storativity.value(ele->centre(), ele->element_accessor()) *
1565  data_.cross_section.value(ele->centre(), ele->element_accessor()) /
1566  time_->dt() / ele->n_sides(),ADD_VALUES);
1567  }
1568  }
1569  VecAssemblyBegin(new_diagonal);
1570  VecAssemblyEnd(new_diagonal);
1571 
1572  MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES);
1573 
1576 }
1577 
1579  START_TIMER("modify system");
1580  if (time_->is_changed_dt() && !schur0->is_matrix_changed()) {
1581  // if time step has changed and setup_time_term not called
1582 
1583  MatDiagonalSet(*( schur0->get_matrix() ),steady_diagonal, INSERT_VALUES);
1584  VecScale(new_diagonal, time_->last_dt()/time_->dt());
1585  MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES);
1587  }
1588 
1589  // modify RHS - add previous solution
1590  VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, schur0->get_solution());
1591  VecAXPY(*( schur0->get_rhs()), 1.0, steady_rhs);
1593 
1594  // swap solutions
1595  VecSwap(previous_solution, schur0->get_solution());
1596 }
1597 
1598 
1599 
1601  int side_row, loc_edge_row, i;
1602  Edge* edg;
1603  ElementIter ele;
1604  double new_pressure, old_pressure, time_coef;
1605 
1606  PetscScalar *loc_prev_sol;
1607  VecGetArray(previous_solution, &loc_prev_sol);
1608 
1609  // modify side fluxes in parallel
1610  // for every local edge take time term on diagonal and add it to the corresponding flux
1611  for (unsigned int i_loc = 0; i_loc < edge_ds->lsize(); i_loc++) {
1612 
1613  edg = &( mesh_->edges[ edge_4_loc[i_loc] ] );
1614  loc_edge_row = side_ds->lsize() + el_ds->lsize() + i_loc;
1615 
1616  new_pressure = (schur0->get_solution_array())[loc_edge_row];
1617  old_pressure = loc_prev_sol[loc_edge_row];
1618  FOR_EDGE_SIDES(edg,i) {
1619  ele = edg->side(i)->element();
1620  side_row = side_row_4_id[ mh_dh.side_dof( edg->side(i) ) ];
1621  time_coef = - ele->measure() *
1622  data_.cross_section.value(ele->centre(), ele->element_accessor()) *
1623  data_.storativity.value(ele->centre(), ele->element_accessor()) /
1624  time_->dt() / ele->n_sides();
1625  VecSetValue(schur0->get_solution(), side_row, time_coef * (new_pressure - old_pressure), ADD_VALUES);
1626  }
1627  }
1628  VecRestoreArray(previous_solution, &loc_prev_sol);
1629 
1630  VecAssemblyBegin(schur0->get_solution());
1631  VecAssemblyEnd(schur0->get_solution());
1632 
1633  int side_rows[4];
1634  double values[4];
1635 
1636  // modify side fluxes in parallel
1637  // for every local edge take time term on digonal and add it to the corresponding flux
1638 
1639  for (unsigned int i_loc = 0; i_loc < el_ds->lsize(); i_loc++) {
1640  ele = mesh_->element(el_4_loc[i_loc]);
1641  FOR_ELEMENT_SIDES(ele,i) {
1642  side_rows[i] = side_row_4_id[ mh_dh.side_dof( ele->side(i) ) ];
1643  values[i] = -1.0 * ele->measure() *
1644  data_.cross_section.value(ele->centre(), ele->element_accessor()) *
1646  ele->n_sides();
1647  }
1648  VecSetValues(schur0->get_solution(), ele->n_sides(), side_rows, values, ADD_VALUES);
1649  }
1650  VecAssemblyBegin(schur0->get_solution());
1651  VecAssemblyEnd(schur0->get_solution());
1652 }
1653 
1654 //-----------------------------------------------------------------------------
1655 // vim: set cindent:
void set_input_list(Input::Array input_list)
Definition: field_set.hh:164
Class MappingP1 implements the affine transformation of the unit cell onto the actual cell...
unsigned int get_proc(unsigned int idx) const
get processor of the given index
FieldSet * eq_data_
Definition: equation.hh:227
void set_limit_side(LimitSide side)
Definition: field_set.hh:171
#define DBGMSG(...)
Definition: global_defs.h:196
void reinit(Mesh *mesh)
double measure() const
Definition: elements.cc:99
Output class for darcy_flow_mh model.
virtual void postprocess()
postprocess velocity field (add sources)
virtual void get_solution_vector(double *&vec, unsigned int &vec_size)
Accessor to input data conforming to declared Array.
Definition: accessors.hh:521
SchurComplement SchurComplement
Definition: linsys.hh:87
virtual void setup_time_term()
void set_symmetric(bool flag=true)
Definition: linsys.hh:462
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
void make_intersec_elements()
Definition: mesh.cc:602
void id_maps(int n_ids, int *id_4_old, Distribution *&new_ds, int *&id_4_loc, int *&new_4_id)
static Input::Type::Record input_type
#define FOR_EDGE_SIDES(i, j)
Definition: edges.h:53
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:39
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:357
unsigned int edge_idx() const
Definition: side_impl.hh:50
MortarMethod mortar_method_
virtual void start_add_assembly()
Definition: linsys.hh:296
Boundary * cond() const
Definition: side_impl.hh:59
FieldBasePtr(* read_field_descriptor_hook)(Input::Record rec, const FieldCommon &field)
Definition: field.hh:71
double fix_dt_until_mark()
Fixing time step until fixed time mark.
virtual PetscErrorCode mat_zero_entries()
Definition: linsys.hh:238
Wrappers for linear systems based on MPIAIJ and MATIS format.
virtual void rhs_set_values(int nrow, int *rows, double *vals)=0
friend class P1_CouplingAssembler
void mat_count_off_proc_values(Mat m, Vec v)
bool is_end() const
Returns true if the actual time is greater than or equal to the end time.
static Input::Type::Selection mh_mortar_selection
void assembly(LinSys &ls)
void next_time()
Proceed to the next time according to current estimated time step.
bool solution_changed_for_scatter
const arma::vec::fixed< spacedim > normal_vector(unsigned int point_no)
Returns the normal vector to a side at given quadrature point.
Definition: fe_values.cc:196
void set_rhs_changed()
Definition: linsys.hh:201
arma::vec3 centre() const
Definition: sides.cc:135
static Default obligatory()
Definition: type_record.hh:87
???
friend class P0_CouplingAssembler
bool is_matrix_changed()
Definition: linsys.hh:207
#define ELEMENT_FULL_ITER(_mesh_, i)
Definition: mesh.h:365
void assembly(LinSys &ls)
Definition: mesh.h:108
virtual void start_allocation()
Definition: linsys.hh:288
static Input::Type::Record input_type
Class FEValues calculates finite element data on the actual cells such as shape function values...
#define FOR_ELEMENT_SIDES(i, j)
Definition: elements.h:151
boost::shared_ptr< Distribution > rows_ds
Record & derive_from(AbstractRecord &parent)
Definition: type_record.cc:169
int index() const
Definition: sys_vector.hh:88
virtual void finish_assembly()=0
virtual double get_solution_precision()=0
static Input::Type::Record input_type
Definition: linsys_PETSC.hh:46
Definition: edges.h:38
BCField< 3, FieldValue< 3 >::Scalar > bc_flux
void pressure_diff(int i_ele, vector< int > &dofs, unsigned int &ele_type, double &delta, arma::vec &dirichlet)
static Input::Type::Record input_type
void set_from_input(const Input::Record in_rec)
BCField< 3, FieldValue< 3 >::Enum > bc_type
Field< 3, FieldValue< 3 >::Scalar > storativity
Class for declaration of the integral input data.
Definition: type_base.hh:341
#define ADD_FIELD(name,...)
Definition: field_set.hh:260
Basic time management functionality for unsteady (and steady) solvers (class Equation).
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
Partitioning * get_part()
Definition: mesh.cc:162
unsigned int n_sides()
Definition: mesh.cc:151
Definition: system.hh:72
Basic time management class.
Class for declaration of inputs sequences.
Definition: type_base.hh:230
static arma::vec4 gravity_
void view(const char *name="") const
void modify_system() override
Symmetric Gauss-Legendre quadrature formulae on simplices.
BCField< 3, FieldValue< 3 >::Scalar > bc_pressure
bool is_preallocated()
Definition: linsys.hh:510
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
void mat_set_value(int row, int col, double val)
Definition: linsys.hh:324
unsigned int size() const
Returns size of the container. This is independent of the allocated space.
Definition: sys_vector.hh:401
virtual void update_solution()
unsigned int n_elements() const
Definition: mesh.h:137
virtual void get_parallel_solution_vector(Vec &vector)
virtual void modify_system()
#define ASSERT(...)
Definition: global_defs.h:121
Definition: system.hh:72
static FileName input()
Definition: type_base.hh:443
static Input::Type::AbstractRecord input_type
Definition: linsys.hh:90
double * get_solution_array()
Definition: linsys.hh:280
void update(ElementFullIter ele, FieldType &cond_anisothropy, FieldType_Scalar &cross_section, FieldType_Scalar &conductivity)
Definition: mh_fe_values.cc:34
unsigned int edge_idx()
#define ASSERT_EQUAL(a, b)
Definition: global_defs.h:136
Neighbour ** neigh_vb
Definition: elements.h:129
const Vec & get_solution()
Definition: linsys.hh:256
Input::Type::Record type() const
Definition: accessors.cc:228
Definitions of basic Lagrangean finite elements with polynomial shape functions.
Field< 3, FieldValue< 3 >::TensorFixed > anisotropy
unsigned int begin(int proc) const
get starting local index
SideIter side()
Selection & add_value(const int value, const std::string &key, const std::string &description="")
Accessor to the data with type Type::Record.
Definition: accessors.hh:308
FieldCommon & input_selection(const Input::Type::Selection *element_selection)
void modify_system() override
const Ret val(const string &key) const
unsigned int n_sides() const
#define xprintf(...)
Definition: system.hh:100
static std::shared_ptr< FieldAlgorithmBase< 3, FieldValue< 3 >::Scalar > > bc_piezo_head_hook(Input::Record rec, const FieldCommon &field)
const Element * slave_iter() const
bool is_changed_dt() const
#define START_TIMER(tag)
Starts a timer with specified tag.
Class for declaration of polymorphic Record.
Definition: type_record.hh:463
Mesh * mesh_
Definition: equation.hh:218
Element * element()
Definition: boundaries.cc:47
unsigned int index(const T *pointer) const
Definition: sys_vector.hh:383
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm) const
Definition: field.hh:399
void read_init_condition() override
static string flow_old_bcd_file_key()
Definition: old_bcd.hh:53
unsigned int side_dof(const SideIter side) const
SideIter side(const unsigned int loc_index)
Mixed-hybrid model of linear Darcy flow, possibly unsteady.
void mark_input_times(TimeMark::Type mark_type)
Definition: field_set.hh:201
static Input::Type::Record input_type
unsigned int np() const
get num of processors
double solution_precision() const
AbstractRecord & declare_key(const string &key, const KeyType &type, const Default &default_value, const string &description)
Definition: type_record.cc:422
void set_solution(double *sol_array)
Definition: linsys.hh:264
static FieldBaseEnum flow_type_hook(Input::Record rec, const FieldCommon &field)
Definition: old_bcd.hh:81
double measure() const
Definition: sides.cc:42
bool is_steady() const
Returns true if the time governor is used for steady problem.
virtual const Vec * get_rhs()
Definition: linsys.hh:186
void * xmalloc(size_t size)
Memory allocation with checking.
Definition: system.cc:209
void set_time(const TimeGovernor &time)
Definition: field_set.hh:186
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:423
Normal vectors.
virtual PetscErrorCode rhs_zero_entries()
Definition: linsys.hh:247
double * local_matrix()
Definition: mh_fe_values.cc:63
Record & copy_keys(const Record &other)
Definition: type_record.cc:183
unsigned int myp() const
get my processor
Definition: system.hh:72
Support classes for parallel programing.
Field< 3, FieldValue< 3 >::Scalar > conductivity
static Input::Type::AbstractRecord input_type
void set_values(int nrow, int *rows, int ncol, int *cols, PetscScalar *mat_vals, PetscScalar *rhs_vals)
Set values in the system matrix and values in the right-hand side vector on corresponding rows...
Definition: linsys.hh:341
Distribution * el_ds
static Input::Type::Record input_type
Definition: linsys_BDDC.hh:51
Field< 3, FieldValue< 3 >::Scalar > sigma
double intersection_true_size() const
Definition: intersection.cc:90
virtual void postprocess()
postprocess velocity field (add sources)
Input::Record input_record_
Definition: equation.hh:220
auto disable_where(const Field< spacedim, typename FieldValue< spacedim >::Enum > &control_field, const vector< FieldEnum > &value_list) -> Field &
Definition: field.impl.hh:149
MH_DofHandler mh_dh
ElementFullIter element() const
Definition: side_impl.hh:41
boost::shared_ptr< LocalToGlobalMap > global_row_4_sub_row
double dt() const
arma::vec3 centre() const
Definition: elements.cc:130
Definition: system.hh:72
void reinit(ElementFullIter &cell, unsigned int sid)
Update cell-dependent data (gradients, Jacobians etc.)
Definition: fe_values.cc:312
void assembly_steady_mh_matrix()
std::vector< Edge > edges
Vector of MH edges, this should not be part of the geometrical mesh.
Definition: mesh.h:209
friend class DarcyFlowMHOutput
Distributed sparse graphs, partitioning.
FullIter full_iter(Iter it)
Definition: sys_vector.hh:438
Abstract linear system class.
Mixed-hybrid of steady Darcy flow with sources and variable density.
unsigned int n_neighs_vb
Definition: elements.h:127
Definitions of particular quadrature rules on simplices.
BCField< 3, FieldValue< 3 >::Scalar > bc_robin_sigma
#define END_TIMER(tag)
Ends a timer with specified tag.
static Input::Type::Record input_type
TimeMark::Type mark_type()
Definition: equation.hh:179
arma::vec::fixed< spacedim > centre() const
Definition: accessors.hh:81
void set_mesh_data_for_bddc(LinSys_BDDC *bddc_ls)
Definition: system.hh:72
void set_matrix_changed()
Definition: linsys.hh:195
ElementAccessor< 3 > element_accessor() const
Gets ElementAccessor of this element.
Definition: elements.cc:158
mixed-hybrid model of linear Darcy flow, possibly unsteady.
unsigned int el_idx() const
Definition: side_impl.hh:70
void set_mesh(const Mesh &mesh)
Definition: field_set.hh:157
void read_init_condition() override
void add_sides(const Element *ele, unsigned int shift, vector< int > &dofs, vector< double > &dirichlet)
Record type proxy class.
Definition: type_record.hh:161
virtual void output_data() override
Write computed fields.
Field< 3, FieldValue< 3 >::Scalar > cross_section
Distribution * side_ds
virtual void mat_set_values(int nrow, int *rows, int ncol, int *cols, double *vals)=0
Distribution * edge_ds
unsigned int n_edges() const
Definition: mesh.h:145
static Input::Type::Selection bc_type_selection
#define xfree(p)
Definition: system.hh:108
Class for representation SI units of Fields.
Definition: unit_si.hh:31
Field< 3, FieldValue< 3 >::Scalar > init_pressure
virtual const Mat * get_matrix()
Definition: linsys.hh:170
double last_dt() const
DarcyFlowMHOutput * output_object
DarcyFlowMH_Steady(Mesh &mesh, const Input::Record in_rec, bool make_tg=true)
CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL.
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:44
#define FOR_SIDES(_mesh_, it)
Definition: mesh.h:401
static FieldBaseScalar flow_flux_hook(Input::Record rec, const FieldCommon &field)
Definition: old_bcd.hh:99
void set_from_input(const Input::Record in_rec)
Definition: linsys_BDDC.cc:280
EqData()
Collect all fields.
#define FOR_EDGES(_mesh_, __i)
Definition: mesh.h:396
SideIter side(const unsigned int i) const
Definition: edges.h:43
bool changed() const
Definition: field_set.cc:120
Template for classes storing finite set of named values.
virtual int solve()=0
Field< 3, FieldValue< 3 >::Scalar > water_source_density
void prepare_parallel(const Input::AbstractRecord in_rec)
ElementAccessor< 3 > element_accessor()
Definition: boundaries.cc:55
void rhs_set_value(int row, double val)
Definition: linsys.hh:336
static FieldBaseScalar flow_sigma_hook(Input::Record rec, const FieldCommon &field)
Definition: old_bcd.hh:108
Solver based on Multilevel BDDC - using corresponding class of OpenFTL package.
TimeGovernor * time_
Definition: equation.hh:219
ElementVector element
Vector of elements of the mesh.
Definition: mesh.h:198
void output()
Calculate values for output.
Calculates finite element data on a side.
Definition: fe_values.hh:415
unsigned int lsize(int proc) const
get local size
Record & declare_key(const string &key, const KeyType &type, const Default &default_value, const string &description)
Definition: type_record.cc:386