28 #include "petscviewer.h" 29 #include "petscerror.h" 82 .
add_value(
MortarP1,
"P1",
"Mortar space: P1 on intersections, using non-conforming pressures.")
90 "Homogeneous Neumann boundary condition\n(zero normal flux over the boundary).")
92 "Dirichlet boundary condition. " 93 "Specify the pressure head through the ``bc_pressure`` field " 94 "or the piezometric head through the ``bc_piezo_head`` field.")
95 .
add_value(total_flux,
"total_flux",
"Flux boundary condition (combines Neumann and Robin type). " 96 "Water inflow equal to (($ \\delta_d(q_d^N + \\sigma_d (h_d^R - h_d) )$)). " 97 "Specify the water inflow by the ``bc_flux`` field, the transition coefficient by ``bc_robin_sigma`` " 98 "and the reference pressure head or pieozmetric head through ``bc_pressure`` or ``bc_piezo_head`` respectively.")
100 "Seepage face boundary condition. Pressure and inflow bounded from above. Boundary with potential seepage flow " 101 "is described by the pair of inequalities: " 102 "(($h_d \\le h_d^D$)) and (($ -\\boldsymbol q_d\\cdot\\boldsymbol n \\le \\delta q_d^N$)), where the equality holds in at least one of them. " 103 "Caution: setting (($q_d^N$)) strictly negative " 104 "may lead to an ill posed problem since a positive outflow is enforced. " 105 "Parameters (($h_d^D$)) and (($q_d^N$)) are given by the fields ``bc_switch_pressure`` (or ``bc_switch_piezo_head``) and ``bc_flux`` respectively." 108 "River boundary condition. For the water level above the bedrock, (($H_d > H_d^S$)), the Robin boundary condition is used with the inflow given by: " 109 "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d) )$)). For the water level under the bedrock, constant infiltration is used: " 110 "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d^S) )$)). Parameters: ``bc_pressure``, ``bc_switch_pressure``, " 111 " ``bc_sigma``, ``bc_flux``." 122 "Boundary piezometric head for BC types: dirichlet, robin, and river." )
124 "Boundary switch piezometric head for BC types: seepage, river." )
126 "Initial condition for the pressure given as the piezometric head." )
128 return field_descriptor;
135 "Linear solver for MH problem.")
137 "Residual tolerance.")
139 "Minimum number of iterations (linear solutions) to use.\nThis is usefull if the convergence criteria " 140 "does not characterize your goal well enough so it converges prematurely, possibly even without a single linear solution." 141 "If greater then 'max_it' the value is set to 'max_it'.")
143 "Maximum number of iterations (linear solutions) of the non-linear solver.")
145 "If a stagnation of the nonlinear solver is detected the solver stops. " 146 "A divergence is reported by default, forcing the end of the simulation. By setting this flag to 'true', the solver " 147 "ends with convergence success on stagnation, but it reports warning about it.")
150 return it::Record(
"Flow_Darcy_MH",
"Mixed-Hybrid solver for saturated Darcy flow.")
153 "Vector of the gravity force. Dimensionless.")
155 "Input data for Darcy flow model.")
157 "Non-linear solver for MH problem.")
159 "Output stream settings.\n Specify file format, precision etc.")
162 "Specification of output fields and output times.")
164 "Output settings specific to Darcy flow model.\n" 165 "Includes raw output and some experimental functionality.")
167 "Settings for computing mass balance.")
169 "Time governor settings for the unsteady Darcy flow model.")
171 "Number of Schur complements to perform when solving MH system.")
173 "Method for coupling Darcy flow between dimensions on incompatible meshes. [Experimental]" )
179 Input::register_class< DarcyMH, Mesh &, const Input::Record >(
"Flow_Darcy_MH") +
186 *
this += anisotropy.name(
"anisotropy")
187 .description(
"Anisotropy of the conductivity tensor.")
188 .input_default(
"1.0")
191 *
this += cross_section.name(
"cross_section")
192 .description(
"Complement dimension parameter (cross section for 1D, thickness for 2D).")
193 .input_default(
"1.0")
194 .units(
UnitSI().m(3).md() );
196 *
this += conductivity.name(
"conductivity")
197 .description(
"Isotropic conductivity scalar.")
198 .input_default(
"1.0")
199 .units(
UnitSI().m().s(-1) )
202 *
this += sigma.name(
"sigma")
203 .description(
"Transition coefficient between dimensions.")
204 .input_default(
"1.0")
207 *
this += water_source_density.name(
"water_source_density")
208 .description(
"Water source density.")
209 .input_default(
"0.0")
212 *
this += bc_type.name(
"bc_type")
213 .description(
"Boundary condition type.")
214 .input_selection( get_bc_type_selection() )
215 .input_default(
"\"none\"")
219 .disable_where(bc_type, {
none, seepage} )
221 .description(
"Prescribed pressure value on the boundary. Used for all values of ``bc_type`` except ``none`` and ``seepage``. " 222 "See documentation of ``bc_type`` for exact meaning of ``bc_pressure`` in individual boundary condition types.")
223 .input_default(
"0.0")
227 .disable_where(bc_type, {
none, dirichlet} )
229 .description(
"Incoming water boundary flux. Used for bc_types : ``total_flux``, ``seepage``, ``river``.")
230 .input_default(
"0.0")
231 .units(
UnitSI().m().s(-1) );
233 *
this += bc_robin_sigma
234 .disable_where(bc_type, {
none, dirichlet, seepage} )
235 .name(
"bc_robin_sigma")
236 .description(
"Conductivity coefficient in the ``total_flux`` or the ``river`` boundary condition type.")
237 .input_default(
"0.0")
240 *
this += bc_switch_pressure
241 .disable_where(bc_type, {
none, dirichlet, total_flux} )
242 .name(
"bc_switch_pressure")
243 .description(
"Critical switch pressure for ``seepage`` and ``river`` boundary conditions.")
244 .input_default(
"0.0")
249 *
this += init_pressure.name(
"init_pressure")
250 .description(
"Initial condition for pressure in time dependent problems.")
251 .input_default(
"0.0")
254 *
this += storativity.name(
"storativity")
255 .description(
"Storativity (in time dependent problems).")
256 .input_default(
"0.0")
300 data_ = make_shared<EqData>();
333 gravity_array.copy_to(gvec);
335 data_->gravity_ = arma::vec(gvec);
336 data_->gravity_vec_ =
data_->gravity_.subvec(0,2);
338 data_->bc_pressure.add_factory(
340 (
data_->gravity_,
"bc_piezo_head") );
341 data_->bc_switch_pressure.add_factory(
343 (
data_->gravity_,
"bc_switch_piezo_head") );
344 data_->init_pressure.add_factory(
346 (
data_->gravity_,
"init_piezo_head") );
354 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
376 .val<Input::AbstractRecord>(
"linear_solver");
380 data_->system_.local_matrix = std::make_shared<arma::mat>();
426 if (zero_time_term_from_right) {
456 bool jump_time =
data_->storativity.is_jump_time();
457 if (! zero_time_term_from_left) {
467 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
476 if (! zero_time_term_from_left && ! jump_time)
output_data();
482 if (zero_time_term_from_right) {
487 }
else if (! zero_time_term_from_left && jump_time) {
488 WarningOut() <<
"Discontinuous time term not supported yet.\n";
499 return (
data_->storativity.input_list_size() == 0);
513 MessageOut().fmt(
"[nonlin solver] norm of initial residual: {}\n", residual_norm);
516 int is_linear_common;
521 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
522 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
523 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
525 if (! is_linear_common) {
533 while (nonlinear_iteration_ < this->min_n_it_ ||
534 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->max_n_it_ )) {
536 convergence_history.push_back(residual_norm);
539 if (convergence_history.size() >= 5 &&
540 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
541 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
547 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
551 if (! is_linear_common)
557 if (is_linear_common)
break;
576 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it:{} (reason: {}) residual: {}\n",
658 vec_size = this->
size;
659 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
665 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
683 START_TIMER(
"DarcyFlowMH_Steady::assembly_steady_mh_matrix");
690 bool fill_matrix = assembler.size() > 0;
691 int side_row, edge_row, loc_b = 0;
694 int side_rows[4], edge_rows[4];
698 for(
int i=0; i<1000; i++) zeros[i]=0.0;
700 double minus_ones[4] = { -1.0, -1.0, -1.0, -1.0 };
701 double * loc_side_rhs =
data_->system_.loc_side_rhs;
703 arma::mat &local_matrix = *(
data_->system_.local_matrix);
711 unsigned int nsides = ele_ac.n_sides();
712 data_->system_.dirichlet_edge.resize(nsides);
716 for (
unsigned int i = 0; i < nsides; i++) {
724 side_rows[i] = side_row = ele_ac.side_row(i);
725 edge_rows[i] = edge_row = ele_ac.edge_row(i);
734 data_->system_.dirichlet_edge[i] = 0;
740 double cross_section =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
745 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
747 loc_side_rhs[i] -= bc_pressure;
750 data_->system_.dirichlet_edge[i] = 1;
755 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
756 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
757 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
767 double bc_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
768 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
769 double side_flux=bc_flux * bcd->
element()->
measure() * cross_section;
772 if (switch_dirichlet) {
777 unsigned int loc_side_row = ele_ac.side_local_row(i);
780 if ( solution_flux < side_flux) {
782 solution_flux = side_flux;
797 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
800 if ( solution_head > bc_pressure) {
802 solution_head = bc_pressure;
812 loc_side_rhs[i] -= bc_pressure;
815 data_->system_.dirichlet_edge[i] = 1;
827 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
828 double bc_switch_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
829 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
830 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
832 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
845 double bc_total_flux = bc_flux + bc_sigma*(bc_switch_pressure - bc_pressure);
870 assembler[ele_ac.dim()-1]->assembly_local_matrix(ele_ac);
882 for(
unsigned int i=0; i < nsides; i++) {
883 double val_side = local_matrix(i,i);
884 double val_edge = -1./local_matrix(i,i);
886 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( side_rows[i], val_side );
887 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( edge_rows[i], val_edge );
896 ls->
mat_set_values(nsides, side_rows, nsides, side_rows, local_matrix.memptr());
898 int ele_row = ele_ac.ele_row();
909 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ele_row, val_ele );
914 for (
unsigned int i = 0; i < ele_ac.full_iter()->n_neighs_vb; i++) {
917 ngh= ele_ac.full_iter()->neigh_vb[i];
922 assembler[ngh->
side()->
dim()]->assembly_local_vb(local_vb, ele_ac.full_iter(), ngh);
928 int ind = tmp_rows[1];
930 double new_val = local_vb[0];
931 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ind, new_val );
942 tmp_rows[2+i] = tmp_rows[1];
951 n_neigh = ele_ac.full_iter()->n_neighs_vb;
953 OLD_ASSERT(n_neigh*n_neigh<1000,
"Too many values in E block.");
955 ele_ac.full_iter()->n_neighs_vb, tmp_rows+2, zeros);
959 ls->
mat_set_values(1, &ele_row, ele_ac.n_sides(), edge_rows, zeros);
960 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, 1, &ele_row, zeros);
962 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, ele_ac.n_sides(), edge_rows, zeros);
987 double cs =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
990 double source = ele_ac.measure() * cs *
991 data_->water_source_density.value(ele_ac.centre(), ele_ac.element_accessor());
1002 vector<int> &dofs,
unsigned int &ele_type,
double &delta, arma::vec &dirichlet) {
1006 if (i_ele == (
int)(ml_it_->size()) ) {
1012 const Intersection &isect=intersections_[ (*ml_it_)[i_ele] ];
1018 dirichlet.resize(ele->
n_sides());
1021 for(
unsigned int i_side=0; i_side < ele->
n_sides(); i_side++ ) {
1022 dofs[i_side]=darcy_.mh_dh.row_4_edge[ele->
side(i_side)->
edge_idx()];
1030 dofs[i_side] = -dofs[i_side];
1031 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.
centre(), b_ele);
1032 dirichlet[i_side] = bc_pressure;
1043 double delta_i, delta_j;
1045 arma::vec dirichlet_i, dirichlet_j;
1046 unsigned int ele_type_i, ele_type_j;
1051 for(ml_it_ = master_list_.begin(); ml_it_ != master_list_.end(); ++ml_it_) {
1053 if (ml_it_->size() == 0)
continue;
1069 master_ = intersections_[ml_it_->front()].master_iter();
1070 delta_0 = master_->measure();
1072 double master_sigma=darcy_.data_->sigma.value( master_->centre(), master_->element_accessor());
1075 double check_delta_sum=0;
1076 for(i = 0; i <= ml_it_->size(); ++i) {
1077 pressure_diff(i, dofs_i, ele_type_i, delta_i, dirichlet_i);
1078 check_delta_sum+=delta_i;
1080 for (j = 0; j <= ml_it_->size(); ++j) {
1081 pressure_diff(j, dofs_j, ele_type_j, delta_j, dirichlet_j);
1083 double scale = -master_sigma * delta_i * delta_j / delta_0;
1084 product = scale * tensor_average[ele_type_i][ele_type_j];
1086 arma::vec rhs(dofs_i.size());
1088 ls.
set_values( dofs_i, dofs_j, product, rhs, dirichlet_i, dirichlet_j);
1094 OLD_ASSERT(check_delta_sum < 1E-5*delta_0, "sum err %f > 0\n
", check_delta_sum/delta_0); 1095 } // loop over master elements 1100 void P1_CouplingAssembler::add_sides(const Element * ele, unsigned int shift, vector<int> &dofs, vector<double> &dirichlet) 1103 for(unsigned int i_side=0; i_side < ele->n_sides(); i_side++ ) { 1104 dofs[shift+i_side] = darcy_.mh_dh.row_4_edge[ele->side(i_side)->edge_idx()]; 1105 Boundary * bcd = ele->side(i_side)->cond(); 1108 ElementAccessor<3> b_ele = bcd->element_accessor(); 1109 auto type = (DarcyMH::EqData::BC_Type)darcy_.data_->bc_type.value(b_ele.centre(), b_ele); 1110 //DebugOut().fmt("bcd
id: {} sidx: {} type: {}\n
", ele->id(), i_side, type); 1111 if (type == DarcyMH::EqData::dirichlet) { 1112 //DebugOut().fmt("Dirichlet: {}\n
", ele->index()); 1113 dofs[shift + i_side] = -dofs[shift + i_side]; 1114 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.centre(), b_ele); 1115 dirichlet[shift + i_side] = bc_pressure; 1128 void P1_CouplingAssembler::assembly(LinSys &ls) {
1130 for (const Intersection &intersec : intersections_) {
1131 const Element * master = intersec.master_iter();
1132 const Element * slave = intersec.slave_iter();
1134 add_sides(slave, 0, dofs, dirichlet);
1135 add_sides(master, 3, dofs, dirichlet);
1137 double master_sigma=darcy_.data_->sigma.value( master->centre(), master->element_accessor());
1140 * Local coordinates on 1D
1146 * t0 = 0.0 on side 0 node 0
1147 * t0 = 1.0 on side 1 node 1
1149 * Local coordinates on 2D
1156 * t0=0.5, t1=0.0 on side 0 nodes (0,1)
1157 * t0=0.5, t1=0.5 on side 1 nodes (1,2)
1158 * t0=0.0, t1=0.5 on side 2 nodes (2,0)
1163 arma::vec point_Y(1);
1165 arma::vec point_2D_Y(intersec.map_to_slave(point_Y)); // local coordinates of Y on slave (1, t0, t1)
1166 arma::vec point_1D_Y(intersec.map_to_master(point_Y)); // local coordinates of Y on master (1, t0)
1168 arma::vec point_X(1);
1170 arma::vec point_2D_X(intersec.map_to_slave(point_X)); // local coordinates of X on slave (1, t0, t1)
1171 arma::vec point_1D_X(intersec.map_to_master(point_X)); // local coordinates of X on master (1, t0)
1173 arma::mat base_2D(3, 3);
1174 // basis functions are numbered as sides
1176 // Use RT finite element to evaluate following matrices.
1178 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1179 // 2D RT_i(t0, t1) = a0 + a1*t0 + a2*t1
1181 base_2D << 1.0 << 0.0 << -2.0 << arma::endr // RT for side 0
1182 << 1.0 << -2.0 << 0.0 << arma::endr // RT for side 1
1183 << -1.0 << 2.0 << 2.0 << arma::endr;// RT for side 2
1186 arma::mat base_1D(2, 2);
1187 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1188 // 1D RT_i(t0) = a0 + a1 * t0
1190 base_1D << 1.0 << -1.0 << arma::endr // RT for side 0,
1191 << 0.0 << 1.0 << arma::endr; // RT for side 1,
1195 // Consider both 2D and 1D value are defined for the test function
1196 // related to the each of 5 DOFs involved in the intersection.
1197 // One of these values is always zero.
1198 // Compute difference of the 2D and 1D value for every DOF.
1199 // Compute value of this difference in both endpoints X,Y of the intersection.
1201 arma::vec difference_in_Y(5);
1202 arma::vec difference_in_X(5);
1203 // slave sides 0,1,2
1204 difference_in_Y.subvec(0, 2) = -base_2D * point_2D_Y;
1205 difference_in_X.subvec(0, 2) = -base_2D * point_2D_X;
1207 difference_in_Y.subvec(3, 4) = base_1D * point_1D_Y;
1208 difference_in_X.subvec(3, 4) = base_1D * point_1D_X;
1210 // applying the Simpson's rule
1211 // to the product of two linear functions f, g we get
1212 // (b-a)/6 * ( 3*f(a)*g(a) + 3*f(b)*g(b) + 2*f(a)*g(b) + 2*f(b)*g(a) )
1214 for (int i = 0; i < 5; ++i) {
1215 for (int j = 0; j < 5; ++j) {
1216 A(i, j) = -master_sigma * intersec.intersection_true_size() *
1217 ( difference_in_Y[i] * difference_in_Y[j]
1218 + difference_in_Y[i] * difference_in_X[j]/2
1219 + difference_in_X[i] * difference_in_Y[j]/2
1220 + difference_in_X[i] * difference_in_X[j]
1226 ls.set_values( dofs_cp, dofs_cp, A, rhs, dirichlet, dirichlet);
1233 /*******************************************************************************
1234 * COMPOSE WATER MH MATRIX WITHOUT SCHUR COMPLEMENT
1235 ******************************************************************************/
1237 void DarcyMH::create_linear_system(Input::AbstractRecord in_rec) {
1239 START_TIMER("preallocation
"); 1241 if (schur0 == NULL) { // create Linear System for MH matrix 1243 if (in_rec.type() == LinSys_BDDC::get_input_type()) { 1244 #ifdef FLOW123D_HAVE_BDDCML 1245 WarningOut() << "For BDDC no Schur complements are used.
"; 1246 mh_dh.prepare_parallel_bddc(); 1248 LinSys_BDDC *ls = new LinSys_BDDC(mh_dh.global_row_4_sub_row->size(), &(*mh_dh.rows_ds), 1249 3, // 3 == la::BddcmlWrapper::SPD_VIA_SYMMETRICGENERAL 1250 1, // 1 == number of subdomains per process 1251 true); // swap signs of matrix and rhs to make the matrix SPD 1252 ls->set_from_input(in_rec); 1253 ls->set_solution( NULL ); 1254 // possible initialization particular to BDDC 1256 set_mesh_data_for_bddc(ls); 1260 xprintf(Err, "Flow123d was not build with BDDCML support.\n
"); 1261 #endif // FLOW123D_HAVE_BDDCML 1263 else if (in_rec.type() == LinSys_PETSC::get_input_type()) { 1264 // use PETSC for serial case even when user wants BDDC 1265 if (n_schur_compls > 2) { 1266 WarningOut() << "Invalid number of Schur Complements. Using 2.
"; 1270 LinSys_PETSC *schur1, *schur2; 1272 if (n_schur_compls == 0) { 1273 LinSys_PETSC *ls = new LinSys_PETSC( &(*mh_dh.rows_ds) ); 1275 // temporary solution; we have to set precision also for sequantial case of BDDC 1276 // final solution should be probably call of direct solver for oneproc case 1277 if (in_rec.type() != LinSys_BDDC::get_input_type()) ls->set_from_input(in_rec); 1279 ls->LinSys::set_from_input(in_rec); // get only common options 1282 ls->set_solution( NULL ); 1286 ISCreateStride(PETSC_COMM_WORLD, mh_dh.side_ds->lsize(), mh_dh.rows_ds->begin(), 1, &is); 1287 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1289 SchurComplement *ls = new SchurComplement(is, &(*mh_dh.rows_ds)); 1292 Distribution *ds = ls->make_complement_distribution(); 1293 if (n_schur_compls==1) { 1294 schur1 = new LinSys_PETSC(ds); 1295 schur1->set_positive_definite(); 1298 ISCreateStride(PETSC_COMM_WORLD, mh_dh.el_ds->lsize(), ls->get_distribution()->begin(), 1, &is); 1299 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1300 SchurComplement *ls1 = new SchurComplement(is, ds); // is is deallocated by SchurComplement 1301 ls1->set_negative_definite(); 1304 schur2 = new LinSys_PETSC( ls1->make_complement_distribution() ); 1305 schur2->set_positive_definite(); 1306 ls1->set_complement( schur2 ); 1309 ls->set_complement( schur1 ); 1310 ls->set_from_input(in_rec); 1311 ls->set_solution( NULL ); 1315 START_TIMER("PETSC PREALLOCATION
"); 1316 schur0->set_symmetric(); 1317 schur0->start_allocation(); 1318 assembly_mh_matrix(MultidimAssembler()); // preallocation 1319 VecZeroEntries(schur0->get_solution()); 1320 END_TIMER("PETSC PREALLOCATION
"); 1323 xprintf(Err, "Unknown solver type. Internal error.\n
"); 1326 END_TIMER("preallocation
"); 1327 make_serial_scatter(); 1336 void DarcyMH::assembly_linear_system() { 1337 START_TIMER("DarcyFlowMH_Steady::assembly_linear_system
"); 1340 bool is_steady = zero_time_term(); 1341 //DebugOut() << "Assembly linear system\n
"; 1342 if (data_changed_) { 1343 data_changed_ = false; 1344 //DebugOut() << "Data changed\n
"; 1345 // currently we have no optimization for cases when just time term data or RHS data are changed 1346 START_TIMER("full assembly
"); 1347 if (typeid(*schur0) != typeid(LinSys_BDDC)) { 1348 schur0->start_add_assembly(); // finish allocation and create matrix 1351 auto multidim_assembler = AssemblyBase::create< AssemblyMH >(data_); 1353 schur0->mat_zero_entries(); 1354 schur0->rhs_zero_entries(); 1356 assembly_source_term(); 1357 assembly_mh_matrix( multidim_assembler ); // fill matrix 1359 schur0->finish_assembly(); 1360 schur0->set_matrix_changed(); 1361 //MatView( *const_cast<Mat*>(schur0->get_matrix()), PETSC_VIEWER_STDOUT_WORLD ); 1362 //VecView( *const_cast<Vec*>(schur0->get_rhs()), PETSC_VIEWER_STDOUT_WORLD); 1365 START_TIMER("fix
time term
"); 1366 //DebugOut() << "setup
time term\n
"; 1367 // assembly time term and rhs 1373 balance_->start_mass_assembly(water_balance_idx_); 1374 balance_->finish_mass_assembly(water_balance_idx_); 1376 END_TIMER("full assembly
"); 1378 START_TIMER("modify system
"); 1382 //xprintf(PrgErr, "Planned computation
time for steady solver, but
data are not changed.\n
"); 1384 END_TIMER("modiffy system
"); 1391 void DarcyMH::set_mesh_data_for_bddc(LinSys_BDDC * bddc_ls) { 1392 START_TIMER("DarcyFlowMH_Steady::set_mesh_data_for_bddc
"); 1393 // prepare mesh for BDDCML 1394 // initialize arrays 1395 // auxiliary map for creating coordinates of local dofs and global-to-local numbering 1396 std::map<int,arma::vec3> localDofMap; 1397 // connectivity for the subdomain, i.e. global dof numbers on element, stored element-by-element 1398 // Indices of Nodes on Elements 1399 std::vector<int> inet; 1400 // number of degrees of freedom on elements - determines elementwise chunks of INET array 1401 // Number of Nodes on Elements 1402 std::vector<int> nnet; 1403 // Indices of Subdomain Elements in Global Numbering - for local elements, their global indices 1404 std::vector<int> isegn; 1406 // This array is currently not used in BDDCML, it was used as an interface scaling alternative to scaling 1407 // by diagonal. It corresponds to the rho-scaling. 1408 std::vector<double> element_permeability; 1410 // maximal and minimal dimension of elements 1413 for ( unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++ ) { 1414 auto ele_ac = mh_dh.accessor(i_loc); 1415 // for each element, create local numbering of dofs as fluxes (sides), pressure (element centre), Lagrange multipliers (edges), compatible connections 1417 elDimMax = std::max( elDimMax, ele_ac.dim() ); 1418 elDimMin = std::min( elDimMin, ele_ac.dim() ); 1420 isegn.push_back( ele_ac.ele_global_idx() ); 1423 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1424 // insert local side dof 1425 int side_row = ele_ac.side_row(si); 1426 arma::vec3 coord = ele_ac.side(si)->centre(); 1428 localDofMap.insert( std::make_pair( side_row, coord ) ); 1429 inet.push_back( side_row ); 1433 // insert local pressure dof 1434 int el_row = ele_ac.ele_row(); 1435 arma::vec3 coord = ele_ac.centre(); 1436 localDofMap.insert( std::make_pair( el_row, coord ) ); 1437 inet.push_back( el_row ); 1440 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1441 // insert local edge dof 1442 int edge_row = ele_ac.edge_row(si); 1443 arma::vec3 coord = ele_ac.side(si)->centre(); 1445 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1446 inet.push_back( edge_row ); 1450 // insert dofs related to compatible connections 1451 for ( unsigned int i_neigh = 0; i_neigh < ele_ac.full_iter()->n_neighs_vb; i_neigh++) { 1452 int edge_row = mh_dh.row_4_edge[ ele_ac.full_iter()->neigh_vb[i_neigh]->edge_idx() ]; 1453 arma::vec3 coord = ele_ac.full_iter()->neigh_vb[i_neigh]->edge()->side(0)->centre(); 1455 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1456 inet.push_back( edge_row ); 1460 nnet.push_back( nne ); 1462 // version for rho scaling 1463 // trace computation 1464 arma::vec3 centre = ele_ac.centre(); 1465 double conduct = data_->conductivity.value( centre , ele_ac.element_accessor() ); 1466 auto aniso = data_->anisotropy.value( centre, ele_ac.element_accessor() ); 1468 // compute mean on the diagonal 1470 for ( int i = 0; i < 3; i++) { 1471 coef = coef + aniso.at(i,i); 1473 // Maybe divide by cs 1474 coef = conduct*coef / 3; 1476 OLD_ASSERT( coef > 0., 1477 "Zero coefficient of hydrodynamic resistance %f . \n
", coef ); 1478 element_permeability.push_back( 1. / coef ); 1480 //convert set of dofs to vectors 1481 // number of nodes (= dofs) on the subdomain 1482 int numNodeSub = localDofMap.size(); 1483 OLD_ASSERT_EQUAL( (unsigned int)numNodeSub, mh_dh.global_row_4_sub_row->size() ); 1484 // Indices of Subdomain Nodes in Global Numbering - for local nodes, their global indices 1485 std::vector<int> isngn( numNodeSub ); 1486 // pseudo-coordinates of local nodes (i.e. dofs) 1487 // they need not be exact, they are used just for some geometrical considerations in BDDCML, 1488 // such as selection of corners maximizing area of a triangle, bounding boxes fro subdomains to 1489 // find candidate neighbours etc. 1490 std::vector<double> xyz( numNodeSub * 3 ) ; 1492 std::map<int,arma::vec3>::iterator itB = localDofMap.begin(); 1493 for ( ; itB != localDofMap.end(); ++itB ) { 1494 isngn[ind] = itB -> first; 1496 arma::vec3 coord = itB -> second; 1497 for ( int j = 0; j < 3; j++ ) { 1498 xyz[ j*numNodeSub + ind ] = coord[j]; 1503 localDofMap.clear(); 1505 // Number of Nodal Degrees of Freedom 1506 // nndf is trivially one - dofs coincide with nodes 1507 std::vector<int> nndf( numNodeSub, 1 ); 1509 // prepare auxiliary map for renumbering nodes 1510 typedef std::map<int,int> Global2LocalMap_; //! type for storage of global to local map 1511 Global2LocalMap_ global2LocalNodeMap; 1512 for ( unsigned ind = 0; ind < isngn.size(); ++ind ) { 1513 global2LocalNodeMap.insert( std::make_pair( static_cast<unsigned>( isngn[ind] ), ind ) ); 1516 // renumber nodes in the inet array to locals 1518 for ( unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) { 1519 int nne = nnet[ iEle ]; 1520 for ( int ien = 0; ien < nne; ien++ ) { 1522 int indGlob = inet[indInet]; 1523 // map it to local node 1524 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob ); 1525 OLD_ASSERT( pos != global2LocalNodeMap.end(), 1526 "Cannot remap node index %d to local indices. \n
", indGlob ); 1527 int indLoc = static_cast<int> ( pos -> second ); 1530 inet[ indInet++ ] = indLoc; 1534 int numNodes = size; 1535 int numDofsInt = size; 1536 int spaceDim = 3; // TODO: what is the proper value here? 1537 int meshDim = elDimMax; 1539 bddc_ls -> load_mesh( spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim ); 1545 //============================================================================= 1546 // DESTROY WATER MH SYSTEM STRUCTURE 1547 //============================================================================= 1548 DarcyMH::~DarcyMH() { 1549 if (schur0 != NULL) { 1551 VecScatterDestroy(&par_to_all); 1554 if (solution != NULL) { 1555 chkerr(VecDestroy(&sol_vec)); 1559 if (output_object) delete output_object; 1566 // ================================================ 1571 void DarcyMH::make_serial_scatter() { 1572 START_TIMER("prepare scatter
"); 1573 // prepare Scatter form parallel to sequantial in original numbering 1576 int i, *loc_idx; //, si; 1578 // create local solution vector 1579 solution = new double[size]; 1580 VecCreateSeqWithArray(PETSC_COMM_SELF,1, size, solution, 1583 // create seq. IS to scatter par solutin to seq. vec. in original order 1584 // use essentialy row_4_id arrays 1585 loc_idx = new int [size]; 1587 FOR_ELEMENTS(mesh_, ele) { 1588 FOR_ELEMENT_SIDES(ele,si) { 1589 loc_idx[i++] = mh_dh.side_row_4_id[ mh_dh.side_dof( ele->side(si) ) ]; 1592 FOR_ELEMENTS(mesh_, ele) { 1593 loc_idx[i++] = mh_dh.row_4_el[ele.index()]; 1595 for(unsigned int i_edg=0; i_edg < mesh_->n_edges(); i_edg++) { 1596 loc_idx[i++] = mh_dh.row_4_edge[i_edg]; 1598 OLD_ASSERT( i==size,"Size of array does not match number of fills.\n
"); 1599 //DBGPRINT_INT("loc_idx
",size,loc_idx); 1600 ISCreateGeneral(PETSC_COMM_SELF, size, loc_idx, PETSC_COPY_VALUES, &(is_loc)); 1602 VecScatterCreate(schur0->get_solution(), is_loc, sol_vec, 1603 PETSC_NULL, &par_to_all); 1604 ISDestroy(&(is_loc)); 1606 solution_changed_for_scatter=true; 1608 END_TIMER("prepare scatter
"); 1614 void mat_count_off_proc_values(Mat m, Vec v) { 1616 const PetscInt *cols; 1617 Distribution distr(v); 1622 MatGetOwnershipRange(m, &first, &last); 1623 for (int row = first; row < last; row++) { 1624 MatGetRow(m, row, &n, &cols, PETSC_NULL); 1625 bool exists_off = false; 1626 for (int i = 0; i < n; i++) 1627 if (distr.get_proc(cols[i]) != distr.myp()) 1628 n_off++, exists_off = true; 1633 MatRestoreRow(m, row, &n, &cols, PETSC_NULL); 1649 void DarcyMH::read_initial_condition() 1651 double *local_sol = schur0->get_solution_array(); 1653 // cycle over local element rows 1655 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1656 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1657 auto ele_ac = mh_dh.accessor(i_loc_el); 1658 // set initial condition 1659 local_sol[ele_ac.ele_local_row()] = data_->init_pressure.value(ele_ac.centre(),ele_ac.element_accessor()); 1662 solution_changed_for_scatter=true; 1666 void DarcyMH::setup_time_term() { 1667 // save diagonal of steady matrix 1668 MatGetDiagonal(*( schur0->get_matrix() ), steady_diagonal); 1670 VecCopy(*( schur0->get_rhs()), steady_rhs); 1673 PetscScalar *local_diagonal; 1674 VecGetArray(new_diagonal,& local_diagonal); 1676 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1678 balance_->start_mass_assembly(water_balance_idx_); 1680 //DebugOut().fmt("time_term lsize: {} {}\n
", mh_dh.el_ds->myp(), mh_dh.el_ds->lsize()); 1681 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1682 auto ele_ac = mh_dh.accessor(i_loc_el); 1685 double diagonal_coeff = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor()) 1686 * data_->storativity.value(ele_ac.centre(), ele_ac.element_accessor()) 1688 local_diagonal[ele_ac.ele_local_row()]= - diagonal_coeff / time_->dt(); 1690 //DebugOut().fmt("time_term: {} {} {} {} {}\n
", mh_dh.el_ds->myp(), ele_ac.ele_global_idx(), i_loc_row, i_loc_el + mh_dh.side_ds->lsize(), diagonal_coeff); 1691 balance_->add_mass_matrix_values(water_balance_idx_, 1692 ele_ac.region().bulk_idx(), { int(ele_ac.ele_row()) }, {diagonal_coeff}); 1694 VecRestoreArray(new_diagonal,& local_diagonal); 1695 MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES); 1697 solution_changed_for_scatter=true; 1698 schur0->set_matrix_changed(); 1700 balance_->finish_mass_assembly(water_balance_idx_); 1703 void DarcyMH::modify_system() { 1704 START_TIMER("modify system
"); 1705 if (time_->is_changed_dt() && time_->step().index()>0) { 1706 double scale_factor=time_->step(-2).length()/time_->step().length(); 1707 if (scale_factor != 1.0) { 1708 // if time step has changed and setup_time_term not called 1709 MatDiagonalSet(*( schur0->get_matrix() ),steady_diagonal, INSERT_VALUES); 1711 VecScale(new_diagonal, time_->last_dt()/time_->dt()); 1712 MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES); 1713 schur0->set_matrix_changed(); 1717 // modify RHS - add previous solution 1718 //VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, previous_solution); 1719 VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, schur0->get_solution()); 1720 VecAXPY(*( schur0->get_rhs()), 1.0, steady_rhs); 1721 schur0->set_rhs_changed(); 1723 //VecSwap(previous_solution, schur0->get_solution()); 1727 //----------------------------------------------------------------------------- 1728 // vim: set cindent:
void get_solution_vector(double *&vec, unsigned int &vec_size) override
static const Input::Type::Record & get_input_type()
Main balance input record type.
Output class for darcy_flow_mh model.
void assembly_mh_matrix(MultidimAssembler ma)
virtual void initialize_specific()
void get_parallel_solution_vector(Vec &vector) override
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
void make_intersec_elements()
static const Input::Type::Record & get_input_type()
The specification of output stream.
unsigned int edge_idx() const
virtual void assembly_source_term()
Source term is implemented differently in LMH version.
friend class DarcyFlowMHOutput
#define MessageOut()
Macro defining 'message' record of log.
virtual void output_data() override
Write computed fields.
Wrappers for linear systems based on MPIAIJ and MATIS format.
virtual void rhs_set_values(int nrow, int *rows, double *vals)=0
bool is_end() const
Returns true if the actual time is greater than or equal to the end time.
void assembly(LinSys &ls)
void next_time()
Proceed to the next time according to current estimated time step.
static const int registrar
Registrar of class to factory.
static const Input::Type::Selection & get_mh_mortar_selection()
Selection for enum MortarMethod.
void initialize() override
RegionSet get_region_set(const string &set_name) const
std::vector< char > bc_switch_dirichlet
Idicator of dirichlet or neumann type of switch boundary conditions.
static const Input::Type::Record & type_field_descriptor()
virtual double get_solution_precision()=0
const RegionDB & region_db() const
void pressure_diff(int i_ele, vector< int > &dofs, unsigned int &ele_type, double &delta, arma::vec &dirichlet)
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
const TimeStep & step(int index=-1) const
static const std::string field_descriptor_record_description(const string &record_name)
Basic time management functionality for unsteady (and steady) solvers (class Equation).
bool solution_changed_for_scatter
void solve_nonlinear()
Solve method common to zero_time_step and update solution.
std::shared_ptr< EqData > data_
Basic time management class.
virtual void set_tolerances(double r_tol, double a_tol, unsigned int max_it)=0
void view(const char *name="") const
MortarMethod mortar_method_
friend class P0_CouplingAssembler
unsigned int nonlinear_iteration_
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
void mat_set_value(int row, int col, double val)
void update_solution() override
unsigned int size() const
Returns size of the container. This is independent of the allocated space.
unsigned int n_elements() const
virtual void postprocess()
double * get_solution_array()
std::shared_ptr< Balance > balance_
FLOW123D_FORCE_LINK_IN_CHILD(darcy_flow_mh)
const Vec & get_solution()
unsigned int n_sides() const
const Element * slave_iter() const
#define START_TIMER(tag)
Starts a timer with specified tag.
static const Input::Type::Instance & get_input_type()
static Input::Type::Abstract & get_input_type()
ElementVector bc_elements
SideIter side(const unsigned int loc_index)
bool use_steady_assembly_
static const Input::Type::Record & get_input_type_specific()
static const Input::Type::Selection & get_bc_type_selection()
Return a Selection corresponding to enum BC_Type.
virtual void assembly_linear_system()
DarcyMH(Mesh &mesh, const Input::Record in_rec)
CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL.
Support classes for parallel programing.
#define MPI_Allreduce(sendbuf, recvbuf, count, datatype, op, comm)
int set_upper_constraint(double upper, std::string message)
Sets upper constraint for the next time step estimating.
void set_values(int nrow, int *rows, int ncol, int *cols, PetscScalar *mat_vals, PetscScalar *rhs_vals)
Set values in the system matrix and values in the right-hand side vector on corresponding rows...
void create_linear_system(Input::AbstractRecord rec)
Initialize global_row_4_sub_row.
MortarMethod
Type of experimental Mortar-like method for non-compatible 1d-2d interaction.
double intersection_true_size() const
Input::Record input_record_
std::shared_ptr< Distribution > rows_ds
LocalElementAccessorBase< 3 > accessor(uint local_ele_idx)
unsigned int water_balance_idx_
index of water balance within the Balance object.
Abstract linear system class.
static const Input::Type::Record & get_input_type()
#define WarningOut()
Macro defining 'warning' record of log.
arma::vec::fixed< spacedim > centre() const
#define OLD_ASSERT_EQUAL(a, b)
EqData()
Creation of all fields.
mixed-hybrid model of linear Darcy flow, possibly unsteady.
void zero_time_step() override
virtual void read_initial_condition()
static Input::Type::Abstract & get_input_type()
virtual void mat_set_values(int nrow, int *rows, int ncol, int *cols, double *vals)=0
DarcyFlowMHOutput * output_object
unsigned int n_edges() const
virtual void prepare_new_time_step()
postprocess velocity field (add sources)
Class for representation SI units of Fields.
virtual double solution_precision() const
static UnitSI & dimensionless()
Returns dimensionless unit.
virtual double compute_residual()=0
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
friend class P1_CouplingAssembler
ElementAccessor< 3 > element_accessor()
void rhs_set_value(int row, double val)
static const Input::Type::Record & get_input_type()
Solver based on Multilevel BDDC - using corresponding class of OpenFTL package.
virtual bool zero_time_term(bool time_global=false)
void output()
Calculate values for output.
unsigned int lsize(int proc) const
get local size