libMesh
Loading...
Searching...
No Matches
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
58namespace 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
162Number 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()
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
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
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
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
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
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
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
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
565void 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
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
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
606bool 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
733void 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
744void 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
756NumericVector<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
861void 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
879const 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
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
903const 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
917NumericVector<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
931const NumericVector<Number> & System::get_vector (std::string_view vec_name) const
932{
933 return *(libmesh_map_find(_vectors, vec_name));
934}
935
936
937
938NumericVector<Number> & System::get_vector (std::string_view vec_name)
939{
940 return *(libmesh_map_find(_vectors, vec_name));
941}
942
943
944
945const 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
958NumericVector<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
971const 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
982const 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
998SparseMatrix<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(),
1023 this->get_dof_map().get_static_condensation());
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
1041SparseMatrix<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
1076void 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
1087const 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
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
1111const SparseMatrix<Number> & System::get_matrix (std::string_view mat_name) const
1112{
1113 return *libmesh_map_find(_matrices, mat_name);
1114}
1115
1116
1117
1118SparseMatrix<Number> & System::get_matrix (std::string_view mat_name)
1119{
1120 return *libmesh_map_find(_matrices, mat_name);
1121}
1122
1123
1124
1125void 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
1135bool 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
1147void 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
1160int System::vector_is_adjoint (std::string_view vec_name) const
1161{
1162 const auto it = _vector_is_adjoint.find(vec_name);
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
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
1344unsigned 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
1353unsigned 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
1366unsigned 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
1375unsigned 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
1386unsigned 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
1393bool System::has_variable (std::string_view var) const
1394{
1395 return this->get_dof_map().has_variable(var);
1396}
1397
1398unsigned int System::variable_number (std::string_view var) const
1399{
1400 return this->get_dof_map().variable_number(var);
1401}
1402
1403void 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
1409void 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
1492Real System::discrete_var_norm(const NumericVector<Number> & v,
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
1511Real System::calculate_norm(const NumericVector<Number> & v,
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
1533Real System::calculate_norm(const NumericVector<Number> & v,
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
1827std::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
1928void System::attach_init_function (void fptr(EquationSystems & es,
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
1940 _init_system_function = fptr;
1941}
1942
1943
1944
1945void System::attach_init_object (System::Initialization & init_in)
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
1959void System::attach_assemble_function (void fptr(EquationSystems & es,
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
1971 _assemble_system_function = fptr;
1972}
1973
1974
1975
1976void System::attach_assemble_object (System::Assembly & assemble_in)
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
1990void System::attach_constraint_function(void fptr(EquationSystems & es,
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
2002 _constrain_system_function = fptr;
2003}
2004
2005
2006
2007void System::attach_constraint_object (System::Constraint & constrain)
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
2019bool System::has_constraint_object () const
2020{
2021 return _constrain_system_object != nullptr;
2022}
2023
2024System::Constraint& System::get_constraint_object ()
2025{
2026 libmesh_assert_msg(_constrain_system_object,"No constraint object available.");
2027 return *_constrain_system_object;
2028}
2029
2030
2031
2032void System::attach_QOI_function(void fptr(EquationSystems &,
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
2045 _qoi_evaluate_function = fptr;
2046}
2047
2048
2049
2050void System::attach_QOI_object (QOI & qoi_in)
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
2064void 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
2073 _qoi_evaluate_derivative_object = nullptr;
2074 }
2075
2076 _qoi_evaluate_derivative_function = fptr;
2077}
2078
2079
2080
2081void System::attach_QOI_derivative_object (QOIDerivative & qoi_derivative)
2082{
2083 if (_qoi_evaluate_derivative_function != nullptr)
2084 {
2085 libmesh_warning("WARNING: Cannot specify both QOI derivative object and function!");
2086
2087 _qoi_evaluate_derivative_function = nullptr;
2088 }
2089
2090 _qoi_evaluate_derivative_object = &qoi_derivative;
2091}
2092
2093
2094
2095void System::user_initialization ()
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)
2104 this->_init_system_object->initialize();
2105}
2106
2107
2108
2109void System::user_assembly ()
2110{
2111 // Call the user-provided assembly function,
2112 // if it was provided
2113 if (_assemble_system_function != nullptr)
2114 this->_assemble_system_function (_equation_systems, this->name());
2115
2116 // ...or the user-provided assembly object.
2117 else if (_assemble_system_object != nullptr)
2118 this->_assemble_system_object->assemble();
2119}
2120
2121
2122
2123void System::user_constrain ()
2124{
2125 // Call the user-provided constraint function,
2126 // if it was provided
2127 if (_constrain_system_function!= nullptr)
2128 this->_constrain_system_function(_equation_systems, this->name());
2129
2130 // ...or the user-provided constraint object.
2131 else if (_constrain_system_object != nullptr)
2132 this->_constrain_system_object->constrain();
2133}
2134
2135
2136
2137void 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
2151void 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)
2158 this->_qoi_evaluate_derivative_function
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)
2164 this->_qoi_evaluate_derivative_object->qoi_derivative
2165 (qoi_indices, include_liftfunc, apply_constraints);
2166}
2167
2168
2169void System::init_qois(unsigned int n_qois)
2170{
2171 _qoi.resize(n_qois);
2172 _qoi_error_estimates.resize(n_qois);
2173}
2174
2175
2176void 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
2184Number 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
2191std::vector<Number> System::get_qoi_values() const
2192{
2193 return this->_qoi;
2194}
2195
2196
2197void 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
2204void 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
2211Number 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
2219Number 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
2280Number 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
2332Number 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
2340Number 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
2348Gradient System::point_gradient(unsigned int var,
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
2410Gradient System::point_gradient(unsigned int var,
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
2475Gradient 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
2483Gradient 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
2492Tensor System::point_hessian(unsigned int var,
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
2553Tensor System::point_hessian(unsigned int var,
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
2613Tensor 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
2621Tensor 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
2628Tensor 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
2637Tensor 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
2646Tensor 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
2654Tensor 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
2664void System::create_static_condensation()
2665{
2666 this->get_dof_map().create_static_condensation(this->get_mesh(), *this);
2667}
2668
2669bool System::has_static_condensation() const
2670{
2671 return this->get_dof_map().has_static_condensation();
2672}
2673
2674unsigned int System::n_vars() const
2675{
2676 return this->get_dof_map().n_vars();
2677}
2678
2679const std::string & System::variable_name (const unsigned int i) const
2680{
2681 return this->get_dof_map().variable_name(i);
2682}
2683
2684bool System::identify_variable_groups () const
2685{
2686 return this->get_dof_map().identify_variable_groups();
2687}
2688
2689void System::identify_variable_groups (const bool ivg)
2690{
2691 this->get_dof_map().identify_variable_groups(ivg);
2692}
2693
2694unsigned int System::n_components() const
2695{
2696 return this->get_dof_map().n_components(this->get_mesh());
2697}
2698
2699unsigned int System::n_variable_groups() const
2700{
2701 return this->get_dof_map().n_variable_groups();
2702}
2703
2704const Variable & System::variable (const unsigned int i) const
2705{
2706 return this->get_dof_map().variable(i);
2707}
2708
2709const VariableGroup & System::variable_group (const unsigned int vg) const
2710{
2711 return this->get_dof_map().variable_group(vg);
2712}
2713
2714unsigned int
2715System::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
2721const FEType & System::variable_type (const unsigned int i) const
2722{
2723 return this->get_dof_map().variable_type(i);
2724}
2725
2726const FEType & System::variable_type (std::string_view var) const
2727{
2728 return this->get_dof_map().variable_type(var);
2729}
2730
2731} // namespace libMesh
unsigned int n_vars
unsigned int dim
dof_id_type first_dof(const processor_id_type proc) const
dof_id_type end_dof(const processor_id_type proc) const
This class handles the numbering of degrees of freedom on a mesh.
Definition dof_map.h:181
void reinit_static_condensation()
Calls reinit on the static condensation map if it exists.
Definition dof_map.C:3140
const std::vector< dof_id_type > & get_send_list() const
Definition dof_map.h:533
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2201
void prepare_send_list()
Takes the _send_list vector (which may have duplicate entries) and sorts it.
Definition dof_map.C:1835
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
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
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
void print_dof_constraints(std::ostream &os=libMesh::out, bool print_nonlocal=false) const
Prints (from processor 0) all DoF and Node constraints.
void clear_sparsity()
Clears the sparsity pattern.
Definition dof_map.C:1981
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
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
const FEType & variable_type(const unsigned int i) const
Definition dof_map.h:2388
void create_dof_constraints(const MeshBase &, Real time=0)
Rebuilds the raw degree of freedom and DofObject constraints, based on attached DirichletBoundary obj...
unsigned int variable_number(std::string_view var) const
Definition dof_map.h:2991
void attach_matrix(SparseMatrix< Number > &matrix)
Additional matrices may be attached to this DofMap.
Definition dof_map.C:240
void process_constraints(MeshBase &)
Postprocesses any constrained degrees of freedom to be constrained only in terms of unconstrained dof...
bool is_evaluable(const DofObjectSubclass &obj, unsigned int var_num=libMesh::invalid_uint) const
Definition dof_map.C:2673
bool has_variable(std::string_view var) const
Definition dof_map.h:2986
processor_id_type processor_id() const
Definition dof_object.h:881
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
Definition elem.C:2784
virtual unsigned short dim() const =0
virtual bool infinite() const =0
This is the EquationSystems class.
class FEComputeData hides arbitrary data to be passed to and from children of FEBase through the FEIn...
std::vector< Gradient > dshape
Storage for the computed shape derivative values.
std::vector< std::vector< Real > > local_transform
Storage for local to global mapping at p.
void enable_derivative()
Enable the computation of shape gradients (dshape).
std::vector< Number > shape
Storage for the computed shape function values.
This class forms the foundation from which generic finite elements may be derived.
Definition fe_base.h:86
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition fe_type.C:34
This is the MeshBase class.
Definition mesh_base.h:81
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual void set(const numeric_index_type i, const T value)=0
Sets v(i) = value.
virtual void get(const std::vector< numeric_index_type > &index, T *values) const
Access multiple components at once.
virtual Real l1_norm() const =0
ParallelType type() const
void set_type(ParallelType t)
Allow the user to change the ParallelType of the NumericVector under some circumstances.
virtual void close()=0
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
virtual void swap(NumericVector< T > &v)
Swaps the contents of this with v.
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...
virtual bool initialized() const
virtual void localize(std::vector< T > &v_local) const =0
Creates a copy of the global vector in the local vector v_local.
virtual Real l2_norm() const =0
virtual numeric_index_type size() const =0
virtual Real linfty_norm() const =0
virtual bool closed() const
virtual Real subset_l1_norm(const std::set< numeric_index_type > &indices) const
virtual numeric_index_type local_size() const =0
virtual Real subset_l2_norm(const std::set< numeric_index_type > &indices) const
virtual Real subset_linfty_norm(const std::set< numeric_index_type > &indices) const
An object whose state is distributed along a set of processors.
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
Data structure for specifying which Parameters should be independent variables in a parameter sensiti...
std::size_t size() const
This is the base class for point locators.
virtual void enable_out_of_mesh_mode()=0
Enables out-of-mesh mode.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
The QBase class provides the basic functionality from which various quadrature rules can be derived.
Definition quadrature.h:62
unsigned int n_points() const
Definition quadrature.h:131
Data structure for specifying which Quantities of Interest should be calculated in an adjoint or a pa...
Definition qoi_set.h:46
std::size_t size(const System &sys) const
Definition qoi_set.C:35
Data structure for holding completed parameter sensitivity calculations.
Generic sparse matrix.
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.
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 bool initialized() const
The StoredRange class defines a contiguous, divisible set of objects.
This class defines a norm/seminorm to be applied to a NumericVector which contains coefficients in a ...
Definition system_norm.h:50
Real weight(unsigned int var) const
This is a base class for classes which represent subsets of the dofs of a System.
Abstract base class to be used for system assembly.
Definition system.h:158
Abstract base class to be used for system constraints.
Definition system.h:182
Abstract base class to be used for system initialization.
Definition system.h:134
Abstract base class to be used for derivatives of quantities of interest.
Definition system.h:230
Abstract base class to be used for quantities of interest.
Definition system.h:206
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
unsigned int n_vectors() const
Definition system.h:2499
virtual void user_QOI_derivative(const QoISet &qoi_indices=QoISet(), bool include_liftfunc=true, bool apply_constraints=true)
Calls user's attached quantity of interest derivative function, or is overridden by the user in deriv...
Definition system.C:2151
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,...
Definition system.h:2272
bool _is_initialized
true when additional vectors and variables do not require immediate initialization,...
Definition system.h:2306
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
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
const std::string & name() const
Definition system.h:2385
virtual bool compare(const System &other_system, const Real threshold, const bool verbose) const
Definition system.C:606
NumericVector< Number > & add_weighted_sensitivity_adjoint_solution(unsigned int i=0)
Definition system.C:1252
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
virtual void reinit()
Reinitializes degrees of freedom and other required data on the current mesh.
Definition system.C:442
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.
Number current_solution(const dof_id_type global_dof_number) const
Definition system.C:162
const SparseMatrix< Number > & get_matrix(std::string_view mat_name) const
Definition system.C:1111
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 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
vectors_iterator vectors_begin()
Beginning of vectors container.
Definition system.h:2505
void remove_matrix(std::string_view mat_name)
Removes the additional matrix mat_name from this system.
Definition system.C:1076
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
std::map< std::string, std::unique_ptr< NumericVector< Number > >, std::less<> > _vectors
Some systems need an arbitrary number of vectors.
Definition system.h:2260
std::map< std::string, std::unique_ptr< SparseMatrix< Number > >, std::less<> > _matrices
Some systems need an arbitrary number of matrices.
Definition system.h:2277
bool prefix_with_name() const
Definition system.h:1974
virtual void user_QOI(const QoISet &qoi_indices)
Calls user's attached quantity of interest function, or is overridden by the user in derived classes.
Definition system.C:2137
virtual ~System()
Definition system.C:111
bool is_initialized() const
Definition system.h:2457
void remove_vector(std::string_view vec_name)
Removes the additional vector vec_name from this system.
Definition system.C:861
NumericVector< Number > & get_weighted_sensitivity_adjoint_solution(unsigned int i=0)
Definition system.C:1264
virtual void create_static_condensation()
Request that static condensation be performed for this system.
Definition system.C:2664
virtual void qoi_parameter_sensitivity(const QoISet &qoi_indices, const ParameterVector &parameters, SensitivityData &sensitivities)
Solves for the derivative of each of the system's quantities of interest q in qoi[qoi_indices] with r...
Definition system.C:590
dof_id_type n_dofs() const
Definition system.C:118
const std::string & vector_name(const unsigned int vec_num) const
Definition system.C:971
virtual void reinit_mesh()
Reinitializes the system with a new mesh.
Definition system.C:289
virtual void prolong_vectors()
Prolong vectors after the mesh has refined.
Definition system.C:432
virtual void user_initialization()
Calls user's attached initialization function, or is overridden by the user in derived classes.
Definition system.C:2095
NumericVector< Number > & add_sensitivity_rhs(unsigned int i=0)
Definition system.C:1314
int vector_is_adjoint(std::string_view vec_name) const
Definition system.C:1160
bool _basic_system_only
Holds true if the components of more advanced system types (e.g.
Definition system.h:2300
MeshBase & _mesh
Constant reference to the mesh data structure used for the simulation.
Definition system.h:2237
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
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
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
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
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 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
const NumericVector< Number > * request_vector(std::string_view vec_name) const
Definition system.C:879
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
virtual void restrict_vectors()
Restrict vectors after the mesh has coarsened.
Definition system.C:374
virtual void user_assembly()
Calls user's attached assembly function, or is overridden by the user in derived classes.
Definition system.C:2109
virtual void assemble()
Prepares matrix and _dof_map for matrix assembly.
Definition system.C:554
System(EquationSystems &es, const std::string &name, const unsigned int number)
Constructor.
Definition system.C:64
bool _prefer_hash_table_matrix_assembly
Whether to use hash table matrix assembly if the matrix sub-classes support it.
Definition system.h:2348
dof_id_type n_local_dofs() const
Definition system.C:155
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
dof_id_type n_constrained_dofs() const
Definition system.C:125
NumericVector< Number > & add_sensitivity_solution(unsigned int i=0)
Definition system.C:1169
virtual void clear()
Clear all the data structures associated with the system.
Definition system.C:173
vectors_iterator vectors_end()
End of vectors container.
Definition system.h:2517
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
virtual void user_constrain()
Calls user's attached constraint function, or is overridden by the user in derived classes.
Definition system.C:2123
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
Definition system.h:1677
NumericVector< Number > & get_sensitivity_solution(unsigned int i=0)
Definition system.C:1179
virtual void add_matrices()
Insertion point for adding matrices in derived classes before init_matrices() is called.
Definition system.h:2017
virtual void re_update()
Re-update the local values when the mesh has changed.
Definition system.C:521
std::unique_ptr< DofMap > _dof_map
Data structure describing the relationship between nodes, variables, etc... and degrees of freedom.
Definition system.h:2225
void init()
Initializes degrees of freedom on the current mesh.
Definition system.C:196
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition system.h:1655
virtual void init_matrices()
Initializes the matrices associated with this system.
Definition system.C:311
const std::string _sys_name
A name associated with this system.
Definition system.h:2242
virtual void init_data()
Initializes the data for the system.
Definition system.C:207
bool _matrices_initialized
false when additional matrices being added require initialization, true otherwise.
Definition system.h:2287
NumericVector< Number > & get_sensitivity_rhs(unsigned int i=0)
Definition system.C:1324
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
NumericVector< Number > & add_adjoint_rhs(unsigned int i=0)
Definition system.C:1284
NumericVector< Number > & add_adjoint_solution(unsigned int i=0)
Definition system.C:1220
virtual void assemble_qoi(const QoISet &qoi_indices=QoISet())
Calls user qoi function.
Definition system.C:565
bool vector_preservation(std::string_view vec_name) const
Definition system.C:1135
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition system.C:498
unsigned int variable_number(std::string_view var) const
Definition system.C:1398
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
bool has_static_condensation() const
Definition system.C:2669
dof_id_type n_local_constrained_dofs() const
Definition system.C:140
bool has_variable(std::string_view var) const
Definition system.C:1393
virtual void reinit_constraints()
Reinitializes the constraints for this system.
Definition system.C:483
NumericVector< Number > & get_weighted_sensitivity_solution()
Definition system.C:1206
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
bool _require_sparsity_pattern
Whether any of our matrices require an initial sparsity pattern computation in order to determine pre...
Definition system.h:2353
NumericVector< Number > & add_weighted_sensitivity_solution()
Definition system.C:1199
std::map< std::string, ParallelType, std::less<> > _matrix_types
Holds the types of the matrices.
Definition system.h:2282
unsigned int n_vars() const
Definition system.C:2674
const DofMap & get_dof_map() const
Definition system.h:2417
NumericVector< Number > & get_adjoint_solution(unsigned int i=0)
Definition system.C:1232
unsigned int number() const
Definition system.h:2393
void late_matrix_init(SparseMatrix< Number > &mat, ParallelType type)
Helper function to keep DofMap forward declarable in system.h.
Definition system.C:1063
const NumericVector< Number > & get_vector(std::string_view vec_name) const
Definition system.C:931
const MeshBase & get_mesh() const
Definition system.h:2401
const SparseMatrix< Number > * request_matrix(std::string_view mat_name) const
Definition system.C:1087
NumericVector< Number > & get_adjoint_rhs(unsigned int i=0)
Definition system.C:1294
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
void add_scaled(const TypeTensor< T2 > &, const T &)
Add a scaled tensor to this tensor without creating a temporary.
This class defines a logically grouped set of variables in the system.
Definition variable.h:216
unsigned int n_variables() const
Definition variable.h:278
const std::string & name(unsigned int v) const
Definition variable.h:307
This class defines the notion of a variable in the system.
Definition variable.h:51
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
MeshBase & mesh
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.
The libMesh namespace provides an interface to certain functionality in the library.
ParallelType
Defines an enum for parallel data structure types.
bool closed()
Checks that the library has been closed.
Definition libmesh.C:331
SubsetSolveMode
defines an enum for the question what happens to the dofs outside the given subset when a system is s...
void libmesh_ignore(const Args &...)
SolverPackage default_solver_package()
Definition libmesh.C:1064
MatrixBuildType
Defines an enum for matrix build types.
libmesh_assert(ctx)
OStreamProxy out
NumberTensorValue Tensor
uint8_t dof_id_type
Definition id_types.h:67
bool on_command_line(std::string arg)
Definition libmesh.C:934
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
Definition id_types.h:104
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
Number fptr(const Point &p, const Parameters &, const std::string &libmesh_dbg_var(sys_name), const std::string &unknown_name)
Definition projection.C:81