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 (($ \\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 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 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' except for 'none' and 'seepage'. " 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, seepage} );
208 bc_pressure.units(
UnitSI().m() );
210 ADD_FIELD(bc_flux,
"Incoming water boundary flux. Used for bc_types : '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 for 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>();
398 if (zero_time_term_from_right) {
428 bool jump_time =
data_->storativity.is_jump_time();
429 if (! zero_time_term_from_left) {
439 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
448 if (! zero_time_term_from_left && ! jump_time)
output_data();
454 if (zero_time_term_from_right) {
459 }
else if (! zero_time_term_from_left && jump_time) {
460 WarningOut() <<
"Discontinuous time term not supported yet.\n";
471 return (
data_->storativity.input_list_size() == 0);
485 MessageOut().fmt(
"[nonlin solver] norm of initial residual: {}\n", residual_norm);
488 int is_linear_common;
493 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
494 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
495 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
497 if (! is_linear_common) {
505 while (nonlinear_iteration_ < this->min_n_it_ ||
506 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->max_n_it_ )) {
508 convergence_history.push_back(residual_norm);
511 if (convergence_history.size() >= 5 &&
512 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
513 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
519 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
523 if (! is_linear_common)
529 if (is_linear_common)
break;
548 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it:{} (reason: {}) residual: {}\n",
630 vec_size = this->
size;
631 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
637 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
655 START_TIMER(
"DarcyFlowMH_Steady::assembly_steady_mh_matrix");
662 bool fill_matrix = assembler.size() > 0;
663 int side_row, edge_row, loc_b = 0;
666 int side_rows[4], edge_rows[4];
670 for(
int i=0; i<1000; i++) zeros[i]=0.0;
672 double minus_ones[4] = { -1.0, -1.0, -1.0, -1.0 };
673 double * loc_side_rhs =
data_->system_.loc_side_rhs;
675 arma::mat &local_matrix = *(
data_->system_.local_matrix);
683 unsigned int nsides = ele_ac.n_sides();
684 data_->system_.dirichlet_edge.resize(nsides);
688 for (
unsigned int i = 0; i < nsides; i++) {
696 side_rows[i] = side_row = ele_ac.side_row(i);
697 edge_rows[i] = edge_row = ele_ac.edge_row(i);
706 data_->system_.dirichlet_edge[i] = 0;
712 double cross_section =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
717 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
719 loc_side_rhs[i] -= bc_pressure;
722 data_->system_.dirichlet_edge[i] = 1;
727 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
728 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
729 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
739 double bc_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
740 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
741 double side_flux=bc_flux * bcd->
element()->
measure() * cross_section;
744 if (switch_dirichlet) {
749 unsigned int loc_side_row = ele_ac.side_local_row(i);
752 if ( solution_flux < side_flux) {
754 solution_flux = side_flux;
769 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
772 if ( solution_head > bc_pressure) {
774 solution_head = bc_pressure;
784 loc_side_rhs[i] -= bc_pressure;
787 data_->system_.dirichlet_edge[i] = 1;
799 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
800 double bc_switch_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
801 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
802 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
804 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
817 double bc_total_flux = bc_flux + bc_sigma*(bc_switch_pressure - bc_pressure);
842 assembler[ele_ac.dim()-1]->assembly_local_matrix(ele_ac);
854 for(
unsigned int i=0; i < nsides; i++) {
855 double val_side = local_matrix(i,i);
856 double val_edge = -1./local_matrix(i,i);
858 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( side_rows[i], val_side );
859 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( edge_rows[i], val_edge );
868 ls->
mat_set_values(nsides, side_rows, nsides, side_rows, local_matrix.memptr());
870 int ele_row = ele_ac.ele_row();
881 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ele_row, val_ele );
886 for (
unsigned int i = 0; i < ele_ac.full_iter()->n_neighs_vb; i++) {
889 ngh= ele_ac.full_iter()->neigh_vb[i];
894 assembler[ngh->
side()->
dim()]->assembly_local_vb(local_vb, ele_ac.full_iter(), ngh);
900 int ind = tmp_rows[1];
902 double new_val = local_vb[0];
903 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ind, new_val );
914 tmp_rows[2+i] = tmp_rows[1];
923 n_neigh = ele_ac.full_iter()->n_neighs_vb;
925 OLD_ASSERT(n_neigh*n_neigh<1000,
"Too many values in E block.");
927 ele_ac.full_iter()->n_neighs_vb, tmp_rows+2, zeros);
931 ls->
mat_set_values(1, &ele_row, ele_ac.n_sides(), edge_rows, zeros);
932 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, 1, &ele_row, zeros);
934 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, ele_ac.n_sides(), edge_rows, zeros);
959 double cs =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
962 double source = ele_ac.measure() * cs *
963 data_->water_source_density.value(ele_ac.centre(), ele_ac.element_accessor());
974 vector<int> &dofs,
unsigned int &ele_type,
double &delta, arma::vec &dirichlet) {
978 if (i_ele == (
int)(ml_it_->size()) ) {
984 const Intersection &isect=intersections_[ (*ml_it_)[i_ele] ];
990 dirichlet.resize(ele->
n_sides());
993 for(
unsigned int i_side=0; i_side < ele->
n_sides(); i_side++ ) {
994 dofs[i_side]=darcy_.mh_dh.row_4_edge[ele->
side(i_side)->
edge_idx()];
1002 dofs[i_side] = -dofs[i_side];
1003 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.
centre(), b_ele);
1004 dirichlet[i_side] = bc_pressure;
1015 double delta_i, delta_j;
1017 arma::vec dirichlet_i, dirichlet_j;
1018 unsigned int ele_type_i, ele_type_j;
1023 for(ml_it_ = master_list_.begin(); ml_it_ != master_list_.end(); ++ml_it_) {
1025 if (ml_it_->size() == 0)
continue;
1041 master_ = intersections_[ml_it_->front()].master_iter();
1042 delta_0 = master_->measure();
1044 double master_sigma=darcy_.data_->sigma.value( master_->centre(), master_->element_accessor());
1047 double check_delta_sum=0;
1048 for(i = 0; i <= ml_it_->size(); ++i) {
1049 pressure_diff(i, dofs_i, ele_type_i, delta_i, dirichlet_i);
1050 check_delta_sum+=delta_i;
1052 for (j = 0; j <= ml_it_->size(); ++j) {
1053 pressure_diff(j, dofs_j, ele_type_j, delta_j, dirichlet_j);
1055 double scale = -master_sigma * delta_i * delta_j / delta_0;
1056 product = scale * tensor_average[ele_type_i][ele_type_j];
1058 arma::vec rhs(dofs_i.size());
1060 ls.
set_values( dofs_i, dofs_j, product, rhs, dirichlet_i, dirichlet_j);
1066 OLD_ASSERT(check_delta_sum < 1E-5*delta_0, "sum err %f > 0\n
", check_delta_sum/delta_0); 1067 } // loop over master elements 1072 void P1_CouplingAssembler::add_sides(const Element * ele, unsigned int shift, vector<int> &dofs, vector<double> &dirichlet) 1075 for(unsigned int i_side=0; i_side < ele->n_sides(); i_side++ ) { 1076 dofs[shift+i_side] = darcy_.mh_dh.row_4_edge[ele->side(i_side)->edge_idx()]; 1077 Boundary * bcd = ele->side(i_side)->cond(); 1080 ElementAccessor<3> b_ele = bcd->element_accessor(); 1081 auto type = (DarcyMH::EqData::BC_Type)darcy_.data_->bc_type.value(b_ele.centre(), b_ele); 1082 //DebugOut().fmt("bcd
id: {} sidx: {} type: {}\n
", ele->id(), i_side, type); 1083 if (type == DarcyMH::EqData::dirichlet) { 1084 //DebugOut().fmt("Dirichlet: {}\n
", ele->index()); 1085 dofs[shift + i_side] = -dofs[shift + i_side]; 1086 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.centre(), b_ele); 1087 dirichlet[shift + i_side] = bc_pressure; 1100 void P1_CouplingAssembler::assembly(LinSys &ls) {
1102 for (const Intersection &intersec : intersections_) {
1103 const Element * master = intersec.master_iter();
1104 const Element * slave = intersec.slave_iter();
1106 add_sides(slave, 0, dofs, dirichlet);
1107 add_sides(master, 3, dofs, dirichlet);
1109 double master_sigma=darcy_.data_->sigma.value( master->centre(), master->element_accessor());
1112 * Local coordinates on 1D
1118 * t0 = 0.0 on side 0 node 0
1119 * t0 = 1.0 on side 1 node 1
1121 * Local coordinates on 2D
1128 * t0=0.5, t1=0.0 on side 0 nodes (0,1)
1129 * t0=0.5, t1=0.5 on side 1 nodes (1,2)
1130 * t0=0.0, t1=0.5 on side 2 nodes (2,0)
1135 arma::vec point_Y(1);
1137 arma::vec point_2D_Y(intersec.map_to_slave(point_Y)); // local coordinates of Y on slave (1, t0, t1)
1138 arma::vec point_1D_Y(intersec.map_to_master(point_Y)); // local coordinates of Y on master (1, t0)
1140 arma::vec point_X(1);
1142 arma::vec point_2D_X(intersec.map_to_slave(point_X)); // local coordinates of X on slave (1, t0, t1)
1143 arma::vec point_1D_X(intersec.map_to_master(point_X)); // local coordinates of X on master (1, t0)
1145 arma::mat base_2D(3, 3);
1146 // basis functions are numbered as sides
1148 // Use RT finite element to evaluate following matrices.
1150 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1151 // 2D RT_i(t0, t1) = a0 + a1*t0 + a2*t1
1153 base_2D << 1.0 << 0.0 << -2.0 << arma::endr // RT for side 0
1154 << 1.0 << -2.0 << 0.0 << arma::endr // RT for side 1
1155 << -1.0 << 2.0 << 2.0 << arma::endr;// RT for side 2
1158 arma::mat base_1D(2, 2);
1159 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1160 // 1D RT_i(t0) = a0 + a1 * t0
1162 base_1D << 1.0 << -1.0 << arma::endr // RT for side 0,
1163 << 0.0 << 1.0 << arma::endr; // RT for side 1,
1167 // Consider both 2D and 1D value are defined for the test function
1168 // related to the each of 5 DOFs involved in the intersection.
1169 // One of these values is always zero.
1170 // Compute difference of the 2D and 1D value for every DOF.
1171 // Compute value of this difference in both endpoints X,Y of the intersection.
1173 arma::vec difference_in_Y(5);
1174 arma::vec difference_in_X(5);
1175 // slave sides 0,1,2
1176 difference_in_Y.subvec(0, 2) = -base_2D * point_2D_Y;
1177 difference_in_X.subvec(0, 2) = -base_2D * point_2D_X;
1179 difference_in_Y.subvec(3, 4) = base_1D * point_1D_Y;
1180 difference_in_X.subvec(3, 4) = base_1D * point_1D_X;
1182 // applying the Simpson's rule
1183 // to the product of two linear functions f, g we get
1184 // (b-a)/6 * ( 3*f(a)*g(a) + 3*f(b)*g(b) + 2*f(a)*g(b) + 2*f(b)*g(a) )
1186 for (int i = 0; i < 5; ++i) {
1187 for (int j = 0; j < 5; ++j) {
1188 A(i, j) = -master_sigma * intersec.intersection_true_size() *
1189 ( difference_in_Y[i] * difference_in_Y[j]
1190 + difference_in_Y[i] * difference_in_X[j]/2
1191 + difference_in_X[i] * difference_in_Y[j]/2
1192 + difference_in_X[i] * difference_in_X[j]
1198 ls.set_values( dofs_cp, dofs_cp, A, rhs, dirichlet, dirichlet);
1205 /*******************************************************************************
1206 * COMPOSE WATER MH MATRIX WITHOUT SCHUR COMPLEMENT
1207 ******************************************************************************/
1209 void DarcyMH::create_linear_system(Input::AbstractRecord in_rec) {
1211 START_TIMER("preallocation
"); 1213 if (schur0 == NULL) { // create Linear System for MH matrix 1215 if (in_rec.type() == LinSys_BDDC::get_input_type()) { 1216 #ifdef FLOW123D_HAVE_BDDCML 1217 WarningOut() << "For BDDC no Schur complements are used.
"; 1218 mh_dh.prepare_parallel_bddc(); 1220 LinSys_BDDC *ls = new LinSys_BDDC(mh_dh.global_row_4_sub_row->size(), &(*mh_dh.rows_ds), 1221 3, // 3 == la::BddcmlWrapper::SPD_VIA_SYMMETRICGENERAL 1222 1, // 1 == number of subdomains per process 1223 true); // swap signs of matrix and rhs to make the matrix SPD 1224 ls->set_from_input(in_rec); 1225 ls->set_solution( NULL ); 1226 // possible initialization particular to BDDC 1228 set_mesh_data_for_bddc(ls); 1232 xprintf(Err, "Flow123d was not build with BDDCML support.\n
"); 1233 #endif // FLOW123D_HAVE_BDDCML 1235 else if (in_rec.type() == LinSys_PETSC::get_input_type()) { 1236 // use PETSC for serial case even when user wants BDDC 1237 if (n_schur_compls > 2) { 1238 WarningOut() << "Invalid number of Schur Complements. Using 2.
"; 1242 LinSys_PETSC *schur1, *schur2; 1244 if (n_schur_compls == 0) { 1245 LinSys_PETSC *ls = new LinSys_PETSC( &(*mh_dh.rows_ds) ); 1247 // temporary solution; we have to set precision also for sequantial case of BDDC 1248 // final solution should be probably call of direct solver for oneproc case 1249 if (in_rec.type() != LinSys_BDDC::get_input_type()) ls->set_from_input(in_rec); 1251 ls->LinSys::set_from_input(in_rec); // get only common options 1254 ls->set_solution( NULL ); 1258 ISCreateStride(PETSC_COMM_WORLD, mh_dh.side_ds->lsize(), mh_dh.rows_ds->begin(), 1, &is); 1259 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1261 SchurComplement *ls = new SchurComplement(is, &(*mh_dh.rows_ds)); 1264 Distribution *ds = ls->make_complement_distribution(); 1265 if (n_schur_compls==1) { 1266 schur1 = new LinSys_PETSC(ds); 1267 schur1->set_positive_definite(); 1270 ISCreateStride(PETSC_COMM_WORLD, mh_dh.el_ds->lsize(), ls->get_distribution()->begin(), 1, &is); 1271 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1272 SchurComplement *ls1 = new SchurComplement(is, ds); // is is deallocated by SchurComplement 1273 ls1->set_negative_definite(); 1276 schur2 = new LinSys_PETSC( ls1->make_complement_distribution() ); 1277 schur2->set_positive_definite(); 1278 ls1->set_complement( schur2 ); 1281 ls->set_complement( schur1 ); 1282 ls->set_from_input(in_rec); 1283 ls->set_solution( NULL ); 1287 START_TIMER("PETSC PREALLOCATION
"); 1288 schur0->set_symmetric(); 1289 schur0->start_allocation(); 1290 assembly_mh_matrix(MultidimAssembler()); // preallocation 1291 VecZeroEntries(schur0->get_solution()); 1292 END_TIMER("PETSC PREALLOCATION
"); 1295 xprintf(Err, "Unknown solver type. Internal error.\n
"); 1298 END_TIMER("preallocation
"); 1299 make_serial_scatter(); 1308 void DarcyMH::assembly_linear_system() { 1309 START_TIMER("DarcyFlowMH_Steady::assembly_linear_system
"); 1312 bool is_steady = zero_time_term(); 1313 //DebugOut() << "Assembly linear system\n
"; 1314 if (data_changed_) { 1315 data_changed_ = false; 1316 //DebugOut() << "Data changed\n
"; 1317 // currently we have no optimization for cases when just time term data or RHS data are changed 1318 START_TIMER("full assembly
"); 1319 if (typeid(*schur0) != typeid(LinSys_BDDC)) { 1320 schur0->start_add_assembly(); // finish allocation and create matrix 1323 auto multidim_assembler = AssemblyBase::create< AssemblyMH >(data_); 1325 schur0->mat_zero_entries(); 1326 schur0->rhs_zero_entries(); 1328 assembly_source_term(); 1329 assembly_mh_matrix( multidim_assembler ); // fill matrix 1331 schur0->finish_assembly(); 1332 schur0->set_matrix_changed(); 1333 //MatView( *const_cast<Mat*>(schur0->get_matrix()), PETSC_VIEWER_STDOUT_WORLD ); 1334 //VecView( *const_cast<Vec*>(schur0->get_rhs()), PETSC_VIEWER_STDOUT_WORLD); 1337 START_TIMER("fix
time term
"); 1338 //DebugOut() << "setup
time term\n
"; 1339 // assembly time term and rhs 1345 balance_->start_mass_assembly(water_balance_idx_); 1346 balance_->finish_mass_assembly(water_balance_idx_); 1348 END_TIMER("full assembly
"); 1350 START_TIMER("modify system
"); 1354 //xprintf(PrgErr, "Planned computation
time for steady solver, but
data are not changed.\n
"); 1356 END_TIMER("modiffy system
"); 1363 void DarcyMH::set_mesh_data_for_bddc(LinSys_BDDC * bddc_ls) { 1364 START_TIMER("DarcyFlowMH_Steady::set_mesh_data_for_bddc
"); 1365 // prepare mesh for BDDCML 1366 // initialize arrays 1367 // auxiliary map for creating coordinates of local dofs and global-to-local numbering 1368 std::map<int,arma::vec3> localDofMap; 1369 // connectivity for the subdomain, i.e. global dof numbers on element, stored element-by-element 1370 // Indices of Nodes on Elements 1371 std::vector<int> inet; 1372 // number of degrees of freedom on elements - determines elementwise chunks of INET array 1373 // Number of Nodes on Elements 1374 std::vector<int> nnet; 1375 // Indices of Subdomain Elements in Global Numbering - for local elements, their global indices 1376 std::vector<int> isegn; 1378 // This array is currently not used in BDDCML, it was used as an interface scaling alternative to scaling 1379 // by diagonal. It corresponds to the rho-scaling. 1380 std::vector<double> element_permeability; 1382 // maximal and minimal dimension of elements 1385 for ( unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++ ) { 1386 auto ele_ac = mh_dh.accessor(i_loc); 1387 // for each element, create local numbering of dofs as fluxes (sides), pressure (element centre), Lagrange multipliers (edges), compatible connections 1389 elDimMax = std::max( elDimMax, ele_ac.dim() ); 1390 elDimMin = std::min( elDimMin, ele_ac.dim() ); 1392 isegn.push_back( ele_ac.ele_global_idx() ); 1395 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1396 // insert local side dof 1397 int side_row = ele_ac.side_row(si); 1398 arma::vec3 coord = ele_ac.side(si)->centre(); 1400 localDofMap.insert( std::make_pair( side_row, coord ) ); 1401 inet.push_back( side_row ); 1405 // insert local pressure dof 1406 int el_row = ele_ac.ele_row(); 1407 arma::vec3 coord = ele_ac.centre(); 1408 localDofMap.insert( std::make_pair( el_row, coord ) ); 1409 inet.push_back( el_row ); 1412 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1413 // insert local edge dof 1414 int edge_row = ele_ac.edge_row(si); 1415 arma::vec3 coord = ele_ac.side(si)->centre(); 1417 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1418 inet.push_back( edge_row ); 1422 // insert dofs related to compatible connections 1423 for ( unsigned int i_neigh = 0; i_neigh < ele_ac.full_iter()->n_neighs_vb; i_neigh++) { 1424 int edge_row = mh_dh.row_4_edge[ ele_ac.full_iter()->neigh_vb[i_neigh]->edge_idx() ]; 1425 arma::vec3 coord = ele_ac.full_iter()->neigh_vb[i_neigh]->edge()->side(0)->centre(); 1427 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1428 inet.push_back( edge_row ); 1432 nnet.push_back( nne ); 1434 // version for rho scaling 1435 // trace computation 1436 arma::vec3 centre = ele_ac.centre(); 1437 double conduct = data_->conductivity.value( centre , ele_ac.element_accessor() ); 1438 auto aniso = data_->anisotropy.value( centre, ele_ac.element_accessor() ); 1440 // compute mean on the diagonal 1442 for ( int i = 0; i < 3; i++) { 1443 coef = coef + aniso.at(i,i); 1445 // Maybe divide by cs 1446 coef = conduct*coef / 3; 1448 OLD_ASSERT( coef > 0., 1449 "Zero coefficient of hydrodynamic resistance %f . \n
", coef ); 1450 element_permeability.push_back( 1. / coef ); 1452 //convert set of dofs to vectors 1453 // number of nodes (= dofs) on the subdomain 1454 int numNodeSub = localDofMap.size(); 1455 OLD_ASSERT_EQUAL( (unsigned int)numNodeSub, mh_dh.global_row_4_sub_row->size() ); 1456 // Indices of Subdomain Nodes in Global Numbering - for local nodes, their global indices 1457 std::vector<int> isngn( numNodeSub ); 1458 // pseudo-coordinates of local nodes (i.e. dofs) 1459 // they need not be exact, they are used just for some geometrical considerations in BDDCML, 1460 // such as selection of corners maximizing area of a triangle, bounding boxes fro subdomains to 1461 // find candidate neighbours etc. 1462 std::vector<double> xyz( numNodeSub * 3 ) ; 1464 std::map<int,arma::vec3>::iterator itB = localDofMap.begin(); 1465 for ( ; itB != localDofMap.end(); ++itB ) { 1466 isngn[ind] = itB -> first; 1468 arma::vec3 coord = itB -> second; 1469 for ( int j = 0; j < 3; j++ ) { 1470 xyz[ j*numNodeSub + ind ] = coord[j]; 1475 localDofMap.clear(); 1477 // Number of Nodal Degrees of Freedom 1478 // nndf is trivially one - dofs coincide with nodes 1479 std::vector<int> nndf( numNodeSub, 1 ); 1481 // prepare auxiliary map for renumbering nodes 1482 typedef std::map<int,int> Global2LocalMap_; //! type for storage of global to local map 1483 Global2LocalMap_ global2LocalNodeMap; 1484 for ( unsigned ind = 0; ind < isngn.size(); ++ind ) { 1485 global2LocalNodeMap.insert( std::make_pair( static_cast<unsigned>( isngn[ind] ), ind ) ); 1488 // renumber nodes in the inet array to locals 1490 for ( unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) { 1491 int nne = nnet[ iEle ]; 1492 for ( int ien = 0; ien < nne; ien++ ) { 1494 int indGlob = inet[indInet]; 1495 // map it to local node 1496 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob ); 1497 OLD_ASSERT( pos != global2LocalNodeMap.end(), 1498 "Cannot remap node index %d to local indices. \n
", indGlob ); 1499 int indLoc = static_cast<int> ( pos -> second ); 1502 inet[ indInet++ ] = indLoc; 1506 int numNodes = size; 1507 int numDofsInt = size; 1508 int spaceDim = 3; // TODO: what is the proper value here? 1509 int meshDim = elDimMax; 1511 bddc_ls -> load_mesh( spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim ); 1517 //============================================================================= 1518 // DESTROY WATER MH SYSTEM STRUCTURE 1519 //============================================================================= 1520 DarcyMH::~DarcyMH() { 1521 if (schur0 != NULL) { 1523 VecScatterDestroy(&par_to_all); 1526 if (solution != NULL) { 1527 chkerr(VecDestroy(&sol_vec)); 1531 if (output_object) delete output_object; 1538 // ================================================ 1543 void DarcyMH::make_serial_scatter() { 1544 START_TIMER("prepare scatter
"); 1545 // prepare Scatter form parallel to sequantial in original numbering 1548 int i, *loc_idx; //, si; 1550 // create local solution vector 1551 solution = new double[size]; 1552 VecCreateSeqWithArray(PETSC_COMM_SELF,1, size, solution, 1555 // create seq. IS to scatter par solutin to seq. vec. in original order 1556 // use essentialy row_4_id arrays 1557 loc_idx = new int [size]; 1559 FOR_ELEMENTS(mesh_, ele) { 1560 FOR_ELEMENT_SIDES(ele,si) { 1561 loc_idx[i++] = mh_dh.side_row_4_id[ mh_dh.side_dof( ele->side(si) ) ]; 1564 FOR_ELEMENTS(mesh_, ele) { 1565 loc_idx[i++] = mh_dh.row_4_el[ele.index()]; 1567 for(unsigned int i_edg=0; i_edg < mesh_->n_edges(); i_edg++) { 1568 loc_idx[i++] = mh_dh.row_4_edge[i_edg]; 1570 OLD_ASSERT( i==size,"Size of array does not match number of fills.\n
"); 1571 //DBGPRINT_INT("loc_idx
",size,loc_idx); 1572 ISCreateGeneral(PETSC_COMM_SELF, size, loc_idx, PETSC_COPY_VALUES, &(is_loc)); 1574 VecScatterCreate(schur0->get_solution(), is_loc, sol_vec, 1575 PETSC_NULL, &par_to_all); 1576 ISDestroy(&(is_loc)); 1578 solution_changed_for_scatter=true; 1580 END_TIMER("prepare scatter
"); 1586 void mat_count_off_proc_values(Mat m, Vec v) { 1588 const PetscInt *cols; 1589 Distribution distr(v); 1594 MatGetOwnershipRange(m, &first, &last); 1595 for (int row = first; row < last; row++) { 1596 MatGetRow(m, row, &n, &cols, PETSC_NULL); 1597 bool exists_off = false; 1598 for (int i = 0; i < n; i++) 1599 if (distr.get_proc(cols[i]) != distr.myp()) 1600 n_off++, exists_off = true; 1605 MatRestoreRow(m, row, &n, &cols, PETSC_NULL); 1621 void DarcyMH::read_initial_condition() 1623 double *local_sol = schur0->get_solution_array(); 1625 // cycle over local element rows 1627 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1628 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1629 auto ele_ac = mh_dh.accessor(i_loc_el); 1630 // set initial condition 1631 local_sol[ele_ac.ele_local_row()] = data_->init_pressure.value(ele_ac.centre(),ele_ac.element_accessor()); 1634 solution_changed_for_scatter=true; 1638 void DarcyMH::setup_time_term() { 1639 // save diagonal of steady matrix 1640 MatGetDiagonal(*( schur0->get_matrix() ), steady_diagonal); 1642 VecCopy(*( schur0->get_rhs()), steady_rhs); 1645 PetscScalar *local_diagonal; 1646 VecGetArray(new_diagonal,& local_diagonal); 1648 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1650 balance_->start_mass_assembly(water_balance_idx_); 1652 //DebugOut().fmt("time_term lsize: {} {}\n
", mh_dh.el_ds->myp(), mh_dh.el_ds->lsize()); 1653 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1654 auto ele_ac = mh_dh.accessor(i_loc_el); 1657 double diagonal_coeff = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor()) 1658 * data_->storativity.value(ele_ac.centre(), ele_ac.element_accessor()) 1660 local_diagonal[ele_ac.ele_local_row()]= - diagonal_coeff / time_->dt(); 1662 //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); 1663 balance_->add_mass_matrix_values(water_balance_idx_, 1664 ele_ac.region().bulk_idx(), { int(ele_ac.ele_row()) }, {diagonal_coeff}); 1666 VecRestoreArray(new_diagonal,& local_diagonal); 1667 MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES); 1669 solution_changed_for_scatter=true; 1670 schur0->set_matrix_changed(); 1672 balance_->finish_mass_assembly(water_balance_idx_); 1675 void DarcyMH::modify_system() { 1676 START_TIMER("modify system
"); 1677 if (time_->is_changed_dt() && time_->step().index()>0) { 1678 double scale_factor=time_->step(-2).length()/time_->step().length(); 1679 if (scale_factor != 1.0) { 1680 // if time step has changed and setup_time_term not called 1681 MatDiagonalSet(*( schur0->get_matrix() ),steady_diagonal, INSERT_VALUES); 1683 VecScale(new_diagonal, time_->last_dt()/time_->dt()); 1684 MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES); 1685 schur0->set_matrix_changed(); 1689 // modify RHS - add previous solution 1690 //VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, previous_solution); 1691 VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, schur0->get_solution()); 1692 VecAXPY(*( schur0->get_rhs()), 1.0, steady_rhs); 1693 schur0->set_rhs_changed(); 1695 //VecSwap(previous_solution, schur0->get_solution()); 1699 //----------------------------------------------------------------------------- 1700 // 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