libMesh
system.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // Local includes
21 #include "libmesh/dof_map.h"
22 #include "libmesh/equation_systems.h"
23 #include "libmesh/int_range.h"
24 #include "libmesh/libmesh_logging.h"
25 #include "libmesh/mesh_base.h"
26 #include "libmesh/numeric_vector.h"
27 #include "libmesh/parameter_vector.h"
28 #include "libmesh/point.h" // For point_value
29 #include "libmesh/point_locator_base.h" // For point_value
30 #include "libmesh/qoi_set.h"
31 #include "libmesh/enum_to_string.h"
32 #include "libmesh/sparse_matrix.h"
33 #include "libmesh/system.h"
34 #include "libmesh/system_norm.h"
35 #include "libmesh/utility.h"
36 #include "libmesh/elem.h"
37 #include "libmesh/fe_type.h"
38 #include "libmesh/parallel_fe_type.h"
39 #include "libmesh/fe_interface.h"
40 #include "libmesh/fe_compute_data.h"
41 #include "libmesh/static_condensation.h"
42 
43 // includes for calculate_norm, point_*
44 #include "libmesh/fe_base.h"
45 #include "libmesh/fe_interface.h"
46 #include "libmesh/parallel.h"
47 #include "libmesh/parallel_algebra.h"
48 #include "libmesh/quadrature.h"
49 #include "libmesh/tensor_value.h"
50 #include "libmesh/vector_value.h"
51 #include "libmesh/tensor_tools.h"
52 #include "libmesh/enum_norm_type.h"
53 #include "libmesh/enum_fe_family.h"
54 
55 // C++ includes
56 #include <sstream> // for std::ostringstream
57 
58 namespace libMesh
59 {
60 
61 
62 // ------------------------------------------------------------
63 // System implementation
65  const std::string & name_in,
66  const unsigned int number_in) :
67 
68  ParallelObject (es),
69  assemble_before_solve (true),
70  use_fixed_solution (false),
71  extra_quadrature_order (0),
72  solution (NumericVector<Number>::build(this->comm())),
73  current_local_solution (NumericVector<Number>::build(this->comm())),
74  time (0.),
75  qoi (0),
76  qoi_error_estimates (0),
77  _init_system_function (nullptr),
78  _init_system_object (nullptr),
79  _assemble_system_function (nullptr),
80  _assemble_system_object (nullptr),
81  _constrain_system_function (nullptr),
82  _constrain_system_object (nullptr),
83  _qoi_evaluate_function (nullptr),
84  _qoi_evaluate_object (nullptr),
85  _qoi_evaluate_derivative_function (nullptr),
86  _qoi_evaluate_derivative_object (nullptr),
87  _dof_map (std::make_unique<DofMap>(number_in, es.get_mesh())),
88  _equation_systems (es),
89  _mesh (es.get_mesh()),
90  _sys_name (name_in),
91  _sys_number (number_in),
92  _active (true),
93  _matrices_initialized (false),
94  _solution_projection (true),
95  _basic_system_only (false),
96  _is_initialized (false),
97  _identify_variable_groups (true),
98  _additional_data_written (false),
99  adjoint_already_solved (false),
100  _hide_output (false),
101  project_with_constraints (true),
102  _prefer_hash_table_matrix_assembly(false),
103  _require_sparsity_pattern (false),
104  _prefix_with_name (false)
105 {
106  if (libMesh::on_command_line("--solver-system-names"))
107  this->prefix_with_name(true);
108  if (libMesh::on_command_line("--" + name_in + "-static-condensation"))
110 }
111 
112 
113 
115 {
116  libmesh_exceptionless_assert (!libMesh::closed());
117 }
118 
119 
120 
122 {
123  return _dof_map->n_dofs();
124 }
125 
126 
127 
129 {
130 #ifdef LIBMESH_ENABLE_CONSTRAINTS
131 
132  return _dof_map->n_constrained_dofs();
133 
134 #else
135 
136  return 0;
137 
138 #endif
139 }
140 
141 
142 
144 {
145 #ifdef LIBMESH_ENABLE_CONSTRAINTS
146 
147  return _dof_map->n_local_constrained_dofs();
148 
149 #else
150 
151  return 0;
152 
153 #endif
154 }
155 
156 
157 
159 {
160  return _dof_map->n_local_dofs();
161 }
162 
163 
164 
165 Number System::current_solution (const dof_id_type global_dof_number) const
166 {
167  // Check the sizes
168  libmesh_assert_less (global_dof_number, _dof_map->n_dofs());
169  libmesh_assert_less (global_dof_number, current_local_solution->size());
170 
171  return (*current_local_solution)(global_dof_number);
172 }
173 
174 
175 
177 {
178  _variables.clear();
179  _variable_numbers.clear();
180  _dof_map->clear ();
181  solution->clear ();
182  current_local_solution->clear ();
183 
184  // clear any user-added vectors
185  _vectors.clear();
186  _vector_projections.clear();
187  _vector_is_adjoint.clear();
188  _is_initialized = false;
189 
190  // clear any user-added matrices
191  _matrices.clear();
192  _matrices_initialized = false;
193 }
194 
195 
196 
198 {
199  // Calling init() twice on the same system currently works evil
200  // magic, whether done directly or via EquationSystems::read()
201  libmesh_assert(!this->is_initialized());
202 
203  this->reinit_mesh();
204 }
205 
206 
207 
209 {
210  parallel_object_only();
211 
212  MeshBase & mesh = this->get_mesh();
213 
214  // Add all variable groups to our underlying DofMap
215  unsigned int n_dof_map_vg = _dof_map->n_variable_groups();
216  for (auto vg : make_range(this->n_variable_groups()))
217  {
218  const VariableGroup & group = this->variable_group(vg);
219  if (vg < n_dof_map_vg)
220  libmesh_assert(group == _dof_map->variable_group(vg));
221  else
222  _dof_map->add_variable_group(group);
223  }
224 
225  // Distribute the degrees of freedom on the mesh
226  auto total_dofs = _dof_map->distribute_dofs (mesh);
227 
228  // Throw an error if the total number of DOFs is not capable of
229  // being indexed by our solution vector.
230  auto max_allowed_id = solution->max_allowed_id();
231  libmesh_error_msg_if(total_dofs > max_allowed_id,
232  "Cannot allocate a NumericVector with " << total_dofs << " degrees of freedom. "
233  "The vector can only index up to " << max_allowed_id << " entries.");
234 
235  // Recreate any user or internal constraints
236  this->reinit_constraints();
237 
238  // Even if there weren't any constraint changes,
239  // reinit_constraints() did prepare_send_list() for us.
240 
241  // Now finally after dof distribution and construction of any
242  // possible constraints, we may init any static condensation
243  // data
244  _dof_map->reinit_static_condensation();
245 
246  // Resize the solution conformal to the current mesh
247  solution->init (this->n_dofs(), this->n_local_dofs(), false, PARALLEL);
248 
249  // Resize the current_local_solution for the current mesh
250 #ifdef LIBMESH_ENABLE_GHOSTED
251  current_local_solution->init (this->n_dofs(), this->n_local_dofs(),
252  _dof_map->get_send_list(), /*fast=*/false,
253  GHOSTED);
254 #else
255  current_local_solution->init (this->n_dofs(), false, SERIAL);
256 #endif
257 
258  // from now on, adding additional vectors or variables can't be done
259  // without immediately initializing them
260  _is_initialized = true;
261 
262  // initialize & zero other vectors, if necessary
263  for (auto & [vec_name, vec] : _vectors)
264  {
265  libmesh_ignore(vec_name); // spurious warning from old gcc
266  const ParallelType type = vec->type();
267 
268  if (type == GHOSTED)
269  {
270 #ifdef LIBMESH_ENABLE_GHOSTED
271  vec->init (this->n_dofs(), this->n_local_dofs(),
272  _dof_map->get_send_list(), /*fast=*/false,
273  GHOSTED);
274 #else
275  libmesh_error_msg("Cannot initialize ghosted vectors when they are not enabled.");
276 #endif
277  }
278  else if (type == SERIAL)
279  {
280  vec->init (this->n_dofs(), false, type);
281  }
282  else
283  {
284  libmesh_assert_equal_to(type, PARALLEL);
285  vec->init (this->n_dofs(), this->n_local_dofs(), false, type);
286  }
287  }
288 
289  // Add matrices
290  this->add_matrices();
291 
292  // Clear any existing matrices
293  for (auto & pr : _matrices)
294  pr.second->clear();
295 
296  // Initialize the matrices for the system
297  if (!_basic_system_only)
298  this->init_matrices();
299 }
300 
302 {
303  parallel_object_only();
304 
305  // First initialize any required data:
306  // either only the basic System data
307  if (_basic_system_only)
309  // or all the derived class' data too
310  else
311  this->init_data();
312 
313  // If no variables have been added to this system
314  // don't do anything
315  if (!this->n_vars())
316  return;
317 
318  // Then call the user-provided initialization function
319  this->user_initialization();
320 
321 }
322 
324 {
325  parallel_object_only();
326 
327  // No matrices to init
328  if (_matrices.empty())
329  {
330  // any future matrices to be added will need their own
331  // initialization
332  _matrices_initialized = true;
333 
334  return;
335  }
336 
337  // Check for quick return in case the first matrix
338  // (and by extension all the matrices) has already
339  // been initialized
340  if (_matrices.begin()->second->initialized())
341  {
343  return;
344  }
345 
346  _matrices_initialized = true;
347 
348  // Tell the matrices about the dof map, and vice versa
349  for (auto & pr : _matrices)
350  {
351  SparseMatrix<Number> & m = *(pr.second);
353 
354  // We want to allow repeated init() on systems, but we don't
355  // want to attach the same matrix to the DofMap twice
356  if (!this->get_dof_map().is_attached(m))
357  this->get_dof_map().attach_matrix(m);
358 
359  // If the user has already explicitly requested that this matrix use a hash table, then we
360  // always honor that
361  const bool use_hash =
362  pr.second->use_hash_table() ||
363  (this->_prefer_hash_table_matrix_assembly && pr.second->supports_hash_table());
364  pr.second->use_hash_table(use_hash);
365  // Make this call after we've determined whether the matrix is using a hash table
366  if (pr.second->require_sparsity_pattern())
367  this->_require_sparsity_pattern = true;
368  }
369 
370  // Compute the sparsity pattern for the current
371  // mesh and DOF distribution. This also updates
372  // additional matrices, \p DofMap now knows them
373  if (this->_require_sparsity_pattern)
374  this->get_dof_map().compute_sparsity(this->get_mesh());
375 
376  // Initialize matrices and set to zero
377  for (auto & [name, mat] : _matrices)
378  {
379  mat->init(_matrix_types[name]);
380  mat->zero();
381  }
382 }
383 
384 
385 
387 {
388  parallel_object_only();
389 
390 #ifdef LIBMESH_ENABLE_AMR
391  // Restrict the _vectors on the coarsened cells
392  for (auto & [vec_name, vec] : _vectors)
393  {
394  NumericVector<Number> * v = vec.get();
395 
396  if (_vector_projections[vec_name])
397  {
398  this->project_vector (*v, this->vector_is_adjoint(vec_name));
399  }
400  else
401  {
402  const ParallelType type = vec->type();
403 
404  if (type == GHOSTED)
405  {
406 #ifdef LIBMESH_ENABLE_GHOSTED
407  vec->init (this->n_dofs(), this->n_local_dofs(),
408  _dof_map->get_send_list(), /*fast=*/false,
409  GHOSTED);
410 #else
411  libmesh_error_msg("Cannot initialize ghosted vectors when they are not enabled.");
412 #endif
413  }
414  else
415  vec->init (this->n_dofs(), this->n_local_dofs(), false, type);
416  }
417  }
418 
419  const std::vector<dof_id_type> & send_list = _dof_map->get_send_list ();
420 
421  // Restrict the solution on the coarsened cells
423  this->project_vector (*solution);
424  // Or at least make sure the solution vector is the correct size
425  else
426  solution->init (this->n_dofs(), this->n_local_dofs(), true, PARALLEL);
427 
428 #ifdef LIBMESH_ENABLE_GHOSTED
429  current_local_solution->init(this->n_dofs(),
430  this->n_local_dofs(), send_list,
431  false, GHOSTED);
432 #else
433  current_local_solution->init(this->n_dofs());
434 #endif
435 
437  solution->localize (*current_local_solution, send_list);
438 
439 #endif // LIBMESH_ENABLE_AMR
440 }
441 
442 
443 
445 {
446 #ifdef LIBMESH_ENABLE_AMR
447  // Currently project_vector handles both restriction and prolongation
448  this->restrict_vectors();
449 #endif
450 }
451 
452 
453 
455 {
456  parallel_object_only();
457 
458  // project_vector handles vector initialization now
459  libmesh_assert_equal_to (solution->size(), current_local_solution->size());
460 
461  // Make sure our static condensation dof map is up-to-date before we init any
462  // static condensation matrices
464 
465  if (!_matrices.empty() && !_basic_system_only)
466  {
467  // Clear the matrices
468  for (auto & pr : _matrices)
469  {
470  pr.second->clear();
471  pr.second->attach_dof_map(this->get_dof_map());
472  }
473 
474  if (this->_require_sparsity_pattern)
475  {
476  // Clear the sparsity pattern
477  this->get_dof_map().clear_sparsity();
478 
479  // Compute the sparsity pattern for the current
480  // mesh and DOF distribution. This also updates
481  // additional matrices, \p DofMap now knows them
482  this->get_dof_map().compute_sparsity (this->get_mesh());
483  }
484 
485  // Initialize matrices and set to zero
486  for (auto & pr : _matrices)
487  {
488  pr.second->init();
489  pr.second->zero();
490  }
491  }
492 }
493 
494 
496 {
497  parallel_object_only();
498 
499 #ifdef LIBMESH_ENABLE_CONSTRAINTS
501  user_constrain();
503  if (libMesh::on_command_line ("--print-constraints"))
505 #endif
507 }
508 
509 
511 {
512  parallel_object_only();
513 
514  libmesh_assert(solution->closed());
515 
516  const std::vector<dof_id_type> & send_list = _dof_map->get_send_list ();
517 
518  // Check sizes
519  libmesh_assert_equal_to (current_local_solution->size(), solution->size());
520  // More processors than elements => empty send_list
521  // libmesh_assert (!send_list.empty());
522  libmesh_assert_less_equal (send_list.size(), solution->size());
523 
524  // Create current_local_solution from solution. This will
525  // put a local copy of solution into current_local_solution.
526  // Only the necessary values (specified by the send_list)
527  // are copied to minimize communication
528  solution->localize (*current_local_solution, send_list);
529 }
530 
531 
532 
534 {
535  parallel_object_only();
536 
537  // If this system is empty... don't do anything!
538  if (!this->n_vars())
539  return;
540 
541  const std::vector<dof_id_type> & send_list = this->get_dof_map().get_send_list ();
542 
543  // Check sizes
544  libmesh_assert_equal_to (current_local_solution->size(), solution->size());
545  // Not true with ghosted vectors
546  // libmesh_assert_equal_to (current_local_solution->local_size(), solution->size());
547  // libmesh_assert (!send_list.empty());
548  libmesh_assert_less_equal (send_list.size(), solution->size());
549 
550  // Create current_local_solution from solution. This will
551  // put a local copy of solution into current_local_solution.
552  solution->localize (*current_local_solution, send_list);
553 }
554 
555 
556 
558  const SubsetSolveMode /*subset_solve_mode*/)
559 {
560  if (subset != nullptr)
561  libmesh_not_implemented();
562 }
563 
564 
565 
567 {
568  // Log how long the user's assembly code takes
569  LOG_SCOPE("assemble()", "System");
570 
571  // Call the user-specified assembly function
572  this->user_assembly();
573 }
574 
575 
576 
577 void System::assemble_qoi (const QoISet & qoi_indices)
578 {
579  // Log how long the user's assembly code takes
580  LOG_SCOPE("assemble_qoi()", "System");
581 
582  // Call the user-specified quantity of interest function
583  this->user_QOI(qoi_indices);
584 }
585 
586 
587 
588 void System::assemble_qoi_derivative(const QoISet & qoi_indices,
589  bool include_liftfunc,
590  bool apply_constraints)
591 {
592  // Log how long the user's assembly code takes
593  LOG_SCOPE("assemble_qoi_derivative()", "System");
594 
595  // Call the user-specified quantity of interest function
596  this->user_QOI_derivative(qoi_indices, include_liftfunc,
597  apply_constraints);
598 }
599 
600 
601 
602 void System::qoi_parameter_sensitivity (const QoISet & qoi_indices,
603  const ParameterVector & parameters_vec,
604  SensitivityData & sensitivities)
605 {
606  // Forward sensitivities are more efficient for Nq > Np
607  if (qoi_indices.size(*this) > parameters_vec.size())
608  forward_qoi_parameter_sensitivity(qoi_indices, parameters_vec, sensitivities);
609  // Adjoint sensitivities are more efficient for Np > Nq,
610  // and an adjoint may be more reusable than a forward
611  // solution sensitivity in the Np == Nq case.
612  else
613  adjoint_qoi_parameter_sensitivity(qoi_indices, parameters_vec, sensitivities);
614 }
615 
616 
617 
618 bool System::compare (const System & other_system,
619  const Real threshold,
620  const bool verbose) const
621 {
622  // we do not care for matrices, but for vectors
624  libmesh_assert (other_system._is_initialized);
625 
626  if (verbose)
627  {
628  libMesh::out << " Systems \"" << _sys_name << "\"" << std::endl;
629  libMesh::out << " comparing matrices not supported." << std::endl;
630  libMesh::out << " comparing names...";
631  }
632 
633  // compare the name: 0 means identical
634  const int name_result = _sys_name.compare(other_system.name());
635  if (verbose)
636  {
637  if (name_result == 0)
638  libMesh::out << " identical." << std::endl;
639  else
640  libMesh::out << " names not identical." << std::endl;
641  libMesh::out << " comparing solution vector...";
642  }
643 
644 
645  // compare the solution: -1 means identical
646  const int solu_result = solution->compare (*other_system.solution.get(),
647  threshold);
648 
649  if (verbose)
650  {
651  if (solu_result == -1)
652  libMesh::out << " identical up to threshold." << std::endl;
653  else
654  libMesh::out << " first difference occurred at index = "
655  << solu_result << "." << std::endl;
656  }
657 
658 
659  // safety check, whether we handle at least the same number
660  // of vectors
661  std::vector<int> ov_result;
662 
663  if (this->n_vectors() != other_system.n_vectors())
664  {
665  if (verbose)
666  {
667  libMesh::out << " Fatal difference. This system handles "
668  << this->n_vectors() << " add'l vectors," << std::endl
669  << " while the other system handles "
670  << other_system.n_vectors()
671  << " add'l vectors." << std::endl
672  << " Aborting comparison." << std::endl;
673  }
674  return false;
675  }
676  else if (this->n_vectors() == 0)
677  {
678  // there are no additional vectors...
679  ov_result.clear ();
680  }
681  else
682  {
683  // compare other vectors
684  for (auto & [vec_name, vec] : _vectors)
685  {
686  if (verbose)
687  libMesh::out << " comparing vector \""
688  << vec_name << "\" ...";
689 
690  // assume they have the same name
691  const NumericVector<Number> & other_system_vector =
692  other_system.get_vector(vec_name);
693 
694  ov_result.push_back(vec->compare(other_system_vector, threshold));
695 
696  if (verbose)
697  {
698  if (ov_result[ov_result.size()-1] == -1)
699  libMesh::out << " identical up to threshold." << std::endl;
700  else
701  libMesh::out << " first difference occurred at" << std::endl
702  << " index = " << ov_result[ov_result.size()-1] << "." << std::endl;
703  }
704  }
705  } // finished comparing additional vectors
706 
707 
708  bool overall_result;
709 
710  // sum up the results
711  if ((name_result==0) && (solu_result==-1))
712  {
713  if (ov_result.size()==0)
714  overall_result = true;
715  else
716  {
717  bool ov_identical;
718  unsigned int n = 0;
719  do
720  {
721  ov_identical = (ov_result[n]==-1);
722  n++;
723  }
724  while (ov_identical && n<ov_result.size());
725  overall_result = ov_identical;
726  }
727  }
728  else
729  overall_result = false;
730 
731  if (verbose)
732  {
733  libMesh::out << " finished comparisons, ";
734  if (overall_result)
735  libMesh::out << "found no differences." << std::endl << std::endl;
736  else
737  libMesh::out << "found differences." << std::endl << std::endl;
738  }
739 
740  return overall_result;
741 }
742 
743 
744 
745 void System::update_global_solution (std::vector<Number> & global_soln) const
746 {
747  parallel_object_only();
748 
749  global_soln.resize (solution->size());
750 
751  solution->localize (global_soln);
752 }
753 
754 
755 
756 void System::update_global_solution (std::vector<Number> & global_soln,
757  const processor_id_type dest_proc) const
758 {
759  parallel_object_only();
760 
761  global_soln.resize (solution->size());
762 
763  solution->localize_to_one (global_soln, dest_proc);
764 }
765 
766 
767 
768 NumericVector<Number> & System::add_vector (std::string_view vec_name,
769  const bool projections,
770  const ParallelType type)
771 {
772  parallel_object_only();
773 
774  libmesh_assert(this->comm().verify(std::string(vec_name)));
775  libmesh_assert(this->comm().verify(int(type)));
776  libmesh_assert(this->comm().verify(projections));
777 
778  // Return the vector if it is already there.
779  if (auto it = this->_vectors.find(vec_name);
780  it != this->_vectors.end())
781  {
782  // If the projection setting has *upgraded*, change it.
783  if (projections) // only do expensive lookup if needed
784  libmesh_map_find(_vector_projections, vec_name) = projections;
785 
786  NumericVector<Number> & vec = *it->second;
787 
788  // If we're in serial, our vectors are effectively SERIAL, so
789  // we'll ignore any type setting. If we're in parallel, we
790  // might have a type change to deal with.
791 
792  if (this->n_processors() > 1)
793  {
794  // If the type setting has changed in a way we can't
795  // perceive as an upgrade or a downgrade, scream.
796  libmesh_assert_equal_to(type == SERIAL,
797  vec.type() == SERIAL);
798 
799  // If the type setting has *upgraded*, change it.
800  if (type == GHOSTED && vec.type() == PARALLEL)
801  {
802  // A *really* late upgrade is expensive, but better not
803  // to risk zeroing data.
804  if (vec.initialized())
805  {
806  if (!vec.closed())
807  vec.close();
808 
809  // Ideally we'd move parallel coefficients and then
810  // add ghosted coefficients, but copy and swap is
811  // simpler. If anyone actually ever uses this case
812  // for real we can look into optimizing it.
813  auto new_vec = NumericVector<Number>::build(this->comm());
814 #ifdef LIBMESH_ENABLE_GHOSTED
815  new_vec->init (this->n_dofs(), this->n_local_dofs(),
816  _dof_map->get_send_list(), /*fast=*/false,
817  GHOSTED);
818 #else
819  libmesh_error_msg("Cannot initialize ghosted vectors when they are not enabled.");
820 #endif
821 
822  *new_vec = vec;
823  vec.swap(*new_vec);
824  }
825  else
826  // The PARALLEL vec is not yet initialized, so we can
827  // just "upgrade" it to GHOSTED.
828  vec.set_type(type);
829  }
830  }
831 
832  // Any upgrades are done; we're happy here.
833  return vec;
834  }
835 
836  // Otherwise, build the vector. The following emplace() is
837  // guaranteed to succeed because, if we made it here, we don't
838  // already have a vector named "vec_name". We pass the user's
839  // requested ParallelType directly to NumericVector::build() so
840  // that, even if the vector is not initialized now, it will get the
841  // right type when it is initialized later.
842  auto pr =
843  _vectors.emplace(vec_name,
846  type));
847  auto buf = pr.first->second.get();
848  _vector_projections.emplace(vec_name, projections);
849 
850  // Vectors are primal by default
851  _vector_is_adjoint.emplace(vec_name, -1);
852 
853  // Initialize it if necessary
854  if (_is_initialized)
855  {
856  if (type == GHOSTED)
857  {
858 #ifdef LIBMESH_ENABLE_GHOSTED
859  buf->init (this->n_dofs(), this->n_local_dofs(),
860  _dof_map->get_send_list(), /*fast=*/false,
861  GHOSTED);
862 #else
863  libmesh_error_msg("Cannot initialize ghosted vectors when they are not enabled.");
864 #endif
865  }
866  else
867  buf->init (this->n_dofs(), this->n_local_dofs(), false, type);
868  }
869 
870  return *buf;
871 }
872 
873 void System::remove_vector (std::string_view vec_name)
874 {
875  parallel_object_only(); // Not strictly needed, but the only safe way to keep in sync
876 
877  if (const auto pos = _vectors.find(vec_name);
878  pos != _vectors.end())
879  {
880  _vectors.erase(pos);
881  auto proj_it = _vector_projections.find(vec_name);
882  libmesh_assert(proj_it != _vector_projections.end());
883  _vector_projections.erase(proj_it);
884 
885  auto adj_it = _vector_is_adjoint.find(vec_name);
886  libmesh_assert(adj_it != _vector_is_adjoint.end());
887  _vector_is_adjoint.erase(adj_it);
888  }
889 }
890 
891 const NumericVector<Number> * System::request_vector (std::string_view vec_name) const
892 {
893  if (const auto pos = _vectors.find(vec_name);
894  pos != _vectors.end())
895  return pos->second.get();
896 
897  // Otherwise, vec_name was not found
898  return nullptr;
899 }
900 
901 
902 
903 NumericVector<Number> * System::request_vector (std::string_view vec_name)
904 {
905  if (auto pos = _vectors.find(vec_name);
906  pos != _vectors.end())
907  return pos->second.get();
908 
909  // Otherwise, vec_name was not found
910  return nullptr;
911 }
912 
913 
914 
915 const NumericVector<Number> * System::request_vector (const unsigned int vec_num) const
916 {
917  // If we don't have that many vectors, return nullptr
918  if (vec_num >= _vectors.size())
919  return nullptr;
920 
921  // Otherwise return a pointer to the vec_num'th vector
922  auto it = vectors_begin();
923  std::advance(it, vec_num);
924  return it->second.get();
925 }
926 
927 
928 
929 NumericVector<Number> * System::request_vector (const unsigned int vec_num)
930 {
931  // If we don't have that many vectors, return nullptr
932  if (vec_num >= _vectors.size())
933  return nullptr;
934 
935  // Otherwise return a pointer to the vec_num'th vector
936  auto it = vectors_begin();
937  std::advance(it, vec_num);
938  return it->second.get();
939 }
940 
941 
942 
943 const NumericVector<Number> & System::get_vector (std::string_view vec_name) const
944 {
945  return *(libmesh_map_find(_vectors, vec_name));
946 }
947 
948 
949 
950 NumericVector<Number> & System::get_vector (std::string_view vec_name)
951 {
952  return *(libmesh_map_find(_vectors, vec_name));
953 }
954 
955 
956 
957 const NumericVector<Number> & System::get_vector (const unsigned int vec_num) const
958 {
959  // If we don't have that many vectors, throw an error
960  libmesh_assert_less(vec_num, _vectors.size());
961 
962  // Otherwise return a reference to the vec_num'th vector
963  auto it = vectors_begin();
964  std::advance(it, vec_num);
965  return *(it->second);
966 }
967 
968 
969 
970 NumericVector<Number> & System::get_vector (const unsigned int vec_num)
971 {
972  // If we don't have that many vectors, throw an error
973  libmesh_assert_less(vec_num, _vectors.size());
974 
975  // Otherwise return a reference to the vec_num'th vector
976  auto it = vectors_begin();
977  std::advance(it, vec_num);
978  return *(it->second);
979 }
980 
981 
982 
983 const std::string & System::vector_name (const unsigned int vec_num) const
984 {
985  // If we don't have that many vectors, throw an error
986  libmesh_assert_less(vec_num, _vectors.size());
987 
988  // Otherwise return a reference to the vec_num'th vector name
989  auto it = vectors_begin();
990  std::advance(it, vec_num);
991  return it->first;
992 }
993 
994 const std::string & System::vector_name (const NumericVector<Number> & vec_reference) const
995 {
996  // Linear search for a vector whose pointer matches vec_reference
997  auto it = std::find_if(vectors_begin(), vectors_end(),
998  [&vec_reference](const decltype(_vectors)::value_type & pr)
999  { return &vec_reference == pr.second.get(); });
1000 
1001  // Before returning, make sure we didn't loop till the end and not find any match
1002  libmesh_assert (it != vectors_end());
1003 
1004  // Return the string associated with the current vector
1005  return it->first;
1006 }
1007 
1008 
1009 
1010 SparseMatrix<Number> & System::add_matrix (std::string_view mat_name,
1011  const ParallelType type,
1012  const MatrixBuildType mat_build_type)
1013 {
1014  parallel_object_only();
1015 
1016  libmesh_assert(this->comm().verify(std::string(mat_name)));
1017  libmesh_assert(this->comm().verify(int(type)));
1018  libmesh_assert(this->comm().verify(int(mat_build_type)));
1019 
1020  // Return the matrix if it is already there.
1021  if (auto it = this->_matrices.find(mat_name);
1022  it != this->_matrices.end())
1023  return *it->second;
1024 
1025  // Otherwise build the matrix to return.
1026  std::unique_ptr<SparseMatrix<Number>> matrix;
1027  if (this->has_static_condensation())
1028  {
1029  if (mat_build_type == MatrixBuildType::DIAGONAL)
1030  libmesh_error_msg(
1031  "We do not currently support static condensation of the diagonal matrix type");
1032  matrix = std::make_unique<StaticCondensation>(this->get_mesh(),
1033  *this,
1034  this->get_dof_map(),
1036  }
1037  else
1039  auto & mat = *matrix;
1040 
1041  _matrices.emplace(mat_name, std::move(matrix));
1042 
1043  _matrix_types.emplace(mat_name, type);
1044 
1045  // Initialize it first if we've already initialized the others.
1046  this->late_matrix_init(mat, type);
1047 
1048  return mat;
1049 }
1050 
1051 
1052 
1053 SparseMatrix<Number> & System::add_matrix (std::string_view mat_name,
1054  std::unique_ptr<SparseMatrix<Number>> matrix,
1055  const ParallelType type)
1056 {
1057  parallel_object_only();
1058 
1059  libmesh_assert(this->comm().verify(std::string(mat_name)));
1060  libmesh_assert(this->comm().verify(int(type)));
1061 
1062  auto [it, inserted] = _matrices.emplace(mat_name, std::move(matrix));
1063  libmesh_error_msg_if(!inserted,
1064  "Tried to add '" << mat_name << "' but the matrix already exists");
1065 
1066  _matrix_types.emplace(mat_name, type);
1067 
1068  SparseMatrix<Number> & mat = *(it->second);
1069 
1070  // Initialize it first if we've already initialized the others.
1071  this->late_matrix_init(mat, type);
1072 
1073  return mat;
1074 }
1075 
1077  ParallelType type)
1078 {
1080  {
1081  this->get_dof_map().attach_matrix(mat);
1082  mat.init(type);
1083  }
1084 }
1085 
1086 
1087 
1088 
1089 void System::remove_matrix (std::string_view mat_name)
1090 {
1091  parallel_object_only(); // Not strictly needed, but the only safe way to keep in sync
1092 
1093  if (const auto pos = _matrices.find(mat_name);
1094  pos != _matrices.end())
1095  _matrices.erase(pos); // erase()'d entries are destroyed
1096 }
1097 
1098 
1099 
1100 const SparseMatrix<Number> * System::request_matrix (std::string_view mat_name) const
1101 {
1102  if (const auto pos = _matrices.find(mat_name);
1103  pos != _matrices.end())
1104  return pos->second.get();
1105 
1106  // Otherwise, mat_name does not exist
1107  return nullptr;
1108 }
1109 
1110 
1111 
1112 SparseMatrix<Number> * System::request_matrix (std::string_view mat_name)
1113 {
1114  if (auto pos = _matrices.find(mat_name);
1115  pos != _matrices.end())
1116  return pos->second.get();
1117 
1118  // Otherwise, mat_name does not exist
1119  return nullptr;
1120 }
1121 
1122 
1123 
1124 const SparseMatrix<Number> & System::get_matrix (std::string_view mat_name) const
1125 {
1126  return *libmesh_map_find(_matrices, mat_name);
1127 }
1128 
1129 
1130 
1131 SparseMatrix<Number> & System::get_matrix (std::string_view mat_name)
1132 {
1133  return *libmesh_map_find(_matrices, mat_name);
1134 }
1135 
1136 
1137 
1138 void System::set_vector_preservation (const std::string & vec_name,
1139  bool preserve)
1140 {
1141  parallel_object_only(); // Not strictly needed, but the only safe way to keep in sync
1142 
1143  _vector_projections[vec_name] = preserve;
1144 }
1145 
1146 
1147 
1148 bool System::vector_preservation (std::string_view vec_name) const
1149 {
1150  if (auto it = _vector_projections.find(vec_name);
1151  it != _vector_projections.end())
1152  return it->second;
1153 
1154  // vec_name was not in the map, return false
1155  return false;
1156 }
1157 
1158 
1159 
1160 void System::set_vector_as_adjoint (const std::string & vec_name,
1161  int qoi_num)
1162 {
1163  parallel_object_only(); // Not strictly needed, but the only safe way to keep in sync
1164 
1165  // We reserve -1 for vectors which get primal constraints, -2 for
1166  // vectors which get no constraints
1167  libmesh_assert_greater_equal(qoi_num, -2);
1168  _vector_is_adjoint[vec_name] = qoi_num;
1169 }
1170 
1171 
1172 
1173 int System::vector_is_adjoint (std::string_view vec_name) const
1174 {
1175  const auto it = _vector_is_adjoint.find(vec_name);
1176  libmesh_assert(it != _vector_is_adjoint.end());
1177  return it->second;
1178 }
1179 
1180 
1181 
1183 {
1184  std::ostringstream sensitivity_name;
1185  sensitivity_name << "sensitivity_solution" << i;
1186 
1187  return this->add_vector(sensitivity_name.str());
1188 }
1189 
1190 
1191 
1193 {
1194  std::ostringstream sensitivity_name;
1195  sensitivity_name << "sensitivity_solution" << i;
1196 
1197  return this->get_vector(sensitivity_name.str());
1198 }
1199 
1200 
1201 
1203 {
1204  std::ostringstream sensitivity_name;
1205  sensitivity_name << "sensitivity_solution" << i;
1206 
1207  return this->get_vector(sensitivity_name.str());
1208 }
1209 
1210 
1211 
1213 {
1214  return this->add_vector("weighted_sensitivity_solution");
1215 }
1216 
1217 
1218 
1220 {
1221  return this->get_vector("weighted_sensitivity_solution");
1222 }
1223 
1224 
1225 
1227 {
1228  return this->get_vector("weighted_sensitivity_solution");
1229 }
1230 
1231 
1232 
1234 {
1235  std::ostringstream adjoint_name;
1236  adjoint_name << "adjoint_solution" << i;
1237 
1238  NumericVector<Number> & returnval = this->add_vector(adjoint_name.str());
1239  this->set_vector_as_adjoint(adjoint_name.str(), i);
1240  return returnval;
1241 }
1242 
1243 
1244 
1246 {
1247  std::ostringstream adjoint_name;
1248  adjoint_name << "adjoint_solution" << i;
1249 
1250  return this->get_vector(adjoint_name.str());
1251 }
1252 
1253 
1254 
1256 {
1257  std::ostringstream adjoint_name;
1258  adjoint_name << "adjoint_solution" << i;
1259 
1260  return this->get_vector(adjoint_name.str());
1261 }
1262 
1263 
1264 
1266 {
1267  std::ostringstream adjoint_name;
1268  adjoint_name << "weighted_sensitivity_adjoint_solution" << i;
1269 
1270  NumericVector<Number> & returnval = this->add_vector(adjoint_name.str());
1271  this->set_vector_as_adjoint(adjoint_name.str(), i);
1272  return returnval;
1273 }
1274 
1275 
1276 
1278 {
1279  std::ostringstream adjoint_name;
1280  adjoint_name << "weighted_sensitivity_adjoint_solution" << i;
1281 
1282  return this->get_vector(adjoint_name.str());
1283 }
1284 
1285 
1286 
1288 {
1289  std::ostringstream adjoint_name;
1290  adjoint_name << "weighted_sensitivity_adjoint_solution" << i;
1291 
1292  return this->get_vector(adjoint_name.str());
1293 }
1294 
1295 
1296 
1298 {
1299  std::ostringstream adjoint_rhs_name;
1300  adjoint_rhs_name << "adjoint_rhs" << i;
1301 
1302  return this->add_vector(adjoint_rhs_name.str(), false);
1303 }
1304 
1305 
1306 
1308 {
1309  std::ostringstream adjoint_rhs_name;
1310  adjoint_rhs_name << "adjoint_rhs" << i;
1311 
1312  return this->get_vector(adjoint_rhs_name.str());
1313 }
1314 
1315 
1316 
1317 const NumericVector<Number> & System::get_adjoint_rhs (unsigned int i) const
1318 {
1319  std::ostringstream adjoint_rhs_name;
1320  adjoint_rhs_name << "adjoint_rhs" << i;
1321 
1322  return this->get_vector(adjoint_rhs_name.str());
1323 }
1324 
1325 
1326 
1328 {
1329  std::ostringstream sensitivity_rhs_name;
1330  sensitivity_rhs_name << "sensitivity_rhs" << i;
1331 
1332  return this->add_vector(sensitivity_rhs_name.str(), false);
1333 }
1334 
1335 
1336 
1338 {
1339  std::ostringstream sensitivity_rhs_name;
1340  sensitivity_rhs_name << "sensitivity_rhs" << i;
1341 
1342  return this->get_vector(sensitivity_rhs_name.str());
1343 }
1344 
1345 
1346 
1348 {
1349  std::ostringstream sensitivity_rhs_name;
1350  sensitivity_rhs_name << "sensitivity_rhs" << i;
1351 
1352  return this->get_vector(sensitivity_rhs_name.str());
1353 }
1354 
1355 
1356 
1357 unsigned int System::add_variable (std::string_view var,
1358  const FEType & type,
1359  const std::set<subdomain_id_type> * const active_subdomains)
1360 {
1361  parallel_object_only(); // Not strictly needed, but the only safe way to keep in sync
1362 
1363  libmesh_assert(this->comm().verify(std::string(var)));
1364  libmesh_assert(this->comm().verify(type));
1365  libmesh_assert(this->comm().verify((active_subdomains == nullptr)));
1366 
1367  if (active_subdomains)
1368  libmesh_assert(this->comm().verify(active_subdomains->size()));
1369 
1370  // Make sure the variable isn't there already
1371  // or if it is, that it's the type we want
1372  for (auto v : make_range(this->n_vars()))
1373  if (this->variable_name(v) == var)
1374  {
1375  if (this->variable_type(v) == type)
1376  {
1377  // Check whether the existing variable's active subdomains also matches
1378  // the incoming variable's active subdomains. If they don't match, then
1379  // either it is an error by the user or the user is trying to change the
1380  // subdomain restriction after the variable has already been added, which
1381  // is not supported.
1382  const Variable & existing_var = this->variable(v);
1383 
1384  // Check whether active_subdomains is not provided/empty and the existing_var is implicitly_active()
1385  bool check1 = (!active_subdomains || active_subdomains->empty()) && existing_var.implicitly_active();
1386 
1387  // Check if the provided active_subdomains is equal to the existing_var's active_subdomains
1388  bool check2 = (active_subdomains && (*active_subdomains == existing_var.active_subdomains()));
1389 
1390  // If either of these checks passed, then we already have this variable
1391  if (check1 || check2)
1392  return _variables[v].number();
1393  }
1394 
1395  libmesh_error_msg("ERROR: incompatible variable " << var << " has already been added for this system!");
1396  }
1397 
1398  libmesh_assert(!this->is_initialized());
1399 
1400  if (this->n_variable_groups())
1401  {
1402  // Optimize for VariableGroups here - if the user is adding multiple
1403  // variables of the same FEType and subdomain restriction, catch
1404  // that here and add them as members of the same VariableGroup.
1405  //
1406  // start by setting this flag to whatever the user has requested
1407  // and then consider the conditions which should negate it.
1408  bool should_be_in_vg = this->identify_variable_groups();
1409 
1410  VariableGroup & vg(_variable_groups.back());
1411 
1412  // get a pointer to their subdomain restriction, if any.
1413  const std::set<subdomain_id_type> * const
1414  their_active_subdomains (vg.implicitly_active() ?
1415  nullptr : &vg.active_subdomains());
1416 
1417  // Different types?
1418  if (vg.type() != type)
1419  should_be_in_vg = false;
1420 
1421  // they are restricted, we aren't?
1422  if (their_active_subdomains &&
1423  (!active_subdomains || (active_subdomains && active_subdomains->empty())))
1424  should_be_in_vg = false;
1425 
1426  // they aren't restricted, we are?
1427  if (!their_active_subdomains && (active_subdomains && !active_subdomains->empty()))
1428  should_be_in_vg = false;
1429 
1430  if (their_active_subdomains && active_subdomains)
1431  // restricted to different sets?
1432  if (*their_active_subdomains != *active_subdomains)
1433  should_be_in_vg = false;
1434 
1435  // OK, after all that, append the variable to the vg if none of the conditions
1436  // were violated
1437  if (should_be_in_vg)
1438  {
1439  const unsigned int curr_n_vars = this->n_vars();
1440 
1441  std::string varstr(var);
1442 
1443  _variable_numbers[varstr] = curr_n_vars;
1444  vg.append (std::move(varstr));
1445  _variables.push_back(vg(vg.n_variables()-1));
1446 
1447  return curr_n_vars;
1448  }
1449  }
1450 
1451  // otherwise, fall back to adding a single variable group
1452  return this->add_variables (std::vector<std::string>(1, std::string(var)),
1453  type,
1454  active_subdomains);
1455 }
1456 
1457 
1458 
1459 unsigned int System::add_variable (std::string_view var,
1460  const Order order,
1461  const FEFamily family,
1462  const std::set<subdomain_id_type> * const active_subdomains)
1463 {
1464  return this->add_variable(var,
1465  FEType(order, family),
1466  active_subdomains);
1467 }
1468 
1469 
1470 
1471 unsigned int System::add_variables (const std::vector<std::string> & vars,
1472  const FEType & type,
1473  const std::set<subdomain_id_type> * const active_subdomains)
1474 {
1475  parallel_object_only(); // Not strictly needed, but the only safe way to keep in sync
1476 
1477  libmesh_assert(!this->is_initialized());
1478 
1479  libmesh_assert(this->comm().verify(vars.size()));
1480  libmesh_assert(this->comm().verify(type));
1481  libmesh_assert(this->comm().verify((active_subdomains == nullptr)));
1482 
1483  if (active_subdomains)
1484  libmesh_assert(this->comm().verify(active_subdomains->size()));
1485 
1486  // Make sure the variable isn't there already
1487  // or if it is, that it's the type we want
1488  for (auto ovar : vars)
1489  {
1490  libmesh_assert(this->comm().verify(ovar));
1491 
1492  for (auto v : make_range(this->n_vars()))
1493  if (this->variable_name(v) == ovar)
1494  {
1495  if (this->variable_type(v) == type)
1496  return _variables[v].number();
1497 
1498  libmesh_error_msg("ERROR: incompatible variable " << ovar << " has already been added for this system!");
1499  }
1500  }
1501 
1502  if (this->n_variable_groups())
1503  {
1504  // Optimize for VariableGroups here - if the user is adding multiple
1505  // variables of the same FEType and subdomain restriction, catch
1506  // that here and add them as members of the same VariableGroup.
1507  //
1508  // start by setting this flag to whatever the user has requested
1509  // and then consider the conditions which should negate it.
1510  bool should_be_in_vg = this->identify_variable_groups();
1511 
1512  VariableGroup & vg(_variable_groups.back());
1513 
1514  // get a pointer to their subdomain restriction, if any.
1515  const std::set<subdomain_id_type> * const
1516  their_active_subdomains (vg.implicitly_active() ?
1517  nullptr : &vg.active_subdomains());
1518 
1519  // Different types?
1520  if (vg.type() != type)
1521  should_be_in_vg = false;
1522 
1523  // they are restricted, we aren't?
1524  if (their_active_subdomains &&
1525  (!active_subdomains || (active_subdomains && active_subdomains->empty())))
1526  should_be_in_vg = false;
1527 
1528  // they aren't restricted, we are?
1529  if (!their_active_subdomains && (active_subdomains && !active_subdomains->empty()))
1530  should_be_in_vg = false;
1531 
1532  if (their_active_subdomains && active_subdomains)
1533  // restricted to different sets?
1534  if (*their_active_subdomains != *active_subdomains)
1535  should_be_in_vg = false;
1536 
1537  // If after all that none of the conditions were violated,
1538  // append the variables to the vg and we're done
1539  if (should_be_in_vg)
1540  {
1541  unsigned int curr_n_vars = this->n_vars();
1542 
1543  for (auto ovar : vars)
1544  {
1545  curr_n_vars = this->n_vars();
1546 
1547  vg.append (ovar);
1548 
1549  _variables.push_back(vg(vg.n_variables()-1));
1550  _variable_numbers[ovar] = curr_n_vars;
1551  }
1552  return curr_n_vars;
1553  }
1554  }
1555 
1556  const unsigned int curr_n_vars = this->n_vars();
1557 
1558  const unsigned int next_first_component = this->n_components();
1559 
1560  // We weren't able to add to an existing variable group, so
1561  // add a new variable group to the list
1562  _variable_groups.push_back((active_subdomains == nullptr) ?
1563  VariableGroup(this, vars, curr_n_vars,
1564  next_first_component, type) :
1565  VariableGroup(this, vars, curr_n_vars,
1566  next_first_component, type, *active_subdomains));
1567 
1568  const VariableGroup & vg (_variable_groups.back());
1569 
1570  // Add each component of the group individually
1571  for (auto v : make_range(vars.size()))
1572  {
1573  _variables.push_back (vg(v));
1574  _variable_numbers[vars[v]] = curr_n_vars+v;
1575  }
1576 
1577  libmesh_assert_equal_to ((curr_n_vars+vars.size()), this->n_vars());
1578 
1579  // BSK - Defer this now to System::init_data() so we can detect
1580  // VariableGroups 12/28/2012
1581  // // Add the variable group to the _dof_map
1582  // _dof_map->add_variable_group (vg);
1583 
1584  // Return the number of the new variable
1585  return cast_int<unsigned int>(curr_n_vars+vars.size()-1);
1586 }
1587 
1588 
1589 
1590 unsigned int System::add_variables (const std::vector<std::string> & vars,
1591  const Order order,
1592  const FEFamily family,
1593  const std::set<subdomain_id_type> * const active_subdomains)
1594 {
1595  return this->add_variables(vars,
1596  FEType(order, family),
1597  active_subdomains);
1598 }
1599 
1600 
1601 
1602 bool System::has_variable (std::string_view var) const
1603 {
1604  return _variable_numbers.count(var);
1605 }
1606 
1607 
1608 
1609 unsigned int System::variable_number (std::string_view var) const
1610 {
1611  auto var_num = libmesh_map_find(_variable_numbers, var);
1612  libmesh_assert_equal_to (_variables[var_num].name(), var);
1613  return var_num;
1614 }
1615 
1616 
1617 void System::get_all_variable_numbers(std::vector<unsigned int> & all_variable_numbers) const
1618 {
1619  all_variable_numbers.resize(n_vars());
1620 
1621  unsigned int count = 0;
1622  for (auto vn : _variable_numbers)
1623  all_variable_numbers[count++] = vn.second;
1624 }
1625 
1626 
1627 void System::local_dof_indices(const unsigned int var,
1628  std::set<dof_id_type> & var_indices) const
1629 {
1630  // Make sure the set is clear
1631  var_indices.clear();
1632 
1633  std::vector<dof_id_type> dof_indices;
1634 
1635  const dof_id_type
1636  first_local = this->get_dof_map().first_dof(),
1637  end_local = this->get_dof_map().end_dof();
1638 
1639  // Begin the loop over the elements
1640  for (const auto & elem : this->get_mesh().active_local_element_ptr_range())
1641  {
1642  this->get_dof_map().dof_indices (elem, dof_indices, var);
1643 
1644  for (dof_id_type dof : dof_indices)
1645  //If the dof is owned by the local processor
1646  if (first_local <= dof && dof < end_local)
1647  var_indices.insert(dof);
1648  }
1649 
1650  // we may have missed assigning DOFs to nodes that we own
1651  // but to which we have no connected elements matching our
1652  // variable restriction criterion. this will happen, for example,
1653  // if variable V is restricted to subdomain S. We may not own
1654  // any elements which live in S, but we may own nodes which are
1655  // *connected* to elements which do.
1656  for (const auto & node : this->get_mesh().local_node_ptr_range())
1657  {
1658  libmesh_assert(node);
1659  this->get_dof_map().dof_indices (node, dof_indices, var);
1660  for (auto dof : dof_indices)
1661  if (first_local <= dof && dof < end_local)
1662  var_indices.insert(dof);
1663  }
1664 }
1665 
1666 
1667 
1669  unsigned int var_num) const
1670 {
1671  /* Make sure the call makes sense. */
1672  libmesh_assert_less (var_num, this->n_vars());
1673 
1674  /* Get a reference to the mesh. */
1675  const MeshBase & mesh = this->get_mesh();
1676 
1677  /* Check which system we are. */
1678  const unsigned int sys_num = this->number();
1679 
1680  // Loop over nodes.
1681  for (const auto & node : mesh.local_node_ptr_range())
1682  {
1683  unsigned int n_comp = node->n_comp(sys_num,var_num);
1684  for (unsigned int i=0; i<n_comp; i++)
1685  {
1686  const dof_id_type index = node->dof_number(sys_num,var_num,i);
1687  v.set(index,0.0);
1688  }
1689  }
1690 
1691  // Loop over elements.
1692  for (const auto & elem : mesh.active_local_element_ptr_range())
1693  {
1694  unsigned int n_comp = elem->n_comp(sys_num,var_num);
1695  for (unsigned int i=0; i<n_comp; i++)
1696  {
1697  const dof_id_type index = elem->dof_number(sys_num,var_num,i);
1698  v.set(index,0.0);
1699  }
1700  }
1701 }
1702 
1703 
1704 
1706  unsigned int var,
1707  FEMNormType norm_type) const
1708 {
1709  std::set<dof_id_type> var_indices;
1710  local_dof_indices(var, var_indices);
1711 
1712  if (norm_type == DISCRETE_L1)
1713  return v.subset_l1_norm(var_indices);
1714  if (norm_type == DISCRETE_L2)
1715  return v.subset_l2_norm(var_indices);
1716  if (norm_type == DISCRETE_L_INF)
1717  return v.subset_linfty_norm(var_indices);
1718  else
1719  libmesh_error_msg("Invalid norm_type = " << Utility::enum_to_string(norm_type));
1720 }
1721 
1722 
1723 
1725  unsigned int var,
1726  FEMNormType norm_type,
1727  std::set<unsigned int> * skip_dimensions) const
1728 {
1729  //short circuit to save time
1730  if (norm_type == DISCRETE_L1 ||
1731  norm_type == DISCRETE_L2 ||
1732  norm_type == DISCRETE_L_INF)
1733  return discrete_var_norm(v,var,norm_type);
1734 
1735  // Not a discrete norm
1736  std::vector<FEMNormType> norms(this->n_vars(), L2);
1737  std::vector<Real> weights(this->n_vars(), 0.0);
1738  norms[var] = norm_type;
1739  weights[var] = 1.0;
1740  Real val = this->calculate_norm(v, SystemNorm(norms, weights), skip_dimensions);
1741  return val;
1742 }
1743 
1744 
1745 
1747  const SystemNorm & norm,
1748  std::set<unsigned int> * skip_dimensions) const
1749 {
1750  // This function must be run on all processors at once
1751  parallel_object_only();
1752 
1753  LOG_SCOPE ("calculate_norm()", "System");
1754 
1755  // Zero the norm before summation
1756  Real v_norm = 0.;
1757 
1758  if (norm.is_discrete())
1759  {
1760  //Check to see if all weights are 1.0 and all types are equal
1761  FEMNormType norm_type0 = norm.type(0);
1762  unsigned int check_var = 0, check_end = this->n_vars();
1763  for (; check_var != check_end; ++check_var)
1764  if ((norm.weight(check_var) != 1.0) || (norm.type(check_var) != norm_type0))
1765  break;
1766 
1767  //All weights were 1.0 so just do the full vector discrete norm
1768  if (check_var == this->n_vars())
1769  {
1770  if (norm_type0 == DISCRETE_L1)
1771  return v.l1_norm();
1772  if (norm_type0 == DISCRETE_L2)
1773  return v.l2_norm();
1774  if (norm_type0 == DISCRETE_L_INF)
1775  return v.linfty_norm();
1776  else
1777  libmesh_error_msg("Invalid norm_type0 = " << Utility::enum_to_string(norm_type0));
1778  }
1779 
1780  for (auto var : make_range(this->n_vars()))
1781  {
1782  // Skip any variables we don't need to integrate
1783  if (norm.weight(var) == 0.0)
1784  continue;
1785 
1786  v_norm += norm.weight(var) * discrete_var_norm(v, var, norm.type(var));
1787  }
1788 
1789  return v_norm;
1790  }
1791 
1792  // Localize the potentially parallel vector
1793  std::unique_ptr<NumericVector<Number>> local_v = NumericVector<Number>::build(this->comm());
1794  local_v->init(v.size(), v.local_size(), _dof_map->get_send_list(),
1795  true, GHOSTED);
1796  v.localize (*local_v, _dof_map->get_send_list());
1797 
1798  // I'm not sure how best to mix Hilbert norms on some variables (for
1799  // which we'll want to square then sum then square root) with norms
1800  // like L_inf (for which we'll just want to take an absolute value
1801  // and then sum).
1802  bool using_hilbert_norm = true,
1803  using_nonhilbert_norm = true;
1804 
1805  // Loop over all variables
1806  for (auto var : make_range(this->n_vars()))
1807  {
1808  // Skip any variables we don't need to integrate
1809  Real norm_weight_sq = norm.weight_sq(var);
1810  if (norm_weight_sq == 0.0)
1811  continue;
1812  Real norm_weight = norm.weight(var);
1813 
1814  // Check for unimplemented norms (rather than just returning 0).
1815  FEMNormType norm_type = norm.type(var);
1816  if ((norm_type==H1) ||
1817  (norm_type==H2) ||
1818  (norm_type==L2) ||
1819  (norm_type==H1_SEMINORM) ||
1820  (norm_type==H2_SEMINORM))
1821  {
1822  if (!using_hilbert_norm)
1823  libmesh_not_implemented();
1824  using_nonhilbert_norm = false;
1825  }
1826  else if ((norm_type==L1) ||
1827  (norm_type==L_INF) ||
1828  (norm_type==W1_INF_SEMINORM) ||
1829  (norm_type==W2_INF_SEMINORM))
1830  {
1831  if (!using_nonhilbert_norm)
1832  libmesh_not_implemented();
1833  using_hilbert_norm = false;
1834  }
1835  else
1836  libmesh_not_implemented();
1837 
1838  const FEType & fe_type = this->get_dof_map().variable_type(var);
1839 
1840  // Allow space for dims 0-3, and for both scalar and vector
1841  // elements, even if we don't use them all
1842  std::vector<std::unique_ptr<FEBase>> fe_ptrs(4);
1843  std::vector<std::unique_ptr<FEVectorBase>> vec_fe_ptrs(4);
1844  std::vector<std::unique_ptr<QBase>> q_rules(4);
1845 
1846  const std::set<unsigned char> & elem_dims = _mesh.elem_dimensions();
1847 
1848  // Prepare finite elements for each dimension present in the mesh
1849  for (const auto & dim : elem_dims)
1850  {
1851  if (skip_dimensions && skip_dimensions->find(dim) != skip_dimensions->end())
1852  continue;
1853 
1854  // Construct quadrature and finite element objects
1855  q_rules[dim] = fe_type.default_quadrature_rule (dim);
1856 
1857  const FEFieldType field_type = FEInterface::field_type(fe_type);
1858  if (field_type == TYPE_SCALAR)
1859  {
1860  fe_ptrs[dim] = FEBase::build(dim, fe_type);
1861  fe_ptrs[dim]->attach_quadrature_rule (q_rules[dim].get());
1862  }
1863  else
1864  {
1865  vec_fe_ptrs[dim] = FEVectorBase::build(dim, fe_type);
1866  vec_fe_ptrs[dim]->attach_quadrature_rule (q_rules[dim].get());
1867  libmesh_assert_equal_to(field_type, TYPE_VECTOR);
1868  }
1869 
1870  }
1871 
1872  std::vector<dof_id_type> dof_indices;
1873 
1874  // Begin the loop over the elements
1875  for (const auto & elem : this->get_mesh().active_local_element_ptr_range())
1876  {
1877  const unsigned int dim = elem->dim();
1878 
1879  // One way for implementing this would be to exchange the fe with the FEInterface- class.
1880  // However, it needs to be discussed whether integral-norms make sense for infinite elements.
1881  // or in which sense they could make sense.
1882  if (elem->infinite() )
1883  libmesh_not_implemented();
1884 
1885  if (skip_dimensions && skip_dimensions->find(dim) != skip_dimensions->end())
1886  continue;
1887 
1888  QBase * qrule = q_rules[dim].get();
1889  libmesh_assert(qrule);
1890 
1891  this->get_dof_map().dof_indices (elem, dof_indices, var);
1892 
1893  auto element_calculation = [&dof_indices, &elem,
1894  norm_type, norm_weight, norm_weight_sq, &qrule,
1895  &local_v, &v_norm](auto & fe) {
1896  typedef typename std::remove_reference<decltype(fe)>::type::OutputShape OutputShape;
1897  typedef typename TensorTools::MakeNumber<OutputShape>::type OutputNumberShape;
1898  typedef typename std::remove_reference<decltype(fe)>::type::OutputGradient OutputGradient;
1899  typedef typename TensorTools::MakeNumber<OutputGradient>::type OutputNumberGradient;
1900 
1901  const std::vector<Real> & JxW = fe.get_JxW();
1902  const std::vector<std::vector<OutputShape>> * phi = nullptr;
1903  if (norm_type == H1 ||
1904  norm_type == H2 ||
1905  norm_type == L2 ||
1906  norm_type == L1 ||
1907  norm_type == L_INF)
1908  phi = &(fe.get_phi());
1909 
1910  const std::vector<std::vector<OutputGradient>> * dphi = nullptr;
1911  if (norm_type == H1 ||
1912  norm_type == H2 ||
1913  norm_type == H1_SEMINORM ||
1914  norm_type == W1_INF_SEMINORM)
1915  dphi = &(fe.get_dphi());
1916 
1917 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1918  typedef typename std::remove_reference<decltype(fe)>::type::OutputTensor OutputTensor;
1919 
1920  const std::vector<std::vector<OutputTensor>> * d2phi = nullptr;
1921  if (norm_type == H2 ||
1922  norm_type == H2_SEMINORM ||
1923  norm_type == W2_INF_SEMINORM)
1924  d2phi = &(fe.get_d2phi());
1925 #endif
1926 
1927  fe.reinit (elem);
1928 
1929  const unsigned int n_qp = qrule->n_points();
1930 
1931  const unsigned int n_sf = cast_int<unsigned int>
1932  (dof_indices.size());
1933 
1934  // Begin the loop over the Quadrature points.
1935  for (unsigned int qp=0; qp<n_qp; qp++)
1936  {
1937  if (norm_type == L1)
1938  {
1939  OutputNumberShape u_h = 0.;
1940  for (unsigned int i=0; i != n_sf; ++i)
1941  u_h += (*phi)[i][qp] * (*local_v)(dof_indices[i]);
1942  v_norm += norm_weight *
1943  JxW[qp] * TensorTools::norm(u_h);
1944  }
1945 
1946  if (norm_type == L_INF)
1947  {
1948  OutputNumberShape u_h = 0.;
1949  for (unsigned int i=0; i != n_sf; ++i)
1950  u_h += (*phi)[i][qp] * (*local_v)(dof_indices[i]);
1951  v_norm = std::max(v_norm, norm_weight * TensorTools::norm(u_h));
1952  }
1953 
1954  if (norm_type == H1 ||
1955  norm_type == H2 ||
1956  norm_type == L2)
1957  {
1958  OutputNumberShape u_h = 0.;
1959  for (unsigned int i=0; i != n_sf; ++i)
1960  u_h += (*phi)[i][qp] * (*local_v)(dof_indices[i]);
1961  v_norm += norm_weight_sq *
1962  JxW[qp] * TensorTools::norm_sq(u_h);
1963  }
1964 
1965  if (norm_type == H1 ||
1966  norm_type == H2 ||
1967  norm_type == H1_SEMINORM)
1968  {
1969  OutputNumberGradient grad_u_h;
1970  for (unsigned int i=0; i != n_sf; ++i)
1971  grad_u_h.add_scaled((*dphi)[i][qp], (*local_v)(dof_indices[i]));
1972  v_norm += norm_weight_sq *
1973  JxW[qp] * grad_u_h.norm_sq();
1974  }
1975 
1976  if (norm_type == W1_INF_SEMINORM)
1977  {
1978  OutputNumberGradient grad_u_h;
1979  for (unsigned int i=0; i != n_sf; ++i)
1980  grad_u_h.add_scaled((*dphi)[i][qp], (*local_v)(dof_indices[i]));
1981  v_norm = std::max(v_norm, norm_weight * grad_u_h.norm());
1982  }
1983 
1984 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1985  typedef typename TensorTools::MakeNumber<OutputTensor>::type OutputNumberTensor;
1986 
1987  if (norm_type == H2 ||
1988  norm_type == H2_SEMINORM)
1989  {
1990  OutputNumberTensor hess_u_h;
1991  for (unsigned int i=0; i != n_sf; ++i)
1992  hess_u_h.add_scaled((*d2phi)[i][qp], (*local_v)(dof_indices[i]));
1993  v_norm += norm_weight_sq *
1994  JxW[qp] * hess_u_h.norm_sq();
1995  }
1996 
1997  if (norm_type == W2_INF_SEMINORM)
1998  {
1999  OutputNumberTensor hess_u_h;
2000  for (unsigned int i=0; i != n_sf; ++i)
2001  hess_u_h.add_scaled((*d2phi)[i][qp], (*local_v)(dof_indices[i]));
2002  v_norm = std::max(v_norm, norm_weight * hess_u_h.norm());
2003  }
2004 #endif
2005  }
2006  };
2007 
2008  FEBase * scalar_fe = fe_ptrs[dim].get();
2009  FEVectorBase * vec_fe = vec_fe_ptrs[dim].get();
2010 
2011  if (scalar_fe)
2012  {
2013  libmesh_assert(!vec_fe);
2014  element_calculation(*scalar_fe);
2015  }
2016 
2017  if (vec_fe)
2018  {
2019  libmesh_assert(!scalar_fe);
2020  element_calculation(*vec_fe);
2021  }
2022  }
2023  }
2024 
2025  if (using_hilbert_norm)
2026  {
2027  this->comm().sum(v_norm);
2028  v_norm = std::sqrt(v_norm);
2029  }
2030  else
2031  {
2032  this->comm().max(v_norm);
2033  }
2034 
2035  return v_norm;
2036 }
2037 
2038 
2039 
2040 std::string System::get_info() const
2041 {
2042  std::ostringstream oss;
2043 
2044 
2045  const std::string & sys_name = this->name();
2046 
2047  oss << " System #" << this->number() << ", \"" << sys_name << "\"\n"
2048  << " Type \"" << this->system_type() << "\"\n"
2049  << " Variables=";
2050 
2051  for (auto vg : make_range(this->n_variable_groups()))
2052  {
2053  const VariableGroup & vg_description (this->variable_group(vg));
2054 
2055  if (vg_description.n_variables() > 1) oss << "{ ";
2056  for (auto vn : make_range(vg_description.n_variables()))
2057  oss << "\"" << vg_description.name(vn) << "\" ";
2058  if (vg_description.n_variables() > 1) oss << "} ";
2059  }
2060 
2061  oss << '\n';
2062 
2063  oss << " Finite Element Types=";
2064 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
2065  for (auto vg : make_range(this->n_variable_groups()))
2066  oss << "\""
2067  << Utility::enum_to_string<FEFamily>(this->get_dof_map().variable_group(vg).type().family)
2068  << "\" ";
2069 #else
2070  for (auto vg : make_range(this->n_variable_groups()))
2071  {
2072  oss << "\""
2073  << Utility::enum_to_string<FEFamily>(this->get_dof_map().variable_group(vg).type().family)
2074  << "\", \""
2075  << Utility::enum_to_string<FEFamily>(this->get_dof_map().variable_group(vg).type().radial_family)
2076  << "\" ";
2077  }
2078 
2079  oss << '\n' << " Infinite Element Mapping=";
2080  for (auto vg : make_range(this->n_variable_groups()))
2081  oss << "\""
2082  << Utility::enum_to_string<InfMapType>(this->get_dof_map().variable_group(vg).type().inf_map)
2083  << "\" ";
2084 #endif
2085 
2086  oss << '\n';
2087 
2088  oss << " Approximation Orders=";
2089  for (auto vg : make_range(this->n_variable_groups()))
2090  {
2091 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
2092  oss << "\""
2093  << Utility::enum_to_string<Order>(this->get_dof_map().variable_group(vg).type().order)
2094  << "\" ";
2095 #else
2096  oss << "\""
2097  << Utility::enum_to_string<Order>(this->get_dof_map().variable_group(vg).type().order)
2098  << "\", \""
2099  << Utility::enum_to_string<Order>(this->get_dof_map().variable_group(vg).type().radial_order)
2100  << "\" ";
2101 #endif
2102  }
2103 
2104  oss << '\n';
2105 
2106  oss << " n_dofs()=" << this->n_dofs() << '\n';
2107  dof_id_type local_dofs = this->n_local_dofs();
2108  oss << " n_local_dofs()=" << local_dofs << '\n';
2109  this->comm().max(local_dofs);
2110  oss << " max(n_local_dofs())=" << local_dofs << '\n';
2111 #ifdef LIBMESH_ENABLE_CONSTRAINTS
2112  oss << " n_constrained_dofs()=" << this->n_constrained_dofs() << '\n';
2113  oss << " n_local_constrained_dofs()=" << this->n_local_constrained_dofs() << '\n';
2114  dof_id_type local_unconstrained_dofs = this->n_local_dofs() - this->n_local_constrained_dofs();
2115  this->comm().max(local_unconstrained_dofs);
2116  oss << " max(local unconstrained dofs)=" << local_unconstrained_dofs << '\n';
2117 #endif
2118 
2119  oss << " " << "n_vectors()=" << this->n_vectors() << '\n';
2120  oss << " " << "n_matrices()=" << this->n_matrices() << '\n';
2121  // oss << " " << "n_additional_matrices()=" << this->n_additional_matrices() << '\n';
2122 
2123  oss << this->get_dof_map().get_info();
2124 
2125  return oss.str();
2126 }
2127 
2128 
2129 
2131  const std::string & name))
2132 {
2134 
2135  if (_init_system_object != nullptr)
2136  {
2137  libmesh_warning("WARNING: Cannot specify both initialization function and object!");
2138 
2139  _init_system_object = nullptr;
2140  }
2141 
2143 }
2144 
2145 
2146 
2148 {
2149  if (_init_system_function != nullptr)
2150  {
2151  libmesh_warning("WARNING: Cannot specify both initialization object and function!");
2152 
2153  _init_system_function = nullptr;
2154  }
2155 
2156  _init_system_object = &init_in;
2157 }
2158 
2159 
2160 
2162  const std::string & name))
2163 {
2165 
2166  if (_assemble_system_object != nullptr)
2167  {
2168  libmesh_warning("WARNING: Cannot specify both assembly function and object!");
2169 
2170  _assemble_system_object = nullptr;
2171  }
2172 
2174 }
2175 
2176 
2177 
2179 {
2180  if (_assemble_system_function != nullptr)
2181  {
2182  libmesh_warning("WARNING: Cannot specify both assembly object and function!");
2183 
2184  _assemble_system_function = nullptr;
2185  }
2186 
2187  _assemble_system_object = &assemble_in;
2188 }
2189 
2190 
2191 
2193  const std::string & name))
2194 {
2196 
2197  if (_constrain_system_object != nullptr)
2198  {
2199  libmesh_warning("WARNING: Cannot specify both constraint function and object!");
2200 
2201  _constrain_system_object = nullptr;
2202  }
2203 
2205 }
2206 
2207 
2208 
2210 {
2211  if (_constrain_system_function != nullptr)
2212  {
2213  libmesh_warning("WARNING: Cannot specify both constraint object and function!");
2214 
2215  _constrain_system_function = nullptr;
2216  }
2217 
2218  _constrain_system_object = &constrain;
2219 }
2220 
2222 {
2223  return _constrain_system_object != nullptr;
2224 }
2225 
2227 {
2228  libmesh_assert_msg(_constrain_system_object,"No constraint object available.");
2229  return *_constrain_system_object;
2230 }
2231 
2232 
2233 
2235  const std::string &,
2236  const QoISet &))
2237 {
2239 
2240  if (_qoi_evaluate_object != nullptr)
2241  {
2242  libmesh_warning("WARNING: Cannot specify both QOI function and object!");
2243 
2244  _qoi_evaluate_object = nullptr;
2245  }
2246 
2248 }
2249 
2250 
2251 
2253 {
2254  if (_qoi_evaluate_function != nullptr)
2255  {
2256  libmesh_warning("WARNING: Cannot specify both QOI object and function!");
2257 
2258  _qoi_evaluate_function = nullptr;
2259  }
2260 
2261  _qoi_evaluate_object = &qoi_in;
2262 }
2263 
2264 
2265 
2266 void System::attach_QOI_derivative(void fptr(EquationSystems &, const std::string &,
2267  const QoISet &, bool, bool))
2268 {
2270 
2271  if (_qoi_evaluate_derivative_object != nullptr)
2272  {
2273  libmesh_warning("WARNING: Cannot specify both QOI derivative function and object!");
2274 
2276  }
2277 
2279 }
2280 
2281 
2282 
2284 {
2285  if (_qoi_evaluate_derivative_function != nullptr)
2286  {
2287  libmesh_warning("WARNING: Cannot specify both QOI derivative object and function!");
2288 
2290  }
2291 
2292  _qoi_evaluate_derivative_object = &qoi_derivative;
2293 }
2294 
2295 
2296 
2298 {
2299  // Call the user-provided initialization function,
2300  // if it was provided
2301  if (_init_system_function != nullptr)
2302  this->_init_system_function (_equation_systems, this->name());
2303 
2304  // ...or the user-provided initialization object.
2305  else if (_init_system_object != nullptr)
2307 }
2308 
2309 
2310 
2312 {
2313  // Call the user-provided assembly function,
2314  // if it was provided
2315  if (_assemble_system_function != nullptr)
2317 
2318  // ...or the user-provided assembly object.
2319  else if (_assemble_system_object != nullptr)
2321 }
2322 
2323 
2324 
2326 {
2327  // Call the user-provided constraint function,
2328  // if it was provided
2329  if (_constrain_system_function!= nullptr)
2331 
2332  // ...or the user-provided constraint object.
2333  else if (_constrain_system_object != nullptr)
2335 }
2336 
2337 
2338 
2339 void System::user_QOI (const QoISet & qoi_indices)
2340 {
2341  // Call the user-provided quantity of interest function,
2342  // if it was provided
2343  if (_qoi_evaluate_function != nullptr)
2344  this->_qoi_evaluate_function(_equation_systems, this->name(), qoi_indices);
2345 
2346  // ...or the user-provided QOI function object.
2347  else if (_qoi_evaluate_object != nullptr)
2348  this->_qoi_evaluate_object->qoi(qoi_indices);
2349 }
2350 
2351 
2352 
2353 void System::user_QOI_derivative(const QoISet & qoi_indices,
2354  bool include_liftfunc,
2355  bool apply_constraints)
2356 {
2357  // Call the user-provided quantity of interest derivative,
2358  // if it was provided
2359  if (_qoi_evaluate_derivative_function != nullptr)
2361  (_equation_systems, this->name(), qoi_indices, include_liftfunc,
2362  apply_constraints);
2363 
2364  // ...or the user-provided QOI derivative function object.
2365  else if (_qoi_evaluate_derivative_object != nullptr)
2367  (qoi_indices, include_liftfunc, apply_constraints);
2368 }
2369 
2370 
2371 void System::init_qois(unsigned int n_qois)
2372 {
2373  qoi.resize(n_qois);
2374  qoi_error_estimates.resize(n_qois);
2375 }
2376 
2377 
2378 void System::set_qoi(unsigned int qoi_index, Number qoi_value)
2379 {
2380  libmesh_assert(qoi_index < qoi.size());
2381 
2382  qoi[qoi_index] = qoi_value;
2383 }
2384 
2385 
2386 Number System::get_qoi_value(unsigned int qoi_index) const
2387 {
2388  libmesh_assert(qoi_index < qoi.size());
2389  return qoi[qoi_index];
2390 }
2391 
2392 
2393 std::vector<Number> System::get_qoi_values() const
2394 {
2395  return this->qoi;
2396 }
2397 
2398 
2399 void System::set_qoi(std::vector<Number> new_qoi)
2400 {
2401  libmesh_assert_equal_to(this->qoi.size(), new_qoi.size());
2402  this->qoi = std::move(new_qoi);
2403 }
2404 
2405 
2406 void System::set_qoi_error_estimate(unsigned int qoi_index, Number qoi_error_estimate)
2407 {
2408  libmesh_assert(qoi_index < qoi_error_estimates.size());
2409 
2410  qoi_error_estimates[qoi_index] = qoi_error_estimate;
2411 }
2412 
2413 Number System::get_qoi_error_estimate_value(unsigned int qoi_index) const
2414 {
2415  libmesh_assert(qoi_index < qoi_error_estimates.size());
2416  return qoi_error_estimates[qoi_index];
2417 }
2418 
2419 
2420 
2421 Number System::point_value(unsigned int var,
2422  const Point & p,
2423  const bool insist_on_success,
2424  const NumericVector<Number> *sol) const
2425 {
2426  // This function must be called on every processor; there's no
2427  // telling where in the partition p falls.
2428  parallel_object_only();
2429 
2430  // And every processor had better agree about which point we're
2431  // looking for
2432 #ifndef NDEBUG
2433  libmesh_assert(this->comm().verify(p(0)));
2434 #if LIBMESH_DIM > 1
2435  libmesh_assert(this->comm().verify(p(1)));
2436 #endif
2437 #if LIBMESH_DIM > 2
2438  libmesh_assert(this->comm().verify(p(2)));
2439 #endif
2440 #endif // NDEBUG
2441 
2442  // Get a reference to the mesh object associated with the system object that calls this function
2443  const MeshBase & mesh = this->get_mesh();
2444 
2445  // Use an existing PointLocator or create a new one
2446  std::unique_ptr<PointLocatorBase> locator_ptr = mesh.sub_point_locator();
2447  PointLocatorBase & locator = *locator_ptr;
2448 
2449  if (!insist_on_success || !mesh.is_serial())
2450  locator.enable_out_of_mesh_mode();
2451 
2452  // Get a pointer to an element that contains p and allows us to
2453  // evaluate var
2454  const std::set<subdomain_id_type> & raw_subdomains =
2455  this->variable(var).active_subdomains();
2456  const std::set<subdomain_id_type> * implicit_subdomains =
2457  raw_subdomains.empty() ? nullptr : &raw_subdomains;
2458  const Elem * e = locator(p, implicit_subdomains);
2459 
2460  Number u = 0;
2461 
2462  if (e && this->get_dof_map().is_evaluable(*e, var))
2463  u = point_value(var, p, *e, sol);
2464 
2465  // If I have an element containing p, then let's let everyone know
2466  processor_id_type lowest_owner =
2467  (e && (e->processor_id() == this->processor_id())) ?
2468  this->processor_id() : this->n_processors();
2469  this->comm().min(lowest_owner);
2470 
2471  // Everybody should get their value from a processor that was able
2472  // to compute it.
2473  // If nobody admits owning the point, we have a problem.
2474  if (lowest_owner != this->n_processors())
2475  this->comm().broadcast(u, lowest_owner);
2476  else
2477  libmesh_assert(!insist_on_success);
2478 
2479  return u;
2480 }
2481 
2482 Number System::point_value(unsigned int var,
2483  const Point & p,
2484  const Elem & e,
2485  const NumericVector<Number> *sol) const
2486 {
2487  // Ensuring that the given point is really in the element is an
2488  // expensive assert, but as long as debugging is turned on we might
2489  // as well try to catch a particularly nasty potential error
2491 
2492  if (!sol)
2493  sol = this->current_local_solution.get();
2494 
2495  // Get the dof map to get the proper indices for our computation
2496  const DofMap & dof_map = this->get_dof_map();
2497 
2498  // Make sure we can evaluate on this element.
2499  libmesh_assert (dof_map.is_evaluable(e, var));
2500 
2501  // Need dof_indices for phi[i][j]
2502  std::vector<dof_id_type> dof_indices;
2503 
2504  // Fill in the dof_indices for our element
2505  dof_map.dof_indices (&e, dof_indices, var);
2506 
2507  // Get the no of dofs associated with this point
2508  const unsigned int num_dofs = cast_int<unsigned int>
2509  (dof_indices.size());
2510 
2511  FEType fe_type = dof_map.variable_type(var);
2512 
2513  // Map the physical co-ordinates to the master co-ordinates
2514  Point coor = FEMap::inverse_map(e.dim(), &e, p);
2515 
2516  // get the shape function value via the FEInterface to also handle the case
2517  // of infinite elements correctly, the shape function is not fe->phi().
2518  FEComputeData fe_data(this->get_equation_systems(), coor);
2519  FEInterface::compute_data(e.dim(), fe_type, &e, fe_data);
2520 
2521  // Get ready to accumulate a value
2522  Number u = 0;
2523 
2524  for (unsigned int l=0; l<num_dofs; l++)
2525  {
2526  u += fe_data.shape[l] * (*sol)(dof_indices[l]);
2527  }
2528 
2529  return u;
2530 }
2531 
2532 
2533 
2534 Number System::point_value(unsigned int var, const Point & p, const Elem * e) const
2535 {
2536  libmesh_assert(e);
2537  return this->point_value(var, p, *e);
2538 }
2539 
2540 
2541 
2542 Number System::point_value(unsigned int var, const Point & p, const NumericVector<Number> * sol) const
2543 {
2544  return this->point_value(var, p, true, sol);
2545 }
2546 
2547 
2548 
2549 
2551  const Point & p,
2552  const bool insist_on_success,
2553  const NumericVector<Number> *sol) const
2554 {
2555  // This function must be called on every processor; there's no
2556  // telling where in the partition p falls.
2557  parallel_object_only();
2558 
2559  // And every processor had better agree about which point we're
2560  // looking for
2561 #ifndef NDEBUG
2562  libmesh_assert(this->comm().verify(p(0)));
2563 #if LIBMESH_DIM > 1
2564  libmesh_assert(this->comm().verify(p(1)));
2565 #endif
2566 #if LIBMESH_DIM > 2
2567  libmesh_assert(this->comm().verify(p(2)));
2568 #endif
2569 #endif // NDEBUG
2570 
2571  // Get a reference to the mesh object associated with the system object that calls this function
2572  const MeshBase & mesh = this->get_mesh();
2573 
2574  // Use an existing PointLocator or create a new one
2575  std::unique_ptr<PointLocatorBase> locator_ptr = mesh.sub_point_locator();
2576  PointLocatorBase & locator = *locator_ptr;
2577 
2578  if (!insist_on_success || !mesh.is_serial())
2579  locator.enable_out_of_mesh_mode();
2580 
2581  // Get a pointer to an element that contains p and allows us to
2582  // evaluate var
2583  const std::set<subdomain_id_type> & raw_subdomains =
2584  this->variable(var).active_subdomains();
2585  const std::set<subdomain_id_type> * implicit_subdomains =
2586  raw_subdomains.empty() ? nullptr : &raw_subdomains;
2587  const Elem * e = locator(p, implicit_subdomains);
2588 
2589  Gradient grad_u;
2590 
2591  if (e && this->get_dof_map().is_evaluable(*e, var))
2592  grad_u = point_gradient(var, p, *e, sol);
2593 
2594  // If I have an element containing p, then let's let everyone know
2595  processor_id_type lowest_owner =
2596  (e && (e->processor_id() == this->processor_id())) ?
2597  this->processor_id() : this->n_processors();
2598  this->comm().min(lowest_owner);
2599 
2600  // Everybody should get their value from a processor that was able
2601  // to compute it.
2602  // If nobody admits owning the point, we may have a problem.
2603  if (lowest_owner != this->n_processors())
2604  this->comm().broadcast(grad_u, lowest_owner);
2605  else
2606  libmesh_assert(!insist_on_success);
2607 
2608  return grad_u;
2609 }
2610 
2611 
2613  const Point & p,
2614  const Elem & e,
2615  const NumericVector<Number> *sol) const
2616 {
2617  // Ensuring that the given point is really in the element is an
2618  // expensive assert, but as long as debugging is turned on we might
2619  // as well try to catch a particularly nasty potential error
2621 
2622  if (!sol)
2623  sol = this->current_local_solution.get();
2624 
2625  // Get the dof map to get the proper indices for our computation
2626  const DofMap & dof_map = this->get_dof_map();
2627 
2628  // write the element dimension into a separate variable.
2629  const unsigned int dim = e.dim();
2630 
2631  // Make sure we can evaluate on this element.
2632  libmesh_assert (dof_map.is_evaluable(e, var));
2633 
2634  // Need dof_indices for phi[i][j]
2635  std::vector<dof_id_type> dof_indices;
2636 
2637  // Fill in the dof_indices for our element
2638  dof_map.dof_indices (&e, dof_indices, var);
2639 
2640  // Get the no of dofs associated with this point
2641  const unsigned int num_dofs = cast_int<unsigned int>
2642  (dof_indices.size());
2643 
2644  FEType fe_type = dof_map.variable_type(var);
2645 
2646  // Map the physical co-ordinates to the master co-ordinates
2647  Point coor = FEMap::inverse_map(dim, &e, p);
2648 
2649  // get the shape function value via the FEInterface to also handle the case
2650  // of infinite elements correctly, the shape function is not fe->phi().
2651  FEComputeData fe_data(this->get_equation_systems(), coor);
2652  fe_data.enable_derivative();
2653  FEInterface::compute_data(dim, fe_type, &e, fe_data);
2654 
2655  // Get ready to accumulate a gradient
2656  Gradient grad_u;
2657 
2658  for (unsigned int l=0; l<num_dofs; l++)
2659  {
2660  // Chartesian coordinates have always LIBMESH_DIM entries,
2661  // local coordinates have as many coordinates as the element has.
2662  for (std::size_t v=0; v<dim; v++)
2663  for (std::size_t xyz=0; xyz<LIBMESH_DIM; xyz++)
2664  {
2665  // FIXME: this needs better syntax: It is matrix-vector multiplication.
2666  grad_u(xyz) += fe_data.local_transform[v][xyz]
2667  * fe_data.dshape[l](v)
2668  * (*sol)(dof_indices[l]);
2669  }
2670  }
2671 
2672  return grad_u;
2673 }
2674 
2675 
2676 
2677 Gradient System::point_gradient(unsigned int var, const Point & p, const Elem * e) const
2678 {
2679  libmesh_assert(e);
2680  return this->point_gradient(var, p, *e);
2681 }
2682 
2683 
2684 
2685 Gradient System::point_gradient(unsigned int var, const Point & p, const NumericVector<Number> * sol) const
2686 {
2687  return this->point_gradient(var, p, true, sol);
2688 }
2689 
2690 
2691 
2692 // We can only accumulate a hessian with --enable-second
2693 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
2695  const Point & p,
2696  const bool insist_on_success,
2697  const NumericVector<Number> *sol) const
2698 {
2699  // This function must be called on every processor; there's no
2700  // telling where in the partition p falls.
2701  parallel_object_only();
2702 
2703  // And every processor had better agree about which point we're
2704  // looking for
2705 #ifndef NDEBUG
2706  libmesh_assert(this->comm().verify(p(0)));
2707 #if LIBMESH_DIM > 1
2708  libmesh_assert(this->comm().verify(p(1)));
2709 #endif
2710 #if LIBMESH_DIM > 2
2711  libmesh_assert(this->comm().verify(p(2)));
2712 #endif
2713 #endif // NDEBUG
2714 
2715  // Get a reference to the mesh object associated with the system object that calls this function
2716  const MeshBase & mesh = this->get_mesh();
2717 
2718  // Use an existing PointLocator or create a new one
2719  std::unique_ptr<PointLocatorBase> locator_ptr = mesh.sub_point_locator();
2720  PointLocatorBase & locator = *locator_ptr;
2721 
2722  if (!insist_on_success || !mesh.is_serial())
2723  locator.enable_out_of_mesh_mode();
2724 
2725  // Get a pointer to an element that contains p and allows us to
2726  // evaluate var
2727  const std::set<subdomain_id_type> & raw_subdomains =
2728  this->variable(var).active_subdomains();
2729  const std::set<subdomain_id_type> * implicit_subdomains =
2730  raw_subdomains.empty() ? nullptr : &raw_subdomains;
2731  const Elem * e = locator(p, implicit_subdomains);
2732 
2733  Tensor hess_u;
2734 
2735  if (e && this->get_dof_map().is_evaluable(*e, var))
2736  hess_u = point_hessian(var, p, *e, sol);
2737 
2738  // If I have an element containing p, then let's let everyone know
2739  processor_id_type lowest_owner =
2740  (e && (e->processor_id() == this->processor_id())) ?
2741  this->processor_id() : this->n_processors();
2742  this->comm().min(lowest_owner);
2743 
2744  // Everybody should get their value from a processor that was able
2745  // to compute it.
2746  // If nobody admits owning the point, we may have a problem.
2747  if (lowest_owner != this->n_processors())
2748  this->comm().broadcast(hess_u, lowest_owner);
2749  else
2750  libmesh_assert(!insist_on_success);
2751 
2752  return hess_u;
2753 }
2754 
2756  const Point & p,
2757  const Elem & e,
2758  const NumericVector<Number> *sol) const
2759 {
2760  // Ensuring that the given point is really in the element is an
2761  // expensive assert, but as long as debugging is turned on we might
2762  // as well try to catch a particularly nasty potential error
2764 
2765  if (!sol)
2766  sol = this->current_local_solution.get();
2767 
2768  if (e.infinite())
2769  libmesh_not_implemented();
2770 
2771  // Get the dof map to get the proper indices for our computation
2772  const DofMap & dof_map = this->get_dof_map();
2773 
2774  // Make sure we can evaluate on this element.
2775  libmesh_assert (dof_map.is_evaluable(e, var));
2776 
2777  // Need dof_indices for phi[i][j]
2778  std::vector<dof_id_type> dof_indices;
2779 
2780  // Fill in the dof_indices for our element
2781  dof_map.dof_indices (&e, dof_indices, var);
2782 
2783  // Get the no of dofs associated with this point
2784  const unsigned int num_dofs = cast_int<unsigned int>
2785  (dof_indices.size());
2786 
2787  FEType fe_type = dof_map.variable_type(var);
2788 
2789  // Build a FE again so we can calculate u(p)
2790  std::unique_ptr<FEBase> fe (FEBase::build(e.dim(), fe_type));
2791 
2792  // Map the physical co-ordinates to the master co-ordinates
2793  // Build a vector of point co-ordinates to send to reinit
2794  std::vector<Point> coor(1, FEMap::inverse_map(e.dim(), &e, p));
2795 
2796  // Get the values of the shape function derivatives
2797  const std::vector<std::vector<RealTensor>> & d2phi = fe->get_d2phi();
2798 
2799  // Reinitialize the element and compute the shape function values at coor
2800  fe->reinit (&e, &coor);
2801 
2802  // Get ready to accumulate a hessian
2803  Tensor hess_u;
2804 
2805  for (unsigned int l=0; l<num_dofs; l++)
2806  {
2807  hess_u.add_scaled (d2phi[l][0], (*sol)(dof_indices[l]));
2808  }
2809 
2810  return hess_u;
2811 }
2812 
2813 
2814 
2815 Tensor System::point_hessian(unsigned int var, const Point & p, const Elem * e) const
2816 {
2817  libmesh_assert(e);
2818  return this->point_hessian(var, p, *e);
2819 }
2820 
2821 
2822 
2823 Tensor System::point_hessian(unsigned int var, const Point & p, const NumericVector<Number> * sol) const
2824 {
2825  return this->point_hessian(var, p, true, sol);
2826 }
2827 
2828 #else
2829 
2830 Tensor System::point_hessian(unsigned int, const Point &, const bool,
2831  const NumericVector<Number> *) const
2832 {
2833  libmesh_error_msg("We can only accumulate a hessian with --enable-second");
2834 
2835  // Avoid compiler warnings
2836  return Tensor();
2837 }
2838 
2839 Tensor System::point_hessian(unsigned int, const Point &, const Elem &,
2840  const NumericVector<Number> *) const
2841 {
2842  libmesh_error_msg("We can only accumulate a hessian with --enable-second");
2843 
2844  // Avoid compiler warnings
2845  return Tensor();
2846 }
2847 
2848 Tensor System::point_hessian(unsigned int, const Point &, const Elem *) const
2849 {
2850  libmesh_error_msg("We can only accumulate a hessian with --enable-second");
2851 
2852  // Avoid compiler warnings
2853  return Tensor();
2854 }
2855 
2856 Tensor System::point_hessian(unsigned int, const Point &, const NumericVector<Number> *) const
2857 {
2858  libmesh_error_msg("We can only accumulate a hessian with --enable-second");
2859 
2860  // Avoid compiler warnings
2861  return Tensor();
2862 }
2863 
2864 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
2865 
2867 {
2868  this->get_dof_map().create_static_condensation(this->get_mesh(), *this);
2869 }
2870 
2872 {
2873  return this->get_dof_map().has_static_condensation();
2874 }
2875 
2876 } // namespace libMesh
void set_vector_as_adjoint(const std::string &vec_name, int qoi_num)
Allows one to set the QoI index controlling whether the vector identified by vec_name represents a so...
Definition: system.C:1160
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
unsigned int add_variables(const std::vector< std::string > &vars, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition: system.C:1471
vectors_iterator vectors_end()
End of vectors container.
Definition: system.h:2576
virtual bool initialized() const
bool is_initialized() const
Definition: system.h:2414
FEFamily family
The type of finite element.
Definition: fe_type.h:221
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
Definition: system.h:1615
void local_dof_indices(const unsigned int var, std::set< dof_id_type > &var_indices) const
Fills the std::set with the degrees of freedom on the local processor corresponding the the variable ...
Definition: system.C:1627
bool closed()
Checks that the library has been closed.
Definition: libmesh.C:283
dof_id_type end_dof(const processor_id_type proc) const
Definition: dof_map_base.h:191
virtual Real subset_l2_norm(const std::set< numeric_index_type > &indices) const
This is the EquationSystems class.
virtual void clear()
Clear all the data structures associated with the system.
Definition: system.C:176
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
virtual void create_static_condensation()
Request that static condensation be performed for this system.
Definition: system.C:2866
void update_global_solution(std::vector< Number > &global_soln) const
Fill the input vector global_soln so that it contains the global solution on all processors.
Definition: system.C:745
Abstract base class to be used for system initialization.
Definition: system.h:131
std::size_t size() const
const Variable & variable(unsigned int var) const
Return a constant reference to Variable var.
Definition: system.h:2458
Assembly * _assemble_system_object
Object that assembles the system.
Definition: system.h:2136
Gradient point_gradient(unsigned int var, const Point &p, const bool insist_on_success=true, const NumericVector< Number > *sol=nullptr) const
Definition: system.C:2550
bool _basic_system_only
Holds true if the components of more advanced system types (e.g.
Definition: system.h:2270
virtual void init_matrices()
Initializes the matrices associated with this system.
Definition: system.C:323
bool _is_initialized
true when additional vectors and variables do not require immediate initialization, false otherwise.
Definition: system.h:2276
void(* _constrain_system_function)(EquationSystems &es, const std::string &name)
Function to impose constraints.
Definition: system.h:2141
NumericVector< Number > & add_adjoint_solution(unsigned int i=0)
Definition: system.C:1233
virtual void forward_qoi_parameter_sensitivity(const QoISet &qoi_indices, const ParameterVector &parameters, SensitivityData &sensitivities)
Solves for parameter sensitivities using the forward method.
Definition: system.h:2672
virtual void get(const std::vector< numeric_index_type > &index, T *values) const
Access multiple components at once.
Data structure for specifying which Parameters should be independent variables in a parameter sensiti...
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition: dof_map.C:2164
Data structure for specifying which Quantities of Interest should be calculated in an adjoint or a pa...
Definition: qoi_set.h:45
Number get_qoi_value(unsigned int qoi_index) const
Definition: system.C:2386
virtual void reinit()
Reinitializes degrees of freedom and other required data on the current mesh.
Definition: system.C:454
unsigned int dim
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true, const bool extra_checks=true)
Definition: fe_map.C:1628
class FEComputeData hides arbitrary data to be passed to and from children of FEBase through the FEIn...
unsigned int n_qois() const
Number of currently active quantities of interest.
Definition: system.h:2621
unsigned int n_components() const
Definition: system.h:2446
virtual bool initialized() const
virtual void initialize()=0
Initialization function.
virtual numeric_index_type size() const =0
NumericVector< Number > & get_sensitivity_solution(unsigned int i=0)
Definition: system.C:1192
OrderWrapper radial_order
The approximation order in radial direction of the infinite element.
Definition: fe_type.h:254
const FEType & variable_type(const unsigned int c) const
Definition: dof_map.h:2220
virtual void assemble_qoi_derivative(const QoISet &qoi_indices=QoISet(), bool include_liftfunc=true, bool apply_constraints=true)
Calls user qoi derivative function.
Definition: system.C:588
NumericVector< Number > & get_sensitivity_rhs(unsigned int i=0)
Definition: system.C:1337
int vector_is_adjoint(std::string_view vec_name) const
Definition: system.C:1173
virtual void assemble()=0
Assembly function.
Constraint * _constrain_system_object
Object that constrains the system.
Definition: system.h:2147
const EquationSystems & get_equation_systems() const
Definition: system.h:721
void sum(T &r) const
unsigned int n_variable_groups() const
Definition: system.h:2438
bool is_attached(SparseMatrix< Number > &matrix)
Matrices should not be attached more than once.
Definition: dof_map.C:329
virtual void assemble()
Prepares matrix and _dof_map for matrix assembly.
Definition: system.C:566
void attach_matrix(SparseMatrix< Number > &matrix)
Additional matrices may be attached to this DofMap.
Definition: dof_map.C:274
virtual void init_data()
Initializes the data for the system.
Definition: system.C:208
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
static FEFieldType field_type(const FEType &fe_type)
FEMNormType
defines an enum for norms defined on vectors of finite element coefficients
void init_qois(unsigned int n_qois)
Accessors for qoi and qoi_error_estimates vectors.
Definition: system.C:2371
Number point_value(unsigned int var, const Point &p, const bool insist_on_success=true, const NumericVector< Number > *sol=nullptr) const
Definition: system.C:2421
std::unique_ptr< DofMap > _dof_map
Data structure describing the relationship between nodes, variables, etc...
Definition: system.h:2179
virtual void user_initialization()
Calls user&#39;s attached initialization function, or is overridden by the user in derived classes...
Definition: system.C:2297
Provides a uniform interface to vector storage schemes for different linear algebra libraries...
Definition: vector_fe_ex5.C:44
std::vector< Gradient > dshape
Storage for the computed shape derivative values.
const Parallel::Communicator & comm() const
std::map< std::string, std::unique_ptr< NumericVector< Number > >, std::less<> > _vectors
Some systems need an arbitrary number of vectors.
Definition: system.h:2230
NumericVector< Number > & add_vector(std::string_view vec_name, const bool projections=true, const ParallelType type=PARALLEL)
Adds the additional vector vec_name to this system.
Definition: system.C:768
std::vector< Variable > _variables
The Variable in this System.
Definition: system.h:2206
void get_all_variable_numbers(std::vector< unsigned int > &all_variable_numbers) const
Fills all_variable_numbers with all the variable numbers for the variables that have been added to th...
Definition: system.C:1617
OrderWrapper order
The approximation order of the element.
Definition: fe_type.h:215
This class defines a norm/seminorm to be applied to a NumericVector which contains coefficients in a ...
Definition: system_norm.h:49
const std::string & name(unsigned int v) const
Definition: variable.h:295
NumericVector< Number > & add_sensitivity_rhs(unsigned int i=0)
Definition: system.C:1327
void reinit_static_condensation()
Calls reinit on the static condensation map if it exists.
Definition: dof_map.C:3080
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
std::vector< std::vector< Real > > local_transform
Storage for local to global mapping at p.
bool has_static_condensation() const
Definition: system.C:2871
The libMesh namespace provides an interface to certain functionality in the library.
vectors_iterator vectors_begin()
Beginning of vectors container.
Definition: system.h:2564
virtual Real subset_linfty_norm(const std::set< numeric_index_type > &indices) const
void attach_QOI_derivative_object(QOIDerivative &qoi_derivative)
Register a user object for evaluating derivatives of a quantity of interest with respect to test func...
Definition: system.C:2283
virtual void adjoint_qoi_parameter_sensitivity(const QoISet &qoi_indices, const ParameterVector &parameters, SensitivityData &sensitivities)
Solves for parameter sensitivities using the adjoint method.
Definition: system.h:2663
dof_id_type n_local_dofs() const
Definition: system.C:158
Abstract base class to be used for system assembly.
Definition: system.h:155
NumericVector< Number > & add_weighted_sensitivity_solution()
Definition: system.C:1212
void(* _qoi_evaluate_function)(EquationSystems &es, const std::string &name, const QoISet &qoi_indices)
Function to evaluate quantity of interest.
Definition: system.h:2152
const SparseMatrix< Number > * request_matrix(std::string_view mat_name) const
Definition: system.C:1100
void init()
Initializes degrees of freedom on the current mesh.
Definition: system.C:197
const MeshBase & get_mesh() const
Definition: system.h:2358
NumericVector< Number > & get_weighted_sensitivity_solution()
Definition: system.C:1219
static std::unique_ptr< SparseMatrix< T > > build(const Parallel::Communicator &comm, const SolverPackage solver_package=libMesh::default_solver_package(), const MatrixBuildType matrix_build_type=MatrixBuildType::AUTOMATIC)
Builds a SparseMatrix<T> using the linear solver package specified by solver_package.
virtual Real subset_l1_norm(const std::set< numeric_index_type > &indices) const
std::string get_info() const
Gets summary info about the sparsity bandwidth and constraints.
Definition: dof_map.C:2925
dof_id_type n_dofs() const
Definition: system.C:121
uint8_t processor_id_type
Definition: id_types.h:104
This is the MeshBase class.
Definition: mesh_base.h:75
virtual void prolong_vectors()
Prolong vectors after the mesh has refined.
Definition: system.C:444
virtual void user_QOI(const QoISet &qoi_indices)
Calls user&#39;s attached quantity of interest function, or is overridden by the user in derived classes...
Definition: system.C:2339
Number current_solution(const dof_id_type global_dof_number) const
Definition: system.C:165
Number fptr(const Point &p, const Parameters &, const std::string &libmesh_dbg_var(sys_name), const std::string &unknown_name)
Definition: projection.C:80
unsigned int variable_number(std::string_view var) const
Definition: system.C:1609
std::map< std::string, std::unique_ptr< SparseMatrix< Number > >, std::less<> > _matrices
Some systems need an arbitrary number of matrices.
Definition: system.h:2247
QOIDerivative * _qoi_evaluate_derivative_object
Object to compute derivatives of quantities of interest.
Definition: system.h:2173
NumericVector< Number > & add_weighted_sensitivity_adjoint_solution(unsigned int i=0)
Definition: system.C:1265
virtual void qoi_derivative(const QoISet &qoi_indices, bool include_liftfunc, bool apply_constraints)=0
Quantity of interest derivative function.
virtual void qoi_parameter_sensitivity(const QoISet &qoi_indices, const ParameterVector &parameters, SensitivityData &sensitivities)
Solves for the derivative of each of the system&#39;s quantities of interest q in qoi[qoi_indices] with r...
Definition: system.C:602
void attach_constraint_object(Constraint &constrain)
Register a user object for imposing constraints.
Definition: system.C:2209
SolverPackage default_solver_package()
Definition: libmesh.C:1117
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition: fe_type.C:34
void attach_init_object(Initialization &init)
Register a user class to use to initialize the system.
Definition: system.C:2147
bool has_variable(std::string_view var) const
Definition: system.C:1602
processor_id_type n_processors() const
void libmesh_ignore(const Args &...)
unsigned int number() const
Definition: system.h:2350
void remove_vector(std::string_view vec_name)
Removes the additional vector vec_name from this system.
Definition: system.C:873
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
Definition: elem.C:2751
This class defines the notion of a variable in the system.
Definition: variable.h:50
const std::set< subdomain_id_type > & active_subdomains() const
Definition: variable.h:181
bool has_static_condensation() const
Checks whether we have static condensation.
Definition: dof_map.h:1668
virtual Real l2_norm() const =0
std::map< std::string, int, std::less<> > _vector_is_adjoint
Holds non-negative if a vector by that name should be projected using adjoint constraints/BCs, -1 if primal.
Definition: system.h:2242
Constraint & get_constraint_object()
Return the user object for imposing constraints.
Definition: system.C:2226
void min(const T &r, T &o, Request &req) const
Data structure for holding completed parameter sensitivity calculations.
bool _is_initialized
Flag that tells if init() has been called.
Definition: libmesh.C:257
StaticCondensationDofMap & get_static_condensation()
Definition: dof_map.h:2689
unsigned int n_variables() const
Definition: variable.h:266
std::vector< Number > qoi
Values of the quantities of interest.
Definition: system.h:1631
void remove_matrix(std::string_view mat_name)
Removes the additional matrix mat_name from this system.
Definition: system.C:1089
std::vector< VariableGroup > _variable_groups
The VariableGroup in this System.
Definition: system.h:2211
This is a base class for classes which represent subsets of the dofs of a System. ...
Definition: system_subset.h:42
unsigned int n_vectors() const
Definition: system.h:2558
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:96
void zero_variable(NumericVector< Number > &v, unsigned int var_num) const
Zeroes all dofs in v that correspond to variable number var_num.
Definition: system.C:1668
bool _prefer_hash_table_matrix_assembly
Whether to use hash table matrix assembly if the matrix sub-classes support it.
Definition: system.h:2324
virtual void add_matrices()
Insertion point for adding matrices in derived classes before init_matrices() is called.
Definition: system.h:1964
static void compute_data(const unsigned int dim, const FEType &fe_t, const Elem *elem, FEComputeData &data)
Lets the appropriate child of FEBase compute the requested data for the input specified in data...
bool has_constraint_object() const
Definition: system.C:2221
std::string get_info() const
Definition: system.C:2040
virtual void qoi(const QoISet &qoi_indices)=0
Quantity of interest function.
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
void attach_QOI_derivative(void fptr(EquationSystems &es, const std::string &name, const QoISet &qoi_indices, bool include_liftfunc, bool apply_constraints))
Register a user function for evaluating derivatives of a quantity of interest with respect to test fu...
Definition: system.C:2266
Real calculate_norm(const NumericVector< Number > &v, unsigned int var, FEMNormType norm_type, std::set< unsigned int > *skip_dimensions=nullptr) const
Definition: system.C:1724
void print_dof_constraints(std::ostream &os=libMesh::out, bool print_nonlocal=false) const
Prints (from processor 0) all DoF and Node constraints.
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
libmesh_assert(ctx)
QOI * _qoi_evaluate_object
Object to compute quantities of interest.
Definition: system.h:2159
Initialization * _init_system_object
Object that initializes the system.
Definition: system.h:2125
void attach_QOI_function(void fptr(EquationSystems &es, const std::string &name, const QoISet &qoi_indices))
Register a user function for evaluating the quantities of interest, whose values should be placed in ...
Definition: system.C:2234
const VariableGroup & variable_group(const unsigned int c) const
Definition: dof_map.h:2180
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition: system.C:1357
const std::string & variable_name(const unsigned int i) const
Definition: system.h:2478
InfMapType inf_map
The coordinate mapping type of the infinite element.
Definition: fe_type.h:275
void(* _init_system_function)(EquationSystems &es, const std::string &name)
Function that initializes the system.
Definition: system.h:2119
const std::set< unsigned char > & elem_dimensions() const
Definition: mesh_base.h:282
std::map< std::string, ParallelType, std::less<> > _matrix_types
Holds the types of the matrices.
Definition: system.h:2252
This is the base class for point locators.
virtual void restrict_vectors()
Restrict vectors after the mesh has coarsened.
Definition: system.C:386
void create_static_condensation(MeshBase &mesh, System &system)
Add a static condensation class.
Definition: dof_map.C:3075
void attach_assemble_function(void fptr(EquationSystems &es, const std::string &name))
Register a user function to use in assembling the system matrix and RHS.
Definition: system.C:2161
auto norm(const T &a) -> decltype(std::abs(a))
Definition: tensor_tools.h:74
unsigned int n_matrices() const
Definition: system.h:2699
An object whose state is distributed along a set of processors.
This class defines a logically grouped set of variables in the system.
Definition: variable.h:203
std::size_t size(const System &sys) const
Definition: qoi_set.C:35
std::vector< Number > qoi_error_estimates
Vector to hold error estimates for qois, either from a steady state calculation, or from a single uns...
Definition: system.h:1639
bool implicitly_active() const
Definition: variable.h:175
void add_scaled(const TypeTensor< T2 > &, const T &)
Add a scaled tensor to this tensor without creating a temporary.
Definition: type_tensor.h:851
NumericVector< Number > & add_adjoint_rhs(unsigned int i=0)
Definition: system.C:1297
virtual Real l1_norm() const =0
virtual void restrict_solve_to(const SystemSubset *subset, const SubsetSolveMode subset_solve_mode=SUBSET_ZERO)
After calling this method, any solve will be restricted to the given subdomain.
Definition: system.C:557
virtual void user_QOI_derivative(const QoISet &qoi_indices=QoISet(), bool include_liftfunc=true, bool apply_constraints=true)
Calls user&#39;s attached quantity of interest derivative function, or is overridden by the user in deriv...
Definition: system.C:2353
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
virtual void reinit_constraints()
Reinitializes the constraints for this system.
Definition: system.C:495
bool identify_variable_groups() const
Definition: system.h:2526
virtual void close()=0
Calls the NumericVector&#39;s internal assembly routines, ensuring that the values are consistent across ...
virtual void reinit_mesh()
Reinitializes the system with a new mesh.
Definition: system.C:301
const NumericVector< Number > * request_vector(std::string_view vec_name) const
Definition: system.C:891
void attach_assemble_object(Assembly &assemble)
Register a user object to use in assembling the system matrix and RHS.
Definition: system.C:2178
FEFamily radial_family
The type of approximation in radial direction.
Definition: fe_type.h:267
bool _solution_projection
Holds true if the solution vector should be projected onto a changed grid, false if it should be zero...
Definition: system.h:2264
EquationSystems & _equation_systems
Constant reference to the EquationSystems object used for the simulation.
Definition: system.h:2185
std::string enum_to_string(const T e)
virtual bool closed() const
virtual std::string system_type() const
Definition: system.h:508
virtual void constrain()=0
Constraint function.
const std::string & vector_name(const unsigned int vec_num) const
Definition: system.C:983
void attach_QOI_object(QOI &qoi)
Register a user object for evaluating the quantities of interest, whose values should be placed in Sy...
Definition: system.C:2252
virtual void user_assembly()
Calls user&#39;s attached assembly function, or is overridden by the user in derived classes.
Definition: system.C:2311
ParallelType type() const
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:510
Real weight(unsigned int var) const
Definition: system_norm.C:134
const FEType & variable_type(const unsigned int i) const
Definition: system.h:2508
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void set_vector_preservation(const std::string &vec_name, bool preserve)
Allows one to set the boolean controlling whether the vector identified by vec_name should be "preser...
Definition: system.C:1138
void process_constraints(MeshBase &)
Postprocesses any constrained degrees of freedom to be constrained only in terms of unconstrained dof...
void set_qoi_error_estimate(unsigned int qoi_index, Number qoi_error_estimate)
Definition: system.C:2406
virtual void swap(NumericVector< T > &v)
Swaps the contents of this with v.
void max(const T &r, T &o, Request &req) const
NumberTensorValue Tensor
virtual unsigned short dim() const =0
bool _matrices_initialized
false when additional matrices being added require initialization, true otherwise.
Definition: system.h:2257
auto norm_sq(const T &a) -> decltype(std::norm(a))
Definition: tensor_tools.h:104
OStreamProxy out
bool _require_sparsity_pattern
Whether any of our matrices require an initial sparsity pattern computation in order to determine pre...
Definition: system.h:2329
const std::string _sys_name
A name associated with this system.
Definition: system.h:2196
virtual numeric_index_type local_size() const =0
Tensor point_hessian(unsigned int var, const Point &p, const bool insist_on_success=true, const NumericVector< Number > *sol=nullptr) const
Definition: system.C:2694
std::map< std::string, unsigned int, std::less<> > _variable_numbers
The variable numbers corresponding to user-specified names, useful for name-based lookups...
Definition: system.h:2217
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:140
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
Builds a NumericVector on the processors in communicator comm using the linear solver package specifi...
void clear_sparsity()
Clears the sparsity pattern.
Definition: dof_map.C:2009
NumericVector< Number > & get_adjoint_solution(unsigned int i=0)
Definition: system.C:1245
virtual void re_update()
Re-update the local values when the mesh has changed.
Definition: system.C:533
Abstract base class to be used for system constraints.
Definition: system.h:179
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
Definition: system.h:1605
void project_vector(NumericVector< Number > &new_vector, FunctionBase< Number > *f, FunctionBase< Gradient > *g=nullptr, int is_adjoint=-1) const
Projects arbitrary functions onto a vector of degree of freedom values for the current system...
virtual bool compare(const System &other_system, const Real threshold, const bool verbose) const
Definition: system.C:618
void set_qoi(unsigned int qoi_index, Number qoi_value)
Definition: system.C:2378
dof_id_type n_local_constrained_dofs() const
Definition: system.C:143
void create_dof_constraints(const MeshBase &, Real time=0)
Rebuilds the raw degree of freedom and DofObject constraints, based on attached DirichletBoundary obj...
virtual void set(const numeric_index_type i, const T value)=0
Sets v(i) = value.
void prepare_send_list()
Takes the _send_list vector (which may have duplicate entries) and sorts it.
Definition: dof_map.C:1864
bool on_command_line(std::string arg)
Definition: libmesh.C:987
virtual bool infinite() const =0
const std::string & name() const
Definition: system.h:2342
void attach_constraint_function(void fptr(EquationSystems &es, const std::string &name))
Register a user function for imposing constraints.
Definition: system.C:2192
virtual void user_constrain()
Calls user&#39;s attached constraint function, or is overridden by the user in derived classes...
Definition: system.C:2325
Real discrete_var_norm(const NumericVector< Number > &v, unsigned int var, FEMNormType norm_type) const
Finds the discrete norm for the entries in the vector corresponding to Dofs associated with var...
Definition: system.C:1705
dof_id_type first_dof(const processor_id_type proc) const
Definition: dof_map_base.h:185
Number get_qoi_error_estimate_value(unsigned int qoi_index) const
Definition: system.C:2413
virtual void assemble_qoi(const QoISet &qoi_indices=QoISet())
Calls user qoi function.
Definition: system.C:577
NumericVector< Number > & add_sensitivity_solution(unsigned int i=0)
Definition: system.C:1182
FEFamily
defines an enum for finite element families.
unsigned int n_vars() const
Definition: system.h:2430
void(* _assemble_system_function)(EquationSystems &es, const std::string &name)
Function that assembles the system.
Definition: system.h:2130
MatrixBuildType
Defines an enum for matrix build types.
virtual ~System()
Definition: system.C:114
void compute_sparsity(const MeshBase &)
Computes the sparsity pattern for the matrices corresponding to proc_id and sends that data to Linear...
Definition: dof_map.C:1988
virtual void enable_out_of_mesh_mode()=0
Enables out-of-mesh mode.
processor_id_type processor_id() const
System(EquationSystems &es, const std::string &name, const unsigned int number)
Constructor.
Definition: system.C:64
void enable_derivative()
Enable the computation of shape gradients (dshape).
bool vector_preservation(std::string_view vec_name) const
Definition: system.C:1148
SparseMatrix< Number > & add_matrix(std::string_view mat_name, ParallelType type=PARALLEL, MatrixBuildType mat_build_type=MatrixBuildType::AUTOMATIC)
Adds the additional matrix mat_name to this system.
Definition: system.C:1010
SubsetSolveMode
defines an enum for the question what happens to the dofs outside the given subset when a system is s...
const DofMap & get_dof_map() const
Definition: system.h:2374
processor_id_type processor_id() const
Definition: dof_object.h:905
void late_matrix_init(SparseMatrix< Number > &mat, ParallelType type)
Helper function to keep DofMap forward declarable in system.h.
Definition: system.C:1076
const SparseMatrix< Number > & get_matrix(std::string_view mat_name) const
Definition: system.C:1124
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
MeshBase & _mesh
Constant reference to the mesh data structure used for the simulation.
Definition: system.h:2191
template class LIBMESH_EXPORT NumericVector< Number >
The QBase class provides the basic functionality from which various quadrature rules can be derived...
Definition: quadrature.h:61
virtual Real linfty_norm() const =0
const VariableGroup & variable_group(unsigned int vg) const
Return a constant reference to VariableGroup vg.
Definition: system.h:2468
const std::vector< dof_id_type > & get_send_list() const
Definition: dof_map.h:526
void attach_init_function(void fptr(EquationSystems &es, const std::string &name))
Register a user function to use in initializing the system.
Definition: system.C:2130
void set_type(ParallelType t)
Allow the user to change the ParallelType of the NumericVector under some circumstances.
std::map< std::string, bool, std::less<> > _vector_projections
Holds true if a vector by that name should be projected onto a changed grid, false if it should be ze...
Definition: system.h:2236
This class forms the foundation from which generic finite elements may be derived.
Abstract base class to be used for quantities of interest.
Definition: system.h:203
bool is_evaluable(const DofObjectSubclass &obj, unsigned int var_num=libMesh::invalid_uint) const
Definition: dof_map.C:2612
const NumericVector< Number > & get_vector(std::string_view vec_name) const
Definition: system.C:943
NumericVector< Number > & get_weighted_sensitivity_adjoint_solution(unsigned int i=0)
Definition: system.C:1277
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
dof_id_type n_constrained_dofs() const
Definition: system.C:128
uint8_t dof_id_type
Definition: id_types.h:67
std::vector< Number > get_qoi_values() const
Returns a copy of qoi, not a reference.
Definition: system.C:2393
virtual void init(const numeric_index_type m, const numeric_index_type n, const numeric_index_type m_l, const numeric_index_type n_l, const numeric_index_type nnz=30, const numeric_index_type noz=10, const numeric_index_type blocksize=1)=0
Initialize SparseMatrix with the specified sizes.
const FEType & type() const
Definition: variable.h:144
void(* _qoi_evaluate_derivative_function)(EquationSystems &es, const std::string &name, const QoISet &qoi_indices, bool include_liftfunc, bool apply_constraints)
Function to evaluate quantity of interest derivative.
Definition: system.h:2164
ParallelType
Defines an enum for parallel data structure types.
Abstract base class to be used for derivatives of quantities of interest.
Definition: system.h:227
NumericVector< Number > & get_adjoint_rhs(unsigned int i=0)
Definition: system.C:1307
bool prefix_with_name() const
Definition: system.h:1932
virtual void localize(std::vector< T > &v_local) const =0
Creates a copy of the global vector in the local vector v_local.
FEFieldType
defines an enum for finite element field types - i.e.