$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 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 00019 // C++ includes 00020 #include <algorithm> // for std::fill 00021 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC 00022 #include <cmath> // for sqrt 00023 00024 00025 // Local Includes 00026 #include "libmesh/libmesh_common.h" 00027 #include "libmesh/exact_error_estimator.h" 00028 #include "libmesh/dof_map.h" 00029 #include "libmesh/equation_systems.h" 00030 #include "libmesh/error_vector.h" 00031 #include "libmesh/fe_base.h" 00032 #include "libmesh/libmesh_logging.h" 00033 #include "libmesh/elem.h" 00034 #include "libmesh/mesh_base.h" 00035 #include "libmesh/mesh_function.h" 00036 #include "libmesh/numeric_vector.h" 00037 #include "libmesh/quadrature.h" 00038 #include "libmesh/system.h" 00039 #include "libmesh/tensor_tools.h" 00040 00041 namespace libMesh 00042 { 00043 00044 //----------------------------------------------------------------- 00045 // ErrorEstimator implementations 00046 void ExactErrorEstimator::attach_exact_value (Number fptr(const Point& p, 00047 const Parameters& parameters, 00048 const std::string& sys_name, 00049 const std::string& unknown_name)) 00050 { 00051 libmesh_assert(fptr); 00052 _exact_value = fptr; 00053 00054 // We're not using a fine grid solution 00055 _equation_systems_fine = NULL; 00056 00057 // We're not using user-provided functors 00058 this->clear_functors(); 00059 } 00060 00061 00062 void ExactErrorEstimator::attach_exact_values (std::vector<FunctionBase<Number> *> f) 00063 { 00064 // Clear out any previous _exact_values entries, then add a new 00065 // entry for each system. 00066 for (unsigned int i=0; i != _exact_values.size(); ++i) 00067 delete (_exact_values[i]); 00068 00069 _exact_values.clear(); 00070 _exact_values.resize(f.size(), NULL); 00071 00072 // We use clone() to get non-sliced copies of FunctionBase 00073 // subclasses, but we don't currently put the resulting UniquePtrs 00074 // into an STL container. 00075 for (unsigned int i=0; i != f.size(); ++i) 00076 if (f[i]) 00077 _exact_values[i] = f[i]->clone().release(); 00078 } 00079 00080 00081 void ExactErrorEstimator::attach_exact_value (unsigned int sys_num, 00082 FunctionBase<Number> * f) 00083 { 00084 if (_exact_values.size() <= sys_num) 00085 _exact_values.resize(sys_num+1, NULL); 00086 00087 if (f) 00088 _exact_values[sys_num] = f->clone().release(); 00089 } 00090 00091 00092 void ExactErrorEstimator::attach_exact_deriv (Gradient gptr(const Point& p, 00093 const Parameters& parameters, 00094 const std::string& sys_name, 00095 const std::string& unknown_name)) 00096 { 00097 libmesh_assert(gptr); 00098 _exact_deriv = gptr; 00099 00100 // We're not using a fine grid solution 00101 _equation_systems_fine = NULL; 00102 00103 // We're not using user-provided functors 00104 this->clear_functors(); 00105 } 00106 00107 00108 void ExactErrorEstimator::attach_exact_derivs (std::vector<FunctionBase<Gradient> *> g) 00109 { 00110 // Clear out any previous _exact_derivs entries, then add a new 00111 // entry for each system. 00112 for (unsigned int i=0; i != _exact_derivs.size(); ++i) 00113 delete (_exact_derivs[i]); 00114 00115 _exact_derivs.clear(); 00116 _exact_derivs.resize(g.size(), NULL); 00117 00118 // We use clone() to get non-sliced copies of FunctionBase 00119 // subclasses, but we don't currently put the resulting UniquePtrs 00120 // into an STL container. 00121 for (unsigned int i=0; i != g.size(); ++i) 00122 if (g[i]) 00123 _exact_derivs[i] = g[i]->clone().release(); 00124 } 00125 00126 00127 void ExactErrorEstimator::attach_exact_deriv (unsigned int sys_num, 00128 FunctionBase<Gradient>* g) 00129 { 00130 if (_exact_derivs.size() <= sys_num) 00131 _exact_derivs.resize(sys_num+1, NULL); 00132 00133 if (g) 00134 _exact_derivs[sys_num] = g->clone().release(); 00135 } 00136 00137 00138 00139 00140 void ExactErrorEstimator::attach_exact_hessian (Tensor hptr(const Point& p, 00141 const Parameters& parameters, 00142 const std::string& sys_name, 00143 const std::string& unknown_name)) 00144 { 00145 libmesh_assert(hptr); 00146 _exact_hessian = hptr; 00147 00148 // We're not using a fine grid solution 00149 _equation_systems_fine = NULL; 00150 00151 // We're not using user-provided functors 00152 this->clear_functors(); 00153 } 00154 00155 00156 void ExactErrorEstimator::attach_exact_hessians (std::vector<FunctionBase<Tensor> *> h) 00157 { 00158 // Clear out any previous _exact_hessians entries, then add a new 00159 // entry for each system. 00160 for (unsigned int i=0; i != _exact_hessians.size(); ++i) 00161 delete (_exact_hessians[i]); 00162 00163 _exact_hessians.clear(); 00164 _exact_hessians.resize(h.size(), NULL); 00165 00166 // We use clone() to get non-sliced copies of FunctionBase 00167 // subclasses, but we don't currently put the resulting UniquePtrs 00168 // into an STL container. 00169 for (unsigned int i=0; i != h.size(); ++i) 00170 if (h[i]) 00171 _exact_hessians[i] = h[i]->clone().release(); 00172 } 00173 00174 00175 void ExactErrorEstimator::attach_exact_hessian (unsigned int sys_num, 00176 FunctionBase<Tensor>* h) 00177 { 00178 if (_exact_hessians.size() <= sys_num) 00179 _exact_hessians.resize(sys_num+1, NULL); 00180 00181 if (h) 00182 _exact_hessians[sys_num] = h->clone().release(); 00183 } 00184 00185 00186 void ExactErrorEstimator::attach_reference_solution (EquationSystems* es_fine) 00187 { 00188 libmesh_assert(es_fine); 00189 _equation_systems_fine = es_fine; 00190 00191 // If we're using a fine grid solution, we're not using exact value 00192 // function pointers or functors. 00193 _exact_value = NULL; 00194 _exact_deriv = NULL; 00195 _exact_hessian = NULL; 00196 00197 this->clear_functors(); 00198 } 00199 00200 #ifdef LIBMESH_ENABLE_AMR 00201 void ExactErrorEstimator::estimate_error (const System& system, 00202 ErrorVector& error_per_cell, 00203 const NumericVector<Number>* solution_vector, 00204 bool estimate_parent_error) 00205 #else 00206 void ExactErrorEstimator::estimate_error (const System& system, 00207 ErrorVector& error_per_cell, 00208 const NumericVector<Number>* solution_vector, 00209 bool /* estimate_parent_error */ ) 00210 #endif 00211 { 00212 // The current mesh 00213 const MeshBase& mesh = system.get_mesh(); 00214 00215 // The dimensionality of the mesh 00216 const unsigned int dim = mesh.mesh_dimension(); 00217 00218 // The number of variables in the system 00219 const unsigned int n_vars = system.n_vars(); 00220 00221 // The DofMap for this system 00222 const DofMap& dof_map = system.get_dof_map(); 00223 00224 // Resize the error_per_cell vector to be 00225 // the number of elements, initialize it to 0. 00226 error_per_cell.resize (mesh.max_elem_id()); 00227 std::fill (error_per_cell.begin(), error_per_cell.end(), 0.); 00228 00229 // Prepare current_local_solution to localize a non-standard 00230 // solution vector if necessary 00231 if (solution_vector && solution_vector != system.solution.get()) 00232 { 00233 NumericVector<Number>* newsol = 00234 const_cast<NumericVector<Number>*>(solution_vector); 00235 System &sys = const_cast<System&>(system); 00236 newsol->swap(*sys.solution); 00237 sys.update(); 00238 } 00239 00240 // Loop over all the variables in the system 00241 for (unsigned int var=0; var<n_vars; var++) 00242 { 00243 // Possibly skip this variable 00244 if (error_norm.weight(var) == 0.0) continue; 00245 00246 // The (string) name of this variable 00247 const std::string& var_name = system.variable_name(var); 00248 00249 // The type of finite element to use for this variable 00250 const FEType& fe_type = dof_map.variable_type (var); 00251 00252 UniquePtr<FEBase> fe (FEBase::build (dim, fe_type)); 00253 00254 // Build an appropriate Gaussian quadrature rule 00255 UniquePtr<QBase> qrule = 00256 fe_type.default_quadrature_rule (dim, 00257 _extra_order); 00258 00259 fe->attach_quadrature_rule (qrule.get()); 00260 00261 // Prepare a global solution and a MeshFunction of the fine system if we need one 00262 UniquePtr<MeshFunction> fine_values; 00263 UniquePtr<NumericVector<Number> > fine_soln = NumericVector<Number>::build(system.comm()); 00264 if (_equation_systems_fine) 00265 { 00266 const System& fine_system = _equation_systems_fine->get_system(system.name()); 00267 00268 std::vector<Number> global_soln; 00269 // FIXME - we're assuming that the fine system solution gets 00270 // used even when a different vector is used for the coarse 00271 // system 00272 fine_system.update_global_solution(global_soln); 00273 fine_soln->init 00274 (cast_int<numeric_index_type>(global_soln.size()), true, 00275 SERIAL); 00276 (*fine_soln) = global_soln; 00277 00278 fine_values = UniquePtr<MeshFunction> 00279 (new MeshFunction(*_equation_systems_fine, 00280 *fine_soln, 00281 fine_system.get_dof_map(), 00282 fine_system.variable_number(var_name))); 00283 fine_values->init(); 00284 } else { 00285 // Initialize functors if we're using them 00286 for (unsigned int i=0; i != _exact_values.size(); ++i) 00287 if (_exact_values[i]) 00288 _exact_values[i]->init(); 00289 00290 for (unsigned int i=0; i != _exact_derivs.size(); ++i) 00291 if (_exact_derivs[i]) 00292 _exact_derivs[i]->init(); 00293 00294 for (unsigned int i=0; i != _exact_hessians.size(); ++i) 00295 if (_exact_hessians[i]) 00296 _exact_hessians[i]->init(); 00297 } 00298 00299 // Request the data we'll need to compute with 00300 fe->get_JxW(); 00301 fe->get_phi(); 00302 fe->get_dphi(); 00303 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00304 fe->get_d2phi(); 00305 #endif 00306 fe->get_xyz(); 00307 00308 #ifdef LIBMESH_ENABLE_AMR 00309 // If we compute on parent elements, we'll want to do so only 00310 // once on each, so we need to keep track of which we've done. 00311 std::vector<bool> computed_var_on_parent; 00312 00313 if (estimate_parent_error) 00314 computed_var_on_parent.resize(error_per_cell.size(), false); 00315 #endif 00316 00317 // TODO: this ought to be threaded (and using subordinate 00318 // MeshFunction objects in each thread rather than a single 00319 // master) 00320 00321 // Iterate over all the active elements in the mesh 00322 // that live on this processor. 00323 MeshBase::const_element_iterator 00324 elem_it = mesh.active_local_elements_begin(); 00325 const MeshBase::const_element_iterator 00326 elem_end = mesh.active_local_elements_end(); 00327 00328 for (;elem_it != elem_end; ++elem_it) 00329 { 00330 // e is necessarily an active element on the local processor 00331 const Elem* elem = *elem_it; 00332 const dof_id_type e_id = elem->id(); 00333 00334 #ifdef LIBMESH_ENABLE_AMR 00335 // See if the parent of element e has been examined yet; 00336 // if not, we may want to compute the estimator on it 00337 const Elem* parent = elem->parent(); 00338 00339 // We only can compute and only need to compute on 00340 // parents with all active children 00341 bool compute_on_parent = true; 00342 if (!parent || !estimate_parent_error) 00343 compute_on_parent = false; 00344 else 00345 for (unsigned int c=0; c != parent->n_children(); ++c) 00346 if (!parent->child(c)->active()) 00347 compute_on_parent = false; 00348 00349 if (compute_on_parent && 00350 !computed_var_on_parent[parent->id()]) 00351 { 00352 computed_var_on_parent[parent->id()] = true; 00353 00354 // Compute a projection onto the parent 00355 DenseVector<Number> Uparent; 00356 FEBase::coarsened_dof_values(*(system.current_local_solution), 00357 dof_map, parent, Uparent, 00358 var, false); 00359 00360 error_per_cell[parent->id()] += 00361 static_cast<ErrorVectorReal> 00362 (find_squared_element_error(system, var_name, 00363 parent, Uparent, 00364 fe.get(), 00365 fine_values.get())); 00366 } 00367 #endif 00368 00369 // Get the local to global degree of freedom maps 00370 std::vector<dof_id_type> dof_indices; 00371 dof_map.dof_indices (elem, dof_indices, var); 00372 const unsigned int n_dofs = 00373 cast_int<unsigned int>(dof_indices.size()); 00374 DenseVector<Number> Uelem(n_dofs); 00375 for (unsigned int i=0; i != n_dofs; ++i) 00376 Uelem(i) = system.current_solution(dof_indices[i]); 00377 00378 error_per_cell[e_id] += 00379 static_cast<ErrorVectorReal> 00380 (find_squared_element_error(system, var_name, elem, 00381 Uelem, fe.get(), 00382 fine_values.get())); 00383 00384 } // End loop over active local elements 00385 } // End loop over variables 00386 00387 00388 00389 // Each processor has now computed the error contribuions 00390 // for its local elements. We need to sum the vector 00391 // and then take the square-root of each component. Note 00392 // that we only need to sum if we are running on multiple 00393 // processors, and we only need to take the square-root 00394 // if the value is nonzero. There will in general be many 00395 // zeros for the inactive elements. 00396 00397 // First sum the vector of estimated error values 00398 this->reduce_error(error_per_cell, system.comm()); 00399 00400 // Compute the square-root of each component. 00401 START_LOG("std::sqrt()", "ExactErrorEstimator"); 00402 for (dof_id_type i=0; i<error_per_cell.size(); i++) 00403 { 00404 00405 if (error_per_cell[i] != 0.) 00406 { 00407 libmesh_assert_greater (error_per_cell[i], 0.); 00408 error_per_cell[i] = std::sqrt(error_per_cell[i]); 00409 } 00410 00411 00412 } 00413 STOP_LOG("std::sqrt()", "ExactErrorEstimator"); 00414 00415 // If we used a non-standard solution before, now is the time to fix 00416 // the current_local_solution 00417 if (solution_vector && solution_vector != system.solution.get()) 00418 { 00419 NumericVector<Number>* newsol = 00420 const_cast<NumericVector<Number>*>(solution_vector); 00421 System &sys = const_cast<System&>(system); 00422 newsol->swap(*sys.solution); 00423 sys.update(); 00424 } 00425 } 00426 00427 00428 00429 Real ExactErrorEstimator::find_squared_element_error(const System& system, 00430 const std::string& var_name, 00431 const Elem *elem, 00432 const DenseVector<Number> &Uelem, 00433 FEBase *fe, 00434 MeshFunction *fine_values) const 00435 { 00436 // The (string) name of this system 00437 const std::string& sys_name = system.name(); 00438 const unsigned int sys_num = system.number(); 00439 00440 const unsigned int var = system.variable_number(var_name); 00441 const unsigned int var_component = 00442 system.variable_scalar_number(var, 0); 00443 00444 const Parameters& parameters = system.get_equation_systems().parameters; 00445 00446 // reinitialize the element-specific data 00447 // for the current element 00448 fe->reinit (elem); 00449 00450 // Get the data we need to compute with 00451 const std::vector<Real> & JxW = fe->get_JxW(); 00452 const std::vector<std::vector<Real> >& phi_values = fe->get_phi(); 00453 const std::vector<std::vector<RealGradient> >& dphi_values = fe->get_dphi(); 00454 const std::vector<Point>& q_point = fe->get_xyz(); 00455 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00456 const std::vector<std::vector<RealTensor> >& d2phi_values = fe->get_d2phi(); 00457 #endif 00458 00459 // The number of shape functions 00460 const unsigned int n_sf = 00461 cast_int<unsigned int>(Uelem.size()); 00462 00463 // The number of quadrature points 00464 const unsigned int n_qp = 00465 cast_int<unsigned int>(JxW.size()); 00466 00467 Real error_val = 0; 00468 00469 // Begin the loop over the Quadrature points. 00470 // 00471 for (unsigned int qp=0; qp<n_qp; qp++) 00472 { 00473 // Real u_h = 0.; 00474 // RealGradient grad_u_h; 00475 00476 Number u_h = 0.; 00477 00478 Gradient grad_u_h; 00479 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00480 Tensor grad2_u_h; 00481 #endif 00482 00483 // Compute solution values at the current 00484 // quadrature point. This reqiures a sum 00485 // over all the shape functions evaluated 00486 // at the quadrature point. 00487 for (unsigned int i=0; i<n_sf; i++) 00488 { 00489 // Values from current solution. 00490 u_h += phi_values[i][qp]*Uelem(i); 00491 grad_u_h += dphi_values[i][qp]*Uelem(i); 00492 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00493 grad2_u_h += d2phi_values[i][qp]*Uelem(i); 00494 #endif 00495 } 00496 00497 // Compute the value of the error at this quadrature point 00498 if (error_norm.type(var) == L2 || 00499 error_norm.type(var) == H1 || 00500 error_norm.type(var) == H2) 00501 { 00502 Number val_error = u_h; 00503 if (_exact_value) 00504 val_error -= _exact_value(q_point[qp],parameters,sys_name,var_name); 00505 else if (_exact_values.size() > sys_num && _exact_values[sys_num]) 00506 val_error -= _exact_values[sys_num]-> 00507 component(var_component, q_point[qp], system.time); 00508 else if (_equation_systems_fine) 00509 val_error -= (*fine_values)(q_point[qp]); 00510 00511 // Add the squares of the error to each contribution 00512 error_val += JxW[qp]*TensorTools::norm_sq(val_error); 00513 } 00514 00515 // Compute the value of the error in the gradient at this 00516 // quadrature point 00517 if (error_norm.type(var) == H1 || 00518 error_norm.type(var) == H1_SEMINORM || 00519 error_norm.type(var) == H2) 00520 { 00521 Gradient grad_error = grad_u_h; 00522 if(_exact_deriv) 00523 grad_error -= _exact_deriv(q_point[qp],parameters,sys_name,var_name); 00524 else if (_exact_derivs.size() > sys_num && _exact_derivs[sys_num]) 00525 grad_error -= _exact_derivs[sys_num]-> 00526 component(var_component, q_point[qp], system.time); 00527 else if(_equation_systems_fine) 00528 grad_error -= fine_values->gradient(q_point[qp]); 00529 00530 error_val += JxW[qp]*grad_error.size_sq(); 00531 } 00532 00533 00534 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00535 // Compute the value of the error in the hessian at this 00536 // quadrature point 00537 if ((error_norm.type(var) == H2_SEMINORM || 00538 error_norm.type(var) == H2)) 00539 { 00540 Tensor grad2_error = grad2_u_h; 00541 if(_exact_hessian) 00542 grad2_error -= _exact_hessian(q_point[qp],parameters,sys_name,var_name); 00543 else if (_exact_hessians.size() > sys_num && _exact_hessians[sys_num]) 00544 grad2_error -= _exact_hessians[sys_num]-> 00545 component(var_component, q_point[qp], system.time); 00546 else if (_equation_systems_fine) 00547 grad2_error -= fine_values->hessian(q_point[qp]); 00548 00549 error_val += JxW[qp]*grad2_error.size_sq(); 00550 } 00551 #endif 00552 00553 } // end qp loop 00554 00555 libmesh_assert_greater_equal (error_val, 0.); 00556 00557 return error_val; 00558 } 00559 00560 00561 00562 void ExactErrorEstimator::clear_functors() 00563 { 00564 // delete will clean up any cloned functors and no-op on any NULL 00565 // pointers 00566 00567 for (unsigned int i=0; i != _exact_values.size(); ++i) 00568 delete (_exact_values[i]); 00569 00570 for (unsigned int i=0; i != _exact_derivs.size(); ++i) 00571 delete (_exact_derivs[i]); 00572 00573 for (unsigned int i=0; i != _exact_hessians.size(); ++i) 00574 delete (_exact_hessians[i]); 00575 } 00576 00577 00578 00579 } // namespace libMesh