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. Caution! Setting $q_d^N$ strictly negative" 103 "may lead to an ill posed problem since a positive outflow is enforced." 104 "Parameters (($h_d^D$)) and (($q_d^N$)) are given by fields ``bc_pressure`` (or ``bc_piezo_head``) and ``bc_flux`` respectively." 107 "River boundary condition. For the water level above the bedrock, (($H > H^S$)), the Robin boundary condition is used with the inflow given by: " 108 "(( $q^N + \\sigma(H^D - H)$)). For the water level under the bedrock, constant infiltration is used " 109 "(( $q^N + \\sigma(H^D - H^S)$)). Parameters: ``bc_pressure``, ``bc_switch_pressure``," 110 " ``bc_sigma, ``bc_flux``." 121 "Boundary piezometric head for BC types: dirichlet, robin, and river." )
123 "Boundary switch piezometric head for BC types: seepage, river." )
125 "Initial condition for the pressure given as the piezometric head." )
127 return field_descriptor;
134 "Linear solver for MH problem.")
136 "Residual tolerance.")
138 "Maximal number of iterations (linear solves) of the non-linear solver.")
140 "If a stagnation of the nonlinear solver is detected the solver stops. " 141 "A divergence is reported by default forcing the end of the simulation. Setting this flag to 'true', the solver" 142 "ends with convergence success on stagnation, but report warning about it.")
145 return it::Record(
"Flow_Darcy_MH",
"Mixed-Hybrid solver for STEADY saturated Darcy flow.")
148 "Vector of the gravitational acceleration (divided by the acceleration). Dimensionless, magnitude one for the Earth conditions.")
150 "Input data for Darcy flow model.")
152 "Non-linear solver for MH problem.")
154 "Parameters of output stream.")
157 "Parameters of output from MH module.")
159 "Parameters of output form MH module.")
161 "Settings for computing mass balance.")
163 "Time governor setting for the unsteady Darcy flow model.")
165 "Number of Schur complements to perform when solving MH system.")
167 "Method for coupling Darcy flow between dimensions." )
173 Input::register_class< DarcyMH, Mesh &, const Input::Record >(
"Flow_Darcy_MH") +
180 ADD_FIELD(anisotropy,
"Anisotropy of the conductivity tensor.",
"1.0" );
183 ADD_FIELD(cross_section,
"Complement dimension parameter (cross section for 1D, thickness for 2D).",
"1.0" );
184 cross_section.units(
UnitSI().m(3).md() );
186 ADD_FIELD(conductivity,
"Isotropic conductivity scalar.",
"1.0" );
187 conductivity.units(
UnitSI().m().s(-1) );
189 ADD_FIELD(sigma,
"Transition coefficient between dimensions.",
"1.0");
192 ADD_FIELD(water_source_density,
"Water source density.",
"0.0");
193 water_source_density.units(
UnitSI().s(-1) );
195 ADD_FIELD(bc_type,
"Boundary condition type, possible values:",
"\"none\"" );
197 bc_type.input_selection( get_bc_type_selection() );
200 ADD_FIELD(bc_pressure,
"Prescribed pressure value on the boundary. Used for all values of 'bc_type' save the bc_type='none'." 201 "See documentation of 'bc_type' for exact meaning of 'bc_pressure' in individual boundary condition types.",
"0.0");
202 bc_pressure.disable_where(bc_type, {
none} );
203 bc_pressure.units(
UnitSI().m() );
205 ADD_FIELD(bc_flux,
"Incoming water boundary flux. Used for bc_types : 'none', 'total_flux', 'seepage', 'river'.",
"0.0");
206 bc_flux.disable_where(bc_type, {
none, dirichlet} );
207 bc_flux.units(
UnitSI().m(4).s(-1).md() );
209 ADD_FIELD(bc_robin_sigma,
"Conductivity coefficient in the 'total_flux' or the 'river' boundary condition type.",
"0.0");
210 bc_robin_sigma.disable_where(bc_type, {
none, dirichlet, seepage} );
211 bc_robin_sigma.units(
UnitSI().m(3).s(-1).md() );
214 "Critical switch pressure for 'seepage' and 'river' boundary conditions.",
"0.0");
215 bc_switch_pressure.disable_where(bc_type, {
none, dirichlet, total_flux} );
216 bc_switch_pressure.units(
UnitSI().m() );
219 ADD_FIELD(init_pressure,
"Initial condition as pressure",
"0.0" );
220 init_pressure.units(
UnitSI().m() );
222 ADD_FIELD(storativity,
"Storativity.",
"0.0" );
223 storativity.units(
UnitSI().m(-1) );
259 if ( in_rec.
opt_val(
"time", time_record) )
265 data_ = make_shared<EqData>();
298 gravity_array.copy_to(gvec);
300 data_->gravity_ = arma::vec(gvec);
301 data_->gravity_vec_ =
data_->gravity_.subvec(0,2);
303 data_->bc_pressure.add_factory(
305 (
data_->gravity_,
"bc_piezo_head") );
306 data_->bc_switch_pressure.add_factory(
308 (
data_->gravity_,
"bc_switch_piezo_head") );
330 .val<Input::AbstractRecord>(
"linear_solver");
334 data_->system_.local_matrix = std::make_shared<arma::mat>();
382 if (zero_time_term_from_right) {
412 bool jump_time =
data_->storativity.is_jump_time();
413 if (! zero_time_term_from_left) {
423 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
432 if (! zero_time_term_from_left && ! jump_time)
output_data();
438 if (zero_time_term_from_right) {
443 }
else if (! zero_time_term_from_left && jump_time) {
444 WarningOut() <<
"Discontinuous time term not supported yet.\n";
466 MessageOut().fmt(
"[nonlin solver] norm of initial residual: {}\n", residual_norm);
469 int is_linear_common;
474 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
476 if (! is_linear_common) {
484 while (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->max_n_it_) {
486 convergence_history.push_back(residual_norm);
489 if (convergence_history.size() >= 5 &&
490 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
491 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
497 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
501 if (! is_linear_common)
507 if (is_linear_common)
break;
519 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it:{} (reason: {}) residual: {}\n",
614 vec_size = this->
size;
615 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
621 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
639 START_TIMER(
"DarcyFlowMH_Steady::assembly_steady_mh_matrix");
646 bool fill_matrix = assembler.size() > 0;
647 int side_row, edge_row, loc_b = 0;
650 int side_rows[4], edge_rows[4];
654 for(
int i=0; i<1000; i++) zeros[i]=0.0;
656 double minus_ones[4] = { -1.0, -1.0, -1.0, -1.0 };
657 double * loc_side_rhs =
data_->system_.loc_side_rhs;
659 arma::mat &local_matrix = *(
data_->system_.local_matrix);
662 if (
balance_ !=
nullptr && fill_matrix)
667 unsigned int nsides = ele_ac.n_sides();
668 data_->system_.dirichlet_edge.resize(nsides);
672 for (
unsigned int i = 0; i < nsides; i++) {
680 side_rows[i] = side_row = ele_ac.side_row(i);
681 edge_rows[i] = edge_row = ele_ac.edge_row(i);
690 data_->system_.dirichlet_edge[i] = 0;
696 double cross_section =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
701 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
703 loc_side_rhs[i] -= bc_pressure;
706 data_->system_.dirichlet_edge[i] = 1;
710 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
711 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
712 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
721 double bc_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
722 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
723 double side_flux=bc_flux * bcd->
element()->
measure() * cross_section;
726 if (switch_dirichlet) {
731 unsigned int loc_side_row = ele_ac.side_local_row(i);
734 if ( solution_flux < side_flux) {
736 solution_flux = side_flux;
751 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
754 if ( solution_head > bc_pressure) {
756 solution_head = bc_pressure;
766 loc_side_rhs[i] -= bc_pressure;
769 data_->system_.dirichlet_edge[i] = 1;
781 double bc_pressure =
data_->bc_pressure.value(b_ele.
centre(), b_ele);
782 double bc_switch_pressure =
data_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
783 double bc_flux = -
data_->bc_flux.value(b_ele.
centre(), b_ele);
784 double bc_sigma =
data_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
786 unsigned int loc_edge_row = ele_ac.edge_local_row(i);
799 double bc_total_flux = bc_flux + bc_sigma*(bc_switch_pressure - bc_pressure);
806 if (
balance_ !=
nullptr && fill_matrix)
824 assembler[ele_ac.dim()-1]->assembly_local_matrix(ele_ac);
836 for(
unsigned int i=0; i < nsides; i++) {
837 double val_side = local_matrix(i,i);
838 double val_edge = -1./local_matrix(i,i);
840 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( side_rows[i], val_side );
841 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( edge_rows[i], val_edge );
850 ls->
mat_set_values(nsides, side_rows, nsides, side_rows, local_matrix.memptr());
852 int ele_row = ele_ac.ele_row();
863 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ele_row, val_ele );
868 for (
unsigned int i = 0; i < ele_ac.full_iter()->n_neighs_vb; i++) {
871 ngh= ele_ac.full_iter()->neigh_vb[i];
876 assembler[ngh->
side()->
dim()]->assembly_local_vb(local_vb, ele_ac.full_iter(), ngh);
882 int ind = tmp_rows[1];
884 double new_val = local_vb[0];
885 static_cast<LinSys_BDDC*
>(ls)->diagonal_weights_set_value( ind, new_val );
896 tmp_rows[2+i] = tmp_rows[1];
905 n_neigh = ele_ac.full_iter()->n_neighs_vb;
907 OLD_ASSERT(n_neigh*n_neigh<1000,
"Too many values in E block.");
909 ele_ac.full_iter()->n_neighs_vb, tmp_rows+2, zeros);
913 ls->
mat_set_values(1, &ele_row, ele_ac.n_sides(), edge_rows, zeros);
914 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, 1, &ele_row, zeros);
916 ls->
mat_set_values(ele_ac.n_sides(), edge_rows, ele_ac.n_sides(), edge_rows, zeros);
920 if (
balance_ !=
nullptr && fill_matrix)
942 double cs =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
945 double source = ele_ac.measure() * cs *
946 data_->water_source_density.value(ele_ac.centre(), ele_ac.element_accessor());
959 vector<int> &dofs,
unsigned int &ele_type,
double &delta, arma::vec &dirichlet) {
963 if (i_ele == (
int)(ml_it_->size()) ) {
969 const Intersection &isect=intersections_[ (*ml_it_)[i_ele] ];
975 dirichlet.resize(ele->
n_sides());
978 for(
unsigned int i_side=0; i_side < ele->
n_sides(); i_side++ ) {
979 dofs[i_side]=darcy_.mh_dh.row_4_edge[ele->
side(i_side)->
edge_idx()];
987 dofs[i_side] = -dofs[i_side];
988 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.
centre(), b_ele);
989 dirichlet[i_side] = bc_pressure;
1000 double delta_i, delta_j;
1002 arma::vec dirichlet_i, dirichlet_j;
1003 unsigned int ele_type_i, ele_type_j;
1008 for(ml_it_ = master_list_.begin(); ml_it_ != master_list_.end(); ++ml_it_) {
1010 if (ml_it_->size() == 0)
continue;
1026 master_ = intersections_[ml_it_->front()].master_iter();
1027 delta_0 = master_->measure();
1029 double master_sigma=darcy_.data_->sigma.value( master_->centre(), master_->element_accessor());
1032 double check_delta_sum=0;
1033 for(i = 0; i <= ml_it_->size(); ++i) {
1034 pressure_diff(i, dofs_i, ele_type_i, delta_i, dirichlet_i);
1035 check_delta_sum+=delta_i;
1037 for (j = 0; j <= ml_it_->size(); ++j) {
1038 pressure_diff(j, dofs_j, ele_type_j, delta_j, dirichlet_j);
1040 double scale = -master_sigma * delta_i * delta_j / delta_0;
1041 product = scale * tensor_average[ele_type_i][ele_type_j];
1043 arma::vec rhs(dofs_i.size());
1045 ls.
set_values( dofs_i, dofs_j, product, rhs, dirichlet_i, dirichlet_j);
1046 auto dofs_i_cp=dofs_i;
1047 auto dofs_j_cp=dofs_j;
1048 ls.
set_values( dofs_i_cp, dofs_j_cp, product, rhs, dirichlet_i, dirichlet_j);
1051 OLD_ASSERT(check_delta_sum < 1E-5*delta_0, "sum err %f > 0\n
", check_delta_sum/delta_0); 1052 } // loop over master elements 1057 void P1_CouplingAssembler::add_sides(const Element * ele, unsigned int shift, vector<int> &dofs, vector<double> &dirichlet) 1060 for(unsigned int i_side=0; i_side < ele->n_sides(); i_side++ ) { 1061 dofs[shift+i_side] = darcy_.mh_dh.row_4_edge[ele->side(i_side)->edge_idx()]; 1062 Boundary * bcd = ele->side(i_side)->cond(); 1065 ElementAccessor<3> b_ele = bcd->element_accessor(); 1066 auto type = (DarcyMH::EqData::BC_Type)darcy_.data_->bc_type.value(b_ele.centre(), b_ele); 1067 //DebugOut().fmt("bcd
id: {} sidx: {} type: {}\n
", ele->id(), i_side, type); 1068 if (type == DarcyMH::EqData::dirichlet) { 1069 //DebugOut().fmt("Dirichlet: {}\n
", ele->index()); 1070 dofs[shift + i_side] = -dofs[shift + i_side]; 1071 double bc_pressure = darcy_.data_->bc_pressure.value(b_ele.centre(), b_ele); 1072 dirichlet[shift + i_side] = bc_pressure; 1085 void P1_CouplingAssembler::assembly(LinSys &ls) {
1087 for (const Intersection &intersec : intersections_) {
1088 const Element * master = intersec.master_iter();
1089 const Element * slave = intersec.slave_iter();
1091 add_sides(slave, 0, dofs, dirichlet);
1092 add_sides(master, 3, dofs, dirichlet);
1094 double master_sigma=darcy_.data_->sigma.value( master->centre(), master->element_accessor());
1097 * Local coordinates on 1D
1103 * t0 = 0.0 on side 0 node 0
1104 * t0 = 1.0 on side 1 node 1
1106 * Local coordinates on 2D
1113 * t0=0.5, t1=0.0 on side 0 nodes (0,1)
1114 * t0=0.5, t1=0.5 on side 1 nodes (1,2)
1115 * t0=0.0, t1=0.5 on side 2 nodes (2,0)
1120 arma::vec point_Y(1);
1122 arma::vec point_2D_Y(intersec.map_to_slave(point_Y)); // local coordinates of Y on slave (1, t0, t1)
1123 arma::vec point_1D_Y(intersec.map_to_master(point_Y)); // local coordinates of Y on master (1, t0)
1125 arma::vec point_X(1);
1127 arma::vec point_2D_X(intersec.map_to_slave(point_X)); // local coordinates of X on slave (1, t0, t1)
1128 arma::vec point_1D_X(intersec.map_to_master(point_X)); // local coordinates of X on master (1, t0)
1130 arma::mat base_2D(3, 3);
1131 // basis functions are numbered as sides
1133 // Use RT finite element to evaluate following matrices.
1135 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1136 // 2D RT_i(t0, t1) = a0 + a1*t0 + a2*t1
1138 base_2D << 1.0 << 0.0 << -2.0 << arma::endr // RT for side 0
1139 << 1.0 << -2.0 << 0.0 << arma::endr // RT for side 1
1140 << -1.0 << 2.0 << 2.0 << arma::endr;// RT for side 2
1143 arma::mat base_1D(2, 2);
1144 // Ravirat - Thomas base functions evaluated in points (0,0), (1,0), (0,1)
1145 // 1D RT_i(t0) = a0 + a1 * t0
1147 base_1D << 1.0 << -1.0 << arma::endr // RT for side 0,
1148 << 0.0 << 1.0 << arma::endr; // RT for side 1,
1152 // Consider both 2D and 1D value are defined for the test function
1153 // related to the each of 5 DOFs involved in the intersection.
1154 // One of these values is always zero.
1155 // Compute difference of the 2D and 1D value for every DOF.
1156 // Compute value of this difference in both endpoints X,Y of the intersection.
1158 arma::vec difference_in_Y(5);
1159 arma::vec difference_in_X(5);
1160 // slave sides 0,1,2
1161 difference_in_Y.subvec(0, 2) = -base_2D * point_2D_Y;
1162 difference_in_X.subvec(0, 2) = -base_2D * point_2D_X;
1164 difference_in_Y.subvec(3, 4) = base_1D * point_1D_Y;
1165 difference_in_X.subvec(3, 4) = base_1D * point_1D_X;
1167 // applying the Simpson's rule
1168 // to the product of two linear functions f, g we get
1169 // (b-a)/6 * ( 3*f(a)*g(a) + 3*f(b)*g(b) + 2*f(a)*g(b) + 2*f(b)*g(a) )
1171 for (int i = 0; i < 5; ++i) {
1172 for (int j = 0; j < 5; ++j) {
1173 A(i, j) = -master_sigma * intersec.intersection_true_size() *
1174 ( difference_in_Y[i] * difference_in_Y[j]
1175 + difference_in_Y[i] * difference_in_X[j]/2
1176 + difference_in_X[i] * difference_in_Y[j]/2
1177 + difference_in_X[i] * difference_in_X[j]
1183 ls.set_values( dofs_cp, dofs_cp, A, rhs, dirichlet, dirichlet);
1190 /*******************************************************************************
1191 * COMPOSE WATER MH MATRIX WITHOUT SCHUR COMPLEMENT
1192 ******************************************************************************/
1194 void DarcyMH::create_linear_system(Input::AbstractRecord in_rec) {
1196 START_TIMER("preallocation
"); 1198 if (schur0 == NULL) { // create Linear System for MH matrix 1200 if (in_rec.type() == LinSys_BDDC::get_input_type()) { 1201 #ifdef FLOW123D_HAVE_BDDCML 1202 WarningOut() << "For BDDC no Schur complements are used.
"; 1203 mh_dh.prepare_parallel_bddc(); 1205 LinSys_BDDC *ls = new LinSys_BDDC(mh_dh.global_row_4_sub_row->size(), &(*mh_dh.rows_ds), 1206 3, // 3 == la::BddcmlWrapper::SPD_VIA_SYMMETRICGENERAL 1207 1, // 1 == number of subdomains per process 1208 true); // swap signs of matrix and rhs to make the matrix SPD 1209 ls->set_from_input(in_rec); 1210 ls->set_solution( NULL ); 1211 // possible initialization particular to BDDC 1213 set_mesh_data_for_bddc(ls); 1217 xprintf(Err, "Flow123d was not build with BDDCML support.\n
"); 1218 #endif // FLOW123D_HAVE_BDDCML 1220 else if (in_rec.type() == LinSys_PETSC::get_input_type()) { 1221 // use PETSC for serial case even when user wants BDDC 1222 if (n_schur_compls > 2) { 1223 WarningOut() << "Invalid number of Schur Complements. Using 2.
"; 1227 LinSys_PETSC *schur1, *schur2; 1229 if (n_schur_compls == 0) { 1230 LinSys_PETSC *ls = new LinSys_PETSC( &(*mh_dh.rows_ds) ); 1232 // temporary solution; we have to set precision also for sequantial case of BDDC 1233 // final solution should be probably call of direct solver for oneproc case 1234 if (in_rec.type() != LinSys_BDDC::get_input_type()) ls->set_from_input(in_rec); 1236 ls->LinSys::set_from_input(in_rec); // get only common options 1239 ls->set_solution( NULL ); 1243 ISCreateStride(PETSC_COMM_WORLD, mh_dh.side_ds->lsize(), mh_dh.rows_ds->begin(), 1, &is); 1244 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1246 SchurComplement *ls = new SchurComplement(is, &(*mh_dh.rows_ds)); 1247 ls->set_from_input(in_rec); 1248 ls->set_solution( NULL ); 1251 Distribution *ds = ls->make_complement_distribution(); 1252 if (n_schur_compls==1) { 1253 schur1 = new LinSys_PETSC(ds); 1254 schur1->set_positive_definite(); 1257 ISCreateStride(PETSC_COMM_WORLD, mh_dh.el_ds->lsize(), ls->get_distribution()->begin(), 1, &is); 1258 //OLD_ASSERT(err == 0,"Error in ISCreateStride.
"); 1259 SchurComplement *ls1 = new SchurComplement(is, ds); // is is deallocated by SchurComplement 1260 ls1->set_negative_definite(); 1263 schur2 = new LinSys_PETSC( ls1->make_complement_distribution() ); 1264 schur2->set_positive_definite(); 1265 schur2->set_from_input(in_rec); 1266 ls1->set_complement( schur2 ); 1269 ls->set_complement( schur1 ); 1273 START_TIMER("PETSC PREALLOCATION
"); 1274 schur0->set_symmetric(); 1275 schur0->start_allocation(); 1276 assembly_mh_matrix(MultidimAssembler()); // preallocation 1277 VecZeroEntries(schur0->get_solution()); 1278 END_TIMER("PETSC PREALLOCATION
"); 1281 xprintf(Err, "Unknown solver type. Internal error.\n
"); 1285 END_TIMER("preallocation
"); 1286 make_serial_scatter(); 1292 void DarcyMH::assembly_linear_system() { 1293 START_TIMER("DarcyFlowMH_Steady::assembly_linear_system
"); 1296 bool is_steady = zero_time_term(); 1297 //DebugOut() << "Assembly linear system\n
"; 1298 if (data_->changed()) { 1299 //DebugOut() << "Data changed\n
"; 1300 // currently we have no optimization for cases when just time term data or RHS data are changed 1301 START_TIMER("full assembly
"); 1302 if (typeid(*schur0) != typeid(LinSys_BDDC)) { 1303 schur0->start_add_assembly(); // finish allocation and create matrix 1306 auto multidim_assembler = AssemblyBase::create< AssemblyMH >(data_); 1308 schur0->mat_zero_entries(); 1309 schur0->rhs_zero_entries(); 1311 assembly_source_term(); 1312 assembly_mh_matrix( multidim_assembler ); // fill matrix 1314 schur0->finish_assembly(); 1315 schur0->set_matrix_changed(); 1316 //MatView( *const_cast<Mat*>(schur0->get_matrix()), PETSC_VIEWER_STDOUT_WORLD ); 1317 //VecView( *const_cast<Vec*>(schur0->get_rhs()), PETSC_VIEWER_STDOUT_WORLD); 1320 START_TIMER("fix
time term
"); 1321 //DebugOut() << "setup
time term\n
"; 1322 // assembly time term and rhs 1326 else if (balance_ != nullptr) 1328 balance_->start_mass_assembly(water_balance_idx_); 1329 balance_->finish_mass_assembly(water_balance_idx_); 1331 END_TIMER("full assembly
"); 1333 START_TIMER("modify system
"); 1337 //xprintf(PrgErr, "Planned computation
time for steady solver, but
data are not changed.\n
"); 1339 END_TIMER("modiffy system
"); 1346 void DarcyMH::set_mesh_data_for_bddc(LinSys_BDDC * bddc_ls) { 1347 START_TIMER("DarcyFlowMH_Steady::set_mesh_data_for_bddc
"); 1348 // prepare mesh for BDDCML 1349 // initialize arrays 1350 // auxiliary map for creating coordinates of local dofs and global-to-local numbering 1351 std::map<int,arma::vec3> localDofMap; 1352 // connectivity for the subdomain, i.e. global dof numbers on element, stored element-by-element 1353 // Indices of Nodes on Elements 1354 std::vector<int> inet; 1355 // number of degrees of freedom on elements - determines elementwise chunks of INET array 1356 // Number of Nodes on Elements 1357 std::vector<int> nnet; 1358 // Indices of Subdomain Elements in Global Numbering - for local elements, their global indices 1359 std::vector<int> isegn; 1361 // This array is currently not used in BDDCML, it was used as an interface scaling alternative to scaling 1362 // by diagonal. It corresponds to the rho-scaling. 1363 std::vector<double> element_permeability; 1365 // maximal and minimal dimension of elements 1368 for ( unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++ ) { 1369 auto ele_ac = mh_dh.accessor(i_loc); 1370 // for each element, create local numbering of dofs as fluxes (sides), pressure (element centre), Lagrange multipliers (edges), compatible connections 1372 elDimMax = std::max( elDimMax, ele_ac.dim() ); 1373 elDimMin = std::min( elDimMin, ele_ac.dim() ); 1375 isegn.push_back( ele_ac.ele_global_idx() ); 1378 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1379 // insert local side dof 1380 int side_row = ele_ac.side_row(si); 1381 arma::vec3 coord = ele_ac.side(si)->centre(); 1383 localDofMap.insert( std::make_pair( side_row, coord ) ); 1384 inet.push_back( side_row ); 1388 // insert local pressure dof 1389 int el_row = ele_ac.ele_row(); 1390 arma::vec3 coord = ele_ac.centre(); 1391 localDofMap.insert( std::make_pair( el_row, coord ) ); 1392 inet.push_back( el_row ); 1395 FOR_ELEMENT_SIDES(ele_ac.full_iter(), si) { 1396 // insert local edge dof 1397 int edge_row = ele_ac.edge_row(si); 1398 arma::vec3 coord = ele_ac.side(si)->centre(); 1400 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1401 inet.push_back( edge_row ); 1405 // insert dofs related to compatible connections 1406 for ( unsigned int i_neigh = 0; i_neigh < ele_ac.full_iter()->n_neighs_vb; i_neigh++) { 1407 int edge_row = mh_dh.row_4_edge[ ele_ac.full_iter()->neigh_vb[i_neigh]->edge_idx() ]; 1408 arma::vec3 coord = ele_ac.full_iter()->neigh_vb[i_neigh]->edge()->side(0)->centre(); 1410 localDofMap.insert( std::make_pair( edge_row, coord ) ); 1411 inet.push_back( edge_row ); 1415 nnet.push_back( nne ); 1417 // version for rho scaling 1418 // trace computation 1419 arma::vec3 centre = ele_ac.centre(); 1420 double conduct = data_->conductivity.value( centre , ele_ac.element_accessor() ); 1421 arma::mat33 aniso = data_->anisotropy.value( centre, ele_ac.element_accessor() ); 1423 // compute mean on the diagonal 1425 for ( int i = 0; i < 3; i++) { 1426 coef = coef + aniso.at(i,i); 1428 // Maybe divide by cs 1429 coef = conduct*coef / 3; 1431 OLD_ASSERT( coef > 0., 1432 "Zero coefficient of hydrodynamic resistance %f . \n
", coef ); 1433 element_permeability.push_back( 1. / coef ); 1435 //convert set of dofs to vectors 1436 // number of nodes (= dofs) on the subdomain 1437 int numNodeSub = localDofMap.size(); 1438 OLD_ASSERT_EQUAL( (unsigned int)numNodeSub, mh_dh.global_row_4_sub_row->size() ); 1439 // Indices of Subdomain Nodes in Global Numbering - for local nodes, their global indices 1440 std::vector<int> isngn( numNodeSub ); 1441 // pseudo-coordinates of local nodes (i.e. dofs) 1442 // they need not be exact, they are used just for some geometrical considerations in BDDCML, 1443 // such as selection of corners maximizing area of a triangle, bounding boxes fro subdomains to 1444 // find candidate neighbours etc. 1445 std::vector<double> xyz( numNodeSub * 3 ) ; 1447 std::map<int,arma::vec3>::iterator itB = localDofMap.begin(); 1448 for ( ; itB != localDofMap.end(); ++itB ) { 1449 isngn[ind] = itB -> first; 1451 arma::vec3 coord = itB -> second; 1452 for ( int j = 0; j < 3; j++ ) { 1453 xyz[ j*numNodeSub + ind ] = coord[j]; 1458 localDofMap.clear(); 1460 // Number of Nodal Degrees of Freedom 1461 // nndf is trivially one - dofs coincide with nodes 1462 std::vector<int> nndf( numNodeSub, 1 ); 1464 // prepare auxiliary map for renumbering nodes 1465 typedef std::map<int,int> Global2LocalMap_; //! type for storage of global to local map 1466 Global2LocalMap_ global2LocalNodeMap; 1467 for ( unsigned ind = 0; ind < isngn.size(); ++ind ) { 1468 global2LocalNodeMap.insert( std::make_pair( static_cast<unsigned>( isngn[ind] ), ind ) ); 1471 // renumber nodes in the inet array to locals 1473 for ( unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) { 1474 int nne = nnet[ iEle ]; 1475 for ( int ien = 0; ien < nne; ien++ ) { 1477 int indGlob = inet[indInet]; 1478 // map it to local node 1479 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob ); 1480 OLD_ASSERT( pos != global2LocalNodeMap.end(), 1481 "Cannot remap node index %d to local indices. \n
", indGlob ); 1482 int indLoc = static_cast<int> ( pos -> second ); 1485 inet[ indInet++ ] = indLoc; 1489 int numNodes = size; 1490 int numDofsInt = size; 1491 int spaceDim = 3; // TODO: what is the proper value here? 1492 int meshDim = elDimMax; 1494 bddc_ls -> load_mesh( spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim ); 1500 //============================================================================= 1501 // DESTROY WATER MH SYSTEM STRUCTURE 1502 //============================================================================= 1503 DarcyMH::~DarcyMH() { 1504 if (schur0 != NULL) delete schur0; 1506 if (solution != NULL) { 1507 chkerr(VecDestroy(&sol_vec)); 1511 delete output_object; 1513 VecScatterDestroy(&par_to_all); 1518 // ================================================ 1523 void DarcyMH::make_serial_scatter() { 1524 START_TIMER("prepare scatter
"); 1525 // prepare Scatter form parallel to sequantial in original numbering 1528 int i, *loc_idx; //, si; 1530 // create local solution vector 1531 solution = new double[size]; 1532 VecCreateSeqWithArray(PETSC_COMM_SELF,1, size, solution, 1535 // create seq. IS to scatter par solutin to seq. vec. in original order 1536 // use essentialy row_4_id arrays 1537 loc_idx = new int [size]; 1539 FOR_ELEMENTS(mesh_, ele) { 1540 FOR_ELEMENT_SIDES(ele,si) { 1541 loc_idx[i++] = mh_dh.side_row_4_id[ mh_dh.side_dof( ele->side(si) ) ]; 1544 FOR_ELEMENTS(mesh_, ele) { 1545 loc_idx[i++] = mh_dh.row_4_el[ele.index()]; 1547 for(unsigned int i_edg=0; i_edg < mesh_->n_edges(); i_edg++) { 1548 loc_idx[i++] = mh_dh.row_4_edge[i_edg]; 1550 OLD_ASSERT( i==size,"Size of array does not match number of fills.\n
"); 1551 //DBGPRINT_INT("loc_idx
",size,loc_idx); 1552 ISCreateGeneral(PETSC_COMM_SELF, size, loc_idx, PETSC_COPY_VALUES, &(is_loc)); 1554 VecScatterCreate(schur0->get_solution(), is_loc, sol_vec, 1555 PETSC_NULL, &par_to_all); 1556 ISDestroy(&(is_loc)); 1558 solution_changed_for_scatter=true; 1560 END_TIMER("prepare scatter
"); 1566 void mat_count_off_proc_values(Mat m, Vec v) { 1568 const PetscInt *cols; 1569 Distribution distr(v); 1574 MatGetOwnershipRange(m, &first, &last); 1575 for (int row = first; row < last; row++) { 1576 MatGetRow(m, row, &n, &cols, PETSC_NULL); 1577 bool exists_off = false; 1578 for (int i = 0; i < n; i++) 1579 if (distr.get_proc(cols[i]) != distr.myp()) 1580 n_off++, exists_off = true; 1585 MatRestoreRow(m, row, &n, &cols, PETSC_NULL); 1601 void DarcyMH::read_initial_condition() 1603 double *local_sol = schur0->get_solution_array(); 1605 // cycle over local element rows 1607 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1608 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1609 auto ele_ac = mh_dh.accessor(i_loc_el); 1610 // set initial condition 1611 local_sol[ele_ac.ele_local_row()] = data_->init_pressure.value(ele_ac.centre(),ele_ac.element_accessor()); 1614 solution_changed_for_scatter=true; 1618 void DarcyMH::setup_time_term() { 1619 // save diagonal of steady matrix 1620 MatGetDiagonal(*( schur0->get_matrix() ), steady_diagonal); 1622 VecCopy(*( schur0->get_rhs()), steady_rhs); 1625 PetscScalar *local_diagonal; 1626 VecGetArray(new_diagonal,& local_diagonal); 1628 DebugOut().fmt("Setup with dt: {}\n
", time_->dt()); 1630 if (balance_ != nullptr) 1631 balance_->start_mass_assembly(water_balance_idx_); 1633 //DebugOut().fmt("time_term lsize: {} {}\n
", mh_dh.el_ds->myp(), mh_dh.el_ds->lsize()); 1634 for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) { 1635 auto ele_ac = mh_dh.accessor(i_loc_el); 1638 double diagonal_coeff = data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor()) 1639 * data_->storativity.value(ele_ac.centre(), ele_ac.element_accessor()) 1641 local_diagonal[ele_ac.ele_local_row()]= - diagonal_coeff / time_->dt(); 1643 //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); 1644 if (balance_ != nullptr) 1645 balance_->add_mass_matrix_values(water_balance_idx_, ele_ac.region().bulk_idx(), {ele_ac.ele_row()}, {diagonal_coeff}); 1647 VecRestoreArray(new_diagonal,& local_diagonal); 1648 MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES); 1650 solution_changed_for_scatter=true; 1651 schur0->set_matrix_changed(); 1653 if (balance_ != nullptr) 1654 balance_->finish_mass_assembly(water_balance_idx_); 1657 void DarcyMH::modify_system() { 1658 START_TIMER("modify system
"); 1659 if (time_->is_changed_dt() && time_->step().index()>0) { 1660 double scale_factor=time_->step(-2).length()/time_->step().length(); 1661 if (scale_factor != 1.0) { 1662 // if time step has changed and setup_time_term not called 1663 MatDiagonalSet(*( schur0->get_matrix() ),steady_diagonal, INSERT_VALUES); 1665 VecScale(new_diagonal, time_->last_dt()/time_->dt()); 1666 MatDiagonalSet(*( schur0->get_matrix() ),new_diagonal, ADD_VALUES); 1667 schur0->set_matrix_changed(); 1671 // modify RHS - add previous solution 1672 //VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, previous_solution); 1673 VecPointwiseMult(*( schur0->get_rhs()), new_diagonal, schur0->get_solution()); 1674 VecAXPY(*( schur0->get_rhs()), 1.0, steady_rhs); 1675 schur0->set_rhs_changed(); 1677 //VecSwap(previous_solution, schur0->get_solution()); 1681 //----------------------------------------------------------------------------- 1682 // 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.
#define ADD_FIELD(name,...)
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)
const TimeStep & step(int index=-1) const
static const std::string field_descriptor_record_description(const string &record_name)
Basic time management functionality for unsteady (and steady) solvers (class Equation).
bool solution_changed_for_scatter
void solve_nonlinear()
Solve method common to zero_time_step and update solution.
std::shared_ptr< EqData > data_
Basic time management class.
virtual void set_tolerances(double r_tol, double a_tol, unsigned int max_it)=0
void view(const char *name="") const
MortarMethod mortar_method_
friend class P0_CouplingAssembler
unsigned int nonlinear_iteration_
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
void mat_set_value(int row, int col, double val)
void update_solution() override
unsigned int size() const
Returns size of the container. This is independent of the allocated space.
unsigned int n_elements() const
virtual void postprocess()
double * get_solution_array()
std::shared_ptr< Balance > balance_
FLOW123D_FORCE_LINK_IN_CHILD(darcy_flow_mh)
const Vec & get_solution()
unsigned int n_sides() const
const Element * slave_iter() const
#define START_TIMER(tag)
Starts a timer with specified tag.
static const Input::Type::Instance & get_input_type()
static Input::Type::Abstract & get_input_type()
ElementVector bc_elements
SideIter side(const unsigned int loc_index)
bool use_steady_assembly_
static const Input::Type::Record & get_input_type_specific()
static const Input::Type::Selection & get_bc_type_selection()
Return a Selection corresponding to enum BC_Type.
virtual void assembly_linear_system()
DarcyMH(Mesh &mesh, const Input::Record in_rec)
CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL.
Support classes for parallel programing.
#define MPI_Allreduce(sendbuf, recvbuf, count, datatype, op, comm)
int set_upper_constraint(double upper, std::string message)
Sets upper constraint for the next time step estimating.
void set_values(int nrow, int *rows, int ncol, int *cols, PetscScalar *mat_vals, PetscScalar *rhs_vals)
Set values in the system matrix and values in the right-hand side vector on corresponding rows...
void create_linear_system(Input::AbstractRecord rec)
Initialize global_row_4_sub_row.
MortarMethod
Type of experimental Mortar-like method for non-compatible 1d-2d interaction.
double intersection_true_size() const
Input::Record input_record_
std::shared_ptr< Distribution > rows_ds
LocalElementAccessorBase< 3 > accessor(uint local_ele_idx)
unsigned int water_balance_idx_
index of water balance within the Balance object.
Abstract linear system class.
static const Input::Type::Record & get_input_type()
#define WarningOut()
Macro defining 'warning' record of log.
arma::vec::fixed< spacedim > centre() const
#define OLD_ASSERT_EQUAL(a, b)
EqData()
Creation of all fields.
mixed-hybrid model of linear Darcy flow, possibly unsteady.
void zero_time_step() override
virtual void read_initial_condition()
static Input::Type::Abstract & get_input_type()
virtual void mat_set_values(int nrow, int *rows, int ncol, int *cols, double *vals)=0
DarcyFlowMHOutput * output_object
unsigned int n_edges() const
virtual void prepare_new_time_step()
postprocess velocity field (add sources)
Class for representation SI units of Fields.
virtual double solution_precision() const
virtual bool zero_time_term()
static UnitSI & dimensionless()
Returns dimensionless unit.
#define DebugOut()
Macro defining 'debug' record of log.
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.
void output()
Calculate values for output.
unsigned int lsize(int proc) const
get local size