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. Zero flux")
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 (($q^N + \\sigma (h^R - h)$)). " 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 \\le h_d^D$)) and (($ q \\le 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 fields ``bc_pressure`` (or ``bc_piezo_head``) and ``bc_flux`` respectively." 108 "River boundary condition. For the water level above the bedrock, (($H > H^S$)), the Robin boundary condition is used with the inflow given by: " 109 "(( $q^N + \\sigma(H^D - H)$)). For the water level under the bedrock, constant infiltration is used " 110 "(( $q^N + \\sigma(H^D - H^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 solves) to use. This is usefull if the convergence criteria " 140 "does not characterize your goal well enough so it converges prematurely possibly without the single linear solve." 141 "If greater then 'max_it' the value is set to 'max_it'.")
143 "Maximum number of iterations (linear solves) 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. Setting this flag to 'true', the solver" 147 "ends with convergence success on stagnation, but report warning about it.")
150 return it::Record(
"Flow_Darcy_MH",
"Mixed-Hybrid solver for STEADY 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 "Parameters of output stream.")
162 "Parameters of output from MH module.")
164 "Parameters of output form MH module.")
166 "Settings for computing mass balance.")
168 "Time governor setting for the unsteady Darcy flow model.")
170 "Number of Schur complements to perform when solving MH system.")
172 "Method for coupling Darcy flow between dimensions." )
178 Input::register_class< DarcyMH, Mesh &, const Input::Record >(
"Flow_Darcy_MH") +
185 ADD_FIELD(anisotropy,
"Anisotropy of the conductivity tensor.",
"1.0" );
188 ADD_FIELD(cross_section,
"Complement dimension parameter (cross section for 1D, thickness for 2D).",
"1.0" );
189 cross_section.units(
UnitSI().m(3).md() );
191 ADD_FIELD(conductivity,
"Isotropic conductivity scalar.",
"1.0" );
192 conductivity.units(
UnitSI().m().s(-1) ).set_limits(0.0);
194 ADD_FIELD(sigma,
"Transition coefficient between dimensions.",
"1.0");
197 ADD_FIELD(water_source_density,
"Water source density.",
"0.0");
198 water_source_density.units(
UnitSI().s(-1) );
200 ADD_FIELD(bc_type,
"Boundary condition type, possible values:",
"\"none\"" );
202 bc_type.input_selection( get_bc_type_selection() );
205 ADD_FIELD(bc_pressure,
"Prescribed pressure value on the boundary. Used for all values of 'bc_type' save the bc_type='none'." 206 "See documentation of 'bc_type' for exact meaning of 'bc_pressure' in individual boundary condition types.",
"0.0");
207 bc_pressure.disable_where(bc_type, {
none} );
208 bc_pressure.units(
UnitSI().m() );
210 ADD_FIELD(bc_flux,
"Incoming water boundary flux. Used for bc_types : 'none', 'total_flux', 'seepage', 'river'.",
"0.0");
211 bc_flux.disable_where(bc_type, {
none, dirichlet} );
212 bc_flux.units(
UnitSI().m(4).s(-1).md() );
214 ADD_FIELD(bc_robin_sigma,
"Conductivity coefficient in the 'total_flux' or the 'river' boundary condition type.",
"0.0");
215 bc_robin_sigma.disable_where(bc_type, {
none, dirichlet, seepage} );
216 bc_robin_sigma.units(
UnitSI().m(3).s(-1).md() );
219 "Critical switch pressure for 'seepage' and 'river' boundary conditions.",
"0.0");
220 bc_switch_pressure.disable_where(bc_type, {
none, dirichlet, total_flux} );
221 bc_switch_pressure.units(
UnitSI().m() );
224 ADD_FIELD(init_pressure,
"Initial condition as pressure",
"0.0" );
225 init_pressure.units(
UnitSI().m() );
227 ADD_FIELD(storativity,
"Storativity.",
"0.0" );
228 storativity.units(
UnitSI().m(-1) );
272 data_ = make_shared<EqData>();
305 gravity_array.copy_to(gvec);
307 data_->gravity_ = arma::vec(gvec);
308 data_->gravity_vec_ =
data_->gravity_.subvec(0,2);
310 data_->bc_pressure.add_factory(
312 (
data_->gravity_,
"bc_piezo_head") );
313 data_->bc_switch_pressure.add_factory(
315 (
data_->gravity_,
"bc_switch_piezo_head") );
316 data_->init_pressure.add_factory(
318 (
data_->gravity_,
"init_piezo_head") );
326 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
348 .val<Input::AbstractRecord>(
"linear_solver");
352 data_->system_.local_matrix = std::make_shared<arma::mat>();
401 if (zero_time_term_from_right) {
431 bool jump_time =
data_->storativity.is_jump_time();
432 if (! zero_time_term_from_left) {
442 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
451 if (! zero_time_term_from_left && ! jump_time)
output_data();
457 if (zero_time_term_from_right) {
462 }
else if (! zero_time_term_from_left && jump_time) {
463 WarningOut() <<
"Discontinuous time term not supported yet.\n";
474 return (
data_->storativity.input_list_size() == 0);
488 MessageOut().fmt(
"[nonlin solver] norm of initial residual: {}\n", residual_norm);
491 int is_linear_common;
496 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
497 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
498 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
500 if (! is_linear_common) {
508 while (nonlinear_iteration_ < this->min_n_it_ ||
509 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->max_n_it_ )) {
511 convergence_history.push_back(residual_norm);
514 if (convergence_history.size() >= 5 &&
515 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
516 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
522 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
526 if (! is_linear_common)
532 if (is_linear_common)
break;
551 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it:{} (reason: {}) residual: {}\n",
646 vec_size = this->
size;
647 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
653 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
671 START_TIMER(
"DarcyFlowMH_Steady::assembly_steady_mh_matrix");
678 bool fill_matrix = assembler.size() > 0;
679 int side_row, edge_row, loc_b = 0;
682 int side_rows[4], edge_rows[4];
686 for(
int i=0; i<1000; i++) zeros[i]=0.0;
688 double minus_ones[4] = { -1.0, -1.0, -1.0, -1.0 };
689 double * loc_side_rhs =
data_->system_.loc_side_rhs;
691 arma::mat &local_matrix = *(
data_->system_.local_matrix);
694 if (
balance_ !=
nullptr && fill_matrix)
699 unsigned int nsides = ele_ac.n_sides();
700 data_->system_.dirichlet_edge.resize(nsides);
704 for (
unsigned int i = 0; i < nsides; i++) {
712 side_rows[i] = side_row = ele_ac.side_row(i);
713 edge_rows[i] = edge_row = ele_ac.edge_row(i);
722 data_->system_.dirichlet_edge[i] = 0;
728 double cross_section =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
733 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
735 loc_side_rhs[i] -= bc_pressure;
738 data_->system_.dirichlet_edge[i] = 1;
743 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
744 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
745 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
755 double bc_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
756 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
757 double side_flux=bc_flux * bcd->
element()->
measure() * cross_section;
760 if (switch_dirichlet) {
765 unsigned int loc_side_row = ele_ac.side_local_row(i);
768 if ( solution_flux < side_flux) {
770 solution_flux = side_flux;
785 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
788 if ( solution_head > bc_pressure) {
790 solution_head = bc_pressure;
800 loc_side_rhs[i] -= bc_pressure;
803 data_->system_.dirichlet_edge[i] = 1;
815 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
816 double bc_switch_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
817 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
818 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
820 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
833 double bc_total_flux = bc_flux + bc_sigma*(bc_switch_pressure - bc_pressure);
840 if (
balance_ !=
nullptr && fill_matrix)
858 assembler[ele_ac.dim()-1]->assembly_local_matrix(ele_ac);
870 for(
unsigned int i=0; i < nsides; i++) {
871 double val_side = local_matrix(i,i);
872 double val_edge = -1./local_matrix(i,i);
874 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( side_rows[i], val_side );
875 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( edge_rows[i], val_edge );
884 ls->
mat_set_values(nsides, side_rows, nsides, side_rows, local_matrix.memptr());
886 int ele_row = ele_ac.ele_row();
897 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ele_row, val_ele );
902 for (
unsigned int i = 0; i < ele_ac.full_iter()->n_neighs_vb; i++) {
905 ngh= ele_ac.full_iter()->neigh_vb[i];
910 assembler[ngh->
side()->
dim()]->assembly_local_vb(local_vb, ele_ac.full_iter(), ngh);
916 int ind = tmp_rows[1];
918 double new_val = local_vb[0];
919 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ind, new_val );
930 tmp_rows[2+i] = tmp_rows[1];
939 n_neigh = ele_ac.full_iter()->n_neighs_vb;
941 OLD_ASSERT(n_neigh*n_neigh<1000,
"Too many values in E block.");
943 ele_ac.full_iter()->n_neighs_vb, tmp_rows+2, zeros);
947 ls->
mat_set_values(1, &ele_row, ele_ac.n_sides(), edge_rows, zeros);
948 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, 1, &ele_row, zeros);
950 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, ele_ac.n_sides(), edge_rows, zeros);
954 if (
balance_ !=
nullptr && fill_matrix)
976 double cs =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
979 double source = ele_ac.measure() * cs *
980 data_->water_source_density.value(ele_ac.centre(), ele_ac.element_accessor());
993 vector<int> &dofs,
unsigned int &ele_type,
double &delta, arma::vec &dirichlet) {
997 if (i_ele == (
int)(ml_it_->size()) ) {
1003 const Intersection &isect=intersections_[ (*ml_it_)[i_ele] ];
1009 dirichlet.resize(ele->
n_sides());
1012 for(
unsigned int i_side=0; i_side < ele->
n_sides(); i_side++ ) {
1013 dofs[i_side]=darcy_.mh_dh.row_4_edge[ele->
side(i_side)->
edge_idx()];
1021 dofs[i_side] = -dofs[i_side];
1022 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.
centre(), b_ele);
1023 dirichlet[i_side] = bc_pressure;
1034 double delta_i, delta_j;
1036 arma::vec dirichlet_i, dirichlet_j;
1037 unsigned int ele_type_i, ele_type_j;
1042 for(ml_it_ = master_list_.begin(); ml_it_ != master_list_.end(); ++ml_it_) {
1044 if (ml_it_->size() == 0)
continue;
1060 master_ = intersections_[ml_it_->front()].master_iter();
1061 delta_0 = master_->measure();
1063 double master_sigma=darcy_.data_->sigma.value( master_->centre(), master_->element_accessor());
1066 double check_delta_sum=0;
1067 for(i = 0; i <= ml_it_->size(); ++i) {
1068 pressure_diff(i, dofs_i, ele_type_i, delta_i, dirichlet_i);
1069 check_delta_sum+=delta_i;
1071 for (j = 0; j <= ml_it_->size(); ++j) {
1072 pressure_diff(j, dofs_j, ele_type_j, delta_j, dirichlet_j);
1074 double scale = -master_sigma * delta_i * delta_j / delta_0;
1075 product = scale * tensor_average[ele_type_i][ele_type_j];
1077 arma::vec rhs(dofs_i.size());
1079 ls.
set_values( dofs_i, dofs_j, product, rhs, dirichlet_i, dirichlet_j);
1085 OLD_ASSERT(check_delta_sum < 1E-5*delta_0, "sum err %f > 0\n
", check_delta_sum/delta_0); 1086 } // loop over master elements 1091 void P1_CouplingAssembler::add_sides(const Element * ele, unsigned int shift, vector<int> &dofs, vector<double> &dirichlet) 1094 for(unsigned int i_side=0; i_side < ele->n_sides(); i_side++ ) { 1095 dofs[shift+i_side] = darcy_.mh_dh.row_4_edge[ele->side(i_side)->edge_idx()]; 1096 Boundary * bcd = ele->side(i_side)->cond(); 1099 ElementAccessor<3> b_ele = bcd->element_accessor(); 1100 auto type = (DarcyMH::EqData::BC_Type)darcy_.data_->bc_type.value(b_ele.centre(), b_ele); 1101 //DebugOut().fmt("bcd
id: {} sidx: {} type: {}\n
", ele->id(), i_side, type); 1102 if (type == DarcyMH::EqData::dirichlet) { 1103 //DebugOut().fmt("Dirichlet: {}\n
", ele->index()); 1104 dofs[shift + i_side] = -dofs[shift + i_side]; 1105 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.centre(), b_ele); 1106 dirichlet[shift + i_side] = bc_pressure; 1119 void P1_CouplingAssembler::assembly(LinSys &ls) {
1121 for (const Intersection &intersec : intersections_) {
1122 const Element * master = intersec.master_iter();
1123 const Element * slave = intersec.slave_iter();
1125 add_sides(slave, 0, dofs, dirichlet);
1126 add_sides(master, 3, dofs, dirichlet);
1128 double master_sigma=darcy_.data_->sigma.value( master->centre(), master->element_accessor());
1131 * Local coordinates on 1D
1137 * t0 = 0.0 on side 0 node 0
1138 * t0 = 1.0 on side 1 node 1
1140 * Local coordinates on 2D
1147 * t0=0.5, t1=0.0 on side 0 nodes (0,1)
1148 * t0=0.5, t1=0.5 on side 1 nodes (1,2)
1149 * t0=0.0, t1=0.5 on side 2 nodes (2,0)
1154 arma::vec point_Y(1);
1156 arma::vec point_2D_Y(intersec.map_to_slave(point_Y)); // local coordinates of Y on slave (1, t0, t1)
1157 arma::vec point_1D_Y(intersec.map_to_master(point_Y)); // local coordinates of Y on master (1, t0)
1159 arma::vec point_X(1);
1161 arma::vec point_2D_X(intersec.map_to_slave(point_X)); // local coordinates of X on slave (1, t0, t1)
1162 arma::vec point_1D_X(intersec.map_to_master(point_X)); // local coordinates of X on master (1, t0)
1164 arma::mat base_2D(3, 3);
1165 // basis functions are numbered as sides
1167 // Use RT finite element to evaluate following matrices.
1169 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1170 // 2D RT_i(t0, t1) = a0 + a1*t0 + a2*t1
1172 base_2D << 1.0 << 0.0 << -2.0 << arma::endr // RT for side 0
1173 << 1.0 << -2.0 << 0.0 << arma::endr // RT for side 1
1174 << -1.0 << 2.0 << 2.0 << arma::endr;// RT for side 2
1177 arma::mat base_1D(2, 2);
1178 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1179 // 1D RT_i(t0) = a0 + a1 * t0
1181 base_1D << 1.0 << -1.0 << arma::endr // RT for side 0,
1182 << 0.0 << 1.0 << arma::endr; // RT for side 1,
1186 // Consider both 2D and 1D value are defined for the test function
1187 // related to the each of 5 DOFs involved in the intersection.
1188 // One of these values is always zero.
1189 // Compute difference of the 2D and 1D value for every DOF.
1190 // Compute value of this difference in both endpoints X,Y of the intersection.
1192 arma::vec difference_in_Y(5);
1193 arma::vec difference_in_X(5);
1194 // slave sides 0,1,2
1195 difference_in_Y.subvec(0, 2) = -base_2D * point_2D_Y;
1196 difference_in_X.subvec(0, 2) = -base_2D * point_2D_X;
1198 difference_in_Y.subvec(3, 4) = base_1D * point_1D_Y;
1199 difference_in_X.subvec(3, 4) = base_1D * point_1D_X;
1201 // applying the Simpson's rule
1202 // to the product of two linear functions f, g we get
1203 // (b-a)/6 * ( 3*f(a)*g(a) + 3*f(b)*g(b) + 2*f(a)*g(b) + 2*f(b)*g(a) )
1205 for (int i = 0; i < 5; ++i) {
1206 for (int j = 0; j < 5; ++j) {
1207 A(i, j) = -master_sigma * intersec.intersection_true_size() *
1208 ( difference_in_Y[i] * difference_in_Y[j]
1209 + difference_in_Y[i] * difference_in_X[j]/2
1210 + difference_in_X[i] * difference_in_Y[j]/2
1211 + difference_in_X[i] * difference_in_X[j]
1217 ls.set_values( dofs_cp, dofs_cp, A, rhs, dirichlet, dirichlet);
1224 /*******************************************************************************
1225 * COMPOSE WATER MH MATRIX WITHOUT SCHUR COMPLEMENT
1226 ******************************************************************************/
1228 void DarcyMH::create_linear_system(Input::AbstractRecord in_rec) {
1230 START_TIMER("preallocation
"); 1232 if (schur0 == NULL) { // create Linear System for MH matrix 1234 if (in_rec.type() == LinSys_BDDC::get_input_type()) { 1235 #ifdef FLOW123D_HAVE_BDDCML 1236 WarningOut() << "For BDDC no Schur complements are used.
"; 1237 mh_dh.prepare_parallel_bddc(); 1239 LinSys_BDDC *ls = new LinSys_BDDC(mh_dh.global_row_4_sub_row->size(), &(*mh_dh.rows_ds), 1240 3, // 3 == la::BddcmlWrapper::SPD_VIA_SYMMETRICGENERAL 1241 1, // 1 == number of subdomains per process 1242 true); // swap signs of matrix and rhs to make the matrix SPD 1243 ls->set_from_input(in_rec); 1244 ls->set_solution( NULL ); 1245 // possible initialization particular to BDDC 1247 set_mesh_data_for_bddc(ls); 1251 xprintf(Err, "Flow123d was not build with BDDCML support.\n
"); 1252 #endif // FLOW123D_HAVE_BDDCML 1254 else if (in_rec.type() == LinSys_PETSC::get_input_type()) { 1255 // use PETSC for serial case even when user wants BDDC 1256 if (n_schur_compls > 2) { 1257 WarningOut() << "Invalid number of Schur Complements. Using 2.
"; 1261 LinSys_PETSC *schur1, *schur2; 1263 if (n_schur_compls == 0) { 1264 LinSys_PETSC *ls = new LinSys_PETSC( &(*mh_dh.rows_ds) ); 1266 // temporary solution; we have to set precision also for sequantial case of BDDC 1267 // final solution should be probably call of direct solver for oneproc case 1268 if (in_rec.type() != LinSys_BDDC::get_input_type()) ls->set_from_input(in_rec); 1270 ls->LinSys::set_from_input(in_rec); // get only common options 1273 ls->set_solution( NULL ); 1277 ISCreateStride(PETSC_COMM_WORLD, mh_dh.side_ds->lsize(), mh_dh.rows_ds->begin(), 1, &is); 1278 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1280 SchurComplement *ls = new SchurComplement(is, &(*mh_dh.rows_ds)); 1283 Distribution *ds = ls->make_complement_distribution(); 1284 if (n_schur_compls==1) { 1285 schur1 = new LinSys_PETSC(ds); 1286 schur1->set_positive_definite(); 1289 ISCreateStride(PETSC_COMM_WORLD, mh_dh.el_ds->lsize(), ls->get_distribution()->begin(), 1, &is); 1290 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1291 SchurComplement *ls1 = new SchurComplement(is, ds); // is is deallocated by SchurComplement 1292 ls1->set_negative_definite(); 1295 schur2 = new LinSys_PETSC( ls1->make_complement_distribution() ); 1296 schur2->set_positive_definite(); 1297 ls1->set_complement( schur2 ); 1300 ls->set_complement( schur1 ); 1301 ls->set_from_input(in_rec); 1302 ls->set_solution( NULL ); 1306 START_TIMER("PETSC PREALLOCATION
"); 1307 schur0->set_symmetric(); 1308 schur0->start_allocation(); 1309 assembly_mh_matrix(MultidimAssembler()); // preallocation 1310 VecZeroEntries(schur0->get_solution()); 1311 END_TIMER("PETSC PREALLOCATION
"); 1314 xprintf(Err, "Unknown solver type. Internal error.\n
"); 1317 END_TIMER("preallocation
"); 1318 make_serial_scatter(); 1327 void DarcyMH::assembly_linear_system() { 1328 START_TIMER("DarcyFlowMH_Steady::assembly_linear_system
"); 1331 bool is_steady = zero_time_term(); 1332 //DebugOut() << "Assembly linear system\n
"; 1333 if (data_changed_) { 1334 data_changed_ = false; 1335 //DebugOut() << "Data changed\n
"; 1336 // currently we have no optimization for cases when just time term data or RHS data are changed 1337 START_TIMER("full assembly
"); 1338 if (typeid(*schur0) != typeid(LinSys_BDDC)) { 1339 schur0->start_add_assembly(); // finish allocation and create matrix 1342 auto multidim_assembler = AssemblyBase::create< AssemblyMH >(data_); 1344 schur0->mat_zero_entries(); 1345 schur0->rhs_zero_entries(); 1347 assembly_source_term(); 1348 assembly_mh_matrix( multidim_assembler ); // fill matrix 1350 schur0->finish_assembly(); 1351 schur0->set_matrix_changed(); 1352 //MatView( *const_cast<Mat*>(schur0->get_matrix()), PETSC_VIEWER_STDOUT_WORLD ); 1353 //VecView( *const_cast<Vec*>(schur0->get_rhs()), PETSC_VIEWER_STDOUT_WORLD); 1356 START_TIMER("fix
time term
"); 1357 //DebugOut() << "setup
time term\n
"; 1358 // assembly time term and rhs 1362 else if (balance_ != nullptr) 1364 balance_->start_mass_assembly(water_balance_idx_); 1365 balance_->finish_mass_assembly(water_balance_idx_); 1367 END_TIMER("full assembly
"); 1369 START_TIMER("modify system
"); 1373 //xprintf(PrgErr, "Planned computation
time for steady solver, but
data are not changed.\n
"); 1375 END_TIMER("modiffy system
"); 1382 void DarcyMH::set_mesh_data_for_bddc(LinSys_BDDC * bddc_ls) { 1383 START_TIMER("DarcyFlowMH_Steady::set_mesh_data_for_bddc
"); 1384 // prepare mesh for BDDCML 1385 // initialize arrays 1386 // auxiliary map for creating coordinates of local dofs and global-to-local numbering 1387 std::map<int,arma::vec3> localDofMap; 1388 // connectivity for the subdomain, i.e. global dof numbers on element, stored element-by-element 1389 // Indices of Nodes on Elements 1390 std::vector<int> inet; 1391 // number of degrees of freedom on elements - determines elementwise chunks of INET array 1392 // Number of Nodes on Elements 1393 std::vector<int> nnet; 1394 // Indices of Subdomain Elements in Global Numbering - for local elements, their global indices 1395 std::vector<int> isegn; 1397 // This array is currently not used in BDDCML, it was used as an interface scaling alternative to scaling 1398 // by diagonal. It corresponds to the rho-scaling. 1399 std::vector<double> element_permeability; 1401 // maximal and minimal dimension of elements 1404 for ( unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++ ) { 1405 auto ele_ac = mh_dh.accessor(i_loc); 1406 // for each element, create local numbering of dofs as fluxes (sides), pressure (element centre), Lagrange multipliers (edges), compatible connections 1408 elDimMax = std::max( elDimMax, ele_ac.dim() ); 1409 elDimMin = std::min( elDimMin, ele_ac.dim() ); 1411 isegn.push_back( ele_ac.ele_global_idx() ); 1414 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1415 // insert local side dof 1416 int side_row = ele_ac.side_row(si); 1417 arma::vec3 coord = ele_ac.side(si)->centre(); 1419 localDofMap.insert( std::make_pair( side_row, coord ) ); 1420 inet.push_back( side_row ); 1424 // insert local pressure dof 1425 int el_row = ele_ac.ele_row(); 1426 arma::vec3 coord = ele_ac.centre(); 1427 localDofMap.insert( std::make_pair( el_row, coord ) ); 1428 inet.push_back( el_row ); 1431 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1432 // insert local edge dof 1433 int edge_row = ele_ac.edge_row(si); 1434 arma::vec3 coord = ele_ac.side(si)->centre(); 1436 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1437 inet.push_back( edge_row ); 1441 // insert dofs related to compatible connections 1442 for ( unsigned int i_neigh = 0; i_neigh < ele_ac.full_iter()->n_neighs_vb; i_neigh++) { 1443 int edge_row = mh_dh.row_4_edge[ ele_ac.full_iter()->neigh_vb[i_neigh]->edge_idx() ]; 1444 arma::vec3 coord = ele_ac.full_iter()->neigh_vb[i_neigh]->edge()->side(0)->centre(); 1446 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1447 inet.push_back( edge_row ); 1451 nnet.push_back( nne ); 1453 // version for rho scaling 1454 // trace computation 1455 arma::vec3 centre = ele_ac.centre(); 1456 double conduct = data_->conductivity.value( centre , ele_ac.element_accessor() ); 1457 auto aniso = data_->anisotropy.value( centre, ele_ac.element_accessor() ); 1459 // compute mean on the diagonal 1461 for ( int i = 0; i < 3; i++) { 1462 coef = coef + aniso.at(i,i); 1464 // Maybe divide by cs 1465 coef = conduct*coef / 3; 1467 OLD_ASSERT( coef > 0., 1468 "Zero coefficient of hydrodynamic resistance %f . \n
", coef ); 1469 element_permeability.push_back( 1. / coef ); 1471 //convert set of dofs to vectors 1472 // number of nodes (= dofs) on the subdomain 1473 int numNodeSub = localDofMap.size(); 1474 OLD_ASSERT_EQUAL( (unsigned int)numNodeSub, mh_dh.global_row_4_sub_row->size() ); 1475 // Indices of Subdomain Nodes in Global Numbering - for local nodes, their global indices 1476 std::vector<int> isngn( numNodeSub ); 1477 // pseudo-coordinates of local nodes (i.e. dofs) 1478 // they need not be exact, they are used just for some geometrical considerations in BDDCML, 1479 // such as selection of corners maximizing area of a triangle, bounding boxes fro subdomains to 1480 // find candidate neighbours etc. 1481 std::vector<double> xyz( numNodeSub * 3 ) ; 1483 std::map<int,arma::vec3>::iterator itB = localDofMap.begin(); 1484 for ( ; itB != localDofMap.end(); ++itB ) { 1485 isngn[ind] = itB -> first; 1487 arma::vec3 coord = itB -> second; 1488 for ( int j = 0; j < 3; j++ ) { 1489 xyz[ j*numNodeSub + ind ] = coord[j]; 1494 localDofMap.clear(); 1496 // Number of Nodal Degrees of Freedom 1497 // nndf is trivially one - dofs coincide with nodes 1498 std::vector<int> nndf( numNodeSub, 1 ); 1500 // prepare auxiliary map for renumbering nodes 1501 typedef std::map<int,int> Global2LocalMap_; //! type for storage of global to local map 1502 Global2LocalMap_ global2LocalNodeMap; 1503 for ( unsigned ind = 0; ind < isngn.size(); ++ind ) { 1504 global2LocalNodeMap.insert( std::make_pair( static_cast<unsigned>( isngn[ind] ), ind ) ); 1507 // renumber nodes in the inet array to locals 1509 for ( unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) { 1510 int nne = nnet[ iEle ]; 1511 for ( int ien = 0; ien < nne; ien++ ) { 1513 int indGlob = inet[indInet]; 1514 // map it to local node 1515 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob ); 1516 OLD_ASSERT( pos != global2LocalNodeMap.end(), 1517 "Cannot remap node index %d to local indices. \n
", indGlob ); 1518 int indLoc = static_cast<int> ( pos -> second ); 1521 inet[ indInet++ ] = indLoc; 1525 int numNodes = size; 1526 int numDofsInt = size; 1527 int spaceDim = 3; // TODO: what is the proper value here? 1528 int meshDim = elDimMax; 1530 bddc_ls -> load_mesh( spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim ); 1536 //============================================================================= 1537 // DESTROY WATER MH SYSTEM STRUCTURE 1538 //============================================================================= 1539 DarcyMH::~DarcyMH() { 1540 if (schur0 != NULL) { 1542 VecScatterDestroy(&par_to_all); 1545 if (solution != NULL) { 1546 chkerr(VecDestroy(&sol_vec)); 1550 if (output_object) delete output_object; 1557 // ================================================ 1562 void DarcyMH::make_serial_scatter() { 1563 START_TIMER("prepare scatter
"); 1564 // prepare Scatter form parallel to sequantial in original numbering 1567 int i, *loc_idx; //, si; 1569 // create local solution vector 1570 solution = new double[size]; 1571 VecCreateSeqWithArray(PETSC_COMM_SELF,1, size, solution, 1574 // create seq. IS to scatter par solutin to seq. vec. in original order 1575 // use essentialy row_4_id arrays 1576 loc_idx = new int [size]; 1578 FOR_ELEMENTS(mesh_, ele) { 1579 FOR_ELEMENT_SIDES(ele,si) { 1580 loc_idx[i++] = mh_dh.side_row_4_id[ mh_dh.side_dof( ele->side(si) ) ]; 1583 FOR_ELEMENTS(mesh_, ele) { 1584 loc_idx[i++] = mh_dh.row_4_el[ele.index()]; 1586 for(unsigned int i_edg=0; i_edg < mesh_->n_edges(); i_edg++) { 1587 loc_idx[i++] = mh_dh.row_4_edge[i_edg]; 1589 OLD_ASSERT( i==size,"Size of array does not match number of fills.\n
"); 1590 //DBGPRINT_INT("loc_idx
",size,loc_idx); 1591 ISCreateGeneral(PETSC_COMM_SELF, size, loc_idx, PETSC_COPY_VALUES, &(is_loc)); 1593 VecScatterCreate(schur0->get_solution(), is_loc, sol_vec, 1594 PETSC_NULL, &par_to_all); 1595 ISDestroy(&(is_loc)); 1597 solution_changed_for_scatter=true; 1599 END_TIMER("prepare scatter
"); 1605 void mat_count_off_proc_values(Mat m, Vec v) { 1607 const PetscInt *cols; 1608 Distribution distr(v); 1613 MatGetOwnershipRange(m, &first, &last); 1614 for (int row = first; row < last; row++) { 1615 MatGetRow(m, row, &n, &cols, PETSC_NULL); 1616 bool exists_off = false; 1617 for (int i = 0; i < n; i++) 1618 if (distr.get_proc(cols[i]) != distr.myp()) 1619 n_off++, exists_off = true; 1624 MatRestoreRow(m, row, &n, &cols, PETSC_NULL); 1640 void DarcyMH::read_initial_condition() 1642 double *local_sol = schur0->get_solution_array(); 1644 // cycle over local element rows 1646 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1647 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1648 auto ele_ac = mh_dh.accessor(i_loc_el); 1649 // set initial condition 1650 local_sol[ele_ac.ele_local_row()] = data_->init_pressure.value(ele_ac.centre(),ele_ac.element_accessor()); 1653 solution_changed_for_scatter=true; 1657 void DarcyMH::setup_time_term() { 1658 // save diagonal of steady matrix 1659 MatGetDiagonal(*( schur0->get_matrix() ), steady_diagonal); 1661 VecCopy(*( schur0->get_rhs()), steady_rhs); 1664 PetscScalar *local_diagonal; 1665 VecGetArray(new_diagonal,& local_diagonal); 1667 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1669 if (balance_ != nullptr) 1670 balance_->start_mass_assembly(water_balance_idx_); 1672 //DebugOut().fmt("time_term lsize: {} {}\n
", mh_dh.el_ds->myp(), mh_dh.el_ds->lsize()); 1673 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1674 auto ele_ac = mh_dh.accessor(i_loc_el); 1677 double diagonal_coeff = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor()) 1678 * data_->storativity.value(ele_ac.centre(), ele_ac.element_accessor()) 1680 local_diagonal[ele_ac.ele_local_row()]= - diagonal_coeff / time_->dt(); 1682 //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); 1683 if (balance_ != nullptr) 1684 balance_->add_mass_matrix_values(water_balance_idx_, 1685 ele_ac.region().bulk_idx(), { int(ele_ac.ele_row()) }, {diagonal_coeff}); 1687 VecRestoreArray(new_diagonal,& local_diagonal); 1688 MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES); 1690 solution_changed_for_scatter=true; 1691 schur0->set_matrix_changed(); 1693 if (balance_ != nullptr) 1694 balance_->finish_mass_assembly(water_balance_idx_); 1697 void DarcyMH::modify_system() { 1698 START_TIMER("modify system
"); 1699 if (time_->is_changed_dt() && time_->step().index()>0) { 1700 double scale_factor=time_->step(-2).length()/time_->step().length(); 1701 if (scale_factor != 1.0) { 1702 // if time step has changed and setup_time_term not called 1703 MatDiagonalSet(*( schur0->get_matrix() ),steady_diagonal, INSERT_VALUES); 1705 VecScale(new_diagonal, time_->last_dt()/time_->dt()); 1706 MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES); 1707 schur0->set_matrix_changed(); 1711 // modify RHS - add previous solution 1712 //VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, previous_solution); 1713 VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, schur0->get_solution()); 1714 VecAXPY(*( schur0->get_rhs()), 1.0, steady_rhs); 1715 schur0->set_rhs_changed(); 1717 //VecSwap(previous_solution, schur0->get_solution()); 1721 //----------------------------------------------------------------------------- 1722 // 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)
#define ADD_FIELD(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