$extrastylesheet
system.C
Go to the documentation of this file.
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