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 ADD_FIELD(anisotropy,
"Anisotropy of the conductivity tensor.",
"1.0" );
189 ADD_FIELD(cross_section,
"Complement dimension parameter (cross section for 1D, thickness for 2D).",
"1.0" );
190 cross_section.units(
UnitSI().m(3).md() );
192 ADD_FIELD(conductivity,
"Isotropic conductivity scalar.",
"1.0" );
193 conductivity.units(
UnitSI().m().s(-1) ).set_limits(0.0);
195 ADD_FIELD(sigma,
"Transition coefficient between dimensions.",
"1.0");
198 ADD_FIELD(water_source_density,
"Water source density.",
"0.0");
199 water_source_density.units(
UnitSI().s(-1) );
201 ADD_FIELD(bc_type,
"Boundary condition type.",
"\"none\"" );
203 bc_type.input_selection( get_bc_type_selection() );
206 ADD_FIELD(bc_pressure,
"Prescribed pressure value on the boundary. Used for all values of ``bc_type`` except ``none`` and ``seepage``. " 207 "See documentation of ``bc_type`` for exact meaning of ``bc_pressure`` in individual boundary condition types.",
"0.0");
208 bc_pressure.disable_where(bc_type, {
none, seepage} );
209 bc_pressure.units(
UnitSI().m() );
211 ADD_FIELD(bc_flux,
"Incoming water boundary flux. Used for bc_types : ``total_flux``, ``seepage``, ``river``.",
"0.0");
212 bc_flux.disable_where(bc_type, {
none, dirichlet} );
213 bc_flux.units(
UnitSI().m(4).s(-1).md() );
215 ADD_FIELD(bc_robin_sigma,
"Conductivity coefficient in the ``total_flux`` or the ``river`` boundary condition type.",
"0.0");
216 bc_robin_sigma.disable_where(bc_type, {
none, dirichlet, seepage} );
217 bc_robin_sigma.units(
UnitSI().m(3).s(-1).md() );
220 "Critical switch pressure for ``seepage`` and ``river`` boundary conditions.",
"0.0");
221 bc_switch_pressure.disable_where(bc_type, {
none, dirichlet, total_flux} );
222 bc_switch_pressure.units(
UnitSI().m() );
225 ADD_FIELD(init_pressure,
"Initial condition for pressure in time dependent problems.",
"0.0" );
226 init_pressure.units(
UnitSI().m() );
228 ADD_FIELD(storativity,
"Storativity (in time dependent problems).",
"0.0" );
229 storativity.units(
UnitSI().m(-1) );
273 data_ = make_shared<EqData>();
306 gravity_array.copy_to(gvec);
308 data_->gravity_ = arma::vec(gvec);
309 data_->gravity_vec_ =
data_->gravity_.subvec(0,2);
311 data_->bc_pressure.add_factory(
313 (
data_->gravity_,
"bc_piezo_head") );
314 data_->bc_switch_pressure.add_factory(
316 (
data_->gravity_,
"bc_switch_piezo_head") );
317 data_->init_pressure.add_factory(
319 (
data_->gravity_,
"init_piezo_head") );
327 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
349 .val<Input::AbstractRecord>(
"linear_solver");
353 data_->system_.local_matrix = std::make_shared<arma::mat>();
399 if (zero_time_term_from_right) {
429 bool jump_time =
data_->storativity.is_jump_time();
430 if (! zero_time_term_from_left) {
440 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
449 if (! zero_time_term_from_left && ! jump_time)
output_data();
455 if (zero_time_term_from_right) {
460 }
else if (! zero_time_term_from_left && jump_time) {
461 WarningOut() <<
"Discontinuous time term not supported yet.\n";
472 return (
data_->storativity.input_list_size() == 0);
486 MessageOut().fmt(
"[nonlin solver] norm of initial residual: {}\n", residual_norm);
489 int is_linear_common;
494 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
495 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
496 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
498 if (! is_linear_common) {
506 while (nonlinear_iteration_ < this->min_n_it_ ||
507 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->max_n_it_ )) {
509 convergence_history.push_back(residual_norm);
512 if (convergence_history.size() >= 5 &&
513 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
514 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
520 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
524 if (! is_linear_common)
530 if (is_linear_common)
break;
549 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it:{} (reason: {}) residual: {}\n",
631 vec_size = this->
size;
632 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
638 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
656 START_TIMER(
"DarcyFlowMH_Steady::assembly_steady_mh_matrix");
663 bool fill_matrix = assembler.size() > 0;
664 int side_row, edge_row, loc_b = 0;
667 int side_rows[4], edge_rows[4];
671 for(
int i=0; i<1000; i++) zeros[i]=0.0;
673 double minus_ones[4] = { -1.0, -1.0, -1.0, -1.0 };
674 double * loc_side_rhs =
data_->system_.loc_side_rhs;
676 arma::mat &local_matrix = *(
data_->system_.local_matrix);
684 unsigned int nsides = ele_ac.n_sides();
685 data_->system_.dirichlet_edge.resize(nsides);
689 for (
unsigned int i = 0; i < nsides; i++) {
697 side_rows[i] = side_row = ele_ac.side_row(i);
698 edge_rows[i] = edge_row = ele_ac.edge_row(i);
707 data_->system_.dirichlet_edge[i] = 0;
713 double cross_section =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
718 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
720 loc_side_rhs[i] -= bc_pressure;
723 data_->system_.dirichlet_edge[i] = 1;
728 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
729 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
730 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
740 double bc_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
741 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
742 double side_flux=bc_flux * bcd->
element()->
measure() * cross_section;
745 if (switch_dirichlet) {
750 unsigned int loc_side_row = ele_ac.side_local_row(i);
753 if ( solution_flux < side_flux) {
755 solution_flux = side_flux;
770 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
773 if ( solution_head > bc_pressure) {
775 solution_head = bc_pressure;
785 loc_side_rhs[i] -= bc_pressure;
788 data_->system_.dirichlet_edge[i] = 1;
800 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
801 double bc_switch_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
802 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
803 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
805 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
818 double bc_total_flux = bc_flux + bc_sigma*(bc_switch_pressure - bc_pressure);
843 assembler[ele_ac.dim()-1]->assembly_local_matrix(ele_ac);
855 for(
unsigned int i=0; i < nsides; i++) {
856 double val_side = local_matrix(i,i);
857 double val_edge = -1./local_matrix(i,i);
859 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( side_rows[i], val_side );
860 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( edge_rows[i], val_edge );
869 ls->
mat_set_values(nsides, side_rows, nsides, side_rows, local_matrix.memptr());
871 int ele_row = ele_ac.ele_row();
882 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ele_row, val_ele );
887 for (
unsigned int i = 0; i < ele_ac.full_iter()->n_neighs_vb; i++) {
890 ngh= ele_ac.full_iter()->neigh_vb[i];
895 assembler[ngh->
side()->
dim()]->assembly_local_vb(local_vb, ele_ac.full_iter(), ngh);
901 int ind = tmp_rows[1];
903 double new_val = local_vb[0];
904 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ind, new_val );
915 tmp_rows[2+i] = tmp_rows[1];
924 n_neigh = ele_ac.full_iter()->n_neighs_vb;
926 OLD_ASSERT(n_neigh*n_neigh<1000,
"Too many values in E block.");
928 ele_ac.full_iter()->n_neighs_vb, tmp_rows+2, zeros);
932 ls->
mat_set_values(1, &ele_row, ele_ac.n_sides(), edge_rows, zeros);
933 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, 1, &ele_row, zeros);
935 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, ele_ac.n_sides(), edge_rows, zeros);
960 double cs =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
963 double source = ele_ac.measure() * cs *
964 data_->water_source_density.value(ele_ac.centre(), ele_ac.element_accessor());
975 vector<int> &dofs,
unsigned int &ele_type,
double &delta, arma::vec &dirichlet) {
979 if (i_ele == (
int)(ml_it_->size()) ) {
985 const Intersection &isect=intersections_[ (*ml_it_)[i_ele] ];
991 dirichlet.resize(ele->
n_sides());
994 for(
unsigned int i_side=0; i_side < ele->
n_sides(); i_side++ ) {
995 dofs[i_side]=darcy_.mh_dh.row_4_edge[ele->
side(i_side)->
edge_idx()];
1003 dofs[i_side] = -dofs[i_side];
1004 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.
centre(), b_ele);
1005 dirichlet[i_side] = bc_pressure;
1016 double delta_i, delta_j;
1018 arma::vec dirichlet_i, dirichlet_j;
1019 unsigned int ele_type_i, ele_type_j;
1024 for(ml_it_ = master_list_.begin(); ml_it_ != master_list_.end(); ++ml_it_) {
1026 if (ml_it_->size() == 0)
continue;
1042 master_ = intersections_[ml_it_->front()].master_iter();
1043 delta_0 = master_->measure();
1045 double master_sigma=darcy_.data_->sigma.value( master_->centre(), master_->element_accessor());
1048 double check_delta_sum=0;
1049 for(i = 0; i <= ml_it_->size(); ++i) {
1050 pressure_diff(i, dofs_i, ele_type_i, delta_i, dirichlet_i);
1051 check_delta_sum+=delta_i;
1053 for (j = 0; j <= ml_it_->size(); ++j) {
1054 pressure_diff(j, dofs_j, ele_type_j, delta_j, dirichlet_j);
1056 double scale = -master_sigma * delta_i * delta_j / delta_0;
1057 product = scale * tensor_average[ele_type_i][ele_type_j];
1059 arma::vec rhs(dofs_i.size());
1061 ls.
set_values( dofs_i, dofs_j, product, rhs, dirichlet_i, dirichlet_j);
1067 OLD_ASSERT(check_delta_sum < 1E-5*delta_0, "sum err %f > 0\n
", check_delta_sum/delta_0); 1068 } // loop over master elements 1073 void P1_CouplingAssembler::add_sides(const Element * ele, unsigned int shift, vector<int> &dofs, vector<double> &dirichlet) 1076 for(unsigned int i_side=0; i_side < ele->n_sides(); i_side++ ) { 1077 dofs[shift+i_side] = darcy_.mh_dh.row_4_edge[ele->side(i_side)->edge_idx()]; 1078 Boundary * bcd = ele->side(i_side)->cond(); 1081 ElementAccessor<3> b_ele = bcd->element_accessor(); 1082 auto type = (DarcyMH::EqData::BC_Type)darcy_.data_->bc_type.value(b_ele.centre(), b_ele); 1083 //DebugOut().fmt("bcd
id: {} sidx: {} type: {}\n
", ele->id(), i_side, type); 1084 if (type == DarcyMH::EqData::dirichlet) { 1085 //DebugOut().fmt("Dirichlet: {}\n
", ele->index()); 1086 dofs[shift + i_side] = -dofs[shift + i_side]; 1087 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.centre(), b_ele); 1088 dirichlet[shift + i_side] = bc_pressure; 1101 void P1_CouplingAssembler::assembly(LinSys &ls) {
1103 for (const Intersection &intersec : intersections_) {
1104 const Element * master = intersec.master_iter();
1105 const Element * slave = intersec.slave_iter();
1107 add_sides(slave, 0, dofs, dirichlet);
1108 add_sides(master, 3, dofs, dirichlet);
1110 double master_sigma=darcy_.data_->sigma.value( master->centre(), master->element_accessor());
1113 * Local coordinates on 1D
1119 * t0 = 0.0 on side 0 node 0
1120 * t0 = 1.0 on side 1 node 1
1122 * Local coordinates on 2D
1129 * t0=0.5, t1=0.0 on side 0 nodes (0,1)
1130 * t0=0.5, t1=0.5 on side 1 nodes (1,2)
1131 * t0=0.0, t1=0.5 on side 2 nodes (2,0)
1136 arma::vec point_Y(1);
1138 arma::vec point_2D_Y(intersec.map_to_slave(point_Y)); // local coordinates of Y on slave (1, t0, t1)
1139 arma::vec point_1D_Y(intersec.map_to_master(point_Y)); // local coordinates of Y on master (1, t0)
1141 arma::vec point_X(1);
1143 arma::vec point_2D_X(intersec.map_to_slave(point_X)); // local coordinates of X on slave (1, t0, t1)
1144 arma::vec point_1D_X(intersec.map_to_master(point_X)); // local coordinates of X on master (1, t0)
1146 arma::mat base_2D(3, 3);
1147 // basis functions are numbered as sides
1149 // Use RT finite element to evaluate following matrices.
1151 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1152 // 2D RT_i(t0, t1) = a0 + a1*t0 + a2*t1
1154 base_2D << 1.0 << 0.0 << -2.0 << arma::endr // RT for side 0
1155 << 1.0 << -2.0 << 0.0 << arma::endr // RT for side 1
1156 << -1.0 << 2.0 << 2.0 << arma::endr;// RT for side 2
1159 arma::mat base_1D(2, 2);
1160 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1161 // 1D RT_i(t0) = a0 + a1 * t0
1163 base_1D << 1.0 << -1.0 << arma::endr // RT for side 0,
1164 << 0.0 << 1.0 << arma::endr; // RT for side 1,
1168 // Consider both 2D and 1D value are defined for the test function
1169 // related to the each of 5 DOFs involved in the intersection.
1170 // One of these values is always zero.
1171 // Compute difference of the 2D and 1D value for every DOF.
1172 // Compute value of this difference in both endpoints X,Y of the intersection.
1174 arma::vec difference_in_Y(5);
1175 arma::vec difference_in_X(5);
1176 // slave sides 0,1,2
1177 difference_in_Y.subvec(0, 2) = -base_2D * point_2D_Y;
1178 difference_in_X.subvec(0, 2) = -base_2D * point_2D_X;
1180 difference_in_Y.subvec(3, 4) = base_1D * point_1D_Y;
1181 difference_in_X.subvec(3, 4) = base_1D * point_1D_X;
1183 // applying the Simpson's rule
1184 // to the product of two linear functions f, g we get
1185 // (b-a)/6 * ( 3*f(a)*g(a) + 3*f(b)*g(b) + 2*f(a)*g(b) + 2*f(b)*g(a) )
1187 for (int i = 0; i < 5; ++i) {
1188 for (int j = 0; j < 5; ++j) {
1189 A(i, j) = -master_sigma * intersec.intersection_true_size() *
1190 ( difference_in_Y[i] * difference_in_Y[j]
1191 + difference_in_Y[i] * difference_in_X[j]/2
1192 + difference_in_X[i] * difference_in_Y[j]/2
1193 + difference_in_X[i] * difference_in_X[j]
1199 ls.set_values( dofs_cp, dofs_cp, A, rhs, dirichlet, dirichlet);
1206 /*******************************************************************************
1207 * COMPOSE WATER MH MATRIX WITHOUT SCHUR COMPLEMENT
1208 ******************************************************************************/
1210 void DarcyMH::create_linear_system(Input::AbstractRecord in_rec) {
1212 START_TIMER("preallocation
"); 1214 if (schur0 == NULL) { // create Linear System for MH matrix 1216 if (in_rec.type() == LinSys_BDDC::get_input_type()) { 1217 #ifdef FLOW123D_HAVE_BDDCML 1218 WarningOut() << "For BDDC no Schur complements are used.
"; 1219 mh_dh.prepare_parallel_bddc(); 1221 LinSys_BDDC *ls = new LinSys_BDDC(mh_dh.global_row_4_sub_row->size(), &(*mh_dh.rows_ds), 1222 3, // 3 == la::BddcmlWrapper::SPD_VIA_SYMMETRICGENERAL 1223 1, // 1 == number of subdomains per process 1224 true); // swap signs of matrix and rhs to make the matrix SPD 1225 ls->set_from_input(in_rec); 1226 ls->set_solution( NULL ); 1227 // possible initialization particular to BDDC 1229 set_mesh_data_for_bddc(ls); 1233 xprintf(Err, "Flow123d was not build with BDDCML support.\n
"); 1234 #endif // FLOW123D_HAVE_BDDCML 1236 else if (in_rec.type() == LinSys_PETSC::get_input_type()) { 1237 // use PETSC for serial case even when user wants BDDC 1238 if (n_schur_compls > 2) { 1239 WarningOut() << "Invalid number of Schur Complements. Using 2.
"; 1243 LinSys_PETSC *schur1, *schur2; 1245 if (n_schur_compls == 0) { 1246 LinSys_PETSC *ls = new LinSys_PETSC( &(*mh_dh.rows_ds) ); 1248 // temporary solution; we have to set precision also for sequantial case of BDDC 1249 // final solution should be probably call of direct solver for oneproc case 1250 if (in_rec.type() != LinSys_BDDC::get_input_type()) ls->set_from_input(in_rec); 1252 ls->LinSys::set_from_input(in_rec); // get only common options 1255 ls->set_solution( NULL ); 1259 ISCreateStride(PETSC_COMM_WORLD, mh_dh.side_ds->lsize(), mh_dh.rows_ds->begin(), 1, &is); 1260 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1262 SchurComplement *ls = new SchurComplement(is, &(*mh_dh.rows_ds)); 1265 Distribution *ds = ls->make_complement_distribution(); 1266 if (n_schur_compls==1) { 1267 schur1 = new LinSys_PETSC(ds); 1268 schur1->set_positive_definite(); 1271 ISCreateStride(PETSC_COMM_WORLD, mh_dh.el_ds->lsize(), ls->get_distribution()->begin(), 1, &is); 1272 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1273 SchurComplement *ls1 = new SchurComplement(is, ds); // is is deallocated by SchurComplement 1274 ls1->set_negative_definite(); 1277 schur2 = new LinSys_PETSC( ls1->make_complement_distribution() ); 1278 schur2->set_positive_definite(); 1279 ls1->set_complement( schur2 ); 1282 ls->set_complement( schur1 ); 1283 ls->set_from_input(in_rec); 1284 ls->set_solution( NULL ); 1288 START_TIMER("PETSC PREALLOCATION
"); 1289 schur0->set_symmetric(); 1290 schur0->start_allocation(); 1291 assembly_mh_matrix(MultidimAssembler()); // preallocation 1292 VecZeroEntries(schur0->get_solution()); 1293 END_TIMER("PETSC PREALLOCATION
"); 1296 xprintf(Err, "Unknown solver type. Internal error.\n
"); 1299 END_TIMER("preallocation
"); 1300 make_serial_scatter(); 1309 void DarcyMH::assembly_linear_system() { 1310 START_TIMER("DarcyFlowMH_Steady::assembly_linear_system
"); 1313 bool is_steady = zero_time_term(); 1314 //DebugOut() << "Assembly linear system\n
"; 1315 if (data_changed_) { 1316 data_changed_ = false; 1317 //DebugOut() << "Data changed\n
"; 1318 // currently we have no optimization for cases when just time term data or RHS data are changed 1319 START_TIMER("full assembly
"); 1320 if (typeid(*schur0) != typeid(LinSys_BDDC)) { 1321 schur0->start_add_assembly(); // finish allocation and create matrix 1324 auto multidim_assembler = AssemblyBase::create< AssemblyMH >(data_); 1326 schur0->mat_zero_entries(); 1327 schur0->rhs_zero_entries(); 1329 assembly_source_term(); 1330 assembly_mh_matrix( multidim_assembler ); // fill matrix 1332 schur0->finish_assembly(); 1333 schur0->set_matrix_changed(); 1334 //MatView( *const_cast<Mat*>(schur0->get_matrix()), PETSC_VIEWER_STDOUT_WORLD ); 1335 //VecView( *const_cast<Vec*>(schur0->get_rhs()), PETSC_VIEWER_STDOUT_WORLD); 1338 START_TIMER("fix
time term
"); 1339 //DebugOut() << "setup
time term\n
"; 1340 // assembly time term and rhs 1346 balance_->start_mass_assembly(water_balance_idx_); 1347 balance_->finish_mass_assembly(water_balance_idx_); 1349 END_TIMER("full assembly
"); 1351 START_TIMER("modify system
"); 1355 //xprintf(PrgErr, "Planned computation
time for steady solver, but
data are not changed.\n
"); 1357 END_TIMER("modiffy system
"); 1364 void DarcyMH::set_mesh_data_for_bddc(LinSys_BDDC * bddc_ls) { 1365 START_TIMER("DarcyFlowMH_Steady::set_mesh_data_for_bddc
"); 1366 // prepare mesh for BDDCML 1367 // initialize arrays 1368 // auxiliary map for creating coordinates of local dofs and global-to-local numbering 1369 std::map<int,arma::vec3> localDofMap; 1370 // connectivity for the subdomain, i.e. global dof numbers on element, stored element-by-element 1371 // Indices of Nodes on Elements 1372 std::vector<int> inet; 1373 // number of degrees of freedom on elements - determines elementwise chunks of INET array 1374 // Number of Nodes on Elements 1375 std::vector<int> nnet; 1376 // Indices of Subdomain Elements in Global Numbering - for local elements, their global indices 1377 std::vector<int> isegn; 1379 // This array is currently not used in BDDCML, it was used as an interface scaling alternative to scaling 1380 // by diagonal. It corresponds to the rho-scaling. 1381 std::vector<double> element_permeability; 1383 // maximal and minimal dimension of elements 1386 for ( unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++ ) { 1387 auto ele_ac = mh_dh.accessor(i_loc); 1388 // for each element, create local numbering of dofs as fluxes (sides), pressure (element centre), Lagrange multipliers (edges), compatible connections 1390 elDimMax = std::max( elDimMax, ele_ac.dim() ); 1391 elDimMin = std::min( elDimMin, ele_ac.dim() ); 1393 isegn.push_back( ele_ac.ele_global_idx() ); 1396 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1397 // insert local side dof 1398 int side_row = ele_ac.side_row(si); 1399 arma::vec3 coord = ele_ac.side(si)->centre(); 1401 localDofMap.insert( std::make_pair( side_row, coord ) ); 1402 inet.push_back( side_row ); 1406 // insert local pressure dof 1407 int el_row = ele_ac.ele_row(); 1408 arma::vec3 coord = ele_ac.centre(); 1409 localDofMap.insert( std::make_pair( el_row, coord ) ); 1410 inet.push_back( el_row ); 1413 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1414 // insert local edge dof 1415 int edge_row = ele_ac.edge_row(si); 1416 arma::vec3 coord = ele_ac.side(si)->centre(); 1418 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1419 inet.push_back( edge_row ); 1423 // insert dofs related to compatible connections 1424 for ( unsigned int i_neigh = 0; i_neigh < ele_ac.full_iter()->n_neighs_vb; i_neigh++) { 1425 int edge_row = mh_dh.row_4_edge[ ele_ac.full_iter()->neigh_vb[i_neigh]->edge_idx() ]; 1426 arma::vec3 coord = ele_ac.full_iter()->neigh_vb[i_neigh]->edge()->side(0)->centre(); 1428 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1429 inet.push_back( edge_row ); 1433 nnet.push_back( nne ); 1435 // version for rho scaling 1436 // trace computation 1437 arma::vec3 centre = ele_ac.centre(); 1438 double conduct = data_->conductivity.value( centre , ele_ac.element_accessor() ); 1439 auto aniso = data_->anisotropy.value( centre, ele_ac.element_accessor() ); 1441 // compute mean on the diagonal 1443 for ( int i = 0; i < 3; i++) { 1444 coef = coef + aniso.at(i,i); 1446 // Maybe divide by cs 1447 coef = conduct*coef / 3; 1449 OLD_ASSERT( coef > 0., 1450 "Zero coefficient of hydrodynamic resistance %f . \n
", coef ); 1451 element_permeability.push_back( 1. / coef ); 1453 //convert set of dofs to vectors 1454 // number of nodes (= dofs) on the subdomain 1455 int numNodeSub = localDofMap.size(); 1456 OLD_ASSERT_EQUAL( (unsigned int)numNodeSub, mh_dh.global_row_4_sub_row->size() ); 1457 // Indices of Subdomain Nodes in Global Numbering - for local nodes, their global indices 1458 std::vector<int> isngn( numNodeSub ); 1459 // pseudo-coordinates of local nodes (i.e. dofs) 1460 // they need not be exact, they are used just for some geometrical considerations in BDDCML, 1461 // such as selection of corners maximizing area of a triangle, bounding boxes fro subdomains to 1462 // find candidate neighbours etc. 1463 std::vector<double> xyz( numNodeSub * 3 ) ; 1465 std::map<int,arma::vec3>::iterator itB = localDofMap.begin(); 1466 for ( ; itB != localDofMap.end(); ++itB ) { 1467 isngn[ind] = itB -> first; 1469 arma::vec3 coord = itB -> second; 1470 for ( int j = 0; j < 3; j++ ) { 1471 xyz[ j*numNodeSub + ind ] = coord[j]; 1476 localDofMap.clear(); 1478 // Number of Nodal Degrees of Freedom 1479 // nndf is trivially one - dofs coincide with nodes 1480 std::vector<int> nndf( numNodeSub, 1 ); 1482 // prepare auxiliary map for renumbering nodes 1483 typedef std::map<int,int> Global2LocalMap_; //! type for storage of global to local map 1484 Global2LocalMap_ global2LocalNodeMap; 1485 for ( unsigned ind = 0; ind < isngn.size(); ++ind ) { 1486 global2LocalNodeMap.insert( std::make_pair( static_cast<unsigned>( isngn[ind] ), ind ) ); 1489 // renumber nodes in the inet array to locals 1491 for ( unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) { 1492 int nne = nnet[ iEle ]; 1493 for ( int ien = 0; ien < nne; ien++ ) { 1495 int indGlob = inet[indInet]; 1496 // map it to local node 1497 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob ); 1498 OLD_ASSERT( pos != global2LocalNodeMap.end(), 1499 "Cannot remap node index %d to local indices. \n
", indGlob ); 1500 int indLoc = static_cast<int> ( pos -> second ); 1503 inet[ indInet++ ] = indLoc; 1507 int numNodes = size; 1508 int numDofsInt = size; 1509 int spaceDim = 3; // TODO: what is the proper value here? 1510 int meshDim = elDimMax; 1512 bddc_ls -> load_mesh( spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim ); 1518 //============================================================================= 1519 // DESTROY WATER MH SYSTEM STRUCTURE 1520 //============================================================================= 1521 DarcyMH::~DarcyMH() { 1522 if (schur0 != NULL) { 1524 VecScatterDestroy(&par_to_all); 1527 if (solution != NULL) { 1528 chkerr(VecDestroy(&sol_vec)); 1532 if (output_object) delete output_object; 1539 // ================================================ 1544 void DarcyMH::make_serial_scatter() { 1545 START_TIMER("prepare scatter
"); 1546 // prepare Scatter form parallel to sequantial in original numbering 1549 int i, *loc_idx; //, si; 1551 // create local solution vector 1552 solution = new double[size]; 1553 VecCreateSeqWithArray(PETSC_COMM_SELF,1, size, solution, 1556 // create seq. IS to scatter par solutin to seq. vec. in original order 1557 // use essentialy row_4_id arrays 1558 loc_idx = new int [size]; 1560 FOR_ELEMENTS(mesh_, ele) { 1561 FOR_ELEMENT_SIDES(ele,si) { 1562 loc_idx[i++] = mh_dh.side_row_4_id[ mh_dh.side_dof( ele->side(si) ) ]; 1565 FOR_ELEMENTS(mesh_, ele) { 1566 loc_idx[i++] = mh_dh.row_4_el[ele.index()]; 1568 for(unsigned int i_edg=0; i_edg < mesh_->n_edges(); i_edg++) { 1569 loc_idx[i++] = mh_dh.row_4_edge[i_edg]; 1571 OLD_ASSERT( i==size,"Size of array does not match number of fills.\n
"); 1572 //DBGPRINT_INT("loc_idx
",size,loc_idx); 1573 ISCreateGeneral(PETSC_COMM_SELF, size, loc_idx, PETSC_COPY_VALUES, &(is_loc)); 1575 VecScatterCreate(schur0->get_solution(), is_loc, sol_vec, 1576 PETSC_NULL, &par_to_all); 1577 ISDestroy(&(is_loc)); 1579 solution_changed_for_scatter=true; 1581 END_TIMER("prepare scatter
"); 1587 void mat_count_off_proc_values(Mat m, Vec v) { 1589 const PetscInt *cols; 1590 Distribution distr(v); 1595 MatGetOwnershipRange(m, &first, &last); 1596 for (int row = first; row < last; row++) { 1597 MatGetRow(m, row, &n, &cols, PETSC_NULL); 1598 bool exists_off = false; 1599 for (int i = 0; i < n; i++) 1600 if (distr.get_proc(cols[i]) != distr.myp()) 1601 n_off++, exists_off = true; 1606 MatRestoreRow(m, row, &n, &cols, PETSC_NULL); 1622 void DarcyMH::read_initial_condition() 1624 double *local_sol = schur0->get_solution_array(); 1626 // cycle over local element rows 1628 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1629 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1630 auto ele_ac = mh_dh.accessor(i_loc_el); 1631 // set initial condition 1632 local_sol[ele_ac.ele_local_row()] = data_->init_pressure.value(ele_ac.centre(),ele_ac.element_accessor()); 1635 solution_changed_for_scatter=true; 1639 void DarcyMH::setup_time_term() { 1640 // save diagonal of steady matrix 1641 MatGetDiagonal(*( schur0->get_matrix() ), steady_diagonal); 1643 VecCopy(*( schur0->get_rhs()), steady_rhs); 1646 PetscScalar *local_diagonal; 1647 VecGetArray(new_diagonal,& local_diagonal); 1649 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1651 balance_->start_mass_assembly(water_balance_idx_); 1653 //DebugOut().fmt("time_term lsize: {} {}\n
", mh_dh.el_ds->myp(), mh_dh.el_ds->lsize()); 1654 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1655 auto ele_ac = mh_dh.accessor(i_loc_el); 1658 double diagonal_coeff = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor()) 1659 * data_->storativity.value(ele_ac.centre(), ele_ac.element_accessor()) 1661 local_diagonal[ele_ac.ele_local_row()]= - diagonal_coeff / time_->dt(); 1663 //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); 1664 balance_->add_mass_matrix_values(water_balance_idx_, 1665 ele_ac.region().bulk_idx(), { int(ele_ac.ele_row()) }, {diagonal_coeff}); 1667 VecRestoreArray(new_diagonal,& local_diagonal); 1668 MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES); 1670 solution_changed_for_scatter=true; 1671 schur0->set_matrix_changed(); 1673 balance_->finish_mass_assembly(water_balance_idx_); 1676 void DarcyMH::modify_system() { 1677 START_TIMER("modify system
"); 1678 if (time_->is_changed_dt() && time_->step().index()>0) { 1679 double scale_factor=time_->step(-2).length()/time_->step().length(); 1680 if (scale_factor != 1.0) { 1681 // if time step has changed and setup_time_term not called 1682 MatDiagonalSet(*( schur0->get_matrix() ),steady_diagonal, INSERT_VALUES); 1684 VecScale(new_diagonal, time_->last_dt()/time_->dt()); 1685 MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES); 1686 schur0->set_matrix_changed(); 1690 // modify RHS - add previous solution 1691 //VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, previous_solution); 1692 VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, schur0->get_solution()); 1693 VecAXPY(*( schur0->get_rhs()), 1.0, steady_rhs); 1694 schur0->set_rhs_changed(); 1696 //VecSwap(previous_solution, schur0->get_solution()); 1700 //----------------------------------------------------------------------------- 1701 // 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