$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 // 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> ¶llel_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> ¶llel_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