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