1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 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 #ifndef LIBMESH_DOF_MAP_H
21 #define LIBMESH_DOF_MAP_H
22
23 // Local Includes
24 #include "libmesh/libmesh_common.h"
25 #include "libmesh/reference_counted_object.h"
26 #include "libmesh/libmesh.h" // libMesh::invalid_uint
27 #include "libmesh/variable.h"
28 #include "libmesh/threads.h"
29 #include "libmesh/threads_allocators.h"
30 #include "libmesh/elem_range.h"
31 #include "libmesh/ghosting_functor.h"
32 #include "libmesh/sparsity_pattern.h"
33 #include "libmesh/parallel_object.h"
34 #include "libmesh/point.h"
35
36 #ifdef LIBMESH_FORWARD_DECLARE_ENUMS
37 namespace libMesh
38 {
39 enum Order : int;
40 }
41 #else
42 #include "libmesh/enum_order.h"
43 #endif
44
45 // C++ Includes
46 #include <algorithm>
47 #include <cstddef>
48 #include <iterator>
49 #include <map>
50 #include <string>
51 #include <vector>
52 #include <memory>
53
54 namespace libMesh
55 {
56
57 // Forward Declarations
58 class CouplingMatrix;
59 class DefaultCoupling;
60 class DirichletBoundary;
61 class DirichletBoundaries;
62 class DofMap;
63 class DofObject;
64 class Elem;
65 class FEType;
66 class MeshBase;
67 class PeriodicBoundaryBase;
68 class PeriodicBoundaries;
69 class System;
70 class NonlinearImplicitSystem;
71 template <typename T> class DenseVectorBase;
72 template <typename T> class DenseVector;
73 template <typename T> class DenseMatrix;
74 template <typename T> class SparseMatrix;
75 template <typename T> class NumericVector;
76
77
78
79 // ------------------------------------------------------------
80 // Do we need constraints for anything?
81
82 #if defined(LIBMESH_ENABLE_AMR) || \
83 defined(LIBMESH_ENABLE_PERIODIC) || \
84 defined(LIBMESH_ENABLE_DIRICHLET)
85 # define LIBMESH_ENABLE_CONSTRAINTS 1
86 #endif
87
88 // ------------------------------------------------------------
89 // AMR constraint matrix types
90
91 #ifdef LIBMESH_ENABLE_CONSTRAINTS
92 /**
93 * A row of the Dof constraint matrix.
94 */
95 typedef std::map<dof_id_type, Real,
96 std::less<dof_id_type>,
97 Threads::scalable_allocator<std::pair<const dof_id_type, Real>>> DofConstraintRow;
98
99 /**
100 * The constraint matrix storage format.
101 * We're using a class instead of a typedef to allow forward
102 * declarations and future flexibility. Don't delete this from
103 * a pointer-to-std-map; the destructor isn't virtual!
104 */
105 class DofConstraints : public std::map<dof_id_type,
106 DofConstraintRow,
107 std::less<dof_id_type>,
108 Threads::scalable_allocator<std::pair<const dof_id_type, DofConstraintRow>>>
109 {
110 };
111
112 /**
113 * Storage for DofConstraint right hand sides for a particular
114 * problem. Each dof id with a non-zero constraint offset
115 * stores it in such a structure.
116 */
117 class DofConstraintValueMap :
118 public std::map<dof_id_type, Number,
119 std::less<dof_id_type>,
120 Threads::scalable_allocator<std::pair<const dof_id_type, Number>>>
121 {
122 };
123
124 /**
125 * Storage for DofConstraint right hand sides for all adjoint
126 * problems.
127 */
128 class AdjointDofConstraintValues :
129 public std::map<unsigned int, DofConstraintValueMap,
130 std::less<unsigned int>,
131 Threads::scalable_allocator
132 <std::pair<const unsigned int, DofConstraintValueMap>>>
133 {
134 };
135
136 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
137 /**
138 * A row of the Node constraint mapping. Currently this just
139 * stores the topology of the constrained Nodes, but for forward
140 * compatibility we also include coefficients, so we could add
141 * Lagrange-positioned-node constraints later.
142 */
143 typedef std::map<const Node *, Real,
144 std::less<const Node *>,
145 Threads::scalable_allocator<std::pair<const Node * const, Real>>> NodeConstraintRow;
146
147 /**
148 * The Node constraint storage format.
149 * We're using a class instead of a typedef to allow forward
150 * declarations and future flexibility. Don't delete this from
151 * a pointer-to-std-map; the destructor isn't virtual!
152 */
153 class NodeConstraints : public std::map<const Node *,
154 std::pair<NodeConstraintRow,Point>,
155 std::less<const Node *>,
156 Threads::scalable_allocator<std::pair<const Node * const, std::pair<NodeConstraintRow,Point>>>>
157 {
158 };
159 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
160
161 #endif // LIBMESH_ENABLE_CONSTRAINTS
162
163
164
165 /**
166 * This class handles the numbering of degrees of freedom on a mesh.
167 * For systems of equations the class supports a fixed number of variables.
168 * The degrees of freedom are numbered such that sequential, contiguous blocks
169 * belong to distinct processors. This is so that the resulting data
170 * structures will work well with parallel linear algebra packages.
171 *
172 * \author Benjamin S. Kirk
173 * \date 2002-2007
174 * \brief Manages the degrees of freedom (DOFs) in a simulation.
175 */
176 class DofMap : public ReferenceCountedObject<DofMap>,
177 public ParallelObject
178 {
179 public:
180
181 /**
182 * Constructor. Requires the number of the system for which we
183 * will be numbering degrees of freedom & the parent object
184 * we are contained in, which defines our communication space.
185 */
186 explicit
187 DofMap(const unsigned int sys_number,
188 MeshBase & mesh);
189
190 /**
191 * Destructor.
192 */
193 ~DofMap();
194
195 /**
196 * Abstract base class to be used to add user-defined implicit
197 * degree of freedom couplings.
198 */
199 class AugmentSparsityPattern
200 {
201 public:
~AugmentSparsityPattern()202 virtual ~AugmentSparsityPattern () {}
203
204 /**
205 * User-defined function to augment the sparsity pattern.
206 */
207 virtual void augment_sparsity_pattern (SparsityPattern::Graph & sparsity,
208 std::vector<dof_id_type> & n_nz,
209 std::vector<dof_id_type> & n_oz) = 0;
210 };
211
212 /**
213 * Abstract base class to be used to add user-defined parallel
214 * degree of freedom couplings.
215 */
216 class AugmentSendList
217 {
218 public:
~AugmentSendList()219 virtual ~AugmentSendList () {}
220
221 /**
222 * User-defined function to augment the send list.
223 */
224 virtual void augment_send_list (std::vector<dof_id_type> & send_list) = 0;
225 };
226
227 /**
228 * Additional matrices may be handled with this \p DofMap.
229 * They are initialized to the same sparsity structure as
230 * the major matrix.
231 */
232 void attach_matrix (SparseMatrix<Number> & matrix);
233
234 /**
235 * Matrices should not be attached more than once. We can test for
236 * an already-attached matrix if necessary using \p is_attached
237 */
238 bool is_attached (SparseMatrix<Number> & matrix);
239
240 /**
241 * Distribute dofs on the current mesh. Also builds the send list for
242 * processor \p proc_id, which defaults to 0 for ease of use in serial
243 * applications.
244 */
245 void distribute_dofs (MeshBase &);
246
247 /**
248 * Computes the sparsity pattern for the matrices corresponding to
249 * \p proc_id and sends that data to Linear Algebra packages for
250 * preallocation of sparse matrices.
251 */
252 void compute_sparsity (const MeshBase &);
253
254 /**
255 * Clears the sparsity pattern
256 */
257 void clear_sparsity();
258
259 /**
260 * Remove any default ghosting functor(s). User-added ghosting
261 * functors will be unaffected.
262 *
263 * Unless user-added equivalent ghosting functors exist, removing
264 * the default coupling functor is only safe for explicit solves,
265 * and removing the default algebraic ghosting functor is only safe
266 * for codes where no evaluations on neighbor cells (e.g. no jump
267 * error estimators) are done.
268 *
269 * Defaults can be restored manually via add_default_ghosting(), or
270 * automatically if clear() returns the DofMap to a default state.
271 */
272 void remove_default_ghosting();
273
274 /**
275 * Add the default functor(s) for coupling and algebraic ghosting.
276 * User-added ghosting functors will be unaffected.
277 */
278 void add_default_ghosting();
279
280 /**
281 * Adds a functor which can specify coupling requirements for
282 * creation of sparse matrices.
283 * Degree of freedom pairs which match the elements and variables
284 * returned by these functors will be added to the sparsity pattern,
285 * and the degrees of freedom which live on other processors will be
286 * added to the send_list for use on ghosted vectors, and the
287 * elements which live on other processors will be ghosted on a
288 * distributed mesh.
289 *
290 * GhostingFunctor memory must be managed by the code which calls
291 * this function; the GhostingFunctor lifetime is expected to extend
292 * until either the functor is removed or the DofMap is destructed.
293 *
294 * When \p to_mesh is true, the \p coupling_functor is also added to
295 * our associated mesh, to ensure that coupled elements do not get
296 * lost during mesh distribution. (if coupled elements were
297 * *already* lost there's no getting them back after the fact,
298 * sorry)
299 *
300 * If \p to_mesh is false, no change to mesh ghosting is made;
301 * the Mesh must already have ghosting functor(s) specifying a
302 * superset of \p coupling_functor or this is a horrible bug.
303 */
304 void add_coupling_functor(GhostingFunctor & coupling_functor,
305 bool to_mesh = true);
306
307 /**
308 * Adds a functor which can specify coupling requirements for
309 * creation of sparse matrices.
310 *
311 * GhostingFunctor memory when using this method is managed by the
312 * shared_ptr mechanism.
313 */
314 void add_coupling_functor(std::shared_ptr<GhostingFunctor> coupling_functor,
315 bool to_mesh = true)
316 { _shared_functors[coupling_functor.get()] = coupling_functor;
317 this->add_coupling_functor(*coupling_functor, to_mesh); }
318
319 /**
320 * Removes a functor which was previously added to the set of
321 * coupling functors, from both this DofMap and from the underlying
322 * mesh.
323 */
324 void remove_coupling_functor(GhostingFunctor & coupling_functor);
325
326 /**
327 * Beginning of range of coupling functors
328 */
coupling_functors_begin()329 std::set<GhostingFunctor *>::const_iterator coupling_functors_begin() const
330 { return _coupling_functors.begin(); }
331
332 /**
333 * End of range of coupling functors
334 */
coupling_functors_end()335 std::set<GhostingFunctor *>::const_iterator coupling_functors_end() const
336 { return _coupling_functors.end(); }
337
338 /**
339 * Default coupling functor
340 */
default_coupling()341 DefaultCoupling & default_coupling() { return *_default_coupling; }
342
343 /**
344 * Adds a functor which can specify algebraic ghosting requirements
345 * for use with distributed vectors. Degrees of freedom on other
346 * processors which match the elements and variables returned by
347 * these functors will be added to the send_list, and the elements
348 * on other processors will be ghosted on a distributed mesh, so
349 * that the elements can always be found and the solutions on them
350 * will always be evaluable.
351 *
352 * GhostingFunctor memory must be managed by the code which calls
353 * this function; the GhostingFunctor lifetime is expected to extend
354 * until either the functor is removed or the DofMap is destructed.
355 *
356 * When \p to_mesh is true, the \p coupling_functor is also added to
357 * our associated mesh, to ensure that evaluable elements do not get
358 * lost during mesh distribution. (if evaluable elements were
359 * *already* lost there's no getting them back after the fact,
360 * sorry)
361 *
362 * If \p to_mesh is false, no change to mesh ghosting is made;
363 * the Mesh must already have ghosting functor(s) specifying a
364 * superset of \p evaluable_functor or this is a horrible bug.
365 */
366 void add_algebraic_ghosting_functor(GhostingFunctor & evaluable_functor,
367 bool to_mesh = true);
368
369 /**
370 * Adds a functor which can specify algebraic ghosting requirements
371 * for use with distributed vectors.
372 *
373 * GhostingFunctor memory when using this method is managed by the
374 * shared_ptr mechanism.
375 */
376 void add_algebraic_ghosting_functor(std::shared_ptr<GhostingFunctor> evaluable_functor,
377 bool to_mesh = true)
378 { _shared_functors[evaluable_functor.get()] = evaluable_functor;
379 this->add_algebraic_ghosting_functor(*evaluable_functor, to_mesh); }
380
381 /**
382 * Removes a functor which was previously added to the set of
383 * algebraic ghosting functors, from both this DofMap and from the
384 * underlying mesh.
385 */
386 void remove_algebraic_ghosting_functor(GhostingFunctor & evaluable_functor);
387
388 /**
389 * Beginning of range of algebraic ghosting functors
390 */
algebraic_ghosting_functors_begin()391 std::set<GhostingFunctor *>::const_iterator algebraic_ghosting_functors_begin() const
392 { return _algebraic_ghosting_functors.begin(); }
393
394 /**
395 * End of range of algebraic ghosting functors
396 */
algebraic_ghosting_functors_end()397 std::set<GhostingFunctor *>::const_iterator algebraic_ghosting_functors_end() const
398 { return _algebraic_ghosting_functors.end(); }
399
400 /**
401 * Default algebraic ghosting functor
402 */
default_algebraic_ghosting()403 DefaultCoupling & default_algebraic_ghosting() { return *_default_evaluating; }
404
405 /**
406 * Attach an object to use to populate the
407 * sparsity pattern with extra entries.
408 *
409 * Care must be taken that when adding entries they are sorted into the Rows
410 *
411 * Further, you _must_ modify n_nz and n_oz properly!
412 *
413 * This is an advanced function... use at your own peril!
414 */
attach_extra_sparsity_object(DofMap::AugmentSparsityPattern & asp)415 void attach_extra_sparsity_object (DofMap::AugmentSparsityPattern & asp)
416 {
417 _augment_sparsity_pattern = &asp;
418 }
419
420 /**
421 * Attach a function pointer to use as a callback to populate the
422 * sparsity pattern with extra entries.
423 *
424 * Care must be taken that when adding entries they are sorted into the Rows
425 *
426 * Further, you _must_ modify n_nz and n_oz properly!
427 *
428 * This is an advanced function... use at your own peril!
429 */
430 void attach_extra_sparsity_function(void (*func)(SparsityPattern::Graph & sparsity,
431 std::vector<dof_id_type> & n_nz,
432 std::vector<dof_id_type> & n_oz,
433 void *),
434 void * context = nullptr)
435 { _extra_sparsity_function = func; _extra_sparsity_context = context; }
436
437 /**
438 * Attach an object to populate the send_list with extra entries.
439 * This should only add to the send list, but no checking is done
440 * to enforce this behavior.
441 *
442 * This is an advanced function... use at your own peril!
443 */
attach_extra_send_list_object(DofMap::AugmentSendList & asl)444 void attach_extra_send_list_object (DofMap::AugmentSendList & asl)
445 {
446 _augment_send_list = &asl;
447 }
448
449 /**
450 * Attach a function pointer to use as a callback to populate the
451 * send_list with extra entries.
452 */
453 void attach_extra_send_list_function(void (*func)(std::vector<dof_id_type> &, void *),
454 void * context = nullptr)
455 { _extra_send_list_function = func; _extra_send_list_context = context; }
456
457 /**
458 * Takes the \p _send_list vector (which may have duplicate entries)
459 * and sorts it. The duplicate entries are then removed, resulting in
460 * a sorted \p _send_list with unique entries. Also calls any user-provided
461 * methods for adding to the send list.
462 */
463 void prepare_send_list ();
464
465 /**
466 * Clears the \p _send_list vector. This should be done in order to completely
467 * rebuild the send_list from scratch rather than merely adding to the existing
468 * send_list.
469 */
clear_send_list()470 void clear_send_list ()
471 {
472 _send_list.clear();
473 }
474
475 /**
476 * Clears the \p _send_list vector and then rebuilds it. This may be needed
477 * in special situations, for example when an algebraic coupling functor cannot
478 * be added to the \p DofMap until after it is completely setup. Then this method
479 * can be used to rebuild the send_list once the algebraic coupling functor is
480 * added. Note that while this will recommunicate constraints with the updated
481 * send_list, this does assume no new constraints have been added since the previous
482 * reinit_constraints call.
483 */
484 void reinit_send_list (MeshBase & mesh);
485
486
487 /**
488 * \returns A constant reference to the \p _send_list for this processor.
489 *
490 * The \p _send_list contains the global indices of all the
491 * variables in the global solution vector that influence the
492 * current processor. This information can be used for gathers at
493 * each solution step to retrieve solution values needed for
494 * computation.
495 */
get_send_list()496 const std::vector<dof_id_type> & get_send_list() const { return _send_list; }
497
498 /**
499 * \returns A constant reference to the \p _n_nz list for this processor.
500 *
501 * The vector contains the bandwidth of the on-processor coupling for each
502 * row of the global matrix that the current processor owns. This
503 * information can be used to preallocate space for a parallel sparse matrix.
504 */
get_n_nz()505 const std::vector<dof_id_type> & get_n_nz() const
506 {
507 libmesh_assert(_n_nz);
508 return *_n_nz;
509 }
510
511 /**
512 * \returns A constant reference to the \p _n_oz list for this processor.
513 *
514 * The vector contains the bandwidth of the off-processor coupling for each
515 * row of the global matrix that the current processor owns. This
516 * information can be used to preallocate space for a parallel sparse matrix.
517 */
get_n_oz()518 const std::vector<dof_id_type> & get_n_oz() const
519 {
520 libmesh_assert(_n_oz);
521 return *_n_oz;
522 }
523
524 // /**
525 // * Add an unknown of order \p order and finite element type
526 // * \p type to the system of equations.
527 // */
528 // void add_variable (const Variable & var);
529
530 /**
531 * Add a group of unknowns of order \p order and finite element type
532 * \p type to the system of equations.
533 */
534 void add_variable_group (const VariableGroup & var_group);
535
536 /**
537 * Specify whether or not we perform an extra (opt-mode enabled) check
538 * for constraint loops. If a constraint loop is present then
539 * the system constraints are not valid, so if \p error_on_constraint_loop
540 * is true we will throw an error in this case.
541 *
542 * \note We previously referred to these types of constraints as
543 * "cyclic" but that has now been deprecated, and these will now
544 * instead be referred to as "constraint loops" in libMesh.
545 */
546 void set_error_on_cyclic_constraint(bool error_on_cyclic_constraint);
547 void set_error_on_constraint_loop(bool error_on_constraint_loop);
548
549 /**
550 * \returns The \p VariableGroup description object for group \p g.
551 */
552 const VariableGroup & variable_group (const unsigned int c) const;
553
554 /**
555 * \returns The variable description object for variable \p c.
556 */
557 const Variable & variable (const unsigned int c) const;
558
559 /**
560 * \returns The approximation order for variable \p c.
561 */
562 Order variable_order (const unsigned int c) const;
563
564 /**
565 * \returns The approximation order for \p VariableGroup \p vg.
566 */
567 Order variable_group_order (const unsigned int vg) const;
568
569 /**
570 * \returns The finite element type for variable \p c.
571 */
572 const FEType & variable_type (const unsigned int c) const;
573
574 /**
575 * \returns The finite element type for \p VariableGroup \p vg.
576 */
577 const FEType & variable_group_type (const unsigned int vg) const;
578
579 /**
580 * \returns The number of variables in the global solution vector. Defaults
581 * to 1, should be 1 for a scalar equation, 3 for 2D incompressible Navier
582 * Stokes (u,v,p), etc...
583 */
n_variable_groups()584 unsigned int n_variable_groups() const
585 { return cast_int<unsigned int>(_variable_groups.size()); }
586
587 /**
588 * \returns The number of variables in the global solution vector. Defaults
589 * to 1, should be 1 for a scalar equation, 3 for 2D incompressible Navier
590 * Stokes (u,v,p), etc...
591 */
n_variables()592 unsigned int n_variables() const
593 { return cast_int<unsigned int>(_variables.size()); }
594
595 /**
596 * \returns \p true if the variables are capable of being stored in a blocked
597 * form. Presently, this means that there can only be one variable group,
598 * and that the group has more than one variable.
599 */
has_blocked_representation()600 bool has_blocked_representation() const
601 {
602 return ((this->n_variable_groups() == 1) && (this->n_variables() > 1));
603 }
604
605 /**
606 * \returns The block size, if the variables are amenable to block storage.
607 * Otherwise 1.
608 * This routine was originally designed to enable a blocked storage, but
609 * it turns out this information is still super useful for solvers even when
610 * we do not use the blocked storage (e.g., MATMPIBAIJ in PETSc). For example (in PCHMG),
611 * for a system of PDEs, to construct an efficient multilevel preconditioner, we coarsen
612 * the matrix of one single PDE instead of the entire huge matrix. In order to
613 * accomplish this, we need to know many PDEs we have. Another use case,
614 * the fieldsplit preconditioner can be constructed in place with this info wihtout
615 * involving any user efforts.
616 */
block_size()617 unsigned int block_size() const
618 {
619 return (this->has_blocked_representation() ? this->n_variables() : 1);
620 }
621
622 /**
623 * \returns The total number of degrees of freedom in the problem.
624 */
n_dofs()625 dof_id_type n_dofs() const { return _n_dfs; }
626
627 /**
628 * \returns The number of SCALAR dofs.
629 */
n_SCALAR_dofs()630 dof_id_type n_SCALAR_dofs() const { return _n_SCALAR_dofs; }
631
632 /**
633 * \returns The number of degrees of freedom on this processor.
634 */
n_local_dofs()635 dof_id_type n_local_dofs () const
636 { return this->n_dofs_on_processor (this->processor_id()); }
637
638 /**
639 * \returns The number of degrees of freedom on partition \p proc.
640 */
n_dofs_on_processor(const processor_id_type proc)641 dof_id_type n_dofs_on_processor(const processor_id_type proc) const
642 {
643 libmesh_assert_less (proc, _first_df.size());
644 return cast_int<dof_id_type>(_end_df[proc] - _first_df[proc]);
645 }
646
647 /**
648 * \returns The first dof index that is local to partition \p proc.
649 */
first_dof(const processor_id_type proc)650 dof_id_type first_dof(const processor_id_type proc) const
651 { libmesh_assert_less (proc, _first_df.size()); return _first_df[proc]; }
652
first_dof()653 dof_id_type first_dof() const
654 { return this->first_dof(this->processor_id()); }
655
656 #ifdef LIBMESH_ENABLE_AMR
657 /**
658 * \returns The first old dof index that is local to partition \p proc.
659 */
first_old_dof(const processor_id_type proc)660 dof_id_type first_old_dof(const processor_id_type proc) const
661 { libmesh_assert_less (proc, _first_old_df.size()); return _first_old_df[proc]; }
662
first_old_dof()663 dof_id_type first_old_dof() const
664 { return this->first_old_dof(this->processor_id()); }
665
666 #endif //LIBMESH_ENABLE_AMR
667
668 /**
669 * \returns The first dof index that is after all indices local to
670 * processor \p proc.
671 *
672 * Analogous to the end() member function of STL containers.
673 */
end_dof(const processor_id_type proc)674 dof_id_type end_dof(const processor_id_type proc) const
675 { libmesh_assert_less (proc, _end_df.size()); return _end_df[proc]; }
676
end_dof()677 dof_id_type end_dof() const
678 { return this->end_dof(this->processor_id()); }
679
680 /**
681 * \returns The processor id that owns the dof index \p dof
682 */
dof_owner(const dof_id_type dof)683 processor_id_type dof_owner(const dof_id_type dof) const
684 { std::vector<dof_id_type>::const_iterator ub =
685 std::upper_bound(_end_df.begin(), _end_df.end(), dof);
686 libmesh_assert (ub != _end_df.end());
687 return cast_int<processor_id_type>(ub - _end_df.begin());
688 }
689
690 #ifdef LIBMESH_ENABLE_AMR
691 /**
692 * \returns The first old dof index that is after all indices local
693 * to processor \p proc.
694 *
695 * Analogous to the end() member function of STL containers.
696 */
end_old_dof(const processor_id_type proc)697 dof_id_type end_old_dof(const processor_id_type proc) const
698 { libmesh_assert_less (proc, _end_old_df.size()); return _end_old_df[proc]; }
699
end_old_dof()700 dof_id_type end_old_dof() const
701 { return this->end_old_dof(this->processor_id()); }
702
703 #endif //LIBMESH_ENABLE_AMR
704
705 /**
706 * Fills the vector \p di with the global degree of freedom indices
707 * for the element.
708 */
709 void dof_indices (const Elem * const elem,
710 std::vector<dof_id_type> & di) const;
711
712 /**
713 * Fills the vector \p di with the global degree of freedom indices
714 * for the element. For one variable, and potentially for a
715 * non-default element p refinement level
716 */
717 void dof_indices (const Elem * const elem,
718 std::vector<dof_id_type> & di,
719 const unsigned int vn,
720 int p_level = -12345) const;
721
722 /**
723 * Fills the vector \p di with the global degree of freedom indices
724 * for the \p node.
725 */
726 void dof_indices (const Node * const node,
727 std::vector<dof_id_type> & di) const;
728
729 /**
730 * Fills the vector \p di with the global degree of freedom indices
731 * for the \p node, for one variable \p vn.
732 */
733 void dof_indices (const Node * const node,
734 std::vector<dof_id_type> & di,
735 const unsigned int vn) const;
736
737 /**
738 * Appends to the vector \p di the global degree of freedom indices
739 * for \p elem.node_ref(n), for one variable \p vn. On hanging
740 * nodes with both vertex and non-vertex DoFs, only those indices
741 * which are directly supported on \p elem are included.
742 */
743 void dof_indices (const Elem & elem,
744 unsigned int n,
745 std::vector<dof_id_type> & di,
746 const unsigned int vn) const;
747
748 #ifdef LIBMESH_ENABLE_AMR
749
750 /**
751 * Appends to the vector \p di the old global degree of freedom
752 * indices for \p elem.node_ref(n), for one variable \p vn. On
753 * hanging nodes with both vertex and non-vertex DoFs, only those
754 * indices which are directly supported on \p elem are included.
755 */
756 void old_dof_indices (const Elem & elem,
757 unsigned int n,
758 std::vector<dof_id_type> & di,
759 const unsigned int vn) const;
760
761 #endif // LIBMESH_ENABLE_AMR
762
763 /**
764 * Fills the vector \p di with the global degree of freedom indices
765 * corresponding to the SCALAR variable vn. If old_dofs=true,
766 * the old SCALAR dof indices are returned.
767 *
768 * \note We do not need to pass in an element since SCALARs are
769 * global variables.
770 */
771 void SCALAR_dof_indices (std::vector<dof_id_type> & di,
772 const unsigned int vn,
773 const bool old_dofs=false) const;
774
775 /**
776 * \returns \p true if degree of freedom index \p dof_index
777 * is either a local index or in the \p send_list.
778 *
779 * \note This is an O(logN) operation for a send_list of size N; we
780 * don't cache enough information for O(1) right now.
781 */
782 bool semilocal_index (dof_id_type dof_index) const;
783
784 /**
785 * \returns \p true if all degree of freedom indices in \p
786 * dof_indices are either local indices or in the \p send_list.
787 *
788 * \note This is an O(logN) operation for a send_list of size N; we
789 * don't cache enough information for O(1) right now.
790 */
791 bool all_semilocal_indices (const std::vector<dof_id_type> & dof_indices) const;
792
793 /**
794 * \returns \p true if degree of freedom index \p dof_index
795 * is a local index.
796 */
local_index(dof_id_type dof_index)797 bool local_index (dof_id_type dof_index) const
798 { return (dof_index >= this->first_dof()) && (dof_index < this->end_dof()); }
799
800 /**
801 * \returns \p true iff our solutions can be locally evaluated on
802 * \p obj (which should be an Elem or a Node) for variable number \p
803 * var_num (for all variables, if \p var_num is invalid_uint)
804 */
805 template <typename DofObjectSubclass>
806 bool is_evaluable(const DofObjectSubclass & obj,
807 unsigned int var_num = libMesh::invalid_uint) const;
808
809 /**
810 * Allow the implicit_neighbor_dofs flag to be set programmatically.
811 * This overrides the --implicit_neighbor_dofs commandline option.
812 * We can use this to set the implicit neighbor dofs option differently
813 * for different systems, whereas the commandline option is the same
814 * for all systems.
815 */
816 void set_implicit_neighbor_dofs(bool implicit_neighbor_dofs);
817
818 /**
819 * Tells other library functions whether or not this problem
820 * includes coupling between dofs in neighboring cells, as can
821 * currently be specified on the command line or inferred from
822 * the use of all discontinuous variables.
823 */
824 bool use_coupled_neighbor_dofs(const MeshBase & mesh) const;
825
826 /**
827 * Builds the local element vector \p Ue from the global vector \p Ug,
828 * accounting for any constrained degrees of freedom. For an element
829 * without constrained degrees of freedom this is the trivial mapping
830 * \f$ Ue[i] = Ug[dof_indices[i]] \f$
831 *
832 * \note The user must ensure that the element vector \p Ue is
833 * properly sized when calling this method. This is because there
834 * is no \p resize() method in the \p DenseVectorBase<> class.
835 */
836 void extract_local_vector (const NumericVector<Number> & Ug,
837 const std::vector<dof_id_type> & dof_indices,
838 DenseVectorBase<Number> & Ue) const;
839
840 /**
841 * Fills an array of those dof indices which belong to the given
842 * variable number and live on the current processor.
843 */
844 void local_variable_indices(std::vector<dof_id_type> & idx,
845 const MeshBase & mesh,
846 unsigned int var_num) const;
847
848 #ifdef LIBMESH_ENABLE_CONSTRAINTS
849
850 //--------------------------------------------------------------------
851 // Constraint-specific methods
852 /**
853 * \returns The total number of constrained degrees of freedom
854 * in the problem.
855 */
856 dof_id_type n_constrained_dofs() const;
857
858 /**
859 * \returns The number of constrained degrees of freedom
860 * on this processor.
861 */
862 dof_id_type n_local_constrained_dofs() const;
863
864 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
865 /**
866 * \returns The total number of constrained Nodes
867 * in the mesh.
868 */
n_constrained_nodes()869 dof_id_type n_constrained_nodes() const
870 { return cast_int<dof_id_type>(_node_constraints.size()); }
871 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
872
873 /**
874 * Rebuilds the raw degree of freedom and DofObject constraints.
875 * A time is specified for use in building time-dependent Dirichlet
876 * constraints.
877 */
878 void create_dof_constraints (const MeshBase &, Real time=0);
879
880 /**
881 * Gathers constraint equation dependencies from other processors
882 */
883 void allgather_recursive_constraints (MeshBase &);
884
885 /**
886 * Sends constraint equations to constraining processors
887 */
888 void scatter_constraints (MeshBase &);
889
890 /**
891 * Helper function for querying about constraint equations on other
892 * processors. If any id in \p requested_dof_ids is constrained on
893 * another processor, its constraint will be added on this processor
894 * as well. If \p look_for_constrainees is true, then constraints
895 * will also be returned if the id appears as a constraining value
896 * not just if it appears as a constrained value.
897 *
898 * This function operates recursively: if the constraint for a
899 * constrained dof is newly added locally, then any other dofs which
900 * constrain it are queried to see if they are in turn constrained,
901 * and so on.
902 */
903 void gather_constraints (MeshBase & mesh,
904 std::set<dof_id_type> & unexpanded_dofs,
905 bool look_for_constrainees);
906
907 /**
908 * Postprocesses any constrained degrees of freedom
909 * to be constrained only in terms of unconstrained dofs, then adds
910 * unconstrained dofs to the send_list and prepares that for use.
911 * This should be run after both system (create_dof_constraints) and
912 * user constraints have all been added.
913 */
914 void process_constraints (MeshBase &);
915
916 /**
917 * Throw an error if we detect any constraint loops, i.e.
918 * A -> B -> C -> A
919 * that is, "dof A is constrained in terms of dof B which is
920 * constrained in terms of dof C which is constrained in terms of
921 * dof A", since these are not supported by libMesh and give
922 * erroneous results if they are present.
923 *
924 * \note The original "cyclic constraint" terminology was
925 * unfortunate since the word cyclic is used by some software to
926 * indicate an actual type of rotational/angular contraint and not
927 * (as here) a cyclic graph. The former nomenclature will eventually
928 * be deprecated in favor of "constraint loop".
929 */
930 void check_for_cyclic_constraints();
931 void check_for_constraint_loops();
932
933 /**
934 * Adds a copy of the user-defined row to the constraint matrix, using
935 * an inhomogeneous right-hand-side for the constraint equation.
936 */
937 void add_constraint_row (const dof_id_type dof_number,
938 const DofConstraintRow & constraint_row,
939 const Number constraint_rhs,
940 const bool forbid_constraint_overwrite);
941
942 /**
943 * Adds a copy of the user-defined row to the constraint matrix,
944 * using an inhomogeneous right-hand-side for the adjoint constraint
945 * equation.
946 *
947 * \p forbid_constraint_overwrite here only tests for overwriting
948 * the rhs. This method should only be used when an equivalent
949 * constraint (with a potentially different rhs) already exists for
950 * the primal problem.
951 */
952 void add_adjoint_constraint_row (const unsigned int qoi_index,
953 const dof_id_type dof_number,
954 const DofConstraintRow & constraint_row,
955 const Number constraint_rhs,
956 const bool forbid_constraint_overwrite);
957
958 /**
959 * Adds a copy of the user-defined row to the constraint matrix, using
960 * a homogeneous right-hand-side for the constraint equation.
961 * By default, produces an error if the DOF was already constrained.
962 */
963 void add_constraint_row (const dof_id_type dof_number,
964 const DofConstraintRow & constraint_row,
965 const bool forbid_constraint_overwrite = true)
966 { add_constraint_row(dof_number, constraint_row, 0., forbid_constraint_overwrite); }
967
968 /**
969 * \returns An iterator pointing to the first DoF constraint row.
970 */
constraint_rows_begin()971 DofConstraints::const_iterator constraint_rows_begin() const
972 { return _dof_constraints.begin(); }
973
974 /**
975 * \returns An iterator pointing just past the last DoF constraint row.
976 */
constraint_rows_end()977 DofConstraints::const_iterator constraint_rows_end() const
978 { return _dof_constraints.end(); }
979
stash_dof_constraints()980 void stash_dof_constraints()
981 {
982 libmesh_assert(_stashed_dof_constraints.empty());
983 _dof_constraints.swap(_stashed_dof_constraints);
984 }
985
unstash_dof_constraints()986 void unstash_dof_constraints()
987 {
988 libmesh_assert(_dof_constraints.empty());
989 _dof_constraints.swap(_stashed_dof_constraints);
990 }
991
992 /**
993 * Similar to the stash/unstash_dof_constraints() API, but swaps
994 * _dof_constraints and _stashed_dof_constraints without asserting
995 * that the source or destination is empty first.
996 *
997 * \note There is an implicit assumption that swapping between sets
998 * of Constraints does not change the sparsity pattern or expand the
999 * send_list, since the only thing changed is the DofConstraints
1000 * themselves. This is intended to work for swapping between
1001 * DofConstraints A and B, where A is used to define the send_list,
1002 * and B is a subset of A.
1003 */
swap_dof_constraints()1004 void swap_dof_constraints()
1005 {
1006 _dof_constraints.swap(_stashed_dof_constraints);
1007 }
1008
1009 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
1010 /**
1011 * \returns An iterator pointing to the first Node constraint row.
1012 */
node_constraint_rows_begin()1013 NodeConstraints::const_iterator node_constraint_rows_begin() const
1014 { return _node_constraints.begin(); }
1015
1016 /**
1017 * \returns An iterator pointing just past the last Node constraint row.
1018 */
node_constraint_rows_end()1019 NodeConstraints::const_iterator node_constraint_rows_end() const
1020 { return _node_constraints.end(); }
1021 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
1022
1023 /**
1024 * \returns \p true if the degree of freedom dof is constrained,
1025 * \p false otherwise.
1026 */
1027 bool is_constrained_dof (const dof_id_type dof) const;
1028
1029 /**
1030 * \returns \p true if the system has any heterogenous constraints for
1031 * adjoint solution \p qoi_num, \p false otherwise.
1032 */
1033 bool has_heterogenous_adjoint_constraints (const unsigned int qoi_num) const;
1034
1035 /**
1036 * \returns The heterogeneous constraint value if the degree of
1037 * freedom \p dof has a heterogenous constraint for adjoint solution
1038 * \p qoi_num, zero otherwise.
1039 */
1040 Number has_heterogenous_adjoint_constraint (const unsigned int qoi_num,
1041 const dof_id_type dof) const;
1042
1043 /**
1044 * \returns A reference to the set of right-hand-side values in
1045 * primal constraint equations
1046 */
1047 DofConstraintValueMap & get_primal_constraint_values();
1048
1049 /**
1050 * \returns \p true if the Node is constrained,
1051 * false otherwise.
1052 */
1053 bool is_constrained_node (const Node * node) const;
1054
1055 /**
1056 * Prints (from processor 0) all DoF and Node constraints. If \p
1057 * print_nonlocal is true, then each constraint is printed once for
1058 * each processor that knows about it, which may be useful for \p
1059 * DistributedMesh debugging.
1060 */
1061 void print_dof_constraints(std::ostream & os=libMesh::out,
1062 bool print_nonlocal=false) const;
1063
1064 /**
1065 * Gets a string reporting all DoF and Node constraints local to
1066 * this processor. If \p print_nonlocal is true, then nonlocal
1067 * constraints which are locally known are included.
1068 */
1069 std::string get_local_constraints(bool print_nonlocal=false) const;
1070
1071
1072 /**
1073 * Tests the constrained degrees of freedom on the numeric vector \p v, which
1074 * represents a solution defined on the mesh, returning a pair whose first
1075 * entry is the maximum absolute error on a constrained DoF and whose second
1076 * entry is the maximum relative error. Useful for debugging purposes.
1077 *
1078 * If \p v == nullptr, the system solution vector is tested.
1079 */
1080 std::pair<Real, Real> max_constraint_error(const System & system,
1081 NumericVector<Number> * v = nullptr) const;
1082
1083 #endif // LIBMESH_ENABLE_CONSTRAINTS
1084
1085 //--------------------------------------------------------------------
1086 // Constraint-specific methods
1087 // Some of these methods are enabled (but inlined away to nothing)
1088 // when constraints are disabled at configure-time. This is to
1089 // increase API compatibility of user code with different library
1090 // builds.
1091
1092 /**
1093 * Constrains the element matrix. This method requires the
1094 * element matrix to be square, in which case the elem_dofs
1095 * correspond to the global DOF indices of both the rows and
1096 * columns of the element matrix. For this case the rows
1097 * and columns of the matrix necessarily correspond to variables
1098 * of the same approximation order.
1099 *
1100 * If \p asymmetric_constraint_rows is set to true (as it is by
1101 * default), constraint row equations will be reinforced in a way
1102 * which breaks matrix symmetry but makes inexact linear solver
1103 * solutions more likely to satisfy hanging node constraints.
1104 */
1105 void constrain_element_matrix (DenseMatrix<Number> & matrix,
1106 std::vector<dof_id_type> & elem_dofs,
1107 bool asymmetric_constraint_rows = true) const;
1108
1109 /**
1110 * Constrains the element matrix. This method allows the
1111 * element matrix to be non-square, in which case the row_dofs
1112 * and col_dofs may be of different size and correspond to
1113 * variables approximated in different spaces.
1114 */
1115 void constrain_element_matrix (DenseMatrix<Number> & matrix,
1116 std::vector<dof_id_type> & row_dofs,
1117 std::vector<dof_id_type> & col_dofs,
1118 bool asymmetric_constraint_rows = true) const;
1119
1120 /**
1121 * Constrains the element vector.
1122 */
1123 void constrain_element_vector (DenseVector<Number> & rhs,
1124 std::vector<dof_id_type> & dofs,
1125 bool asymmetric_constraint_rows = true) const;
1126
1127 /**
1128 * Constrains the element matrix and vector. This method requires
1129 * the element matrix to be square, in which case the elem_dofs
1130 * correspond to the global DOF indices of both the rows and
1131 * columns of the element matrix. For this case the rows
1132 * and columns of the matrix necessarily correspond to variables
1133 * of the same approximation order.
1134 */
1135 void constrain_element_matrix_and_vector (DenseMatrix<Number> & matrix,
1136 DenseVector<Number> & rhs,
1137 std::vector<dof_id_type> & elem_dofs,
1138 bool asymmetric_constraint_rows = true) const;
1139
1140 /**
1141 * Constrains the element matrix and vector. This method requires
1142 * the element matrix to be square, in which case the elem_dofs
1143 * correspond to the global DOF indices of both the rows and
1144 * columns of the element matrix. For this case the rows
1145 * and columns of the matrix necessarily correspond to variables
1146 * of the same approximation order.
1147 *
1148 * The heterogenous version of this method creates linear systems in
1149 * which heterogenously constrained degrees of freedom will solve to
1150 * their correct offset values, as would be appropriate for finding
1151 * a solution to a linear problem in a single algebraic solve. The
1152 * non-heterogenous version of this method creates linear systems in
1153 * which even heterogenously constrained degrees of freedom are
1154 * solved without offset values taken into account, as would be
1155 * appropriate for finding linearized updates to a solution in which
1156 * heterogenous constraints are already satisfied.
1157 *
1158 * By default, the constraints for the primal solution of this
1159 * system are used. If a non-negative \p qoi_index is passed in,
1160 * then the constraints for the corresponding adjoint solution are
1161 * used instead.
1162 */
1163 void heterogenously_constrain_element_matrix_and_vector (DenseMatrix<Number> & matrix,
1164 DenseVector<Number> & rhs,
1165 std::vector<dof_id_type> & elem_dofs,
1166 bool asymmetric_constraint_rows = true,
1167 int qoi_index = -1) const;
1168
1169 /**
1170 * Constrains the element vector. This method requires
1171 * the element matrix to be square and not-yet-constrained, in which
1172 * case the elem_dofs correspond to the global DOF indices of both
1173 * the rows and columns of the element matrix.
1174 *
1175 * The heterogenous version of this method creates linear systems in
1176 * which heterogenously constrained degrees of freedom will solve to
1177 * their correct offset values, as would be appropriate for finding
1178 * a solution to a linear problem in a single algebraic solve. The
1179 * non-heterogenous version of this method creates linear systems in
1180 * which even heterogenously constrained degrees of freedom are
1181 * solved without offset values taken into account, as would be
1182 * appropriate for finding linearized updates to a solution in which
1183 * heterogenous constraints are already satisfied.
1184 *
1185 * By default, the constraints for the primal solution of this
1186 * system are used. If a non-negative \p qoi_index is passed in,
1187 * then the constraints for the corresponding adjoint solution are
1188 * used instead.
1189 */
1190 void heterogenously_constrain_element_vector (const DenseMatrix<Number> & matrix,
1191 DenseVector<Number> & rhs,
1192 std::vector<dof_id_type> & elem_dofs,
1193 bool asymmetric_constraint_rows = true,
1194 int qoi_index = -1) const;
1195
1196
1197
1198 /**
1199 * Constrains a dyadic element matrix B = v w'. This method
1200 * requires the element matrix to be square, in which case the
1201 * elem_dofs correspond to the global DOF indices of both the rows
1202 * and columns of the element matrix. For this case the rows and
1203 * columns of the matrix necessarily correspond to variables of the
1204 * same approximation order.
1205 */
1206 void constrain_element_dyad_matrix (DenseVector<Number> & v,
1207 DenseVector<Number> & w,
1208 std::vector<dof_id_type> & row_dofs,
1209 bool asymmetric_constraint_rows = true) const;
1210
1211 /**
1212 * Does not actually constrain anything, but modifies \p dofs in the
1213 * same way as any of the constrain functions would do, i.e. adds
1214 * those dofs in terms of which any of the existing dofs is
1215 * constrained.
1216 */
1217 void constrain_nothing (std::vector<dof_id_type> & dofs) const;
1218
1219 /**
1220 * Constrains the numeric vector \p v, which represents a solution defined on
1221 * the mesh. This may need to be used after a linear solve, if your linear
1222 * solver's solutions do not satisfy your DoF constraints to a tight enough
1223 * tolerance.
1224 *
1225 * If \p v == nullptr, the system solution vector is constrained
1226 *
1227 * If \p homogeneous == true, heterogeneous constraints are enforced
1228 * as if they were homogeneous. This might be appropriate for e.g. a
1229 * vector representing a difference between two
1230 * heterogeneously-constrained solutions.
1231 */
1232 void enforce_constraints_exactly (const System & system,
1233 NumericVector<Number> * v = nullptr,
1234 bool homogeneous = false) const;
1235
1236 /**
1237 * Heterogenously constrains the numeric vector \p v, which
1238 * represents an adjoint solution defined on the mesh for quantity
1239 * fo interest \p q. For homogeneous constraints, use \p
1240 * enforce_constraints_exactly instead
1241 */
1242 void enforce_adjoint_constraints_exactly (NumericVector<Number> & v,
1243 unsigned int q) const;
1244
1245 void enforce_constraints_on_residual (const NonlinearImplicitSystem & system,
1246 NumericVector<Number> * rhs,
1247 NumericVector<Number> const * solution,
1248 bool homogeneous = true) const;
1249
1250 void enforce_constraints_on_jacobian (const NonlinearImplicitSystem & system,
1251 SparseMatrix<Number> * jac) const;
1252
1253 #ifdef LIBMESH_ENABLE_PERIODIC
1254
1255 //--------------------------------------------------------------------
1256 // PeriodicBoundary-specific methods
1257
1258 /**
1259 * Adds a copy of the specified periodic boundary to the system.
1260 */
1261 void add_periodic_boundary (const PeriodicBoundaryBase & periodic_boundary);
1262
1263 /**
1264 * Add a periodic boundary pair
1265 *
1266 * \param boundary - primary boundary
1267 * \param inverse_boundary - inverse boundary
1268 */
1269 void add_periodic_boundary (const PeriodicBoundaryBase & boundary, const PeriodicBoundaryBase & inverse_boundary);
1270
1271 /**
1272 * \returns \p true if the boundary given by \p boundaryid is periodic,
1273 * false otherwise
1274 */
1275 bool is_periodic_boundary (const boundary_id_type boundaryid) const;
1276
get_periodic_boundaries()1277 PeriodicBoundaries * get_periodic_boundaries()
1278 {
1279 return _periodic_boundaries.get();
1280 }
1281
1282 #endif // LIBMESH_ENABLE_PERIODIC
1283
1284
1285 #ifdef LIBMESH_ENABLE_DIRICHLET
1286
1287 //--------------------------------------------------------------------
1288 // DirichletBoundary-specific methods
1289
1290 /**
1291 * Adds a copy of the specified Dirichlet boundary to the system.
1292 *
1293 * The constraints implied by DirichletBoundary objects are imposed
1294 * in the same order in which DirichletBoundary objects are added to
1295 * the DofMap. When multiple DirichletBoundary objects would impose
1296 * competing constraints on a given DOF, the *first*
1297 * DirichletBoundary to constrain the DOF "wins". This distinction
1298 * is important when e.g. two surfaces (sidesets) intersect. The
1299 * nodes on the intersection will be constrained according to
1300 * whichever sideset's DirichletBoundary object was added to the
1301 * DofMap first.
1302 */
1303 void add_dirichlet_boundary (const DirichletBoundary & dirichlet_boundary);
1304
1305 /**
1306 * Adds a copy of the specified Dirichlet boundary to the system,
1307 * corresponding to the adjoint problem defined by Quantity of
1308 * Interest \p q.
1309 */
1310 void add_adjoint_dirichlet_boundary (const DirichletBoundary & dirichlet_boundary,
1311 unsigned int q);
1312
1313 /**
1314 * Removes the specified Dirichlet boundary from the system.
1315 */
1316 void remove_dirichlet_boundary (const DirichletBoundary & dirichlet_boundary);
1317
1318 /**
1319 * Removes from the system the specified Dirichlet boundary for the
1320 * adjoint equation defined by Quantity of interest index q
1321 */
1322 void remove_adjoint_dirichlet_boundary (const DirichletBoundary & dirichlet_boundary,
1323 unsigned int q);
1324
get_dirichlet_boundaries()1325 const DirichletBoundaries * get_dirichlet_boundaries() const
1326 {
1327 return _dirichlet_boundaries.get();
1328 }
1329
get_dirichlet_boundaries()1330 DirichletBoundaries * get_dirichlet_boundaries()
1331 {
1332 return _dirichlet_boundaries.get();
1333 }
1334
1335 bool has_adjoint_dirichlet_boundaries(unsigned int q) const;
1336
1337 const DirichletBoundaries *
1338 get_adjoint_dirichlet_boundaries(unsigned int q) const;
1339
1340 DirichletBoundaries *
1341 get_adjoint_dirichlet_boundaries(unsigned int q);
1342
1343 #endif // LIBMESH_ENABLE_DIRICHLET
1344
1345
1346 #ifdef LIBMESH_ENABLE_AMR
1347
1348 //--------------------------------------------------------------------
1349 // AMR-specific methods
1350
1351 /**
1352 * After a mesh is refined and repartitioned it is possible that the
1353 * \p _send_list will need to be augmented. This is the case when an
1354 * element is refined and its children end up on different processors
1355 * than the parent. These children will need values from the parent
1356 * when projecting the solution onto the refined mesh, hence the parent's
1357 * DOF indices need to be included in the \p _send_list.
1358 */
1359 // void augment_send_list_for_projection(const MeshBase &);
1360
1361 #ifdef LIBMESH_ENABLE_AMR
1362
1363 /**
1364 * Fills the vector di with the global degree of freedom indices
1365 * for the element using the \p DofMap::old_dof_object.
1366 * If no variable number is specified then all
1367 * variables are returned.
1368 */
1369 void old_dof_indices (const Elem * const elem,
1370 std::vector<dof_id_type> & di,
1371 const unsigned int vn = libMesh::invalid_uint) const;
1372
1373 /**
1374 * \returns The total number of degrees of freedom on old_dof_objects
1375 */
n_old_dofs()1376 dof_id_type n_old_dofs() const { return _n_old_dfs; }
1377
1378 #endif // LIBMESH_ENABLE_AMR
1379
1380 /**
1381 * Constrains degrees of freedom on side \p s of element \p elem which
1382 * correspond to variable number \p var and to p refinement levels
1383 * above \p p.
1384 */
1385 void constrain_p_dofs (unsigned int var,
1386 const Elem * elem,
1387 unsigned int s,
1388 unsigned int p);
1389
1390 #endif // LIBMESH_ENABLE_AMR
1391
1392 /**
1393 * Reinitialize the underlying data structures conformal to the current mesh.
1394 */
1395 void reinit (MeshBase & mesh);
1396
1397 /**
1398 * Free all new memory associated with the object, but restore its
1399 * original state, with the mesh pointer and any default ghosting.
1400 */
1401 void clear ();
1402
1403 /**
1404 * Prints summary info about the sparsity bandwidth and constraints.
1405 */
1406 void print_info(std::ostream & os=libMesh::out) const;
1407
1408 /**
1409 * Gets summary info about the sparsity bandwidth and constraints.
1410 */
1411 std::string get_info() const;
1412
1413 /**
1414 * Degree of freedom coupling. If left empty each DOF
1415 * couples to all others. Can be used to reduce memory
1416 * requirements for sparse matrices. DOF 0 might only
1417 * couple to itself, in which case \p dof_coupling(0,0)
1418 * should be 1 and \p dof_coupling(0,j) = 0 for j not equal
1419 * to 0.
1420 *
1421 * This variable is named as though it were class private,
1422 * but it is in the public interface. Also there are no
1423 * public methods for accessing it... This typically means
1424 * you should only use it if you know what you are doing.
1425 */
1426 CouplingMatrix * _dof_coupling;
1427
1428 /**
1429 * \returns The number of the system we are responsible for.
1430 */
1431 unsigned int sys_number() const;
1432
1433 private:
1434
1435 /**
1436 * Helper function that gets the dof indices on the current element
1437 * for a non-SCALAR type variable, where the variable is identified
1438 * by its variable group number \p vg and its offset \p vig from the
1439 * first variable in that group.
1440 *
1441 * In DEBUG mode, the tot_size parameter will add up the total
1442 * number of dof indices that should have been added to di, and v
1443 * will be the variable number corresponding to vg and vig.
1444 */
1445 void _dof_indices (const Elem & elem,
1446 int p_level,
1447 std::vector<dof_id_type> & di,
1448 const unsigned int vg,
1449 const unsigned int vig,
1450 const Node * const * nodes,
1451 unsigned int n_nodes
1452 #ifdef DEBUG
1453 ,
1454 const unsigned int v,
1455 std::size_t & tot_size
1456 #endif
1457 ) const;
1458
1459 /**
1460 * Helper function that implements the element-nodal versions of
1461 * dof_indices and old_dof_indices
1462 */
1463 void _node_dof_indices (const Elem & elem,
1464 unsigned int n,
1465 const DofObject & obj,
1466 std::vector<dof_id_type> & di,
1467 const unsigned int vn) const;
1468
1469 /**
1470 * Builds a sparsity pattern
1471 */
1472 std::unique_ptr<SparsityPattern::Build> build_sparsity(const MeshBase & mesh) const;
1473
1474 /**
1475 * Invalidates all active DofObject dofs for this system
1476 */
1477 void invalidate_dofs(MeshBase & mesh) const;
1478
1479 /**
1480 * \returns The Node pointer with index \p i from the \p mesh.
1481 */
1482 DofObject * node_ptr(MeshBase & mesh, dof_id_type i) const;
1483
1484 /**
1485 * \returns The Elem pointer with index \p i from the \p mesh.
1486 */
1487 DofObject * elem_ptr(MeshBase & mesh, dof_id_type i) const;
1488
1489 /**
1490 * A member function type like \p node_ptr() or \p elem_ptr().
1491 */
1492 typedef DofObject * (DofMap::*dofobject_accessor)
1493 (MeshBase & mesh, dof_id_type i) const;
1494
1495 /**
1496 * Helper function for distributing dofs in parallel
1497 */
1498 template<typename iterator_type>
1499 void set_nonlocal_dof_objects(iterator_type objects_begin,
1500 iterator_type objects_end,
1501 MeshBase & mesh,
1502 dofobject_accessor objects);
1503
1504 /**
1505 * Distributes the global degrees of freedom, for dofs on
1506 * this processor. In this format the local
1507 * degrees of freedom are in a contiguous block for each
1508 * variable in the system.
1509 * Starts at index next_free_dof, and increments it to
1510 * the post-final index.
1511 */
1512 void distribute_local_dofs_var_major (dof_id_type & next_free_dof,
1513 MeshBase & mesh);
1514
1515 /**
1516 * Distributes the global degrees of freedom for dofs on this
1517 * processor. In this format all the degrees of freedom at a
1518 * node/element are in contiguous blocks. Starts at index \p
1519 * next_free_dof, and increments it to the post-final index. If \p
1520 * build_send_list is \p true, builds the send list. If \p false,
1521 * clears and reserves the send list.
1522 *
1523 * \note The degrees of freedom for a given variable are not in
1524 * contiguous blocks, as in the case of \p distribute_local_dofs_var_major.
1525 */
1526 void distribute_local_dofs_node_major (dof_id_type & next_free_dof,
1527 MeshBase & mesh);
1528
1529 /*
1530 * A utility method for obtaining a set of elements to ghost along
1531 * with merged coupling matrices.
1532 */
1533 static void
1534 merge_ghost_functor_outputs (GhostingFunctor::map_type & elements_to_ghost,
1535 std::set<CouplingMatrix *> & temporary_coupling_matrices,
1536 const std::set<GhostingFunctor *>::iterator & gf_begin,
1537 const std::set<GhostingFunctor *>::iterator & gf_end,
1538 const MeshBase::const_element_iterator & elems_begin,
1539 const MeshBase::const_element_iterator & elems_end,
1540 processor_id_type p);
1541
1542 /**
1543 * Adds entries to the \p _send_list vector corresponding to DoFs
1544 * on elements neighboring the current processor.
1545 */
1546 void add_neighbors_to_send_list(MeshBase & mesh);
1547
1548 #ifdef LIBMESH_ENABLE_CONSTRAINTS
1549
1550 /**
1551 * Build the constraint matrix C associated with the element
1552 * degree of freedom indices elem_dofs. The optional parameter
1553 * \p called_recursively should be left at the default value
1554 * \p false. This is used to handle the special case of
1555 * an element's degrees of freedom being constrained in terms
1556 * of other, local degrees of freedom. The usual case is
1557 * for an elements DOFs to be constrained by some other,
1558 * external DOFs.
1559 */
1560 void build_constraint_matrix (DenseMatrix<Number> & C,
1561 std::vector<dof_id_type> & elem_dofs,
1562 const bool called_recursively=false) const;
1563
1564 /**
1565 * Build the constraint matrix C and the forcing vector H
1566 * associated with the element degree of freedom indices elem_dofs.
1567 * The optional parameter \p called_recursively should be left at
1568 * the default value \p false. This is used to handle the special
1569 * case of an element's degrees of freedom being constrained in
1570 * terms of other, local degrees of freedom. The usual case is for
1571 * an elements DOFs to be constrained by some other, external DOFs
1572 * and/or Dirichlet conditions.
1573 *
1574 * The forcing vector will depend on which solution's heterogenous
1575 * constraints are being applied. For the default \p qoi_index this
1576 * will be the primal solution; for \p qoi_index >= 0 the
1577 * corresponding adjoint solution's constraints will be used.
1578 */
1579 void build_constraint_matrix_and_vector (DenseMatrix<Number> & C,
1580 DenseVector<Number> & H,
1581 std::vector<dof_id_type> & elem_dofs,
1582 int qoi_index = -1,
1583 const bool called_recursively=false) const;
1584
1585 /**
1586 * Finds all the DOFS associated with the element DOFs elem_dofs.
1587 * This will account for off-element couplings via hanging nodes.
1588 */
1589 void find_connected_dofs (std::vector<dof_id_type> & elem_dofs) const;
1590
1591 /**
1592 * Finds all the DofObjects associated with the set in \p objs.
1593 * This will account for off-element couplings via hanging nodes.
1594 */
1595 void find_connected_dof_objects (std::vector<const DofObject *> & objs) const;
1596
1597 /**
1598 * Adds entries to the \p _send_list vector corresponding to DoFs
1599 * which are dependencies for constraint equations on the current
1600 * processor.
1601 */
1602 void add_constraints_to_send_list();
1603
1604 #endif // LIBMESH_ENABLE_CONSTRAINTS
1605
1606 /**
1607 * This flag indicates whether or not we do an opt-mode check for
1608 * the presence of constraint loops, i.e. cases where the constraint
1609 * graph is cyclic.
1610 */
1611 bool _error_on_constraint_loop;
1612
1613 /**
1614 * The finite element type for each variable.
1615 */
1616 std::vector<Variable> _variables;
1617
1618 /**
1619 * The finite element type for each variable group.
1620 */
1621 std::vector<VariableGroup> _variable_groups;
1622
1623 /**
1624 * The variable group number for each variable.
1625 */
1626 std::vector<unsigned int> _variable_group_numbers;
1627
1628 /**
1629 * The number of the system we manage DOFs for.
1630 */
1631 const unsigned int _sys_number;
1632
1633 /**
1634 * The mesh that system uses.
1635 */
1636 MeshBase & _mesh;
1637
1638 /**
1639 * Additional matrices handled by this object. These pointers do \e
1640 * not handle the memory, instead, \p System, who
1641 * told \p DofMap about them, owns them.
1642 */
1643 std::vector<SparseMatrix<Number> * > _matrices;
1644
1645 /**
1646 * First DOF index on processor \p p.
1647 */
1648 std::vector<dof_id_type> _first_df;
1649
1650 /**
1651 * Last DOF index (plus 1) on processor \p p.
1652 */
1653 std::vector<dof_id_type> _end_df;
1654
1655 /**
1656 * First DOF index for SCALAR variable v, or garbage for non-SCALAR
1657 * variable v
1658 */
1659 std::vector<dof_id_type> _first_scalar_df;
1660
1661 /**
1662 * A list containing all the global DOF indices that affect the
1663 * solution on my processor.
1664 */
1665 std::vector<dof_id_type> _send_list;
1666
1667 /**
1668 * Function object to call to add extra entries to the sparsity pattern
1669 */
1670 AugmentSparsityPattern * _augment_sparsity_pattern;
1671
1672 /**
1673 * A function pointer to a function to call to add extra entries to the sparsity pattern
1674 */
1675 void (*_extra_sparsity_function)(SparsityPattern::Graph &,
1676 std::vector<dof_id_type> & n_nz,
1677 std::vector<dof_id_type> & n_oz,
1678 void *);
1679 /**
1680 * A pointer associated with the extra sparsity that can optionally be passed in
1681 */
1682 void * _extra_sparsity_context;
1683
1684 /**
1685 * Function object to call to add extra entries to the send list
1686 */
1687 AugmentSendList * _augment_send_list;
1688
1689 /**
1690 * A function pointer to a function to call to add extra entries to the send list
1691 */
1692 void (*_extra_send_list_function)(std::vector<dof_id_type> &, void *);
1693
1694 /**
1695 * A pointer associated with the extra send list that can optionally be passed in
1696 */
1697 void * _extra_send_list_context;
1698
1699 /**
1700 * The default coupling GhostingFunctor, used to implement standard
1701 * libMesh sparsity pattern construction.
1702 *
1703 * We use a std::unique_ptr here to reduce header dependencies.
1704 */
1705 std::unique_ptr<DefaultCoupling> _default_coupling;
1706
1707 /**
1708 * The default algebraic GhostingFunctor, used to implement standard
1709 * libMesh send_list construction.
1710 *
1711 * We use a std::unique_ptr here to reduce header dependencies.
1712 */
1713 std::unique_ptr<DefaultCoupling> _default_evaluating;
1714
1715 /**
1716 * The list of all GhostingFunctor objects to be used when
1717 * distributing ghosted vectors.
1718 *
1719 * The library should automatically copy these functors to the
1720 * MeshBase, too, so any algebraically ghosted dofs will live on
1721 * geometrically ghosted elements.
1722 */
1723 std::set<GhostingFunctor *> _algebraic_ghosting_functors;
1724
1725 /**
1726 * The list of all GhostingFunctor objects to be used when
1727 * coupling degrees of freedom in matrix sparsity patterns.
1728 *
1729 * These objects will *also* be used as algebraic ghosting functors,
1730 * but not vice-versa.
1731 *
1732 * The library should automatically copy these functors to the
1733 * MeshBase, too, so any dofs coupled to local dofs will live on
1734 * geometrically ghosted elements.
1735 */
1736 std::set<GhostingFunctor *> _coupling_functors;
1737
1738 /**
1739 * Hang on to references to any GhostingFunctor objects we were
1740 * passed in shared_ptr form
1741 */
1742 std::map<GhostingFunctor *, std::shared_ptr<GhostingFunctor> > _shared_functors;
1743
1744 /**
1745 * Default false; set to true if any attached matrix requires a full
1746 * sparsity pattern.
1747 */
1748 bool need_full_sparsity_pattern;
1749
1750 /**
1751 * The sparsity pattern of the global matrix, kept around if it
1752 * might be needed by future additions of the same type of matrix.
1753 */
1754 std::unique_ptr<SparsityPattern::Build> _sp;
1755
1756 /**
1757 * The number of on-processor nonzeros in my portion of the
1758 * global matrix. If need_full_sparsity_pattern is true, this will
1759 * just be a pointer into the corresponding sparsity pattern vector.
1760 * Otherwise we have to new/delete it ourselves.
1761 */
1762 std::vector<dof_id_type> * _n_nz;
1763
1764 /**
1765 * The number of off-processor nonzeros in my portion of the
1766 * global matrix; allocated similar to _n_nz.
1767 */
1768 std::vector<dof_id_type> * _n_oz;
1769
1770 /**
1771 * Total number of degrees of freedom.
1772 */
1773 dof_id_type _n_dfs;
1774
1775 /**
1776 * The total number of SCALAR dofs associated to
1777 * all SCALAR variables.
1778 */
1779 dof_id_type _n_SCALAR_dofs;
1780
1781 #ifdef LIBMESH_ENABLE_AMR
1782
1783 /**
1784 * Total number of degrees of freedom on old dof objects
1785 */
1786 dof_id_type _n_old_dfs;
1787
1788 /**
1789 * First old DOF index on processor \p p.
1790 */
1791 std::vector<dof_id_type> _first_old_df;
1792
1793 /**
1794 * Last old DOF index (plus 1) on processor \p p.
1795 */
1796 std::vector<dof_id_type> _end_old_df;
1797
1798 /**
1799 * First old DOF index for SCALAR variable v, or garbage for
1800 * non-SCALAR variable v
1801 */
1802 std::vector<dof_id_type> _first_old_scalar_df;
1803
1804 #endif
1805
1806 #ifdef LIBMESH_ENABLE_CONSTRAINTS
1807 /**
1808 * Data structure containing DOF constraints. The ith
1809 * entry is the constraint matrix row for DOF i.
1810 */
1811 DofConstraints _dof_constraints, _stashed_dof_constraints;
1812
1813 DofConstraintValueMap _primal_constraint_values;
1814
1815 AdjointDofConstraintValues _adjoint_constraint_values;
1816 #endif
1817
1818 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
1819 /**
1820 * Data structure containing DofObject constraints.
1821 */
1822 NodeConstraints _node_constraints;
1823 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
1824
1825
1826 #ifdef LIBMESH_ENABLE_PERIODIC
1827 /**
1828 * Data structure containing periodic boundaries. The ith
1829 * entry is the constraint matrix row for boundaryid i.
1830 */
1831 std::unique_ptr<PeriodicBoundaries> _periodic_boundaries;
1832 #endif
1833
1834 #ifdef LIBMESH_ENABLE_DIRICHLET
1835 /**
1836 * Check that all the ids in dirichlet_bcids are actually present in the mesh.
1837 * If not, this will throw an error.
1838 */
1839 void check_dirichlet_bcid_consistency (const MeshBase & mesh,
1840 const DirichletBoundary & boundary) const;
1841 /**
1842 * Data structure containing Dirichlet functions. The ith
1843 * entry is the constraint matrix row for boundaryid i.
1844 */
1845 std::unique_ptr<DirichletBoundaries> _dirichlet_boundaries;
1846
1847 /**
1848 * Data structure containing Dirichlet functions. The ith
1849 * entry is the constraint matrix row for boundaryid i.
1850 */
1851 std::vector<DirichletBoundaries *> _adjoint_dirichlet_boundaries;
1852 #endif
1853
1854 friend class SparsityPattern::Build;
1855
1856 /**
1857 * Bools to indicate if we override the --implicit_neighbor_dofs
1858 * commandline options.
1859 */
1860 bool _implicit_neighbor_dofs_initialized;
1861 bool _implicit_neighbor_dofs;
1862 };
1863
1864
1865 // ------------------------------------------------------------
1866 // Dof Map inline member functions
1867 inline
sys_number()1868 unsigned int DofMap::sys_number() const
1869 {
1870 return _sys_number;
1871 }
1872
1873
1874
1875 inline
variable_group(const unsigned int g)1876 const VariableGroup & DofMap::variable_group (const unsigned int g) const
1877 {
1878 libmesh_assert_less (g, _variable_groups.size());
1879
1880 return _variable_groups[g];
1881 }
1882
1883
1884
1885 inline
variable(const unsigned int c)1886 const Variable & DofMap::variable (const unsigned int c) const
1887 {
1888 libmesh_assert_less (c, _variables.size());
1889
1890 return _variables[c];
1891 }
1892
1893
1894
1895 inline
variable_order(const unsigned int c)1896 Order DofMap::variable_order (const unsigned int c) const
1897 {
1898 libmesh_assert_less (c, _variables.size());
1899
1900 return _variables[c].type().order;
1901 }
1902
1903
1904
1905 inline
variable_group_order(const unsigned int vg)1906 Order DofMap::variable_group_order (const unsigned int vg) const
1907 {
1908 libmesh_assert_less (vg, _variable_groups.size());
1909
1910 return _variable_groups[vg].type().order;
1911 }
1912
1913
1914
1915 inline
variable_type(const unsigned int c)1916 const FEType & DofMap::variable_type (const unsigned int c) const
1917 {
1918 libmesh_assert_less (c, _variables.size());
1919
1920 return _variables[c].type();
1921 }
1922
1923
1924
1925 inline
variable_group_type(const unsigned int vg)1926 const FEType & DofMap::variable_group_type (const unsigned int vg) const
1927 {
1928 libmesh_assert_less (vg, _variable_groups.size());
1929
1930 return _variable_groups[vg].type();
1931 }
1932
1933
1934 #ifdef LIBMESH_ENABLE_CONSTRAINTS
1935
1936
1937 inline
is_constrained_node(const Node * node)1938 bool DofMap::is_constrained_node (const Node *
1939 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
1940 node
1941 #endif
1942 ) const
1943 {
1944 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
1945 if (_node_constraints.count(node))
1946 return true;
1947 #endif
1948
1949 return false;
1950 }
1951
1952
1953 inline
is_constrained_dof(const dof_id_type dof)1954 bool DofMap::is_constrained_dof (const dof_id_type dof) const
1955 {
1956 if (_dof_constraints.count(dof))
1957 return true;
1958
1959 return false;
1960 }
1961
1962
1963 inline
has_heterogenous_adjoint_constraints(const unsigned int qoi_num)1964 bool DofMap::has_heterogenous_adjoint_constraints (const unsigned int qoi_num) const
1965 {
1966 AdjointDofConstraintValues::const_iterator it =
1967 _adjoint_constraint_values.find(qoi_num);
1968 if (it == _adjoint_constraint_values.end())
1969 return false;
1970 if (it->second.empty())
1971 return false;
1972
1973 return true;
1974 }
1975
1976
1977 inline
has_heterogenous_adjoint_constraint(const unsigned int qoi_num,const dof_id_type dof)1978 Number DofMap::has_heterogenous_adjoint_constraint (const unsigned int qoi_num,
1979 const dof_id_type dof) const
1980 {
1981 AdjointDofConstraintValues::const_iterator it =
1982 _adjoint_constraint_values.find(qoi_num);
1983 if (it != _adjoint_constraint_values.end())
1984 {
1985 DofConstraintValueMap::const_iterator rhsit =
1986 it->second.find(dof);
1987 if (rhsit == it->second.end())
1988 return 0;
1989 else
1990 return rhsit->second;
1991 }
1992
1993 return 0;
1994 }
1995
1996
1997
1998 inline
get_primal_constraint_values()1999 DofConstraintValueMap & DofMap::get_primal_constraint_values()
2000 {
2001 return _primal_constraint_values;
2002 }
2003
2004
2005
2006 #else
2007
2008 //--------------------------------------------------------------------
2009 // Constraint-specific methods get inlined into nothing if
2010 // constraints are disabled, so there's no reason for users not to
2011 // use them.
2012
constrain_element_matrix(DenseMatrix<Number> &,std::vector<dof_id_type> &,bool)2013 inline void DofMap::constrain_element_matrix (DenseMatrix<Number> &,
2014 std::vector<dof_id_type> &,
2015 bool) const {}
2016
constrain_element_matrix(DenseMatrix<Number> &,std::vector<dof_id_type> &,std::vector<dof_id_type> &,bool)2017 inline void DofMap::constrain_element_matrix (DenseMatrix<Number> &,
2018 std::vector<dof_id_type> &,
2019 std::vector<dof_id_type> &,
2020 bool) const {}
2021
constrain_element_vector(DenseVector<Number> &,std::vector<dof_id_type> &,bool)2022 inline void DofMap::constrain_element_vector (DenseVector<Number> &,
2023 std::vector<dof_id_type> &,
2024 bool) const {}
2025
constrain_element_matrix_and_vector(DenseMatrix<Number> &,DenseVector<Number> &,std::vector<dof_id_type> &,bool)2026 inline void DofMap::constrain_element_matrix_and_vector (DenseMatrix<Number> &,
2027 DenseVector<Number> &,
2028 std::vector<dof_id_type> &,
2029 bool) const {}
2030
heterogenously_constrain_element_matrix_and_vector(DenseMatrix<Number> &,DenseVector<Number> &,std::vector<dof_id_type> &,bool,int)2031 inline void DofMap::heterogenously_constrain_element_matrix_and_vector
2032 (DenseMatrix<Number> &, DenseVector<Number> &,
2033 std::vector<dof_id_type> &, bool, int) const {}
2034
heterogenously_constrain_element_vector(const DenseMatrix<Number> &,DenseVector<Number> &,std::vector<dof_id_type> &,bool,int)2035 inline void DofMap::heterogenously_constrain_element_vector
2036 (const DenseMatrix<Number> &, DenseVector<Number> &,
2037 std::vector<dof_id_type> &, bool, int) const {}
2038
constrain_element_dyad_matrix(DenseVector<Number> &,DenseVector<Number> &,std::vector<dof_id_type> &,bool)2039 inline void DofMap::constrain_element_dyad_matrix (DenseVector<Number> &,
2040 DenseVector<Number> &,
2041 std::vector<dof_id_type> &,
2042 bool) const {}
2043
constrain_nothing(std::vector<dof_id_type> &)2044 inline void DofMap::constrain_nothing (std::vector<dof_id_type> &) const {}
2045
enforce_constraints_exactly(const System &,NumericVector<Number> *,bool)2046 inline void DofMap::enforce_constraints_exactly (const System &,
2047 NumericVector<Number> *,
2048 bool) const {}
2049
enforce_adjoint_constraints_exactly(NumericVector<Number> &,unsigned int)2050 inline void DofMap::enforce_adjoint_constraints_exactly (NumericVector<Number> &,
2051 unsigned int) const {}
2052
2053
enforce_constraints_on_residual(const NonlinearImplicitSystem &,NumericVector<Number> *,NumericVector<Number> const *,bool)2054 inline void DofMap::enforce_constraints_on_residual
2055 (const NonlinearImplicitSystem &,
2056 NumericVector<Number> *,
2057 NumericVector<Number> const *,
2058 bool) const {}
2059
enforce_constraints_on_jacobian(const NonlinearImplicitSystem &,SparseMatrix<Number> *)2060 inline void DofMap::enforce_constraints_on_jacobian
2061 (const NonlinearImplicitSystem &,
2062 SparseMatrix<Number> *) const {}
2063
2064 #endif // LIBMESH_ENABLE_CONSTRAINTS
2065
2066 } // namespace libMesh
2067
2068 #endif // LIBMESH_DOF_MAP_H
2069