hp_coarsentest.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 // C++ includes 00019 #include <limits> // for std::numeric_limits::max 00020 #include <math.h> // for sqrt 00021 00022 00023 // Local Includes 00024 #include "libmesh/hp_coarsentest.h" 00025 #include "libmesh/dense_matrix.h" 00026 #include "libmesh/dense_vector.h" 00027 #include "libmesh/dof_map.h" 00028 #include "libmesh/fe_base.h" 00029 #include "libmesh/fe_interface.h" 00030 #include "libmesh/libmesh_logging.h" 00031 #include "libmesh/elem.h" 00032 #include "libmesh/error_vector.h" 00033 #include "libmesh/mesh_base.h" 00034 #include "libmesh/quadrature.h" 00035 #include "libmesh/system.h" 00036 #include "libmesh/tensor_value.h" 00037 00038 #ifdef LIBMESH_ENABLE_AMR 00039 00040 namespace libMesh 00041 { 00042 00043 //----------------------------------------------------------------- 00044 // HPCoarsenTest implementations 00045 00046 void HPCoarsenTest::add_projection(const System &system, 00047 const Elem *elem, 00048 unsigned int var) 00049 { 00050 // If we have children, we need to add their projections instead 00051 if (!elem->active()) 00052 { 00053 libmesh_assert(!elem->subactive()); 00054 for (unsigned int c = 0; c != elem->n_children(); ++c) 00055 this->add_projection(system, elem->child(c), var); 00056 return; 00057 } 00058 00059 // The DofMap for this system 00060 const DofMap& dof_map = system.get_dof_map(); 00061 00062 // The type of finite element to use for this variable 00063 const FEType& fe_type = dof_map.variable_type (var); 00064 00065 const FEContinuity cont = fe->get_continuity(); 00066 00067 fe->reinit(elem); 00068 00069 dof_map.dof_indices(elem, dof_indices, var); 00070 00071 const unsigned int n_dofs = 00072 libmesh_cast_int<unsigned int>(dof_indices.size()); 00073 00074 FEInterface::inverse_map (system.get_mesh().mesh_dimension(), 00075 fe_type, coarse, *xyz_values, coarse_qpoints); 00076 00077 fe_coarse->reinit(coarse, &coarse_qpoints); 00078 00079 const unsigned int n_coarse_dofs = 00080 libmesh_cast_int<unsigned int>(phi_coarse->size()); 00081 00082 if (Uc.size() == 0) 00083 { 00084 Ke.resize(n_coarse_dofs, n_coarse_dofs); 00085 Ke.zero(); 00086 Fe.resize(n_coarse_dofs); 00087 Fe.zero(); 00088 Uc.resize(n_coarse_dofs); 00089 Uc.zero(); 00090 } 00091 libmesh_assert_equal_to (Uc.size(), phi_coarse->size()); 00092 00093 // Loop over the quadrature points 00094 for (unsigned int qp=0; qp<qrule->n_points(); qp++) 00095 { 00096 // The solution value at the quadrature point 00097 Number val = libMesh::zero; 00098 Gradient grad; 00099 Tensor hess; 00100 00101 for (unsigned int i=0; i != n_dofs; i++) 00102 { 00103 dof_id_type dof_num = dof_indices[i]; 00104 val += (*phi)[i][qp] * 00105 system.current_solution(dof_num); 00106 if (cont == C_ZERO || cont == C_ONE) 00107 grad.add_scaled((*dphi)[i][qp],system.current_solution(dof_num)); 00108 // grad += (*dphi)[i][qp] * 00109 // system.current_solution(dof_num); 00110 if (cont == C_ONE) 00111 hess.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); 00112 // hess += (*d2phi)[i][qp] * 00113 // system.current_solution(dof_num); 00114 } 00115 00116 // The projection matrix and vector 00117 for (unsigned int i=0; i != Fe.size(); ++i) 00118 { 00119 Fe(i) += (*JxW)[qp] * 00120 (*phi_coarse)[i][qp]*val; 00121 if (cont == C_ZERO || cont == C_ONE) 00122 Fe(i) += (*JxW)[qp] * 00123 (grad*(*dphi_coarse)[i][qp]); 00124 if (cont == C_ONE) 00125 Fe(i) += (*JxW)[qp] * 00126 hess.contract((*d2phi_coarse)[i][qp]); 00127 // Fe(i) += (*JxW)[qp] * 00128 // (*d2phi_coarse)[i][qp].contract(hess); 00129 00130 for (unsigned int j=0; j != Fe.size(); ++j) 00131 { 00132 Ke(i,j) += (*JxW)[qp] * 00133 (*phi_coarse)[i][qp]*(*phi_coarse)[j][qp]; 00134 if (cont == C_ZERO || cont == C_ONE) 00135 Ke(i,j) += (*JxW)[qp] * 00136 (*dphi_coarse)[i][qp]*(*dphi_coarse)[j][qp]; 00137 if (cont == C_ONE) 00138 Ke(i,j) += (*JxW)[qp] * 00139 ((*d2phi_coarse)[i][qp].contract((*d2phi_coarse)[j][qp])); 00140 } 00141 } 00142 } 00143 } 00144 00145 void HPCoarsenTest::select_refinement (System &system) 00146 { 00147 START_LOG("select_refinement()", "HPCoarsenTest"); 00148 00149 // The current mesh 00150 MeshBase& mesh = system.get_mesh(); 00151 00152 // The dimensionality of the mesh 00153 const unsigned int dim = mesh.mesh_dimension(); 00154 00155 // The number of variables in the system 00156 const unsigned int n_vars = system.n_vars(); 00157 00158 // The DofMap for this system 00159 const DofMap& dof_map = system.get_dof_map(); 00160 00161 // The system number (for doing bad hackery) 00162 const unsigned int sys_num = system.number(); 00163 00164 // Check for a valid component_scale 00165 if (!component_scale.empty()) 00166 { 00167 if (component_scale.size() != n_vars) 00168 { 00169 libMesh::err << "ERROR: component_scale is the wrong size:" 00170 << std::endl 00171 << " component_scale.size()=" << component_scale.size() 00172 << std::endl 00173 << " n_vars=" << n_vars 00174 << std::endl; 00175 libmesh_error(); 00176 } 00177 } 00178 else 00179 { 00180 // No specified scaling. Scale all variables by one. 00181 component_scale.resize (n_vars, 1.0); 00182 } 00183 00184 // Resize the error_per_cell vectors to handle 00185 // the number of elements, initialize them to 0. 00186 std::vector<ErrorVectorReal> h_error_per_cell(mesh.n_elem(), 0.); 00187 std::vector<ErrorVectorReal> p_error_per_cell(mesh.n_elem(), 0.); 00188 00189 // Loop over all the variables in the system 00190 for (unsigned int var=0; var<n_vars; var++) 00191 { 00192 // Possibly skip this variable 00193 if (!component_scale.empty()) 00194 if (component_scale[var] == 0.0) continue; 00195 00196 // The type of finite element to use for this variable 00197 const FEType& fe_type = dof_map.variable_type (var); 00198 00199 // Finite element objects for a fine (and probably a coarse) 00200 // element will be needed 00201 fe = FEBase::build (dim, fe_type); 00202 fe_coarse = FEBase::build (dim, fe_type); 00203 00204 // Any cached coarse element results have expired 00205 coarse = NULL; 00206 unsigned int cached_coarse_p_level = 0; 00207 00208 const FEContinuity cont = fe->get_continuity(); 00209 libmesh_assert (cont == DISCONTINUOUS || cont == C_ZERO || 00210 cont == C_ONE); 00211 00212 // Build an appropriate quadrature rule 00213 qrule = fe_type.default_quadrature_rule(dim); 00214 00215 // Tell the refined finite element about the quadrature 00216 // rule. The coarse finite element need not know about it 00217 fe->attach_quadrature_rule (qrule.get()); 00218 00219 // We will always do the integration 00220 // on the fine elements. Get their Jacobian values, etc.. 00221 JxW = &(fe->get_JxW()); 00222 xyz_values = &(fe->get_xyz()); 00223 00224 // The shape functions 00225 phi = &(fe->get_phi()); 00226 phi_coarse = &(fe_coarse->get_phi()); 00227 00228 // The shape function derivatives 00229 if (cont == C_ZERO || cont == C_ONE) 00230 { 00231 dphi = &(fe->get_dphi()); 00232 dphi_coarse = &(fe_coarse->get_dphi()); 00233 } 00234 00235 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00236 // The shape function second derivatives 00237 if (cont == C_ONE) 00238 { 00239 d2phi = &(fe->get_d2phi()); 00240 d2phi_coarse = &(fe_coarse->get_d2phi()); 00241 } 00242 #endif // defined (LIBMESH_ENABLE_SECOND_DERIVATIVES) 00243 00244 // Iterate over all the active elements in the mesh 00245 // that live on this processor. 00246 00247 MeshBase::const_element_iterator elem_it = 00248 mesh.active_local_elements_begin(); 00249 const MeshBase::const_element_iterator elem_end = 00250 mesh.active_local_elements_end(); 00251 00252 for (; elem_it != elem_end; ++elem_it) 00253 { 00254 const Elem* elem = *elem_it; 00255 00256 // We're only checking elements that are already flagged for h 00257 // refinement 00258 if (elem->refinement_flag() != Elem::REFINE) 00259 continue; 00260 00261 const dof_id_type e_id = elem->id(); 00262 00263 // Find the projection onto the parent element, 00264 // if necessary 00265 if (elem->parent() && 00266 (coarse != elem->parent() || 00267 cached_coarse_p_level != elem->p_level())) 00268 { 00269 Uc.resize(0); 00270 00271 coarse = elem->parent(); 00272 cached_coarse_p_level = elem->p_level(); 00273 00274 unsigned int old_parent_level = coarse->p_level(); 00275 (const_cast<Elem *>(coarse))->hack_p_level(elem->p_level()); 00276 00277 this->add_projection(system, coarse, var); 00278 00279 (const_cast<Elem *>(coarse))->hack_p_level(old_parent_level); 00280 00281 // Solve the h-coarsening projection problem 00282 Ke.cholesky_solve(Fe, Uc); 00283 } 00284 00285 fe->reinit(elem); 00286 00287 // Get the DOF indices for the fine element 00288 dof_map.dof_indices (elem, dof_indices, var); 00289 00290 // The number of quadrature points 00291 const unsigned int n_qp = qrule->n_points(); 00292 00293 // The number of DOFS on the fine element 00294 const unsigned int n_dofs = 00295 libmesh_cast_int<unsigned int>(dof_indices.size()); 00296 00297 // The number of nodes on the fine element 00298 const unsigned int n_nodes = elem->n_nodes(); 00299 00300 // The average element value (used as an ugly hack 00301 // when we have nothing p-coarsened to compare to) 00302 // Real average_val = 0.; 00303 Number average_val = 0.; 00304 00305 // Calculate this variable's contribution to the p 00306 // refinement error 00307 00308 if (elem->p_level() == 0) 00309 { 00310 unsigned int n_vertices = 0; 00311 for (unsigned int n = 0; n != n_nodes; ++n) 00312 if (elem->is_vertex(n)) 00313 { 00314 n_vertices++; 00315 const Node * const node = elem->get_node(n); 00316 average_val += system.current_solution 00317 (node->dof_number(sys_num,var,0)); 00318 } 00319 average_val /= n_vertices; 00320 } 00321 else 00322 { 00323 unsigned int old_elem_level = elem->p_level(); 00324 (const_cast<Elem *>(elem))->hack_p_level(old_elem_level - 1); 00325 00326 fe_coarse->reinit(elem, &(qrule->get_points())); 00327 00328 const unsigned int n_coarse_dofs = 00329 libmesh_cast_int<unsigned int>(phi_coarse->size()); 00330 00331 (const_cast<Elem *>(elem))->hack_p_level(old_elem_level); 00332 00333 Ke.resize(n_coarse_dofs, n_coarse_dofs); 00334 Ke.zero(); 00335 Fe.resize(n_coarse_dofs); 00336 Fe.zero(); 00337 00338 // Loop over the quadrature points 00339 for (unsigned int qp=0; qp<qrule->n_points(); qp++) 00340 { 00341 // The solution value at the quadrature point 00342 Number val = libMesh::zero; 00343 Gradient grad; 00344 Tensor hess; 00345 00346 for (unsigned int i=0; i != n_dofs; i++) 00347 { 00348 dof_id_type dof_num = dof_indices[i]; 00349 val += (*phi)[i][qp] * 00350 system.current_solution(dof_num); 00351 if (cont == C_ZERO || cont == C_ONE) 00352 grad.add_scaled((*dphi)[i][qp], system.current_solution(dof_num)); 00353 // grad += (*dphi)[i][qp] * 00354 // system.current_solution(dof_num); 00355 if (cont == C_ONE) 00356 hess.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); 00357 // hess += (*d2phi)[i][qp] * 00358 // system.current_solution(dof_num); 00359 } 00360 00361 // The projection matrix and vector 00362 for (unsigned int i=0; i != Fe.size(); ++i) 00363 { 00364 Fe(i) += (*JxW)[qp] * 00365 (*phi_coarse)[i][qp]*val; 00366 if (cont == C_ZERO || cont == C_ONE) 00367 Fe(i) += (*JxW)[qp] * 00368 grad * (*dphi_coarse)[i][qp]; 00369 if (cont == C_ONE) 00370 Fe(i) += (*JxW)[qp] * 00371 hess.contract((*d2phi_coarse)[i][qp]); 00372 00373 for (unsigned int j=0; j != Fe.size(); ++j) 00374 { 00375 Ke(i,j) += (*JxW)[qp] * 00376 (*phi_coarse)[i][qp]*(*phi_coarse)[j][qp]; 00377 if (cont == C_ZERO || cont == C_ONE) 00378 Ke(i,j) += (*JxW)[qp] * 00379 (*dphi_coarse)[i][qp]*(*dphi_coarse)[j][qp]; 00380 if (cont == C_ONE) 00381 Ke(i,j) += (*JxW)[qp] * 00382 ((*d2phi_coarse)[i][qp].contract((*d2phi_coarse)[j][qp])); 00383 } 00384 } 00385 } 00386 00387 // Solve the p-coarsening projection problem 00388 Ke.cholesky_solve(Fe, Up); 00389 } 00390 00391 // loop over the integration points on the fine element 00392 for (unsigned int qp=0; qp<n_qp; qp++) 00393 { 00394 Number value_error = 0.; 00395 Gradient grad_error; 00396 Tensor hessian_error; 00397 for (unsigned int i=0; i<n_dofs; i++) 00398 { 00399 const dof_id_type dof_num = dof_indices[i]; 00400 value_error += (*phi)[i][qp] * 00401 system.current_solution(dof_num); 00402 if (cont == C_ZERO || cont == C_ONE) 00403 grad_error.add_scaled((*dphi)[i][qp], system.current_solution(dof_num)); 00404 // grad_error += (*dphi)[i][qp] * 00405 // system.current_solution(dof_num); 00406 if (cont == C_ONE) 00407 hessian_error.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); 00408 // hessian_error += (*d2phi)[i][qp] * 00409 // system.current_solution(dof_num); 00410 } 00411 if (elem->p_level() == 0) 00412 { 00413 value_error -= average_val; 00414 } 00415 else 00416 { 00417 for (unsigned int i=0; i<Up.size(); i++) 00418 { 00419 value_error -= (*phi_coarse)[i][qp] * Up(i); 00420 if (cont == C_ZERO || cont == C_ONE) 00421 grad_error.subtract_scaled((*dphi_coarse)[i][qp], Up(i)); 00422 // grad_error -= (*dphi_coarse)[i][qp] * Up(i); 00423 if (cont == C_ONE) 00424 hessian_error.subtract_scaled((*d2phi_coarse)[i][qp], Up(i)); 00425 // hessian_error -= (*d2phi_coarse)[i][qp] * Up(i); 00426 } 00427 } 00428 00429 p_error_per_cell[e_id] += static_cast<ErrorVectorReal> 00430 (component_scale[var] * 00431 (*JxW)[qp] * TensorTools::norm_sq(value_error)); 00432 if (cont == C_ZERO || cont == C_ONE) 00433 p_error_per_cell[e_id] += static_cast<ErrorVectorReal> 00434 (component_scale[var] * 00435 (*JxW)[qp] * grad_error.size_sq()); 00436 if (cont == C_ONE) 00437 p_error_per_cell[e_id] += static_cast<ErrorVectorReal> 00438 (component_scale[var] * 00439 (*JxW)[qp] * hessian_error.size_sq()); 00440 } 00441 00442 // Calculate this variable's contribution to the h 00443 // refinement error 00444 00445 if (!elem->parent()) 00446 { 00447 // For now, we'll always start with an h refinement 00448 h_error_per_cell[e_id] = 00449 std::numeric_limits<ErrorVectorReal>::max() / 2; 00450 } 00451 else 00452 { 00453 FEInterface::inverse_map (dim, fe_type, coarse, 00454 *xyz_values, coarse_qpoints); 00455 00456 unsigned int old_parent_level = coarse->p_level(); 00457 (const_cast<Elem *>(coarse))->hack_p_level(elem->p_level()); 00458 00459 fe_coarse->reinit(coarse, &coarse_qpoints); 00460 00461 (const_cast<Elem *>(coarse))->hack_p_level(old_parent_level); 00462 00463 // The number of DOFS on the coarse element 00464 unsigned int n_coarse_dofs = 00465 libmesh_cast_int<unsigned int>(phi_coarse->size()); 00466 00467 // Loop over the quadrature points 00468 for (unsigned int qp=0; qp<n_qp; qp++) 00469 { 00470 // The solution difference at the quadrature point 00471 Number value_error = libMesh::zero; 00472 Gradient grad_error; 00473 Tensor hessian_error; 00474 00475 for (unsigned int i=0; i != n_dofs; ++i) 00476 { 00477 const dof_id_type dof_num = dof_indices[i]; 00478 value_error += (*phi)[i][qp] * 00479 system.current_solution(dof_num); 00480 if (cont == C_ZERO || cont == C_ONE) 00481 grad_error.add_scaled((*dphi)[i][qp], system.current_solution(dof_num)); 00482 // grad_error += (*dphi)[i][qp] * 00483 // system.current_solution(dof_num); 00484 if (cont == C_ONE) 00485 hessian_error.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); 00486 // hessian_error += (*d2phi)[i][qp] * 00487 // system.current_solution(dof_num); 00488 } 00489 00490 for (unsigned int i=0; i != n_coarse_dofs; ++i) 00491 { 00492 value_error -= (*phi_coarse)[i][qp] * Uc(i); 00493 if (cont == C_ZERO || cont == C_ONE) 00494 // grad_error -= (*dphi_coarse)[i][qp] * Uc(i); 00495 grad_error.subtract_scaled((*dphi_coarse)[i][qp], Uc(i)); 00496 if (cont == C_ONE) 00497 hessian_error.subtract_scaled((*d2phi_coarse)[i][qp], Uc(i)); 00498 // hessian_error -= (*d2phi_coarse)[i][qp] * Uc(i); 00499 } 00500 00501 h_error_per_cell[e_id] += static_cast<ErrorVectorReal> 00502 (component_scale[var] * 00503 (*JxW)[qp] * TensorTools::norm_sq(value_error)); 00504 if (cont == C_ZERO || cont == C_ONE) 00505 h_error_per_cell[e_id] += static_cast<ErrorVectorReal> 00506 (component_scale[var] * 00507 (*JxW)[qp] * grad_error.size_sq()); 00508 if (cont == C_ONE) 00509 h_error_per_cell[e_id] += static_cast<ErrorVectorReal> 00510 (component_scale[var] * 00511 (*JxW)[qp] * hessian_error.size_sq()); 00512 } 00513 00514 } 00515 } 00516 } 00517 00518 // Now that we've got our approximations for p_error and h_error, let's see 00519 // if we want to switch any h refinement flags to p refinement 00520 00521 // Iterate over all the active elements in the mesh 00522 // that live on this processor. 00523 00524 MeshBase::element_iterator elem_it = 00525 mesh.active_local_elements_begin(); 00526 const MeshBase::element_iterator elem_end = 00527 mesh.active_local_elements_end(); 00528 00529 for (; elem_it != elem_end; ++elem_it) 00530 { 00531 Elem* elem = *elem_it; 00532 00533 // We're only checking elements that are already flagged for h 00534 // refinement 00535 if (elem->refinement_flag() != Elem::REFINE) 00536 continue; 00537 00538 const dof_id_type e_id = elem->id(); 00539 00540 unsigned int dofs_per_elem = 0, dofs_per_p_elem = 0; 00541 00542 // Loop over all the variables in the system 00543 for (unsigned int var=0; var<n_vars; var++) 00544 { 00545 // The type of finite element to use for this variable 00546 const FEType& fe_type = dof_map.variable_type (var); 00547 00548 // FIXME: we're overestimating the number of DOFs added by h 00549 // refinement 00550 FEType elem_fe_type = fe_type; 00551 elem_fe_type.order = 00552 static_cast<Order>(fe_type.order + elem->p_level()); 00553 dofs_per_elem += 00554 FEInterface::n_dofs(dim, elem_fe_type, elem->type()); 00555 00556 elem_fe_type.order = 00557 static_cast<Order>(fe_type.order + elem->p_level() + 1); 00558 dofs_per_p_elem += 00559 FEInterface::n_dofs(dim, elem_fe_type, elem->type()); 00560 } 00561 00562 const unsigned int new_h_dofs = dofs_per_elem * 00563 (elem->n_children() - 1); 00564 00565 const unsigned int new_p_dofs = dofs_per_p_elem - 00566 dofs_per_elem; 00567 00568 /* 00569 libMesh::err << "Cell " << e_id << ": h = " << elem->hmax() 00570 << ", p = " << elem->p_level() + 1 << "," << std::endl 00571 << " h_error = " << h_error_per_cell[e_id] 00572 << ", p_error = " << p_error_per_cell[e_id] << std::endl 00573 << " new_h_dofs = " << new_h_dofs 00574 << ", new_p_dofs = " << new_p_dofs << std::endl; 00575 */ 00576 const Real p_value = 00577 std::sqrt(p_error_per_cell[e_id]) * p_weight / new_p_dofs; 00578 const Real h_value = 00579 std::sqrt(h_error_per_cell[e_id]) / 00580 static_cast<Real>(new_h_dofs); 00581 if (p_value > h_value) 00582 { 00583 elem->set_p_refinement_flag(Elem::REFINE); 00584 elem->set_refinement_flag(Elem::DO_NOTHING); 00585 } 00586 } 00587 00588 STOP_LOG("select_refinement()", "HPCoarsenTest"); 00589 } 00590 00591 } // namespace libMesh 00592 00593 #endif // #ifdef LIBMESH_ENABLE_AMR
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:47 UTC
Hosted By: