$extrastylesheet
equation_systems.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 // System includes
00020 #include <sstream>
00021 
00022 // Local Includes
00023 #include "libmesh/explicit_system.h"
00024 #include "libmesh/fe_interface.h"
00025 #include "libmesh/frequency_system.h"
00026 #include "libmesh/linear_implicit_system.h"
00027 #include "libmesh/mesh_refinement.h"
00028 #include "libmesh/newmark_system.h"
00029 #include "libmesh/nonlinear_implicit_system.h"
00030 #include "libmesh/rb_construction.h"
00031 #include "libmesh/transient_rb_construction.h"
00032 #include "libmesh/eigen_system.h"
00033 #include "libmesh/parallel.h"
00034 #include "libmesh/transient_system.h"
00035 #include "libmesh/dof_map.h"
00036 #include "libmesh/mesh_base.h"
00037 #include "libmesh/elem.h"
00038 #include "libmesh/libmesh_logging.h"
00039 
00040 // Include the systems before this one to avoid
00041 // overlapping forward declarations.
00042 #include "libmesh/equation_systems.h"
00043 
00044 namespace libMesh
00045 {
00046 
00047 // Forward Declarations
00048 
00049 
00050 
00051 
00052 // ------------------------------------------------------------
00053 // EquationSystems class implementation
00054 EquationSystems::EquationSystems (MeshBase& m, MeshData* mesh_data) :
00055   ParallelObject (m),
00056   _mesh          (m),
00057   _mesh_data     (mesh_data)
00058 {
00059   // Set default parameters
00060   this->parameters.set<Real>        ("linear solver tolerance") = TOLERANCE * TOLERANCE;
00061   this->parameters.set<unsigned int>("linear solver maximum iterations") = 5000;
00062 }
00063 
00064 
00065 
00066 EquationSystems::~EquationSystems ()
00067 {
00068   this->clear ();
00069 }
00070 
00071 
00072 
00073 void EquationSystems::clear ()
00074 {
00075   // Clear any additional parameters
00076   parameters.clear ();
00077 
00078   // clear the systems.  We must delete them
00079   // since we newed them!
00080   while (!_systems.empty())
00081     {
00082       system_iterator pos = _systems.begin();
00083 
00084       System *sys = pos->second;
00085       delete sys;
00086       sys = NULL;
00087 
00088       _systems.erase (pos);
00089     }
00090 }
00091 
00092 
00093 
00094 void EquationSystems::init ()
00095 {
00096   const unsigned int n_sys = this->n_systems();
00097 
00098   libmesh_assert_not_equal_to (n_sys, 0);
00099 
00100   // Distribute the mesh if possible
00101   if (this->n_processors() > 1)
00102     _mesh.delete_remote_elements();
00103 
00104   // Tell all the \p DofObject entities how many systems
00105   // there are.
00106   {
00107     MeshBase::node_iterator       node_it  = _mesh.nodes_begin();
00108     const MeshBase::node_iterator node_end = _mesh.nodes_end();
00109 
00110     for ( ; node_it != node_end; ++node_it)
00111       (*node_it)->set_n_systems(n_sys);
00112 
00113     MeshBase::element_iterator       elem_it  = _mesh.elements_begin();
00114     const MeshBase::element_iterator elem_end = _mesh.elements_end();
00115 
00116     for ( ; elem_it != elem_end; ++elem_it)
00117       (*elem_it)->set_n_systems(n_sys);
00118   }
00119 
00120   for (unsigned int i=0; i != this->n_systems(); ++i)
00121     this->get_system(i).init();
00122 
00123 #ifdef LIBMESH_ENABLE_AMR
00124   MeshRefinement mesh_refine(_mesh);
00125   mesh_refine.clean_refinement_flags();
00126 #endif
00127 }
00128 
00129 
00130 
00131 void EquationSystems::reinit ()
00132 {
00133   parallel_object_only();
00134 
00135   const unsigned int n_sys = this->n_systems();
00136   libmesh_assert_not_equal_to (n_sys, 0);
00137 
00138   // We may have added new systems since our last
00139   // EquationSystems::(re)init call
00140   bool _added_new_systems = false;
00141   for (unsigned int i=0; i != n_sys; ++i)
00142     if (!this->get_system(i).is_initialized())
00143       _added_new_systems = true;
00144 
00145   if (_added_new_systems)
00146     {
00147       // Our DofObjects will need space for the additional systems
00148       MeshBase::node_iterator       node_it  = _mesh.nodes_begin();
00149       const MeshBase::node_iterator node_end = _mesh.nodes_end();
00150 
00151       for ( ; node_it != node_end; ++node_it)
00152         (*node_it)->set_n_systems(n_sys);
00153 
00154       MeshBase::element_iterator       elem_it  = _mesh.elements_begin();
00155       const MeshBase::element_iterator elem_end = _mesh.elements_end();
00156 
00157       for ( ; elem_it != elem_end; ++elem_it)
00158         (*elem_it)->set_n_systems(n_sys);
00159 
00160       // And any new systems will need initialization
00161       for (unsigned int i=0; i != n_sys; ++i)
00162         if (!this->get_system(i).is_initialized())
00163           this->get_system(i).init();
00164     }
00165 
00166 #ifdef DEBUG
00167   // Make sure all the \p DofObject entities know how many systems
00168   // there are.
00169   {
00170     // All the nodes
00171     MeshBase::node_iterator       node_it  = _mesh.nodes_begin();
00172     const MeshBase::node_iterator node_end = _mesh.nodes_end();
00173 
00174     for ( ; node_it != node_end; ++node_it)
00175       {
00176         Node *node = *node_it;
00177         libmesh_assert_equal_to (node->n_systems(), this->n_systems());
00178       }
00179 
00180     // All the elements
00181     MeshBase::element_iterator       elem_it  = _mesh.elements_begin();
00182     const MeshBase::element_iterator elem_end = _mesh.elements_end();
00183 
00184     for ( ; elem_it != elem_end; ++elem_it)
00185       {
00186         Elem *elem = *elem_it;
00187         libmesh_assert_equal_to (elem->n_systems(), this->n_systems());
00188       }
00189   }
00190 #endif
00191 
00192   // Localize each system's vectors
00193   for (unsigned int i=0; i != this->n_systems(); ++i)
00194     this->get_system(i).re_update();
00195 
00196 #ifdef LIBMESH_ENABLE_AMR
00197 
00198   bool dof_constraints_created = false;
00199   bool mesh_changed = false;
00200 
00201   // FIXME: For backwards compatibility, assume
00202   // refine_and_coarsen_elements or refine_uniformly have already
00203   // been called
00204   {
00205     for (unsigned int i=0; i != this->n_systems(); ++i)
00206       {
00207         System &sys = this->get_system(i);
00208 
00209         // Even if the system doesn't have any variables in it we want
00210         // consistent behavior; e.g. distribute_dofs should have the
00211         // opportunity to count up zero dofs on each processor.
00212         //
00213         // Who's been adding zero-var systems anyway, outside of my
00214         // unit tests? - RHS
00215         // if(!sys.n_vars())
00216           // continue;
00217 
00218         sys.get_dof_map().distribute_dofs(_mesh);
00219 
00220         // Recreate any hanging node constraints
00221         sys.get_dof_map().create_dof_constraints(_mesh, sys.time);
00222 
00223         // Apply any user-defined constraints
00224         sys.user_constrain();
00225 
00226         // Expand any recursive constraints
00227         sys.get_dof_map().process_constraints(_mesh);
00228 
00229         // And clean up the send_list before we use it again
00230         sys.get_dof_map().prepare_send_list();
00231 
00232         sys.prolong_vectors();
00233       }
00234     mesh_changed = true;
00235     dof_constraints_created = true;
00236   }
00237 
00238   // FIXME: Where should the user set maintain_level_one now??
00239   // Don't override previous settings, for now
00240 
00241   MeshRefinement mesh_refine(_mesh);
00242 
00243   mesh_refine.face_level_mismatch_limit() = false;
00244 
00245   // Try to coarsen the mesh, then restrict each system's vectors
00246   // if necessary
00247   if (mesh_refine.coarsen_elements())
00248     {
00249       for (unsigned int i=0; i != this->n_systems(); ++i)
00250         {
00251           System &sys = this->get_system(i);
00252           if (!dof_constraints_created)
00253             {
00254               sys.get_dof_map().distribute_dofs(_mesh);
00255               sys.get_dof_map().create_dof_constraints(_mesh, sys.time);
00256               sys.user_constrain();
00257               sys.get_dof_map().process_constraints(_mesh);
00258               sys.get_dof_map().prepare_send_list();
00259 
00260             }
00261           sys.restrict_vectors();
00262         }
00263       mesh_changed = true;
00264       dof_constraints_created = true;
00265     }
00266 
00267   // Once vectors are all restricted, we can delete
00268   // children of coarsened elements
00269   if (mesh_changed)
00270     this->get_mesh().contract();
00271 
00272   // Try to refine the mesh, then prolong each system's vectors
00273   // if necessary
00274   if (mesh_refine.refine_elements())
00275     {
00276       for (unsigned int i=0; i != this->n_systems(); ++i)
00277         {
00278           System &sys = this->get_system(i);
00279           if (!dof_constraints_created)
00280             {
00281               sys.get_dof_map().distribute_dofs(_mesh);
00282               sys.get_dof_map().create_dof_constraints(_mesh, sys.time);
00283               sys.user_constrain();
00284               sys.get_dof_map().process_constraints(_mesh);
00285               sys.get_dof_map().prepare_send_list();
00286 
00287             }
00288           sys.prolong_vectors();
00289         }
00290       mesh_changed = true;
00291       // dof_constraints_created = true;
00292     }
00293 
00294   // If the mesh has changed, systems will need to create new dof
00295   // constraints and update their global solution vectors
00296   if (mesh_changed)
00297     {
00298       for (unsigned int i=0; i != this->n_systems(); ++i)
00299         this->get_system(i).reinit();
00300     }
00301 #endif // #ifdef LIBMESH_ENABLE_AMR
00302 }
00303 
00304 
00305 
00306 void EquationSystems::allgather ()
00307 {
00308   // A serial mesh means nothing needs to be done
00309   if (_mesh.is_serial())
00310     return;
00311 
00312   const unsigned int n_sys = this->n_systems();
00313 
00314   libmesh_assert_not_equal_to (n_sys, 0);
00315 
00316   // Gather the mesh
00317   _mesh.allgather();
00318 
00319   // Tell all the \p DofObject entities how many systems
00320   // there are.
00321   {
00322     MeshBase::node_iterator       node_it  = _mesh.nodes_begin();
00323     const MeshBase::node_iterator node_end = _mesh.nodes_end();
00324 
00325     for ( ; node_it != node_end; ++node_it)
00326       (*node_it)->set_n_systems(n_sys);
00327 
00328     MeshBase::element_iterator       elem_it  = _mesh.elements_begin();
00329     const MeshBase::element_iterator elem_end = _mesh.elements_end();
00330 
00331     for ( ; elem_it != elem_end; ++elem_it)
00332       (*elem_it)->set_n_systems(n_sys);
00333   }
00334 
00335   // And distribute each system's dofs
00336   for (unsigned int i=0; i != this->n_systems(); ++i)
00337     {
00338       System &sys = this->get_system(i);
00339       DofMap &dof_map = sys.get_dof_map();
00340       dof_map.distribute_dofs(_mesh);
00341 
00342 #ifdef LIBMESH_ENABLE_CONSTRAINTS
00343       // The user probably won't need constraint equations or the
00344       // send_list after an allgather, but let's keep it in consistent
00345       // shape just in case.
00346       dof_map.create_dof_constraints(_mesh, sys.time);
00347       sys.user_constrain();
00348       dof_map.process_constraints(_mesh);
00349 #endif
00350       dof_map.prepare_send_list();
00351     }
00352 }
00353 
00354 
00355 
00356 
00357 void EquationSystems::update ()
00358 {
00359   START_LOG("update()","EquationSystems");
00360 
00361   // Localize each system's vectors
00362   for (unsigned int i=0; i != this->n_systems(); ++i)
00363     this->get_system(i).update();
00364 
00365   STOP_LOG("update()","EquationSystems");
00366 }
00367 
00368 
00369 
00370 System & EquationSystems::add_system (const std::string& sys_type,
00371                                       const std::string& name)
00372 {
00373   // If the user already built a system with this name, we'll
00374   // trust them and we'll use it.  That way they can pre-add
00375   // non-standard derived system classes, and if their restart file
00376   // has some non-standard sys_type we won't throw an error.
00377   if (_systems.count(name))
00378     {
00379       return this->get_system(name);
00380     }
00381   // Build a basic System
00382   else if (sys_type == "Basic")
00383     this->add_system<System> (name);
00384 
00385   // Build a Newmark system
00386   else if (sys_type == "Newmark")
00387     this->add_system<NewmarkSystem> (name);
00388 
00389   // Build an Explicit system
00390   else if ((sys_type == "Explicit"))
00391     this->add_system<ExplicitSystem> (name);
00392 
00393   // Build an Implicit system
00394   else if ((sys_type == "Implicit") ||
00395            (sys_type == "Steady"  ))
00396     this->add_system<ImplicitSystem> (name);
00397 
00398   // build a transient implicit linear system
00399   else if ((sys_type == "Transient") ||
00400            (sys_type == "TransientImplicit") ||
00401            (sys_type == "TransientLinearImplicit"))
00402     this->add_system<TransientLinearImplicitSystem> (name);
00403 
00404   // build a transient implicit nonlinear system
00405   else if (sys_type == "TransientNonlinearImplicit")
00406     this->add_system<TransientNonlinearImplicitSystem> (name);
00407 
00408   // build a transient explicit system
00409   else if (sys_type == "TransientExplicit")
00410     this->add_system<TransientExplicitSystem> (name);
00411 
00412   // build a linear implicit system
00413   else if (sys_type == "LinearImplicit")
00414     this->add_system<LinearImplicitSystem> (name);
00415 
00416   // build a nonlinear implicit system
00417   else if (sys_type == "NonlinearImplicit")
00418     this->add_system<NonlinearImplicitSystem> (name);
00419 
00420   // build a Reduced Basis Construction system
00421   else if (sys_type == "RBConstruction")
00422     this->add_system<RBConstruction> (name);
00423 
00424   // build a transient Reduced Basis Construction system
00425   else if (sys_type == "TransientRBConstruction")
00426     this->add_system<TransientRBConstruction> (name);
00427 
00428 #ifdef LIBMESH_HAVE_SLEPC
00429   // build an eigen system
00430   else if (sys_type == "Eigen")
00431     this->add_system<EigenSystem> (name);
00432 #endif
00433 
00434 #if defined(LIBMESH_USE_COMPLEX_NUMBERS)
00435   // build a frequency system
00436   else if (sys_type == "Frequency")
00437     this->add_system<FrequencySystem> (name);
00438 #endif
00439 
00440   else
00441     libmesh_error_msg("ERROR: Unknown system type: " << sys_type);
00442 
00443   // Return a reference to the new system
00444   //return (*this)(name);
00445   return this->get_system(name);
00446 }
00447 
00448 
00449 
00450 
00451 
00452 
00453 void EquationSystems::delete_system (const std::string& name)
00454 {
00455   libmesh_deprecated();
00456 
00457   if (!_systems.count(name))
00458     libmesh_error_msg("ERROR: no system named " << name);
00459 
00460   delete _systems[name];
00461 
00462   _systems.erase (name);
00463 }
00464 
00465 
00466 
00467 void EquationSystems::solve ()
00468 {
00469   libmesh_assert (this->n_systems());
00470 
00471   for (unsigned int i=0; i != this->n_systems(); ++i)
00472     this->get_system(i).solve();
00473 }
00474 
00475 
00476 
00477 void EquationSystems::sensitivity_solve (const ParameterVector& parameters_in)
00478 {
00479   libmesh_assert (this->n_systems());
00480 
00481   for (unsigned int i=0; i != this->n_systems(); ++i)
00482     this->get_system(i).sensitivity_solve(parameters_in);
00483 }
00484 
00485 
00486 
00487 void EquationSystems::adjoint_solve (const QoISet& qoi_indices)
00488 {
00489   libmesh_assert (this->n_systems());
00490 
00491   for (unsigned int i=this->n_systems(); i != 0; --i)
00492     this->get_system(i-1).adjoint_solve(qoi_indices);
00493 }
00494 
00495 
00496 
00497 void EquationSystems::build_variable_names (std::vector<std::string>& var_names,
00498                                             const FEType *type,
00499                                             const std::set<std::string>* system_names) const
00500 {
00501   libmesh_assert (this->n_systems());
00502 
00503   unsigned int var_num=0;
00504 
00505   const_system_iterator       pos = _systems.begin();
00506   const const_system_iterator end = _systems.end();
00507 
00508   // Need to size var_names by scalar variables plus all the
00509   // vector components for all the vector variables
00510   //Could this be replaced by a/some convenience methods?[PB]
00511   {
00512     unsigned int n_scalar_vars = 0;
00513     unsigned int n_vector_vars = 0;
00514 
00515     for (; pos != end; ++pos)
00516       {
00517         // Check current system is listed in system_names, and skip pos if not
00518         bool use_current_system = (system_names == NULL);
00519         if (!use_current_system)
00520           use_current_system = system_names->count(pos->first);
00521         if (!use_current_system)
00522           continue;
00523 
00524         for (unsigned int vn=0; vn<pos->second->n_vars(); vn++)
00525           {
00526             if( FEInterface::field_type(pos->second->variable_type(vn)) ==
00527                 TYPE_VECTOR )
00528               n_vector_vars++;
00529             else
00530               n_scalar_vars++;
00531           }
00532       }
00533 
00534     // Here, we're assuming the number of vector components is the same
00535     // as the mesh dimension. Will break for mixed dimension meshes.
00536     unsigned int dim = this->get_mesh().mesh_dimension();
00537     unsigned int nv = n_scalar_vars + dim*n_vector_vars;
00538 
00539     // We'd better not have more than dim*his->n_vars() (all vector variables)
00540     libmesh_assert_less_equal ( nv, dim*this->n_vars() );
00541 
00542     // Here, we're assuming the number of vector components is the same
00543     // as the mesh dimension. Will break for mixed dimension meshes.
00544 
00545     var_names.resize( nv );
00546   }
00547 
00548   // reset
00549   pos = _systems.begin();
00550 
00551   for (; pos != end; ++pos)
00552     {
00553       // Check current system is listed in system_names, and skip pos if not
00554       bool use_current_system = (system_names == NULL);
00555       if (!use_current_system)
00556         use_current_system = system_names->count(pos->first);
00557       if (!use_current_system)
00558         continue;
00559 
00560       for (unsigned int vn=0; vn<pos->second->n_vars(); vn++)
00561         {
00562           std::string var_name = pos->second->variable_name(vn);
00563           FEType fe_type = pos->second->variable_type(vn);
00564 
00565           unsigned int n_vec_dim = FEInterface::n_vec_dim( pos->second->get_mesh(), fe_type);
00566 
00567           // Filter on the type if requested
00568           if (type == NULL || (type && *type == fe_type))
00569             {
00570               if( FEInterface::field_type(fe_type) == TYPE_VECTOR )
00571                 {
00572                   switch(n_vec_dim)
00573                     {
00574                     case 0:
00575                     case 1:
00576                       var_names[var_num++] = var_name;
00577                       break;
00578                     case 2:
00579                       var_names[var_num++] = var_name+"_x";
00580                       var_names[var_num++] = var_name+"_y";
00581                       break;
00582                     case 3:
00583                       var_names[var_num++] = var_name+"_x";
00584                       var_names[var_num++] = var_name+"_y";
00585                       var_names[var_num++] = var_name+"_z";
00586                       break;
00587                     default:
00588                       libmesh_error_msg("Invalid dim in build_variable_names");
00589                     }
00590                 }
00591               else
00592                 var_names[var_num++] = var_name;
00593             }
00594         }
00595     }
00596   // Now resize again in case we filtered any names
00597   var_names.resize(var_num);
00598 }
00599 
00600 
00601 
00602 void EquationSystems::build_solution_vector (std::vector<Number>&,
00603                                              const std::string&,
00604                                              const std::string&) const
00605 {
00606   //TODO:[BSK] re-implement this from the method below
00607   libmesh_not_implemented();
00608 
00609   //   // Get a reference to the named system
00610   //   const System& system = this->get_system(system_name);
00611 
00612   //   // Get the number associated with the variable_name we are passed
00613   //   const unsigned short int variable_num = system.variable_number(variable_name);
00614 
00615   //   // Get the dimension of the current mesh
00616   //   const unsigned int dim = _mesh.mesh_dimension();
00617 
00618   //   // If we're on processor 0, allocate enough memory to hold the solution.
00619   //   // Since we're only looking at one variable, there will be one solution value
00620   //   // for each node in the mesh.
00621   //   if (_mesh.processor_id() == 0)
00622   //     soln.resize(_mesh.n_nodes());
00623 
00624   //   // Vector to hold the global solution from all processors
00625   //   std::vector<Number> sys_soln;
00626 
00627   //   // Update the global solution from all processors
00628   //   system.update_global_solution (sys_soln, 0);
00629 
00630   //   // Temporary vector to store the solution on an individual element.
00631   //   std::vector<Number>       elem_soln;
00632 
00633   //   // The FE solution interpolated to the nodes
00634   //   std::vector<Number>       nodal_soln;
00635 
00636   //   // The DOF indices for the element
00637   //   std::vector<dof_id_type> dof_indices;
00638 
00639   //   // Determine the finite/infinite element type used in this system
00640   //   const FEType& fe_type    = system.variable_type(variable_num);
00641 
00642   //   // Define iterators to iterate over all the elements of the mesh
00643   //   const_active_elem_iterator       it (_mesh.elements_begin());
00644   //   const const_active_elem_iterator end(_mesh.elements_end());
00645 
00646   //   // Loop over elements
00647   //   for ( ; it != end; ++it)
00648   //     {
00649   //       // Convenient shortcut to the element pointer
00650   //       const Elem* elem = *it;
00651 
00652   //       // Fill the dof_indices vector for this variable
00653   //       system.get_dof_map().dof_indices(elem,
00654   //        dof_indices,
00655   //        variable_num);
00656 
00657   //       // Resize the element solution vector to fit the
00658   //       // dof_indices for this element.
00659   //       elem_soln.resize(dof_indices.size());
00660 
00661   //       // Transfer the system solution to the element
00662   //       // solution by mapping it through the dof_indices vector.
00663   //       for (unsigned int i=0; i<dof_indices.size(); i++)
00664   // elem_soln[i] = sys_soln[dof_indices[i]];
00665 
00666   //       // Using the FE interface, compute the nodal_soln
00667   //       // for the current elemnt type given the elem_soln
00668   //       FEInterface::nodal_soln (dim,
00669   //        fe_type,
00670   //        elem,
00671   //        elem_soln,
00672   //        nodal_soln);
00673 
00674   //       // Sanity check -- make sure that there are the same number
00675   //       // of entries in the nodal_soln as there are nodes in the
00676   //       // element!
00677   //       libmesh_assert_equal_to (nodal_soln.size(), elem->n_nodes());
00678 
00679   //       // Copy the nodal solution over into the correct place in
00680   //       // the global soln vector which will be returned to the user.
00681   //       for (unsigned int n=0; n<elem->n_nodes(); n++)
00682   // soln[elem->node(n)] = nodal_soln[n];
00683   //     }
00684 }
00685 
00686 
00687 
00688 
00689 void EquationSystems::build_solution_vector (std::vector<Number>& soln,
00690                                              const std::set<std::string>* system_names) const
00691 {
00692   START_LOG("build_solution_vector()", "EquationSystems");
00693 
00694   // This function must be run on all processors at once
00695   parallel_object_only();
00696 
00697   libmesh_assert (this->n_systems());
00698 
00699   const unsigned int dim = _mesh.mesh_dimension();
00700   const dof_id_type nn   = _mesh.n_nodes();
00701 
00702   // We'd better have a contiguous node numbering
00703   libmesh_assert_equal_to (nn, _mesh.max_node_id());
00704 
00705   // allocate storage to hold
00706   // (number_of_nodes)*(number_of_variables) entries.
00707   // We have to differentiate between between scalar and vector
00708   // variables. We intercept vector variables and treat each
00709   // component as a scalar variable (consistently with build_solution_names).
00710 
00711   unsigned int nv = 0;
00712 
00713   //Could this be replaced by a/some convenience methods?[PB]
00714   {
00715     unsigned int n_scalar_vars = 0;
00716     unsigned int n_vector_vars = 0;
00717     const_system_iterator       pos = _systems.begin();
00718     const const_system_iterator end = _systems.end();
00719 
00720     for (; pos != end; ++pos)
00721       {
00722         // Check current system is listed in system_names, and skip pos if not
00723         bool use_current_system = (system_names == NULL);
00724         if (!use_current_system)
00725           use_current_system = system_names->count(pos->first);
00726         if (!use_current_system)
00727           continue;
00728 
00729         for (unsigned int vn=0; vn<pos->second->n_vars(); vn++)
00730           {
00731             if( FEInterface::field_type(pos->second->variable_type(vn)) ==
00732                 TYPE_VECTOR )
00733               n_vector_vars++;
00734             else
00735               n_scalar_vars++;
00736           }
00737       }
00738     // Here, we're assuming the number of vector components is the same
00739     // as the mesh dimension. Will break for mixed dimension meshes.
00740     nv = n_scalar_vars + dim*n_vector_vars;
00741   }
00742 
00743   // Get the number of elements that share each node.  We will
00744   // compute the average value at each node.  This is particularly
00745   // useful for plotting discontinuous data.
00746   MeshBase::element_iterator       e_it  = _mesh.active_local_elements_begin();
00747   const MeshBase::element_iterator e_end = _mesh.active_local_elements_end();
00748 
00749   // Get the number of local nodes
00750   dof_id_type n_local_nodes = cast_int<dof_id_type>
00751     (std::distance(_mesh.local_nodes_begin(),
00752                    _mesh.local_nodes_end()));
00753 
00754   // Create a NumericVector to hold the parallel solution
00755   UniquePtr<NumericVector<Number> > parallel_soln_ptr = NumericVector<Number>::build(_communicator);
00756   NumericVector<Number> &parallel_soln = *parallel_soln_ptr;
00757   parallel_soln.init(nn*nv, n_local_nodes*nv, false, PARALLEL);
00758 
00759   // Create a NumericVector to hold the "repeat_count" for each node - this is essentially
00760   // the number of elements contributing to that node's value
00761   UniquePtr<NumericVector<Number> > repeat_count_ptr = NumericVector<Number>::build(_communicator);
00762   NumericVector<Number> &repeat_count = *repeat_count_ptr;
00763   repeat_count.init(nn*nv, n_local_nodes*nv, false, PARALLEL);
00764 
00765   repeat_count.close();
00766 
00767   unsigned int var_num=0;
00768 
00769   // For each system in this EquationSystems object,
00770   // update the global solution and if we are on processor 0,
00771   // loop over the elements and build the nodal solution
00772   // from the element solution.  Then insert this nodal solution
00773   // into the vector passed to build_solution_vector.
00774   const_system_iterator       pos = _systems.begin();
00775   const const_system_iterator end = _systems.end();
00776 
00777   for (; pos != end; ++pos)
00778     {
00779       // Check current system is listed in system_names, and skip pos if not
00780       bool use_current_system = (system_names == NULL);
00781       if (!use_current_system)
00782         use_current_system = system_names->count(pos->first);
00783       if (!use_current_system)
00784         continue;
00785 
00786       const System& system  = *(pos->second);
00787       const unsigned int nv_sys = system.n_vars();
00788       const unsigned int sys_num = system.number();
00789 
00790       //Could this be replaced by a/some convenience methods?[PB]
00791       unsigned int n_scalar_vars = 0;
00792       unsigned int n_vector_vars = 0;
00793       for (unsigned int vn=0; vn<pos->second->n_vars(); vn++)
00794         {
00795           if( FEInterface::field_type(pos->second->variable_type(vn)) ==
00796               TYPE_VECTOR )
00797             n_vector_vars++;
00798           else
00799             n_scalar_vars++;
00800         }
00801 
00802       // Here, we're assuming the number of vector components is the same
00803       // as the mesh dimension. Will break for mixed dimension meshes.
00804       unsigned int nv_sys_split = n_scalar_vars + dim*n_vector_vars;
00805 
00806       // Update the current_local_solution
00807       {
00808         System & non_const_sys = const_cast<System &>(system);
00809         non_const_sys.solution->close();
00810         non_const_sys.update();
00811       }
00812 
00813       NumericVector<Number> & sys_soln(*system.current_local_solution);
00814 
00815       std::vector<Number>      elem_soln;   // The finite element solution
00816       std::vector<Number>      nodal_soln;  // The FE solution interpolated to the nodes
00817       std::vector<dof_id_type> dof_indices; // The DOF indices for the finite element
00818 
00819       for (unsigned int var=0; var<nv_sys; var++)
00820         {
00821           const FEType& fe_type           = system.variable_type(var);
00822           const Variable &var_description = system.variable(var);
00823           const DofMap &dof_map           = system.get_dof_map();
00824 
00825           unsigned int n_vec_dim = FEInterface::n_vec_dim( pos->second->get_mesh(), fe_type );
00826 
00827           MeshBase::element_iterator       it       = _mesh.active_local_elements_begin();
00828           const MeshBase::element_iterator end_elem = _mesh.active_local_elements_end();
00829 
00830           for ( ; it != end_elem; ++it)
00831             {
00832               const Elem* elem = *it;
00833 
00834               if (var_description.active_on_subdomain((*it)->subdomain_id()))
00835                 {
00836                   dof_map.dof_indices (elem, dof_indices, var);
00837 
00838                   elem_soln.resize(dof_indices.size());
00839 
00840                   for (unsigned int i=0; i<dof_indices.size(); i++)
00841                     elem_soln[i] = sys_soln(dof_indices[i]);
00842 
00843                   FEInterface::nodal_soln (dim,
00844                                            fe_type,
00845                                            elem,
00846                                            elem_soln,
00847                                            nodal_soln);
00848 
00849 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
00850                   // infinite elements should be skipped...
00851                   if (!elem->infinite())
00852 #endif
00853                     {
00854                       libmesh_assert_equal_to (nodal_soln.size(), n_vec_dim*elem->n_nodes());
00855 
00856                       for (unsigned int n=0; n<elem->n_nodes(); n++)
00857                         {
00858                           for( unsigned int d=0; d < n_vec_dim; d++ )
00859                             {
00860                               // For vector-valued elements, all components are in nodal_soln. For each
00861                               // node, the components are stored in order, i.e. node_0 -> s0_x, s0_y, s0_z
00862                               parallel_soln.add(nv*(elem->node(n)) + (var+d + var_num), nodal_soln[n_vec_dim*n+d]);
00863 
00864                               // Increment the repeat count for this position
00865                               repeat_count.add(nv*(elem->node(n)) + (var+d + var_num), 1);
00866                             }
00867                         }
00868                     }
00869                 }
00870               else // If this variable doesn't exist on this subdomain we have to still increment repeat_count so that we won't divide by 0 later:
00871                 for (unsigned int n=0; n<elem->n_nodes(); n++)
00872                   // Only do this if this variable has NO DoFs at this node... it might have some from an ajoining element...
00873                   if(!elem->get_node(n)->n_dofs(sys_num, var))
00874                     for( unsigned int d=0; d < n_vec_dim; d++ )
00875                       repeat_count.add(nv*(elem->node(n)) + (var+d + var_num), 1);
00876 
00877             } // end loop over elements
00878         } // end loop on variables in this system
00879 
00880       var_num += nv_sys_split;
00881     } // end loop over systems
00882 
00883   parallel_soln.close();
00884   repeat_count.close();
00885 
00886   // Divide to get the average value at the nodes
00887   parallel_soln /= repeat_count;
00888 
00889   parallel_soln.localize_to_one(soln);
00890 
00891   STOP_LOG("build_solution_vector()", "EquationSystems");
00892 }
00893 
00894 
00895 void EquationSystems::get_solution (std::vector<Number>& soln,
00896                                     std::vector<std::string> & names ) const
00897 {
00898   // This function must be run on all processors at once
00899   parallel_object_only();
00900 
00901   libmesh_assert (this->n_systems());
00902 
00903   const dof_id_type ne  = _mesh.n_elem();
00904 
00905   libmesh_assert_equal_to (ne, _mesh.max_elem_id());
00906 
00907   // Get the number of local elements
00908   dof_id_type n_local_elems = cast_int<dof_id_type>
00909     (std::distance(_mesh.local_elements_begin(),
00910                    _mesh.local_elements_end()));
00911 
00912   // If the names vector has entries, we will only populate the soln vector
00913   // with names included in that list.  Note: The names vector may be
00914   // reordered upon exiting this function
00915   std::vector<std::string> filter_names = names;
00916   bool is_filter_names = ! filter_names.empty();
00917 
00918   soln.clear();
00919   names.clear();
00920 
00921   const FEType type(CONSTANT, MONOMIAL);
00922 
00923   dof_id_type nv = 0;
00924 
00925   // Find the total number of variables to output
00926   {
00927     const_system_iterator       pos = _systems.begin();
00928     const const_system_iterator end = _systems.end();
00929 
00930     for (; pos != end; ++pos)
00931       {
00932         const System& system  = *(pos->second);
00933         const unsigned int nv_sys = system.n_vars();
00934 
00935         for (unsigned int var=0; var < nv_sys; ++var)
00936           {
00937             if ( system.variable_type( var ) != type ||
00938                  ( is_filter_names && std::find(filter_names.begin(), filter_names.end(), system.variable_name( var )) == filter_names.end()) )
00939               continue;
00940 
00941             nv++;
00942           }
00943       }
00944   }
00945 
00946   if(!nv) // If there are no variables to write out don't do anything...
00947     return;
00948 
00949   // Create a NumericVector to hold the parallel solution
00950   UniquePtr<NumericVector<Number> > parallel_soln_ptr = NumericVector<Number>::build(_communicator);
00951   NumericVector<Number> &parallel_soln = *parallel_soln_ptr;
00952   parallel_soln.init(ne*nv, n_local_elems*nv, false, PARALLEL);
00953 
00954   dof_id_type var_num = 0;
00955 
00956   // For each system in this EquationSystems object,
00957   // update the global solution and collect the
00958   // CONSTANT MONOMIALs.  The entries are in variable-major
00959   // format.
00960   const_system_iterator       pos = _systems.begin();
00961   const const_system_iterator end = _systems.end();
00962 
00963   for (; pos != end; ++pos)
00964     {
00965       const System& system  = *(pos->second);
00966       const unsigned int nv_sys = system.n_vars();
00967 
00968       // Update the current_local_solution
00969       {
00970         System & non_const_sys = const_cast<System &>(system);
00971         non_const_sys.solution->close();
00972         non_const_sys.update();
00973       }
00974 
00975       NumericVector<Number> & sys_soln(*system.current_local_solution);
00976 
00977       std::vector<dof_id_type> dof_indices; // The DOF indices for the finite element
00978 
00979       // Loop over the variable names and load them in order
00980       for (unsigned int var=0; var < nv_sys; ++var)
00981         {
00982           if ( system.variable_type( var ) != type ||
00983                ( is_filter_names && std::find(filter_names.begin(), filter_names.end(), system.variable_name( var )) == filter_names.end()) )
00984             continue;
00985 
00986           names.push_back( system.variable_name( var ) );
00987 
00988           const Variable & variable = system.variable(var);
00989           const DofMap & dof_map = system.get_dof_map();
00990 
00991           MeshBase::element_iterator       it       = _mesh.active_local_elements_begin();
00992           const MeshBase::element_iterator end_elem = _mesh.active_local_elements_end();
00993 
00994           for ( ; it != end_elem; ++it)
00995             {
00996               if (variable.active_on_subdomain((*it)->subdomain_id()))
00997                 {
00998                   const Elem* elem = *it;
00999 
01000                   dof_map.dof_indices (elem, dof_indices, var);
01001 
01002                   libmesh_assert_equal_to ( 1, dof_indices.size() );
01003 
01004                   parallel_soln.set((ne*var_num)+elem->id(), sys_soln(dof_indices[0]));
01005                 }
01006             }
01007 
01008           var_num++;
01009         } // end loop on variables in this system
01010     } // end loop over systems
01011 
01012   parallel_soln.close();
01013 
01014   parallel_soln.localize_to_one(soln);
01015 }
01016 
01017 
01018 
01019 void EquationSystems::build_discontinuous_solution_vector (std::vector<Number>& soln,
01020                                                            const std::set<std::string>* system_names) const
01021 {
01022   START_LOG("build_discontinuous_solution_vector()", "EquationSystems");
01023 
01024   libmesh_assert (this->n_systems());
01025 
01026   const unsigned int dim = _mesh.mesh_dimension();
01027 
01028   // Get the number of variables (nv) by counting the number of variables
01029   // in each system listed in system_names
01030   unsigned int nv = 0;
01031 
01032   {
01033     const_system_iterator       pos = _systems.begin();
01034     const const_system_iterator end = _systems.end();
01035 
01036     for (; pos != end; ++pos)
01037       {
01038         // Check current system is listed in system_names, and skip pos if not
01039         bool use_current_system = (system_names == NULL);
01040         if (!use_current_system)
01041           use_current_system = system_names->count(pos->first);
01042         if (!use_current_system)
01043           continue;
01044 
01045         const System& system  = *(pos->second);
01046         nv += system.n_vars();
01047       }
01048   }
01049 
01050   unsigned int tw=0;
01051 
01052   // get the total weight
01053   {
01054     MeshBase::element_iterator       it  = _mesh.active_elements_begin();
01055     const MeshBase::element_iterator end = _mesh.active_elements_end();
01056 
01057     for ( ; it != end; ++it)
01058       tw += (*it)->n_nodes();
01059   }
01060 
01061 
01062   // Only if we are on processor zero, allocate the storage
01063   // to hold (number_of_nodes)*(number_of_variables) entries.
01064   if (_mesh.processor_id() == 0)
01065     soln.resize(tw*nv);
01066 
01067   std::vector<Number> sys_soln;
01068 
01069 
01070   unsigned int var_num=0;
01071 
01072   // For each system in this EquationSystems object,
01073   // update the global solution and if we are on processor 0,
01074   // loop over the elements and build the nodal solution
01075   // from the element solution.  Then insert this nodal solution
01076   // into the vector passed to build_solution_vector.
01077   {
01078     const_system_iterator       pos = _systems.begin();
01079     const const_system_iterator end = _systems.end();
01080 
01081     for (; pos != end; ++pos)
01082       {
01083         // Check current system is listed in system_names, and skip pos if not
01084         bool use_current_system = (system_names == NULL);
01085         if (!use_current_system)
01086           use_current_system = system_names->count(pos->first);
01087         if (!use_current_system)
01088           continue;
01089 
01090         const System& system  = *(pos->second);
01091         const unsigned int nv_sys = system.n_vars();
01092 
01093         system.update_global_solution (sys_soln, 0);
01094 
01095         if (_mesh.processor_id() == 0)
01096           {
01097             std::vector<Number>       elem_soln;   // The finite element solution
01098             std::vector<Number>       nodal_soln;  // The FE solution interpolated to the nodes
01099             std::vector<dof_id_type>  dof_indices; // The DOF indices for the finite element
01100 
01101             for (unsigned int var=0; var<nv_sys; var++)
01102               {
01103                 const FEType& fe_type    = system.variable_type(var);
01104 
01105                 MeshBase::element_iterator       it       = _mesh.active_elements_begin();
01106                 const MeshBase::element_iterator end_elem = _mesh.active_elements_end();
01107 
01108                 unsigned int nn=0;
01109 
01110                 for ( ; it != end_elem; ++it)
01111                   {
01112                     const Elem* elem = *it;
01113                     system.get_dof_map().dof_indices (elem, dof_indices, var);
01114 
01115                     elem_soln.resize(dof_indices.size());
01116 
01117                     for (unsigned int i=0; i<dof_indices.size(); i++)
01118                       elem_soln[i] = sys_soln[dof_indices[i]];
01119 
01120                     FEInterface::nodal_soln (dim,
01121                                              fe_type,
01122                                              elem,
01123                                              elem_soln,
01124                                              nodal_soln);
01125 
01126 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
01127                     // infinite elements should be skipped...
01128                     if (!elem->infinite())
01129 #endif
01130                       {
01131                         libmesh_assert_equal_to (nodal_soln.size(), elem->n_nodes());
01132 
01133                         for (unsigned int n=0; n<elem->n_nodes(); n++)
01134                           {
01135                             soln[nv*(nn++) + (var + var_num)] +=
01136                               nodal_soln[n];
01137                           }
01138                       }
01139                   }
01140               }
01141           }
01142 
01143         var_num += nv_sys;
01144       }
01145   }
01146 
01147   STOP_LOG("build_discontinuous_solution_vector()", "EquationSystems");
01148 }
01149 
01150 
01151 
01152 bool EquationSystems::compare (const EquationSystems& other_es,
01153                                const Real threshold,
01154                                const bool verbose) const
01155 {
01156   // safety check, whether we handle at least the same number
01157   // of systems
01158   std::vector<bool> os_result;
01159 
01160   if (this->n_systems() != other_es.n_systems())
01161     {
01162       if (verbose)
01163         {
01164           libMesh::out << "  Fatal difference. This system handles "
01165                        << this->n_systems() << " systems," << std::endl
01166                        << "  while the other system handles "
01167                        << other_es.n_systems()
01168                        << " systems." << std::endl
01169                        << "  Aborting comparison." << std::endl;
01170         }
01171       return false;
01172     }
01173   else
01174     {
01175       // start comparing each system
01176       const_system_iterator       pos = _systems.begin();
01177       const const_system_iterator end = _systems.end();
01178 
01179       for (; pos != end; ++pos)
01180         {
01181           const std::string& sys_name = pos->first;
01182           const System&  system        = *(pos->second);
01183 
01184           // get the other system
01185           const System& other_system   = other_es.get_system (sys_name);
01186 
01187           os_result.push_back (system.compare (other_system, threshold, verbose));
01188 
01189         }
01190 
01191     }
01192 
01193 
01194   // sum up the results
01195   if (os_result.size()==0)
01196     return true;
01197   else
01198     {
01199       bool os_identical;
01200       unsigned int n = 0;
01201       do
01202         {
01203           os_identical = os_result[n];
01204           n++;
01205         }
01206       while (os_identical && n<os_result.size());
01207       return os_identical;
01208     }
01209 }
01210 
01211 
01212 
01213 std::string EquationSystems::get_info () const
01214 {
01215   std::ostringstream oss;
01216 
01217   oss << " EquationSystems\n"
01218       << "  n_systems()=" << this->n_systems() << '\n';
01219 
01220   // Print the info for the individual systems
01221   const_system_iterator       pos = _systems.begin();
01222   const const_system_iterator end = _systems.end();
01223 
01224   for (; pos != end; ++pos)
01225     oss << pos->second->get_info();
01226 
01227 
01228   //   // Possibly print the parameters
01229   //   if (!this->parameters.empty())
01230   //     {
01231   //       oss << "  n_parameters()=" << this->n_parameters() << '\n';
01232   //       oss << "   Parameters:\n";
01233 
01234   //       for (std::map<std::string, Real>::const_iterator
01235   //      param = _parameters.begin(); param != _parameters.end();
01236   //    ++param)
01237   // oss << "    "
01238   //     << "\""
01239   //     << param->first
01240   //     << "\""
01241   //     << "="
01242   //     << param->second
01243   //     << '\n';
01244   //     }
01245 
01246   return oss.str();
01247 }
01248 
01249 
01250 
01251 void EquationSystems::print_info (std::ostream& os) const
01252 {
01253   os << this->get_info()
01254      << std::endl;
01255 }
01256 
01257 
01258 
01259 std::ostream& operator << (std::ostream& os, const EquationSystems& es)
01260 {
01261   es.print_info(os);
01262   return os;
01263 }
01264 
01265 
01266 
01267 unsigned int EquationSystems::n_vars () const
01268 {
01269   unsigned int tot=0;
01270 
01271   const_system_iterator       pos = _systems.begin();
01272   const const_system_iterator end = _systems.end();
01273 
01274   for (; pos != end; ++pos)
01275     tot += pos->second->n_vars();
01276 
01277   return tot;
01278 }
01279 
01280 
01281 
01282 std::size_t EquationSystems::n_dofs () const
01283 {
01284   std::size_t tot=0;
01285 
01286   const_system_iterator       pos = _systems.begin();
01287   const const_system_iterator end = _systems.end();
01288 
01289   for (; pos != end; ++pos)
01290     tot += pos->second->n_dofs();
01291 
01292   return tot;
01293 }
01294 
01295 
01296 
01297 
01298 std::size_t EquationSystems::n_active_dofs () const
01299 {
01300   std::size_t tot=0;
01301 
01302   const_system_iterator       pos = _systems.begin();
01303   const const_system_iterator end = _systems.end();
01304 
01305   for (; pos != end; ++pos)
01306     tot += pos->second->n_active_dofs();
01307 
01308   return tot;
01309 }
01310 
01311 
01312 void EquationSystems::_add_system_to_nodes_and_elems()
01313 {
01314   // All the nodes
01315   MeshBase::node_iterator       node_it  = _mesh.nodes_begin();
01316   const MeshBase::node_iterator node_end = _mesh.nodes_end();
01317 
01318   for ( ; node_it != node_end; ++node_it)
01319     (*node_it)->add_system();
01320 
01321   // All the elements
01322   MeshBase::element_iterator       elem_it  = _mesh.elements_begin();
01323   const MeshBase::element_iterator elem_end = _mesh.elements_end();
01324 
01325   for ( ; elem_it != elem_end; ++elem_it)
01326     (*elem_it)->add_system();
01327 }
01328 
01329 } // namespace libMesh