$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 00020 // C++ includes 00021 #include <sstream> // for std::ostringstream 00022 00023 00024 // Local includes 00025 #include "libmesh/dof_map.h" 00026 #include "libmesh/equation_systems.h" 00027 #include "libmesh/libmesh_logging.h" 00028 #include "libmesh/mesh_base.h" 00029 #include "libmesh/numeric_vector.h" 00030 #include "libmesh/parameter_vector.h" 00031 #include "libmesh/point.h" // For point_value 00032 #include "libmesh/point_locator_base.h" // For point_value 00033 #include "libmesh/qoi_set.h" 00034 #include "libmesh/string_to_enum.h" 00035 #include "libmesh/system.h" 00036 #include "libmesh/system_norm.h" 00037 #include "libmesh/utility.h" 00038 00039 // includes for calculate_norm, point_* 00040 #include "libmesh/fe_base.h" 00041 #include "libmesh/fe_interface.h" 00042 #include "libmesh/parallel.h" 00043 #include "libmesh/parallel_algebra.h" 00044 #include "libmesh/quadrature.h" 00045 #include "libmesh/tensor_value.h" 00046 #include "libmesh/vector_value.h" 00047 #include "libmesh/tensor_tools.h" 00048 00049 namespace libMesh 00050 { 00051 00052 00053 // ------------------------------------------------------------ 00054 // System implementation 00055 System::System (EquationSystems& es, 00056 const std::string& name_in, 00057 const unsigned int number_in) : 00058 00059 ParallelObject (es), 00060 assemble_before_solve (true), 00061 use_fixed_solution (false), 00062 extra_quadrature_order (0), 00063 solution (NumericVector<Number>::build(this->comm())), 00064 current_local_solution (NumericVector<Number>::build(this->comm())), 00065 time (0.), 00066 qoi (0), 00067 _init_system_function (NULL), 00068 _init_system_object (NULL), 00069 _assemble_system_function (NULL), 00070 _assemble_system_object (NULL), 00071 _constrain_system_function (NULL), 00072 _constrain_system_object (NULL), 00073 _qoi_evaluate_function (NULL), 00074 _qoi_evaluate_object (NULL), 00075 _qoi_evaluate_derivative_function (NULL), 00076 _qoi_evaluate_derivative_object (NULL), 00077 _dof_map (new DofMap(number_in, *this)), 00078 _equation_systems (es), 00079 _mesh (es.get_mesh()), 00080 _sys_name (name_in), 00081 _sys_number (number_in), 00082 _active (true), 00083 _solution_projection (true), 00084 _basic_system_only (false), 00085 _is_initialized (false), 00086 _identify_variable_groups (true), 00087 _additional_data_written (false), 00088 adjoint_already_solved (false) 00089 { 00090 } 00091 00092 00093 00094 // No copy construction of System objects! 00095 System::System (const System& other) : 00096 ReferenceCountedObject<System>(), 00097 ParallelObject(other), 00098 _equation_systems(other._equation_systems), 00099 _mesh(other._mesh), 00100 _sys_number(other._sys_number) 00101 { 00102 libmesh_not_implemented(); 00103 } 00104 00105 00106 00107 System& System::operator= (const System&) 00108 { 00109 libmesh_not_implemented(); 00110 } 00111 00112 00113 System::~System () 00114 { 00115 // Null-out the function pointers. Since this 00116 // class is getting destructed it is pointless, 00117 // but a good habit. 00118 _init_system_function = 00119 _assemble_system_function = 00120 _constrain_system_function = NULL; 00121 00122 _qoi_evaluate_function = NULL; 00123 _qoi_evaluate_derivative_function = NULL; 00124 00125 // NULL-out user-provided objects. 00126 _init_system_object = NULL; 00127 _assemble_system_object = NULL; 00128 _constrain_system_object = NULL; 00129 _qoi_evaluate_object = NULL; 00130 _qoi_evaluate_derivative_object = NULL; 00131 00132 // Clear data 00133 this->clear (); 00134 00135 libmesh_exceptionless_assert (!libMesh::closed()); 00136 } 00137 00138 00139 00140 dof_id_type System::n_dofs() const 00141 { 00142 return _dof_map->n_dofs(); 00143 } 00144 00145 00146 00147 dof_id_type System::n_constrained_dofs() const 00148 { 00149 #ifdef LIBMESH_ENABLE_CONSTRAINTS 00150 00151 return _dof_map->n_constrained_dofs(); 00152 00153 #else 00154 00155 return 0; 00156 00157 #endif 00158 } 00159 00160 00161 00162 dof_id_type System::n_local_constrained_dofs() const 00163 { 00164 #ifdef LIBMESH_ENABLE_CONSTRAINTS 00165 00166 return _dof_map->n_local_constrained_dofs(); 00167 00168 #else 00169 00170 return 0; 00171 00172 #endif 00173 } 00174 00175 00176 00177 dof_id_type System::n_local_dofs() const 00178 { 00179 return _dof_map->n_dofs_on_processor (this->processor_id()); 00180 } 00181 00182 00183 00184 Number System::current_solution (const dof_id_type global_dof_number) const 00185 { 00186 // Check the sizes 00187 libmesh_assert_less (global_dof_number, _dof_map->n_dofs()); 00188 libmesh_assert_less (global_dof_number, current_local_solution->size()); 00189 00190 return (*current_local_solution)(global_dof_number); 00191 } 00192 00193 00194 00195 void System::clear () 00196 { 00197 _variables.clear(); 00198 00199 _variable_numbers.clear(); 00200 00201 _dof_map->clear (); 00202 00203 solution->clear (); 00204 00205 current_local_solution->clear (); 00206 00207 // clear any user-added vectors 00208 { 00209 for (vectors_iterator pos = _vectors.begin(); pos != _vectors.end(); ++pos) 00210 { 00211 pos->second->clear (); 00212 delete pos->second; 00213 pos->second = NULL; 00214 } 00215 00216 _vectors.clear(); 00217 _vector_projections.clear(); 00218 _vector_is_adjoint.clear(); 00219 _vector_types.clear(); 00220 _is_initialized = false; 00221 } 00222 00223 } 00224 00225 00226 00227 void System::init () 00228 { 00229 // First initialize any required data: 00230 // either only the basic System data 00231 if (_basic_system_only) 00232 System::init_data(); 00233 // or all the derived class' data too 00234 else 00235 this->init_data(); 00236 00237 // If no variables have been added to this system 00238 // don't do anything 00239 if(!this->n_vars()) 00240 return; 00241 00242 // Then call the user-provided intialization function 00243 this->user_initialization(); 00244 } 00245 00246 00247 00248 void System::init_data () 00249 { 00250 MeshBase &mesh = this->get_mesh(); 00251 00252 // Add all variable groups to our underlying DofMap 00253 for (unsigned int vg=0; vg<this->n_variable_groups(); vg++) 00254 _dof_map->add_variable_group(this->variable_group(vg)); 00255 00256 // Distribute the degrees of freedom on the mesh 00257 _dof_map->distribute_dofs (mesh); 00258 00259 #ifdef LIBMESH_ENABLE_CONSTRAINTS 00260 00261 // Recreate any hanging node constraints 00262 _dof_map->create_dof_constraints(mesh); 00263 00264 // Apply any user-defined constraints 00265 this->user_constrain(); 00266 00267 // Expand any recursive constraints 00268 _dof_map->process_constraints(mesh); 00269 00270 #endif 00271 00272 // And clean up the send_list before we first use it 00273 _dof_map->prepare_send_list(); 00274 00275 // Resize the solution conformal to the current mesh 00276 solution->init (this->n_dofs(), this->n_local_dofs(), false, PARALLEL); 00277 00278 // Resize the current_local_solution for the current mesh 00279 #ifdef LIBMESH_ENABLE_GHOSTED 00280 current_local_solution->init (this->n_dofs(), this->n_local_dofs(), 00281 _dof_map->get_send_list(), false, 00282 GHOSTED); 00283 #else 00284 current_local_solution->init (this->n_dofs(), false, SERIAL); 00285 #endif 00286 00287 // from now on, adding additional vectors or variables can't be done 00288 // without immediately initializing them 00289 _is_initialized = true; 00290 00291 // initialize & zero other vectors, if necessary 00292 for (vectors_iterator pos = _vectors.begin(); pos != _vectors.end(); ++pos) 00293 { 00294 ParallelType type = _vector_types[pos->first]; 00295 00296 if (type == GHOSTED) 00297 { 00298 #ifdef LIBMESH_ENABLE_GHOSTED 00299 pos->second->init (this->n_dofs(), this->n_local_dofs(), 00300 _dof_map->get_send_list(), false, 00301 GHOSTED); 00302 #else 00303 libmesh_error_msg("Cannot initialize ghosted vectors when they are not enabled."); 00304 #endif 00305 } 00306 else if (type == SERIAL) 00307 { 00308 pos->second->init (this->n_dofs(), false, type); 00309 } 00310 else 00311 { 00312 libmesh_assert_equal_to(type, PARALLEL); 00313 pos->second->init (this->n_dofs(), this->n_local_dofs(), false, type); 00314 } 00315 } 00316 } 00317 00318 00319 00320 void System::restrict_vectors () 00321 { 00322 #ifdef LIBMESH_ENABLE_AMR 00323 // Restrict the _vectors on the coarsened cells 00324 for (vectors_iterator pos = _vectors.begin(); pos != _vectors.end(); ++pos) 00325 { 00326 NumericVector<Number>* v = pos->second; 00327 00328 if (_vector_projections[pos->first]) 00329 { 00330 this->project_vector (*v, this->vector_is_adjoint(pos->first)); 00331 } 00332 else 00333 { 00334 ParallelType type = _vector_types[pos->first]; 00335 00336 if(type == GHOSTED) 00337 { 00338 #ifdef LIBMESH_ENABLE_GHOSTED 00339 pos->second->init (this->n_dofs(), this->n_local_dofs(), 00340 _dof_map->get_send_list(), false, 00341 GHOSTED); 00342 #else 00343 libmesh_error_msg("Cannot initialize ghosted vectors when they are not enabled."); 00344 #endif 00345 } 00346 else 00347 pos->second->init (this->n_dofs(), this->n_local_dofs(), false, type); 00348 } 00349 } 00350 00351 const std::vector<dof_id_type>& send_list = _dof_map->get_send_list (); 00352 00353 // Restrict the solution on the coarsened cells 00354 if (_solution_projection) 00355 this->project_vector (*solution); 00356 00357 #ifdef LIBMESH_ENABLE_GHOSTED 00358 current_local_solution->init(this->n_dofs(), 00359 this->n_local_dofs(), send_list, 00360 false, GHOSTED); 00361 #else 00362 current_local_solution->init(this->n_dofs()); 00363 #endif 00364 00365 if (_solution_projection) 00366 solution->localize (*current_local_solution, send_list); 00367 00368 #endif // LIBMESH_ENABLE_AMR 00369 } 00370 00371 00372 00373 void System::prolong_vectors () 00374 { 00375 #ifdef LIBMESH_ENABLE_AMR 00376 // Currently project_vector handles both restriction and prolongation 00377 this->restrict_vectors(); 00378 #endif 00379 } 00380 00381 00382 00383 void System::reinit () 00384 { 00385 //If no variables have been added to this system 00386 //don't do anything 00387 if(!this->n_vars()) 00388 return; 00389 00390 // Constraints get handled in EquationSystems::reinit now 00391 // _dof_map->create_dof_constraints(this->get_mesh()); 00392 00393 // Update the solution based on the projected 00394 // current_local_solution. 00395 solution->init (this->n_dofs(), this->n_local_dofs(), true, PARALLEL); 00396 00397 libmesh_assert_equal_to (solution->size(), current_local_solution->size()); 00398 // Not true with ghosted vectors 00399 // libmesh_assert_equal_to (solution->size(), current_local_solution->local_size()); 00400 00401 const dof_id_type first_local_dof = solution->first_local_index(); 00402 const dof_id_type local_size = solution->local_size(); 00403 00404 for (dof_id_type i=0; i<local_size; i++) 00405 solution->set(i+first_local_dof, 00406 (*current_local_solution)(i+first_local_dof)); 00407 00408 solution->close(); 00409 } 00410 00411 00412 void System::reinit_constraints() 00413 { 00414 get_dof_map().create_dof_constraints(_mesh, this->time); 00415 user_constrain(); 00416 get_dof_map().process_constraints(_mesh); 00417 get_dof_map().prepare_send_list(); 00418 } 00419 00420 00421 void System::update () 00422 { 00423 libmesh_assert(solution->closed()); 00424 00425 const std::vector<dof_id_type>& send_list = _dof_map->get_send_list (); 00426 00427 // Check sizes 00428 libmesh_assert_equal_to (current_local_solution->size(), solution->size()); 00429 // More processors than elements => empty send_list 00430 // libmesh_assert (!send_list.empty()); 00431 libmesh_assert_less_equal (send_list.size(), solution->size()); 00432 00433 // Create current_local_solution from solution. This will 00434 // put a local copy of solution into current_local_solution. 00435 // Only the necessary values (specified by the send_list) 00436 // are copied to minimize communication 00437 solution->localize (*current_local_solution, send_list); 00438 } 00439 00440 00441 00442 void System::re_update () 00443 { 00444 parallel_object_only(); 00445 00446 // If this system is empty... don't do anything! 00447 if(!this->n_vars()) 00448 return; 00449 00450 const std::vector<dof_id_type>& send_list = this->get_dof_map().get_send_list (); 00451 00452 // Check sizes 00453 libmesh_assert_equal_to (current_local_solution->size(), solution->size()); 00454 // Not true with ghosted vectors 00455 // libmesh_assert_equal_to (current_local_solution->local_size(), solution->size()); 00456 // libmesh_assert (!send_list.empty()); 00457 libmesh_assert_less_equal (send_list.size(), solution->size()); 00458 00459 // Create current_local_solution from solution. This will 00460 // put a local copy of solution into current_local_solution. 00461 solution->localize (*current_local_solution, send_list); 00462 } 00463 00464 00465 00466 void System::restrict_solve_to (const SystemSubset* subset, 00467 const SubsetSolveMode /*subset_solve_mode*/) 00468 { 00469 if(subset!=NULL) 00470 { 00471 libmesh_not_implemented(); 00472 } 00473 } 00474 00475 00476 00477 void System::assemble () 00478 { 00479 // Log how long the user's assembly code takes 00480 START_LOG("assemble()", "System"); 00481 00482 // Call the user-specified assembly function 00483 this->user_assembly(); 00484 00485 // Stop logging the user code 00486 STOP_LOG("assemble()", "System"); 00487 } 00488 00489 00490 00491 void System::assemble_qoi (const QoISet& qoi_indices) 00492 { 00493 // Log how long the user's assembly code takes 00494 START_LOG("assemble_qoi()", "System"); 00495 00496 // Call the user-specified quantity of interest function 00497 this->user_QOI(qoi_indices); 00498 00499 // Stop logging the user code 00500 STOP_LOG("assemble_qoi()", "System"); 00501 } 00502 00503 00504 00505 void System::assemble_qoi_derivative(const QoISet& qoi_indices, 00506 bool include_liftfunc, 00507 bool apply_constraints) 00508 { 00509 // Log how long the user's assembly code takes 00510 START_LOG("assemble_qoi_derivative()", "System"); 00511 00512 // Call the user-specified quantity of interest function 00513 this->user_QOI_derivative(qoi_indices, include_liftfunc, 00514 apply_constraints); 00515 00516 // Stop logging the user code 00517 STOP_LOG("assemble_qoi_derivative()", "System"); 00518 } 00519 00520 00521 00522 void System::qoi_parameter_sensitivity 00523 (const QoISet& qoi_indices, 00524 const ParameterVector& parameters, 00525 SensitivityData& sensitivities) 00526 { 00527 // Forward sensitivities are more efficient for Nq > Np 00528 if (qoi_indices.size(*this) > parameters.size()) 00529 forward_qoi_parameter_sensitivity(qoi_indices, parameters, sensitivities); 00530 // Adjoint sensitivities are more efficient for Np > Nq, 00531 // and an adjoint may be more reusable than a forward 00532 // solution sensitivity in the Np == Nq case. 00533 else 00534 adjoint_qoi_parameter_sensitivity(qoi_indices, parameters, sensitivities); 00535 } 00536 00537 00538 00539 bool System::compare (const System& other_system, 00540 const Real threshold, 00541 const bool verbose) const 00542 { 00543 // we do not care for matrices, but for vectors 00544 libmesh_assert (_is_initialized); 00545 libmesh_assert (other_system._is_initialized); 00546 00547 if (verbose) 00548 { 00549 libMesh::out << " Systems \"" << _sys_name << "\"" << std::endl; 00550 libMesh::out << " comparing matrices not supported." << std::endl; 00551 libMesh::out << " comparing names..."; 00552 } 00553 00554 // compare the name: 0 means identical 00555 const int name_result = _sys_name.compare(other_system.name()); 00556 if (verbose) 00557 { 00558 if (name_result == 0) 00559 libMesh::out << " identical." << std::endl; 00560 else 00561 libMesh::out << " names not identical." << std::endl; 00562 libMesh::out << " comparing solution vector..."; 00563 } 00564 00565 00566 // compare the solution: -1 means identical 00567 const int solu_result = solution->compare (*other_system.solution.get(), 00568 threshold); 00569 00570 if (verbose) 00571 { 00572 if (solu_result == -1) 00573 libMesh::out << " identical up to threshold." << std::endl; 00574 else 00575 libMesh::out << " first difference occured at index = " 00576 << solu_result << "." << std::endl; 00577 } 00578 00579 00580 // safety check, whether we handle at least the same number 00581 // of vectors 00582 std::vector<int> ov_result; 00583 00584 if (this->n_vectors() != other_system.n_vectors()) 00585 { 00586 if (verbose) 00587 { 00588 libMesh::out << " Fatal difference. This system handles " 00589 << this->n_vectors() << " add'l vectors," << std::endl 00590 << " while the other system handles " 00591 << other_system.n_vectors() 00592 << " add'l vectors." << std::endl 00593 << " Aborting comparison." << std::endl; 00594 } 00595 return false; 00596 } 00597 else if (this->n_vectors() == 0) 00598 { 00599 // there are no additional vectors... 00600 ov_result.clear (); 00601 } 00602 else 00603 { 00604 // compare other vectors 00605 for (const_vectors_iterator pos = _vectors.begin(); 00606 pos != _vectors.end(); ++pos) 00607 { 00608 if (verbose) 00609 libMesh::out << " comparing vector \"" 00610 << pos->first << "\" ..."; 00611 00612 // assume they have the same name 00613 const NumericVector<Number>& other_system_vector = 00614 other_system.get_vector(pos->first); 00615 00616 ov_result.push_back(pos->second->compare (other_system_vector, 00617 threshold)); 00618 00619 if (verbose) 00620 { 00621 if (ov_result[ov_result.size()-1] == -1) 00622 libMesh::out << " identical up to threshold." << std::endl; 00623 else 00624 libMesh::out << " first difference occured at" << std::endl 00625 << " index = " << ov_result[ov_result.size()-1] << "." << std::endl; 00626 } 00627 00628 } 00629 00630 } // finished comparing additional vectors 00631 00632 00633 bool overall_result; 00634 00635 // sum up the results 00636 if ((name_result==0) && (solu_result==-1)) 00637 { 00638 if (ov_result.size()==0) 00639 overall_result = true; 00640 else 00641 { 00642 bool ov_identical; 00643 unsigned int n = 0; 00644 do 00645 { 00646 ov_identical = (ov_result[n]==-1); 00647 n++; 00648 } 00649 while (ov_identical && n<ov_result.size()); 00650 overall_result = ov_identical; 00651 } 00652 } 00653 else 00654 overall_result = false; 00655 00656 if (verbose) 00657 { 00658 libMesh::out << " finished comparisons, "; 00659 if (overall_result) 00660 libMesh::out << "found no differences." << std::endl << std::endl; 00661 else 00662 libMesh::out << "found differences." << std::endl << std::endl; 00663 } 00664 00665 return overall_result; 00666 } 00667 00668 00669 00670 void System::update_global_solution (std::vector<Number>& global_soln) const 00671 { 00672 global_soln.resize (solution->size()); 00673 00674 solution->localize (global_soln); 00675 } 00676 00677 00678 00679 void System::update_global_solution (std::vector<Number>& global_soln, 00680 const processor_id_type dest_proc) const 00681 { 00682 global_soln.resize (solution->size()); 00683 00684 solution->localize_to_one (global_soln, dest_proc); 00685 } 00686 00687 00688 00689 NumericVector<Number> & System::add_vector (const std::string& vec_name, 00690 const bool projections, 00691 const ParallelType type) 00692 { 00693 // Return the vector if it is already there. 00694 if (this->have_vector(vec_name)) 00695 return *(_vectors[vec_name]); 00696 00697 // Otherwise build the vector 00698 NumericVector<Number>* buf = NumericVector<Number>::build(this->comm()).release(); 00699 _vectors.insert (std::make_pair (vec_name, buf)); 00700 _vector_projections.insert (std::make_pair (vec_name, projections)); 00701 00702 _vector_types.insert (std::make_pair (vec_name, type)); 00703 00704 // Vectors are primal by default 00705 _vector_is_adjoint.insert (std::make_pair (vec_name, -1)); 00706 00707 // Initialize it if necessary 00708 if (_is_initialized) 00709 { 00710 if(type == GHOSTED) 00711 { 00712 #ifdef LIBMESH_ENABLE_GHOSTED 00713 buf->init (this->n_dofs(), this->n_local_dofs(), 00714 _dof_map->get_send_list(), false, 00715 GHOSTED); 00716 #else 00717 libmesh_error_msg("Cannot initialize ghosted vectors when they are not enabled."); 00718 #endif 00719 } 00720 else 00721 buf->init (this->n_dofs(), this->n_local_dofs(), false, type); 00722 } 00723 00724 return *buf; 00725 } 00726 00727 void System::remove_vector (const std::string& vec_name) 00728 { 00729 //Return if the vector does not exist 00730 if ( !(this->have_vector(vec_name)) ) 00731 return; 00732 00733 _vectors[vec_name]->clear(); 00734 delete _vectors[vec_name]; 00735 _vectors[vec_name] = NULL; 00736 00737 _vectors.erase(vec_name); 00738 _vector_projections.erase(vec_name); 00739 _vector_is_adjoint.erase(vec_name); 00740 _vector_types.erase(vec_name); 00741 } 00742 00743 const NumericVector<Number> * System::request_vector (const std::string& vec_name) const 00744 { 00745 const_vectors_iterator pos = _vectors.find(vec_name); 00746 00747 if (pos == _vectors.end()) 00748 return NULL; 00749 00750 return pos->second; 00751 } 00752 00753 00754 00755 NumericVector<Number> * System::request_vector (const std::string& vec_name) 00756 { 00757 vectors_iterator pos = _vectors.find(vec_name); 00758 00759 if (pos == _vectors.end()) 00760 return NULL; 00761 00762 return pos->second; 00763 } 00764 00765 00766 00767 const NumericVector<Number> * System::request_vector (const unsigned int vec_num) const 00768 { 00769 const_vectors_iterator v = vectors_begin(); 00770 const_vectors_iterator v_end = vectors_end(); 00771 unsigned int num = 0; 00772 while((num<vec_num) && (v!=v_end)) 00773 { 00774 num++; 00775 ++v; 00776 } 00777 if (v==v_end) 00778 return NULL; 00779 return v->second; 00780 } 00781 00782 00783 00784 NumericVector<Number> * System::request_vector (const unsigned int vec_num) 00785 { 00786 vectors_iterator v = vectors_begin(); 00787 vectors_iterator v_end = vectors_end(); 00788 unsigned int num = 0; 00789 while((num<vec_num) && (v!=v_end)) 00790 { 00791 num++; 00792 ++v; 00793 } 00794 if (v==v_end) 00795 return NULL; 00796 return v->second; 00797 } 00798 00799 00800 00801 const NumericVector<Number> & System::get_vector (const std::string& vec_name) const 00802 { 00803 // Make sure the vector exists 00804 const_vectors_iterator pos = _vectors.find(vec_name); 00805 00806 if (pos == _vectors.end()) 00807 libmesh_error_msg("ERROR: vector " << vec_name << " does not exist in this system!"); 00808 00809 return *(pos->second); 00810 } 00811 00812 00813 00814 NumericVector<Number> & System::get_vector (const std::string& vec_name) 00815 { 00816 // Make sure the vector exists 00817 vectors_iterator pos = _vectors.find(vec_name); 00818 00819 if (pos == _vectors.end()) 00820 libmesh_error_msg("ERROR: vector " << vec_name << " does not exist in this system!"); 00821 00822 return *(pos->second); 00823 } 00824 00825 00826 00827 const NumericVector<Number> & System::get_vector (const unsigned int vec_num) const 00828 { 00829 const_vectors_iterator v = vectors_begin(); 00830 const_vectors_iterator v_end = vectors_end(); 00831 unsigned int num = 0; 00832 while((num<vec_num) && (v!=v_end)) 00833 { 00834 num++; 00835 ++v; 00836 } 00837 libmesh_assert (v != v_end); 00838 return *(v->second); 00839 } 00840 00841 00842 00843 NumericVector<Number> & System::get_vector (const unsigned int vec_num) 00844 { 00845 vectors_iterator v = vectors_begin(); 00846 vectors_iterator v_end = vectors_end(); 00847 unsigned int num = 0; 00848 while((num<vec_num) && (v!=v_end)) 00849 { 00850 num++; 00851 ++v; 00852 } 00853 libmesh_assert (v != v_end); 00854 return *(v->second); 00855 } 00856 00857 00858 00859 const std::string& System::vector_name (const unsigned int vec_num) const 00860 { 00861 const_vectors_iterator v = vectors_begin(); 00862 const_vectors_iterator v_end = vectors_end(); 00863 unsigned int num = 0; 00864 while((num<vec_num) && (v!=v_end)) 00865 { 00866 num++; 00867 ++v; 00868 } 00869 libmesh_assert (v != v_end); 00870 return v->first; 00871 } 00872 00873 const std::string & System::vector_name (const NumericVector<Number> & vec_reference) const 00874 { 00875 const_vectors_iterator v = vectors_begin(); 00876 const_vectors_iterator v_end = vectors_end(); 00877 00878 for(; v != v_end; ++v) 00879 { 00880 // Check if the current vector is the one whose name we want 00881 if(&vec_reference == v->second) 00882 break; // exit loop if it is 00883 } 00884 00885 // Before returning, make sure we didnt loop till the end and not find any match 00886 libmesh_assert (v != v_end); 00887 00888 // Return the string associated with the current vector 00889 return v->first; 00890 } 00891 00892 00893 00894 void System::set_vector_preservation (const std::string &vec_name, 00895 bool preserve) 00896 { 00897 _vector_projections[vec_name] = preserve; 00898 } 00899 00900 00901 00902 bool System::vector_preservation (const std::string &vec_name) const 00903 { 00904 if (_vector_projections.find(vec_name) == _vector_projections.end()) 00905 return false; 00906 00907 return _vector_projections.find(vec_name)->second; 00908 } 00909 00910 00911 00912 void System::set_vector_as_adjoint (const std::string &vec_name, 00913 int qoi_num) 00914 { 00915 // We reserve -1 for vectors which get primal constraints, -2 for 00916 // vectors which get no constraints 00917 libmesh_assert_greater_equal(qoi_num, -2); 00918 _vector_is_adjoint[vec_name] = qoi_num; 00919 } 00920 00921 00922 00923 int System::vector_is_adjoint (const std::string &vec_name) const 00924 { 00925 libmesh_assert(_vector_is_adjoint.find(vec_name) != 00926 _vector_is_adjoint.end()); 00927 00928 return _vector_is_adjoint.find(vec_name)->second; 00929 } 00930 00931 00932 00933 NumericVector<Number> & System::add_sensitivity_solution (unsigned int i) 00934 { 00935 std::ostringstream sensitivity_name; 00936 sensitivity_name << "sensitivity_solution" << i; 00937 00938 return this->add_vector(sensitivity_name.str()); 00939 } 00940 00941 00942 00943 NumericVector<Number> & System::get_sensitivity_solution (unsigned int i) 00944 { 00945 std::ostringstream sensitivity_name; 00946 sensitivity_name << "sensitivity_solution" << i; 00947 00948 return this->get_vector(sensitivity_name.str()); 00949 } 00950 00951 00952 00953 const NumericVector<Number> & System::get_sensitivity_solution (unsigned int i) const 00954 { 00955 std::ostringstream sensitivity_name; 00956 sensitivity_name << "sensitivity_solution" << i; 00957 00958 return this->get_vector(sensitivity_name.str()); 00959 } 00960 00961 00962 00963 NumericVector<Number> & System::add_weighted_sensitivity_solution () 00964 { 00965 return this->add_vector("weighted_sensitivity_solution"); 00966 } 00967 00968 00969 00970 NumericVector<Number> & System::get_weighted_sensitivity_solution () 00971 { 00972 return this->get_vector("weighted_sensitivity_solution"); 00973 } 00974 00975 00976 00977 const NumericVector<Number> & System::get_weighted_sensitivity_solution () const 00978 { 00979 return this->get_vector("weighted_sensitivity_solution"); 00980 } 00981 00982 00983 00984 NumericVector<Number> & System::add_adjoint_solution (unsigned int i) 00985 { 00986 std::ostringstream adjoint_name; 00987 adjoint_name << "adjoint_solution" << i; 00988 00989 NumericVector<Number> &returnval = this->add_vector(adjoint_name.str()); 00990 this->set_vector_as_adjoint(adjoint_name.str(), i); 00991 return returnval; 00992 } 00993 00994 00995 00996 NumericVector<Number> & System::get_adjoint_solution (unsigned int i) 00997 { 00998 std::ostringstream adjoint_name; 00999 adjoint_name << "adjoint_solution" << i; 01000 01001 return this->get_vector(adjoint_name.str()); 01002 } 01003 01004 01005 01006 const NumericVector<Number> & System::get_adjoint_solution (unsigned int i) const 01007 { 01008 std::ostringstream adjoint_name; 01009 adjoint_name << "adjoint_solution" << i; 01010 01011 return this->get_vector(adjoint_name.str()); 01012 } 01013 01014 01015 01016 NumericVector<Number> & System::add_weighted_sensitivity_adjoint_solution (unsigned int i) 01017 { 01018 std::ostringstream adjoint_name; 01019 adjoint_name << "weighted_sensitivity_adjoint_solution" << i; 01020 01021 NumericVector<Number> &returnval = this->add_vector(adjoint_name.str()); 01022 this->set_vector_as_adjoint(adjoint_name.str(), i); 01023 return returnval; 01024 } 01025 01026 01027 01028 NumericVector<Number> & System::get_weighted_sensitivity_adjoint_solution (unsigned int i) 01029 { 01030 std::ostringstream adjoint_name; 01031 adjoint_name << "weighted_sensitivity_adjoint_solution" << i; 01032 01033 return this->get_vector(adjoint_name.str()); 01034 } 01035 01036 01037 01038 const NumericVector<Number> & System::get_weighted_sensitivity_adjoint_solution (unsigned int i) const 01039 { 01040 std::ostringstream adjoint_name; 01041 adjoint_name << "weighted_sensitivity_adjoint_solution" << i; 01042 01043 return this->get_vector(adjoint_name.str()); 01044 } 01045 01046 01047 01048 NumericVector<Number> & System::add_adjoint_rhs (unsigned int i) 01049 { 01050 std::ostringstream adjoint_rhs_name; 01051 adjoint_rhs_name << "adjoint_rhs" << i; 01052 01053 return this->add_vector(adjoint_rhs_name.str(), false); 01054 } 01055 01056 01057 01058 NumericVector<Number> & System::get_adjoint_rhs (unsigned int i) 01059 { 01060 std::ostringstream adjoint_rhs_name; 01061 adjoint_rhs_name << "adjoint_rhs" << i; 01062 01063 return this->get_vector(adjoint_rhs_name.str()); 01064 } 01065 01066 01067 01068 const NumericVector<Number> & System::get_adjoint_rhs (unsigned int i) const 01069 { 01070 std::ostringstream adjoint_rhs_name; 01071 adjoint_rhs_name << "adjoint_rhs" << i; 01072 01073 return this->get_vector(adjoint_rhs_name.str()); 01074 } 01075 01076 01077 01078 NumericVector<Number> & System::add_sensitivity_rhs (unsigned int i) 01079 { 01080 std::ostringstream sensitivity_rhs_name; 01081 sensitivity_rhs_name << "sensitivity_rhs" << i; 01082 01083 return this->add_vector(sensitivity_rhs_name.str(), false); 01084 } 01085 01086 01087 01088 NumericVector<Number> & System::get_sensitivity_rhs (unsigned int i) 01089 { 01090 std::ostringstream sensitivity_rhs_name; 01091 sensitivity_rhs_name << "sensitivity_rhs" << i; 01092 01093 return this->get_vector(sensitivity_rhs_name.str()); 01094 } 01095 01096 01097 01098 const NumericVector<Number> & System::get_sensitivity_rhs (unsigned int i) const 01099 { 01100 std::ostringstream sensitivity_rhs_name; 01101 sensitivity_rhs_name << "sensitivity_rhs" << i; 01102 01103 return this->get_vector(sensitivity_rhs_name.str()); 01104 } 01105 01106 01107 01108 unsigned int System::add_variable (const std::string& var, 01109 const FEType& type, 01110 const std::set<subdomain_id_type> * const active_subdomains) 01111 { 01112 libmesh_assert(!this->is_initialized()); 01113 01114 // Make sure the variable isn't there already 01115 // or if it is, that it's the type we want 01116 for (unsigned int v=0; v<this->n_vars(); v++) 01117 if (this->variable_name(v) == var) 01118 { 01119 if (this->variable_type(v) == type) 01120 return _variables[v].number(); 01121 01122 libmesh_error_msg("ERROR: incompatible variable " << var << " has already been added for this system!"); 01123 } 01124 01125 // Optimize for VariableGroups here - if the user is adding multiple 01126 // variables of the same FEType and subdomain restriction, catch 01127 // that here and add them as members of the same VariableGroup. 01128 // 01129 // start by setting this flag to whatever the user has requested 01130 // and then consider the conditions which should negate it. 01131 bool should_be_in_vg = this->identify_variable_groups(); 01132 01133 // No variable groups, nothing to add to 01134 if (!this->n_variable_groups()) 01135 should_be_in_vg = false; 01136 01137 else 01138 { 01139 VariableGroup &vg(_variable_groups.back()); 01140 01141 // get a pointer to their subdomain restriction, if any. 01142 const std::set<subdomain_id_type> * const 01143 their_active_subdomains (vg.implicitly_active() ? 01144 NULL : &vg.active_subdomains()); 01145 01146 // Different types? 01147 if (vg.type() != type) 01148 should_be_in_vg = false; 01149 01150 // they are restricted, we aren't? 01151 if (their_active_subdomains && !active_subdomains) 01152 should_be_in_vg = false; 01153 01154 // they aren't restriced, we are? 01155 if (!their_active_subdomains && active_subdomains) 01156 should_be_in_vg = false; 01157 01158 if (their_active_subdomains && active_subdomains) 01159 // restricted to different sets? 01160 if (*their_active_subdomains != *active_subdomains) 01161 should_be_in_vg = false; 01162 01163 // OK, after all that, append the variable to the vg if none of the conditions 01164 // were violated 01165 if (should_be_in_vg) 01166 { 01167 const unsigned short curr_n_vars = cast_int<unsigned short> 01168 (this->n_vars()); 01169 01170 vg.append (var); 01171 01172 _variables.push_back(vg(vg.n_variables()-1)); 01173 _variable_numbers[var] = curr_n_vars; 01174 return curr_n_vars; 01175 } 01176 } 01177 01178 // otherwise, fall back to adding a single variable group 01179 return this->add_variables (std::vector<std::string>(1, var), 01180 type, 01181 active_subdomains); 01182 } 01183 01184 01185 01186 unsigned int System::add_variable (const std::string& var, 01187 const Order order, 01188 const FEFamily family, 01189 const std::set<subdomain_id_type> * const active_subdomains) 01190 { 01191 return this->add_variable(var, 01192 FEType(order, family), 01193 active_subdomains); 01194 } 01195 01196 01197 01198 unsigned int System::add_variables (const std::vector<std::string> &vars, 01199 const FEType& type, 01200 const std::set<subdomain_id_type> * const active_subdomains) 01201 { 01202 libmesh_assert(!this->is_initialized()); 01203 01204 // Make sure the variable isn't there already 01205 // or if it is, that it's the type we want 01206 for (unsigned int ov=0; ov<vars.size(); ov++) 01207 for (unsigned int v=0; v<this->n_vars(); v++) 01208 if (this->variable_name(v) == vars[ov]) 01209 { 01210 if (this->variable_type(v) == type) 01211 return _variables[v].number(); 01212 01213 libmesh_error_msg("ERROR: incompatible variable " << vars[ov] << " has already been added for this system!"); 01214 } 01215 01216 const unsigned short curr_n_vars = cast_int<unsigned short> 01217 (this->n_vars()); 01218 01219 const unsigned int next_first_component = this->n_components(); 01220 01221 // Add the variable group to the list 01222 _variable_groups.push_back((active_subdomains == NULL) ? 01223 VariableGroup(this, vars, curr_n_vars, 01224 next_first_component, type) : 01225 VariableGroup(this, vars, curr_n_vars, 01226 next_first_component, type, *active_subdomains)); 01227 01228 const VariableGroup &vg (_variable_groups.back()); 01229 01230 // Add each component of the group individually 01231 for (unsigned short v=0; v<vars.size(); v++) 01232 { 01233 _variables.push_back (vg(v)); 01234 _variable_numbers[vars[v]] = cast_int<unsigned short> 01235 (curr_n_vars+v); 01236 } 01237 01238 libmesh_assert_equal_to ((curr_n_vars+vars.size()), this->n_vars()); 01239 01240 // BSK - Defer this now to System::init_data() so we can detect 01241 // VariableGroups 12/28/2012 01242 // // Add the variable group to the _dof_map 01243 // _dof_map->add_variable_group (vg); 01244 01245 // Return the number of the new variable 01246 return cast_int<unsigned int>(curr_n_vars+vars.size()-1); 01247 } 01248 01249 01250 01251 unsigned int System::add_variables (const std::vector<std::string> &vars, 01252 const Order order, 01253 const FEFamily family, 01254 const std::set<subdomain_id_type> * const active_subdomains) 01255 { 01256 return this->add_variables(vars, 01257 FEType(order, family), 01258 active_subdomains); 01259 } 01260 01261 01262 01263 bool System::has_variable (const std::string& var) const 01264 { 01265 return _variable_numbers.count(var); 01266 } 01267 01268 01269 01270 unsigned short int System::variable_number (const std::string& var) const 01271 { 01272 // Make sure the variable exists 01273 std::map<std::string, unsigned short int>::const_iterator 01274 pos = _variable_numbers.find(var); 01275 01276 if (pos == _variable_numbers.end()) 01277 libmesh_error_msg("ERROR: variable " << var << " does not exist in this system!"); 01278 01279 libmesh_assert_equal_to (_variables[pos->second].name(), var); 01280 01281 return pos->second; 01282 } 01283 01284 01285 void System::get_all_variable_numbers(std::vector<unsigned int>& all_variable_numbers) const 01286 { 01287 all_variable_numbers.resize(n_vars()); 01288 01289 // Make sure the variable exists 01290 std::map<std::string, unsigned short int>::const_iterator 01291 it = _variable_numbers.begin(); 01292 std::map<std::string, unsigned short int>::const_iterator 01293 it_end = _variable_numbers.end(); 01294 01295 unsigned int count = 0; 01296 for( ; it != it_end; ++it) 01297 { 01298 all_variable_numbers[count] = it->second; 01299 count++; 01300 } 01301 } 01302 01303 01304 void System::local_dof_indices(const unsigned int var, 01305 std::set<dof_id_type> & var_indices) const 01306 { 01307 // Make sure the set is clear 01308 var_indices.clear(); 01309 01310 std::vector<dof_id_type> dof_indices; 01311 01312 // Begin the loop over the elements 01313 MeshBase::const_element_iterator el = 01314 this->get_mesh().active_local_elements_begin(); 01315 const MeshBase::const_element_iterator end_el = 01316 this->get_mesh().active_local_elements_end(); 01317 01318 const dof_id_type 01319 first_local = this->get_dof_map().first_dof(), 01320 end_local = this->get_dof_map().end_dof(); 01321 01322 for ( ; el != end_el; ++el) 01323 { 01324 const Elem* elem = *el; 01325 this->get_dof_map().dof_indices (elem, dof_indices, var); 01326 01327 for(unsigned int i=0; i<dof_indices.size(); i++) 01328 { 01329 dof_id_type dof = dof_indices[i]; 01330 01331 //If the dof is owned by the local processor 01332 if(first_local <= dof && dof < end_local) 01333 var_indices.insert(dof_indices[i]); 01334 } 01335 } 01336 } 01337 01338 01339 01340 void System::zero_variable (NumericVector<Number>& v, unsigned int var_num) const 01341 { 01342 /* Make sure the call makes sense. */ 01343 libmesh_assert_less (var_num, this->n_vars()); 01344 01345 /* Get a reference to the mesh. */ 01346 const MeshBase& mesh = this->get_mesh(); 01347 01348 /* Check which system we are. */ 01349 const unsigned int sys_num = this->number(); 01350 01351 /* Loop over nodes. */ 01352 { 01353 MeshBase::const_node_iterator it = mesh.local_nodes_begin(); 01354 const MeshBase::const_node_iterator end_it = mesh.local_nodes_end(); 01355 for ( ; it != end_it; ++it) 01356 { 01357 const Node* node = *it; 01358 unsigned int n_comp = node->n_comp(sys_num,var_num); 01359 for(unsigned int i=0; i<n_comp; i++) 01360 { 01361 const dof_id_type index = node->dof_number(sys_num,var_num,i); 01362 v.set(index,0.0); 01363 } 01364 } 01365 } 01366 01367 /* Loop over elements. */ 01368 { 01369 MeshBase::const_element_iterator it = mesh.active_local_elements_begin(); 01370 const MeshBase::const_element_iterator end_it = mesh.active_local_elements_end(); 01371 for ( ; it != end_it; ++it) 01372 { 01373 const Elem* elem = *it; 01374 unsigned int n_comp = elem->n_comp(sys_num,var_num); 01375 for(unsigned int i=0; i<n_comp; i++) 01376 { 01377 const dof_id_type index = elem->dof_number(sys_num,var_num,i); 01378 v.set(index,0.0); 01379 } 01380 } 01381 } 01382 } 01383 01384 01385 01386 Real System::discrete_var_norm(const NumericVector<Number>& v, 01387 unsigned int var, 01388 FEMNormType norm_type) const 01389 { 01390 std::set<dof_id_type> var_indices; 01391 local_dof_indices(var, var_indices); 01392 01393 if(norm_type == DISCRETE_L1) 01394 return v.subset_l1_norm(var_indices); 01395 if(norm_type == DISCRETE_L2) 01396 return v.subset_l2_norm(var_indices); 01397 if(norm_type == DISCRETE_L_INF) 01398 return v.subset_linfty_norm(var_indices); 01399 else 01400 libmesh_error_msg("Invalid norm_type = " << norm_type); 01401 } 01402 01403 01404 01405 Real System::calculate_norm(const NumericVector<Number>& v, 01406 unsigned int var, 01407 FEMNormType norm_type) const 01408 { 01409 //short circuit to save time 01410 if(norm_type == DISCRETE_L1 || 01411 norm_type == DISCRETE_L2 || 01412 norm_type == DISCRETE_L_INF) 01413 return discrete_var_norm(v,var,norm_type); 01414 01415 // Not a discrete norm 01416 std::vector<FEMNormType> norms(this->n_vars(), L2); 01417 std::vector<Real> weights(this->n_vars(), 0.0); 01418 norms[var] = norm_type; 01419 weights[var] = 1.0; 01420 Real val = this->calculate_norm(v, SystemNorm(norms, weights)); 01421 return val; 01422 } 01423 01424 01425 01426 Real System::calculate_norm(const NumericVector<Number>& v, 01427 const SystemNorm &norm) const 01428 { 01429 // This function must be run on all processors at once 01430 parallel_object_only(); 01431 01432 START_LOG ("calculate_norm()", "System"); 01433 01434 // Zero the norm before summation 01435 Real v_norm = 0.; 01436 01437 if (norm.is_discrete()) 01438 { 01439 STOP_LOG ("calculate_norm()", "System"); 01440 //Check to see if all weights are 1.0 and all types are equal 01441 FEMNormType norm_type0 = norm.type(0); 01442 unsigned int check_var = 0; 01443 for (; check_var != this->n_vars(); ++check_var) 01444 if((norm.weight(check_var) != 1.0) || (norm.type(check_var) != norm_type0)) 01445 break; 01446 01447 //All weights were 1.0 so just do the full vector discrete norm 01448 if(check_var == this->n_vars()) 01449 { 01450 if(norm_type0 == DISCRETE_L1) 01451 return v.l1_norm(); 01452 if(norm_type0 == DISCRETE_L2) 01453 return v.l2_norm(); 01454 if(norm_type0 == DISCRETE_L_INF) 01455 return v.linfty_norm(); 01456 else 01457 libmesh_error_msg("Invalid norm_type0 = " << norm_type0); 01458 } 01459 01460 for (unsigned int var=0; var != this->n_vars(); ++var) 01461 { 01462 // Skip any variables we don't need to integrate 01463 if (norm.weight(var) == 0.0) 01464 continue; 01465 01466 v_norm += norm.weight(var) * discrete_var_norm(v, var, norm.type(var)); 01467 } 01468 01469 return v_norm; 01470 } 01471 01472 // Localize the potentially parallel vector 01473 UniquePtr<NumericVector<Number> > local_v = NumericVector<Number>::build(this->comm()); 01474 local_v->init(v.size(), true, SERIAL); 01475 v.localize (*local_v, _dof_map->get_send_list()); 01476 01477 unsigned int dim = this->get_mesh().mesh_dimension(); 01478 01479 // I'm not sure how best to mix Hilbert norms on some variables (for 01480 // which we'll want to square then sum then square root) with norms 01481 // like L_inf (for which we'll just want to take an absolute value 01482 // and then sum). 01483 bool using_hilbert_norm = true, 01484 using_nonhilbert_norm = true; 01485 01486 // Loop over all variables 01487 for (unsigned int var=0; var != this->n_vars(); ++var) 01488 { 01489 // Skip any variables we don't need to integrate 01490 Real norm_weight_sq = norm.weight_sq(var); 01491 if (norm_weight_sq == 0.0) 01492 continue; 01493 Real norm_weight = norm.weight(var); 01494 01495 // Check for unimplemented norms (rather than just returning 0). 01496 FEMNormType norm_type = norm.type(var); 01497 if((norm_type==H1) || 01498 (norm_type==H2) || 01499 (norm_type==L2) || 01500 (norm_type==H1_SEMINORM) || 01501 (norm_type==H2_SEMINORM)) 01502 { 01503 if (!using_hilbert_norm) 01504 libmesh_not_implemented(); 01505 using_nonhilbert_norm = false; 01506 } 01507 else if ((norm_type==L1) || 01508 (norm_type==L_INF) || 01509 (norm_type==W1_INF_SEMINORM) || 01510 (norm_type==W2_INF_SEMINORM)) 01511 { 01512 if (!using_nonhilbert_norm) 01513 libmesh_not_implemented(); 01514 using_hilbert_norm = false; 01515 } 01516 else 01517 libmesh_not_implemented(); 01518 01519 const FEType& fe_type = this->get_dof_map().variable_type(var); 01520 UniquePtr<QBase> qrule = 01521 fe_type.default_quadrature_rule (dim); 01522 UniquePtr<FEBase> fe 01523 (FEBase::build(dim, fe_type)); 01524 fe->attach_quadrature_rule (qrule.get()); 01525 01526 const std::vector<Real>& JxW = fe->get_JxW(); 01527 const std::vector<std::vector<Real> >* phi = NULL; 01528 if (norm_type == H1 || 01529 norm_type == H2 || 01530 norm_type == L2 || 01531 norm_type == L1 || 01532 norm_type == L_INF) 01533 phi = &(fe->get_phi()); 01534 01535 const std::vector<std::vector<RealGradient> >* dphi = NULL; 01536 if (norm_type == H1 || 01537 norm_type == H2 || 01538 norm_type == H1_SEMINORM || 01539 norm_type == W1_INF_SEMINORM) 01540 dphi = &(fe->get_dphi()); 01541 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 01542 const std::vector<std::vector<RealTensor> >* d2phi = NULL; 01543 if (norm_type == H2 || 01544 norm_type == H2_SEMINORM || 01545 norm_type == W2_INF_SEMINORM) 01546 d2phi = &(fe->get_d2phi()); 01547 #endif 01548 01549 std::vector<dof_id_type> dof_indices; 01550 01551 // Begin the loop over the elements 01552 MeshBase::const_element_iterator el = 01553 this->get_mesh().active_local_elements_begin(); 01554 const MeshBase::const_element_iterator end_el = 01555 this->get_mesh().active_local_elements_end(); 01556 01557 for ( ; el != end_el; ++el) 01558 { 01559 const Elem* elem = *el; 01560 01561 fe->reinit (elem); 01562 01563 this->get_dof_map().dof_indices (elem, dof_indices, var); 01564 01565 const unsigned int n_qp = qrule->n_points(); 01566 01567 const unsigned int n_sf = cast_int<unsigned int> 01568 (dof_indices.size()); 01569 01570 // Begin the loop over the Quadrature points. 01571 for (unsigned int qp=0; qp<n_qp; qp++) 01572 { 01573 if (norm_type == L1) 01574 { 01575 Number u_h = 0.; 01576 for (unsigned int i=0; i != n_sf; ++i) 01577 u_h += (*phi)[i][qp] * (*local_v)(dof_indices[i]); 01578 v_norm += norm_weight * 01579 JxW[qp] * std::abs(u_h); 01580 } 01581 01582 if (norm_type == L_INF) 01583 { 01584 Number u_h = 0.; 01585 for (unsigned int i=0; i != n_sf; ++i) 01586 u_h += (*phi)[i][qp] * (*local_v)(dof_indices[i]); 01587 v_norm = std::max(v_norm, norm_weight * std::abs(u_h)); 01588 } 01589 01590 if (norm_type == H1 || 01591 norm_type == H2 || 01592 norm_type == L2) 01593 { 01594 Number u_h = 0.; 01595 for (unsigned int i=0; i != n_sf; ++i) 01596 u_h += (*phi)[i][qp] * (*local_v)(dof_indices[i]); 01597 v_norm += norm_weight_sq * 01598 JxW[qp] * TensorTools::norm_sq(u_h); 01599 } 01600 01601 if (norm_type == H1 || 01602 norm_type == H2 || 01603 norm_type == H1_SEMINORM) 01604 { 01605 Gradient grad_u_h; 01606 for (unsigned int i=0; i != n_sf; ++i) 01607 grad_u_h.add_scaled((*dphi)[i][qp], (*local_v)(dof_indices[i])); 01608 v_norm += norm_weight_sq * 01609 JxW[qp] * grad_u_h.size_sq(); 01610 } 01611 01612 if (norm_type == W1_INF_SEMINORM) 01613 { 01614 Gradient grad_u_h; 01615 for (unsigned int i=0; i != n_sf; ++i) 01616 grad_u_h.add_scaled((*dphi)[i][qp], (*local_v)(dof_indices[i])); 01617 v_norm = std::max(v_norm, norm_weight * grad_u_h.size()); 01618 } 01619 01620 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 01621 if (norm_type == H2 || 01622 norm_type == H2_SEMINORM) 01623 { 01624 Tensor hess_u_h; 01625 for (unsigned int i=0; i != n_sf; ++i) 01626 hess_u_h.add_scaled((*d2phi)[i][qp], (*local_v)(dof_indices[i])); 01627 v_norm += norm_weight_sq * 01628 JxW[qp] * hess_u_h.size_sq(); 01629 } 01630 01631 if (norm_type == W2_INF_SEMINORM) 01632 { 01633 Tensor hess_u_h; 01634 for (unsigned int i=0; i != n_sf; ++i) 01635 hess_u_h.add_scaled((*d2phi)[i][qp], (*local_v)(dof_indices[i])); 01636 v_norm = std::max(v_norm, norm_weight * hess_u_h.size()); 01637 } 01638 #endif 01639 } 01640 } 01641 } 01642 01643 if (using_hilbert_norm) 01644 { 01645 this->comm().sum(v_norm); 01646 v_norm = std::sqrt(v_norm); 01647 } 01648 else 01649 { 01650 this->comm().max(v_norm); 01651 } 01652 01653 STOP_LOG ("calculate_norm()", "System"); 01654 01655 return v_norm; 01656 } 01657 01658 01659 01660 std::string System::get_info() const 01661 { 01662 std::ostringstream oss; 01663 01664 01665 const std::string& sys_name = this->name(); 01666 01667 oss << " System #" << this->number() << ", \"" << sys_name << "\"\n" 01668 << " Type \"" << this->system_type() << "\"\n" 01669 << " Variables="; 01670 01671 for (unsigned int vg=0; vg<this->n_variable_groups(); vg++) 01672 { 01673 const VariableGroup &vg_description (this->variable_group(vg)); 01674 01675 if (vg_description.n_variables() > 1) oss << "{ "; 01676 for (unsigned int vn=0; vn<vg_description.n_variables(); vn++) 01677 oss << "\"" << vg_description.name(vn) << "\" "; 01678 if (vg_description.n_variables() > 1) oss << "} "; 01679 } 01680 01681 oss << '\n'; 01682 01683 oss << " Finite Element Types="; 01684 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS 01685 for (unsigned int vg=0; vg<this->n_variable_groups(); vg++) 01686 oss << "\"" 01687 << Utility::enum_to_string<FEFamily>(this->get_dof_map().variable_group(vg).type().family) 01688 << "\" "; 01689 #else 01690 for (unsigned int vg=0; vg<this->n_variable_groups(); vg++) 01691 { 01692 oss << "\"" 01693 << Utility::enum_to_string<FEFamily>(this->get_dof_map().variable_group(vg).type().family) 01694 << "\", \"" 01695 << Utility::enum_to_string<FEFamily>(this->get_dof_map().variable_group(vg).type().radial_family) 01696 << "\" "; 01697 } 01698 01699 oss << '\n' << " Infinite Element Mapping="; 01700 for (unsigned int vg=0; vg<this->n_variable_groups(); vg++) 01701 oss << "\"" 01702 << Utility::enum_to_string<InfMapType>(this->get_dof_map().variable_group(vg).type().inf_map) 01703 << "\" "; 01704 #endif 01705 01706 oss << '\n'; 01707 01708 oss << " Approximation Orders="; 01709 for (unsigned int vg=0; vg<this->n_variable_groups(); vg++) 01710 { 01711 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS 01712 oss << "\"" 01713 << Utility::enum_to_string<Order>(this->get_dof_map().variable_group(vg).type().order) 01714 << "\" "; 01715 #else 01716 oss << "\"" 01717 << Utility::enum_to_string<Order>(this->get_dof_map().variable_group(vg).type().order) 01718 << "\", \"" 01719 << Utility::enum_to_string<Order>(this->get_dof_map().variable_group(vg).type().radial_order) 01720 << "\" "; 01721 #endif 01722 } 01723 01724 oss << '\n'; 01725 01726 oss << " n_dofs()=" << this->n_dofs() << '\n'; 01727 oss << " n_local_dofs()=" << this->n_local_dofs() << '\n'; 01728 #ifdef LIBMESH_ENABLE_CONSTRAINTS 01729 oss << " n_constrained_dofs()=" << this->n_constrained_dofs() << '\n'; 01730 oss << " n_local_constrained_dofs()=" << this->n_local_constrained_dofs() << '\n'; 01731 #endif 01732 01733 oss << " " << "n_vectors()=" << this->n_vectors() << '\n'; 01734 oss << " " << "n_matrices()=" << this->n_matrices() << '\n'; 01735 // oss << " " << "n_additional_matrices()=" << this->n_additional_matrices() << '\n'; 01736 01737 oss << this->get_dof_map().get_info(); 01738 01739 return oss.str(); 01740 } 01741 01742 01743 01744 void System::attach_init_function (void fptr(EquationSystems& es, 01745 const std::string& name)) 01746 { 01747 libmesh_assert(fptr); 01748 01749 if (_init_system_object != NULL) 01750 { 01751 libmesh_here(); 01752 libMesh::out << "WARNING: Cannot specify both initialization function and object!" 01753 << std::endl; 01754 01755 _init_system_object = NULL; 01756 } 01757 01758 _init_system_function = fptr; 01759 } 01760 01761 01762 01763 void System::attach_init_object (System::Initialization& init_in) 01764 { 01765 if (_init_system_function != NULL) 01766 { 01767 libmesh_here(); 01768 libMesh::out << "WARNING: Cannot specify both initialization object and function!" 01769 << std::endl; 01770 01771 _init_system_function = NULL; 01772 } 01773 01774 _init_system_object = &init_in; 01775 } 01776 01777 01778 01779 void System::attach_assemble_function (void fptr(EquationSystems& es, 01780 const std::string& name)) 01781 { 01782 libmesh_assert(fptr); 01783 01784 if (_assemble_system_object != NULL) 01785 { 01786 libmesh_here(); 01787 libMesh::out << "WARNING: Cannot specify both assembly function and object!" 01788 << std::endl; 01789 01790 _assemble_system_object = NULL; 01791 } 01792 01793 _assemble_system_function = fptr; 01794 } 01795 01796 01797 01798 void System::attach_assemble_object (System::Assembly& assemble_in) 01799 { 01800 if (_assemble_system_function != NULL) 01801 { 01802 libmesh_here(); 01803 libMesh::out << "WARNING: Cannot specify both assembly object and function!" 01804 << std::endl; 01805 01806 _assemble_system_function = NULL; 01807 } 01808 01809 _assemble_system_object = &assemble_in; 01810 } 01811 01812 01813 01814 void System::attach_constraint_function(void fptr(EquationSystems& es, 01815 const std::string& name)) 01816 { 01817 libmesh_assert(fptr); 01818 01819 if (_constrain_system_object != NULL) 01820 { 01821 libmesh_here(); 01822 libMesh::out << "WARNING: Cannot specify both constraint function and object!" 01823 << std::endl; 01824 01825 _constrain_system_object = NULL; 01826 } 01827 01828 _constrain_system_function = fptr; 01829 } 01830 01831 01832 01833 void System::attach_constraint_object (System::Constraint& constrain) 01834 { 01835 if (_constrain_system_function != NULL) 01836 { 01837 libmesh_here(); 01838 libMesh::out << "WARNING: Cannot specify both constraint object and function!" 01839 << std::endl; 01840 01841 _constrain_system_function = NULL; 01842 } 01843 01844 _constrain_system_object = &constrain; 01845 } 01846 01847 01848 01849 void System::attach_QOI_function(void fptr(EquationSystems&, 01850 const std::string&, 01851 const QoISet&)) 01852 { 01853 libmesh_assert(fptr); 01854 01855 if (_qoi_evaluate_object != NULL) 01856 { 01857 libmesh_here(); 01858 libMesh::out << "WARNING: Cannot specify both QOI function and object!" 01859 << std::endl; 01860 01861 _qoi_evaluate_object = NULL; 01862 } 01863 01864 _qoi_evaluate_function = fptr; 01865 } 01866 01867 01868 01869 void System::attach_QOI_object (QOI& qoi_in) 01870 { 01871 if (_qoi_evaluate_function != NULL) 01872 { 01873 libmesh_here(); 01874 libMesh::out << "WARNING: Cannot specify both QOI object and function!" 01875 << std::endl; 01876 01877 _qoi_evaluate_function = NULL; 01878 } 01879 01880 _qoi_evaluate_object = &qoi_in; 01881 } 01882 01883 01884 01885 void System::attach_QOI_derivative(void fptr(EquationSystems&, const std::string&, 01886 const QoISet&, bool, bool)) 01887 { 01888 libmesh_assert(fptr); 01889 01890 if (_qoi_evaluate_derivative_object != NULL) 01891 { 01892 libmesh_here(); 01893 libMesh::out << "WARNING: Cannot specify both QOI derivative function and object!" 01894 << std::endl; 01895 01896 _qoi_evaluate_derivative_object = NULL; 01897 } 01898 01899 _qoi_evaluate_derivative_function = fptr; 01900 } 01901 01902 01903 01904 void System::attach_QOI_derivative_object (QOIDerivative& qoi_derivative) 01905 { 01906 if (_qoi_evaluate_derivative_function != NULL) 01907 { 01908 libmesh_here(); 01909 libMesh::out << "WARNING: Cannot specify both QOI derivative object and function!" 01910 << std::endl; 01911 01912 _qoi_evaluate_derivative_function = NULL; 01913 } 01914 01915 _qoi_evaluate_derivative_object = &qoi_derivative; 01916 } 01917 01918 01919 01920 void System::user_initialization () 01921 { 01922 // Call the user-provided intialization function, 01923 // if it was provided 01924 if (_init_system_function != NULL) 01925 this->_init_system_function (_equation_systems, this->name()); 01926 01927 // ...or the user-provided initialization object. 01928 else if (_init_system_object != NULL) 01929 this->_init_system_object->initialize(); 01930 } 01931 01932 01933 01934 void System::user_assembly () 01935 { 01936 // Call the user-provided assembly function, 01937 // if it was provided 01938 if (_assemble_system_function != NULL) 01939 this->_assemble_system_function (_equation_systems, this->name()); 01940 01941 // ...or the user-provided assembly object. 01942 else if (_assemble_system_object != NULL) 01943 this->_assemble_system_object->assemble(); 01944 } 01945 01946 01947 01948 void System::user_constrain () 01949 { 01950 // Call the user-provided constraint function, 01951 // if it was provided 01952 if (_constrain_system_function!= NULL) 01953 this->_constrain_system_function(_equation_systems, this->name()); 01954 01955 // ...or the user-provided constraint object. 01956 else if (_constrain_system_object != NULL) 01957 this->_constrain_system_object->constrain(); 01958 } 01959 01960 01961 01962 void System::user_QOI (const QoISet& qoi_indices) 01963 { 01964 // Call the user-provided quantity of interest function, 01965 // if it was provided 01966 if (_qoi_evaluate_function != NULL) 01967 this->_qoi_evaluate_function(_equation_systems, this->name(), qoi_indices); 01968 01969 // ...or the user-provided QOI function object. 01970 else if (_qoi_evaluate_object != NULL) 01971 this->_qoi_evaluate_object->qoi(qoi_indices); 01972 } 01973 01974 01975 01976 void System::user_QOI_derivative(const QoISet& qoi_indices, 01977 bool include_liftfunc, 01978 bool apply_constraints) 01979 { 01980 // Call the user-provided quantity of interest derivative, 01981 // if it was provided 01982 if (_qoi_evaluate_derivative_function != NULL) 01983 this->_qoi_evaluate_derivative_function 01984 (_equation_systems, this->name(), qoi_indices, include_liftfunc, 01985 apply_constraints); 01986 01987 // ...or the user-provided QOI derivative function object. 01988 else if (_qoi_evaluate_derivative_object != NULL) 01989 this->_qoi_evaluate_derivative_object->qoi_derivative 01990 (qoi_indices, include_liftfunc, apply_constraints); 01991 } 01992 01993 01994 01995 Number System::point_value(unsigned int var, const Point &p, const bool insist_on_success) const 01996 { 01997 // This function must be called on every processor; there's no 01998 // telling where in the partition p falls. 01999 parallel_object_only(); 02000 02001 // And every processor had better agree about which point we're 02002 // looking for 02003 #ifndef NDEBUG 02004 this->comm().verify(p); 02005 #endif // NDEBUG 02006 02007 // Get a reference to the mesh object associated with the system object that calls this function 02008 const MeshBase &mesh = this->get_mesh(); 02009 02010 // Use an existing PointLocator or create a new one 02011 UniquePtr<PointLocatorBase> locator_ptr = mesh.sub_point_locator(); 02012 PointLocatorBase& locator = *locator_ptr; 02013 02014 if (!insist_on_success) 02015 locator.enable_out_of_mesh_mode(); 02016 02017 // Get a pointer to the element that contains P 02018 const Elem *e = locator(p); 02019 02020 Number u = 0; 02021 02022 if (e && e->processor_id() == this->processor_id()) 02023 u = point_value(var, p, *e); 02024 02025 // If I have an element containing p, then let's let everyone know 02026 processor_id_type lowest_owner = 02027 (e && (e->processor_id() == this->processor_id())) ? 02028 this->processor_id() : this->n_processors(); 02029 this->comm().min(lowest_owner); 02030 02031 // Everybody should get their value from a processor that was able 02032 // to compute it. 02033 // If nobody admits owning the point, we have a problem. 02034 if (lowest_owner != this->n_processors()) 02035 this->comm().broadcast(u, lowest_owner); 02036 else 02037 libmesh_assert(!insist_on_success); 02038 02039 return u; 02040 } 02041 02042 Number System::point_value(unsigned int var, const Point &p, const Elem &e) const 02043 { 02044 libmesh_assert_equal_to (e.processor_id(), this->processor_id()); 02045 02046 // Ensuring that the given point is really in the element is an 02047 // expensive assert, but as long as debugging is turned on we might 02048 // as well try to catch a particularly nasty potential error 02049 libmesh_assert (e.contains_point(p)); 02050 02051 // Get the dof map to get the proper indices for our computation 02052 const DofMap& dof_map = this->get_dof_map(); 02053 02054 // Need dof_indices for phi[i][j] 02055 std::vector<dof_id_type> dof_indices; 02056 02057 // Fill in the dof_indices for our element 02058 dof_map.dof_indices (&e, dof_indices, var); 02059 02060 // Get the no of dofs assciated with this point 02061 const unsigned int num_dofs = cast_int<unsigned int> 02062 (dof_indices.size()); 02063 02064 FEType fe_type = dof_map.variable_type(var); 02065 02066 // Build a FE so we can calculate u(p) 02067 UniquePtr<FEBase> fe (FEBase::build(e.dim(), fe_type)); 02068 02069 // Map the physical co-ordinates to the master co-ordinates using the inverse_map from fe_interface.h 02070 // Build a vector of point co-ordinates to send to reinit 02071 std::vector<Point> coor(1, FEInterface::inverse_map(e.dim(), fe_type, &e, p)); 02072 02073 // Get the shape function values 02074 const std::vector<std::vector<Real> >& phi = fe->get_phi(); 02075 02076 // Reinitialize the element and compute the shape function values at coor 02077 fe->reinit (&e, &coor); 02078 02079 // Get ready to accumulate a value 02080 Number u = 0; 02081 02082 for (unsigned int l=0; l<num_dofs; l++) 02083 { 02084 u += phi[l][0]*this->current_solution (dof_indices[l]); 02085 } 02086 02087 return u; 02088 } 02089 02090 02091 02092 Gradient System::point_gradient(unsigned int var, const Point &p, const bool insist_on_success) const 02093 { 02094 // This function must be called on every processor; there's no 02095 // telling where in the partition p falls. 02096 parallel_object_only(); 02097 02098 // And every processor had better agree about which point we're 02099 // looking for 02100 #ifndef NDEBUG 02101 this->comm().verify(p); 02102 #endif // NDEBUG 02103 02104 // Get a reference to the mesh object associated with the system object that calls this function 02105 const MeshBase &mesh = this->get_mesh(); 02106 02107 // Use an existing PointLocator or create a new one 02108 UniquePtr<PointLocatorBase> locator_ptr = mesh.sub_point_locator(); 02109 PointLocatorBase& locator = *locator_ptr; 02110 02111 if (!insist_on_success) 02112 locator.enable_out_of_mesh_mode(); 02113 02114 // Get a pointer to the element that contains P 02115 const Elem *e = locator(p); 02116 02117 Gradient grad_u; 02118 02119 if (e && e->processor_id() == this->processor_id()) 02120 grad_u = point_gradient(var, p, *e); 02121 02122 // If I have an element containing p, then let's let everyone know 02123 processor_id_type lowest_owner = 02124 (e && (e->processor_id() == this->processor_id())) ? 02125 this->processor_id() : this->n_processors(); 02126 this->comm().min(lowest_owner); 02127 02128 // Everybody should get their value from a processor that was able 02129 // to compute it. 02130 // If nobody admits owning the point, we may have a problem. 02131 if (lowest_owner != this->n_processors()) 02132 this->comm().broadcast(grad_u, lowest_owner); 02133 else 02134 libmesh_assert(!insist_on_success); 02135 02136 return grad_u; 02137 } 02138 02139 02140 Gradient System::point_gradient(unsigned int var, const Point &p, const Elem &e) const 02141 { 02142 libmesh_assert_equal_to (e.processor_id(), this->processor_id()); 02143 02144 // Ensuring that the given point is really in the element is an 02145 // expensive assert, but as long as debugging is turned on we might 02146 // as well try to catch a particularly nasty potential error 02147 libmesh_assert (e.contains_point(p)); 02148 02149 // Get the dof map to get the proper indices for our computation 02150 const DofMap& dof_map = this->get_dof_map(); 02151 02152 // Need dof_indices for phi[i][j] 02153 std::vector<dof_id_type> dof_indices; 02154 02155 // Fill in the dof_indices for our element 02156 dof_map.dof_indices (&e, dof_indices, var); 02157 02158 // Get the no of dofs assciated with this point 02159 const unsigned int num_dofs = cast_int<unsigned int> 02160 (dof_indices.size()); 02161 02162 FEType fe_type = dof_map.variable_type(var); 02163 02164 // Build a FE again so we can calculate u(p) 02165 UniquePtr<FEBase> fe (FEBase::build(e.dim(), fe_type)); 02166 02167 // Map the physical co-ordinates to the master co-ordinates using the inverse_map from fe_interface.h 02168 // Build a vector of point co-ordinates to send to reinit 02169 std::vector<Point> coor(1, FEInterface::inverse_map(e.dim(), fe_type, &e, p)); 02170 02171 // Get the values of the shape function derivatives 02172 const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi(); 02173 02174 // Reinitialize the element and compute the shape function values at coor 02175 fe->reinit (&e, &coor); 02176 02177 // Get ready to accumulate a gradient 02178 Gradient grad_u; 02179 02180 for (unsigned int l=0; l<num_dofs; l++) 02181 { 02182 grad_u.add_scaled (dphi[l][0], this->current_solution (dof_indices[l])); 02183 } 02184 02185 return grad_u; 02186 } 02187 02188 02189 // We can only accumulate a hessian with --enable-second 02190 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 02191 Tensor System::point_hessian(unsigned int var, const Point &p, const bool insist_on_success) const 02192 { 02193 // This function must be called on every processor; there's no 02194 // telling where in the partition p falls. 02195 parallel_object_only(); 02196 02197 // And every processor had better agree about which point we're 02198 // looking for 02199 #ifndef NDEBUG 02200 this->comm().verify(p); 02201 #endif // NDEBUG 02202 02203 // Get a reference to the mesh object associated with the system object that calls this function 02204 const MeshBase &mesh = this->get_mesh(); 02205 02206 // Use an existing PointLocator or create a new one 02207 UniquePtr<PointLocatorBase> locator_ptr = mesh.sub_point_locator(); 02208 PointLocatorBase& locator = *locator_ptr; 02209 02210 if (!insist_on_success) 02211 locator.enable_out_of_mesh_mode(); 02212 02213 // Get a pointer to the element that contains P 02214 const Elem *e = locator(p); 02215 02216 Tensor hess_u; 02217 02218 if (e && e->processor_id() == this->processor_id()) 02219 hess_u = point_hessian(var, p, *e); 02220 02221 // If I have an element containing p, then let's let everyone know 02222 processor_id_type lowest_owner = 02223 (e && (e->processor_id() == this->processor_id())) ? 02224 this->processor_id() : this->n_processors(); 02225 this->comm().min(lowest_owner); 02226 02227 // Everybody should get their value from a processor that was able 02228 // to compute it. 02229 // If nobody admits owning the point, we may have a problem. 02230 if (lowest_owner != this->n_processors()) 02231 this->comm().broadcast(hess_u, lowest_owner); 02232 else 02233 libmesh_assert(!insist_on_success); 02234 02235 return hess_u; 02236 } 02237 02238 Tensor System::point_hessian(unsigned int var, const Point &p, const Elem &e) const 02239 { 02240 libmesh_assert_equal_to (e.processor_id(), this->processor_id()); 02241 02242 // Ensuring that the given point is really in the element is an 02243 // expensive assert, but as long as debugging is turned on we might 02244 // as well try to catch a particularly nasty potential error 02245 libmesh_assert (e.contains_point(p)); 02246 02247 // Get the dof map to get the proper indices for our computation 02248 const DofMap& dof_map = this->get_dof_map(); 02249 02250 // Need dof_indices for phi[i][j] 02251 std::vector<dof_id_type> dof_indices; 02252 02253 // Fill in the dof_indices for our element 02254 dof_map.dof_indices (&e, dof_indices, var); 02255 02256 // Get the no of dofs assciated with this point 02257 const unsigned int num_dofs = cast_int<unsigned int> 02258 (dof_indices.size()); 02259 02260 FEType fe_type = dof_map.variable_type(var); 02261 02262 // Build a FE again so we can calculate u(p) 02263 UniquePtr<FEBase> fe (FEBase::build(e.dim(), fe_type)); 02264 02265 // Map the physical co-ordinates to the master co-ordinates using the inverse_map from fe_interface.h 02266 // Build a vector of point co-ordinates to send to reinit 02267 std::vector<Point> coor(1, FEInterface::inverse_map(e.dim(), fe_type, &e, p)); 02268 02269 // Get the values of the shape function derivatives 02270 const std::vector<std::vector<RealTensor> >& d2phi = fe->get_d2phi(); 02271 02272 // Reinitialize the element and compute the shape function values at coor 02273 fe->reinit (&e, &coor); 02274 02275 // Get ready to accumulate a hessian 02276 Tensor hess_u; 02277 02278 for (unsigned int l=0; l<num_dofs; l++) 02279 { 02280 hess_u.add_scaled (d2phi[l][0], this->current_solution (dof_indices[l])); 02281 } 02282 02283 return hess_u; 02284 } 02285 #else 02286 Tensor System::point_hessian(unsigned int, const Point &, const bool) const 02287 { 02288 libmesh_error_msg("We can only accumulate a hessian with --enable-second"); 02289 02290 // Avoid compiler warnings 02291 return Tensor(); 02292 } 02293 02294 Tensor System::point_hessian(unsigned int, const Point &, const Elem &) const 02295 { 02296 libmesh_error_msg("We can only accumulate a hessian with --enable-second"); 02297 02298 // Avoid compiler warnings 02299 return Tensor(); 02300 } 02301 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES 02302 02303 } // namespace libMesh