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_OBJECT_H
21 #define LIBMESH_DOF_OBJECT_H
22 
23 // Local includes
24 #include "libmesh/id_types.h"
25 #include "libmesh/int_range.h"
26 #include "libmesh/libmesh_config.h"
27 #include "libmesh/libmesh_common.h"
28 #include "libmesh/libmesh.h" // libMesh::invalid_uint
29 #include "libmesh/reference_counted_object.h"
30 
31 // C++ includes
32 #include <cstddef>
33 #include <cstring>
34 #include <vector>
35 
36 namespace libMesh
37 {
38 
39 // Forward declarations
40 class DofObject;
41 
42 
43 /**
44  * The \p DofObject defines an abstract base class for objects that
45  * have degrees of freedom associated with them.  Examples of such
46  * objects are the \p Node and \p Elem classes.  This class can
47  * not be instantiated, only derived from.
48  *
49  * \author Benjamin S. Kirk
50  * \date 2003, 2011
51  */
52 
53 class DofObject : public ReferenceCountedObject<DofObject>
54 {
55 #ifdef LIBMESH_IS_UNIT_TESTING
56 public:
57 #else
58 protected:
59 #endif
60 
61   /**
62    * Constructor. Protected so that you can't instantiate one of these
63    * except as a part of a Node or Elem.
64    */
65   DofObject ();
66 
67   /**
68    * Destructor. Protected so that you can't destroy one of these
69    * except as a part of a Node or Elem.
70    */
71   ~DofObject ();
72 
73 public:
74 
75 #ifdef LIBMESH_ENABLE_AMR
76 
77   /**
78    * This object on the last mesh.  Useful for projecting
79    * solutions from one mesh to another.
80    */
81   DofObject * old_dof_object;
82 
83   /**
84    * Sets the \p old_dof_object to nullptr
85    */
86   void clear_old_dof_object ();
87 
88   /**
89    * Sets the \p old_dof_object to a copy of \p this
90    */
91   void set_old_dof_object ();
92 
93 #endif
94 
95   /**
96    * Clear the \p DofMap data structures holding degree of freedom
97    * data.
98    *
99    * If any extra integers are associated with this \p DofObject,
100    * their count and values are unchanged.
101    */
102   void clear_dofs ();
103 
104   /**
105    * Sets all degree of freedom numbers to \p invalid_id
106    */
107   void invalidate_dofs (const unsigned int sys_num = libMesh::invalid_uint);
108 
109   /**
110    * Sets the id to \p invalid_id
111    */
112   void invalidate_id ();
113 
114   /**
115    * Sets the processor id to \p invalid_processor_id
116    */
117   void invalidate_processor_id ();
118 
119   /**
120    * Invalidates all the indices for this \p DofObject
121    */
122   void invalidate ();
123 
124   /**
125    * \returns The number of degrees of freedom associated with
126    * system \p s for this object. Optionally only counts degrees
127    * of freedom for variable number \p var
128    */
129   unsigned int n_dofs (const unsigned int s,
130                        const unsigned int var =
131                        libMesh::invalid_uint) const;
132 
133   /**
134    * \returns The \p id for this \p DofObject
135    */
136   dof_id_type id () const;
137 
138   /**
139    * \returns The \p id for this \p DofObject as a writable reference.
140    */
141   dof_id_type & set_id ();
142 
143   /**
144    * \returns The globally \p unique_id for this \p DofObject
145    */
146   unique_id_type unique_id () const;
147 
148   /**
149    * \returns The globally \p unique_id for this \p DofObject as a
150    * writable reference.  Deprecated; use the API taking an input
151    * instead.
152    */
153   unique_id_type & set_unique_id ();
154 
155   /**
156    * Sets the \p unique_id for this \p DofObject
157    */
158   void set_unique_id (unique_id_type new_id);
159 
160   /**
161    * Sets the \p id for this \p DofObject
162    */
set_id(const dof_id_type dofid)163   void set_id (const dof_id_type dofid)
164   { this->set_id() = dofid; }
165 
166   /**
167    * \returns \p true if this \p DofObject has a valid \p id set,
168    * \p false otherwise.
169    */
170   bool valid_id () const;
171 
172   /**
173    * \returns \p true if this \p DofObject has a valid \p unique_id set,
174    * \p false otherwise.
175    */
176   bool valid_unique_id () const;
177 
178   /**
179    * \returns The processor that this DofObject belongs to.
180    *
181    * When partitioning and DoF numbering have been performed by
182    * libMesh, every current DoF on this DofObject will belong to its
183    * processor.
184    */
185   processor_id_type processor_id () const;
186 
187   /**
188    * \returns The processor that this DofObject belongs to as a
189    * writable reference.
190    */
191   processor_id_type & processor_id ();
192 
193   /**
194    * Sets the \p processor_id for this \p DofObject.
195    */
196   void processor_id (const processor_id_type pid);
197 
198   /**
199    * \returns \p true if this \p DofObject has a valid \p id set,
200    * \p false otherwise.
201    */
202   bool valid_processor_id () const;
203 
204   /**
205    * \returns The number of systems associated with this
206    * \p DofObject
207    */
208   unsigned int n_systems() const;
209 
210   /**
211    * \returns The total number of pseudo-systems associated with this
212    * \p DofObject :
213    * n_systems(), plus one iff \p this->has_extra_integers()
214    */
215   unsigned int n_pseudo_systems() const;
216 
217   /**
218    * Sets the number of systems for this \p DofObject.  If this number
219    * is a change, also clears all variable count and DoF indexing
220    * associated with this \p DofObject.
221    *
222    * If any extra integers are associated with this \p DofObject,
223    * their count and values are unchanged.
224    */
225   void set_n_systems (const unsigned int s);
226 
227   /**
228    * Sets the value on this object of the extra integer associated
229    * with \p index, which should have been obtained via a call to \p
230    * MeshBase::add_elem_integer or \p MeshBase::add_node_integer
231    */
232   void set_extra_integer (const unsigned int index, const dof_id_type value);
233 
234   /**
235    * Gets the value on this object of the extra integer associated
236    * with \p index, which should have been obtained via a call to \p
237    * MeshBase::add_elem_integer or \p MeshBase::add_node_integer
238    */
239   dof_id_type get_extra_integer (const unsigned int index) const;
240 
241   /**
242    * Sets the value on this object of the extra datum associated
243    * with \p index, which should have been obtained via a call to \p
244    * MeshBase::add_elem_datum or \p MeshBase::add_node_datum using
245    * the same type T.
246    */
247   template <typename T>
248   void set_extra_datum (const unsigned int index, const T value);
249 
250   /**
251    * Gets the value on this object of the extra datum associated
252    * with \p index, which should have been obtained via a call to \p
253    * MeshBase::add_elem_datum or \p MeshBase::add_node_datum using
254    * the same type T.
255    */
256   template <typename T>
257   T get_extra_datum (const unsigned int index) const;
258 
259 
260   /**
261    * Adds an additional system to the \p DofObject
262    */
263   void add_system ();
264 
265   /**
266    * \returns The number of \p VariableGroup variable groups
267    * associated with system \p s for this \p DofObject
268    */
269   unsigned int n_var_groups(const unsigned int s) const;
270 
271   /**
272    * \returns The number of \p Variable variables associated
273    * with \p VariableGroup \p vg in system \p s for this \p DofObject
274    */
275   unsigned int n_vars(const unsigned int s,
276                       const unsigned int vg) const;
277 
278   /**
279    * \returns The number of \p Variable variables associated
280    * with system \p s for this \p DofObject
281    */
282   unsigned int n_vars(const unsigned int s) const;
283 
284   /**
285    * Sets number of variables in each group associated with system \p s for this
286    * \p DofObject. Implicit in this is also setting the number of \p VariableGroup
287    * variable groups for the system.
288    * Has the effect of setting the number of components
289    * to 0 even when called even with (nvg == this->n_var_groups(s)).
290    */
291   void set_n_vars_per_group(const unsigned int s,
292                             const std::vector<unsigned int> & nvpg);
293 
294   /**
295    * \returns The number of components for variable \p var
296    * of system \p s associated with this \p DofObject.
297    * For example, the \p HIERARCHIC shape functions may
298    * have multiple DoFs associated with one node.  Another
299    * example is the \p MONOMIALs, where only the elements
300    * hold the DoFs.  For the different spatial directions,
301    * and orders, see \p FE.
302    */
303   unsigned int n_comp(const unsigned int s,
304                       const unsigned int var) const;
305 
306   /**
307    * \returns The number of components for \p VariableGroup \p vg
308    * of system \p s associated with this \p DofObject.
309    * For example, the \p HIERARCHIC shape functions may
310    * have multiple DoFs associated with one node.  Another
311    * example is the \p MONOMIALs, where only the elements
312    * hold the DoFs.  For the different spatial directions,
313    * and orders, see \p FE.
314    */
315   unsigned int n_comp_group(const unsigned int s,
316                             const unsigned int vg) const;
317 
318   /**
319    * Sets the number of components for \p Variable \p var
320    * of system \p s associated with this \p DofObject
321    */
322   void set_n_comp(const unsigned int s,
323                   const unsigned int var,
324                   const unsigned int ncomp);
325 
326   /**
327    * Sets the number of components for \p VariableGroup \p vg
328    * of system \p s associated with this \p DofObject
329    */
330   void set_n_comp_group(const unsigned int s,
331                         const unsigned int vg,
332                         const unsigned int ncomp);
333 
334   /**
335    * \returns The global degree of freedom number for variable \p var,
336    * component \p comp for system \p s associated with this \p DofObject
337    *
338    * When partitioning and DoF numbering have been performed by
339    * libMesh, every current DoF on this DofObject will belong to its
340    * processor.
341    */
342   dof_id_type dof_number(const unsigned int s,
343                          const unsigned int var,
344                          const unsigned int comp) const;
345 
346   /**
347    * \returns The global degree of freedom number for variable group
348    * \p vg, variable index \p vig within the group, component \p comp
349    * out of \p n_comp, for system \p s on this \p DofObject
350    *
351    * Even users who need to call dof_number from user code probably
352    * don't want to call this overload.
353    */
354   dof_id_type dof_number(const unsigned int s,
355                          const unsigned int vg,
356                          const unsigned int vig,
357                          const unsigned int comp,
358                          const unsigned int n_comp) const;
359 
360   /**
361    * \returns A pair consisting of the variable group number and the
362    * offset index from the start of that group for variable \p var on
363    * system \p s associated with this \p DofObject
364    */
365   std::pair<unsigned int, unsigned int>
366   var_to_vg_and_offset(const unsigned int s,
367                        const unsigned int var) const;
368 
369   /**
370    * Sets the global degree of freedom number for variable \p var,
371    * component \p comp for system \p s associated with this \p DofObject
372    */
373   void set_dof_number(const unsigned int s,
374                       const unsigned int var,
375                       const unsigned int comp,
376                       const dof_id_type dn);
377 
378   /**
379    * \returns \p true if any system has variables which have been assigned,
380    * \p false otherwise.
381    */
382   bool has_dofs(const unsigned int s=libMesh::invalid_uint) const;
383 
384   /**
385    * \p VariableGroup DoF indices are indexed as
386    * id = base + var_in_vg*ncomp + comp
387    * This method allows for direct access to the base.
388    */
389   void set_vg_dof_base(const unsigned int s,
390                        const unsigned int vg,
391                        const dof_id_type db);
392 
393   /**
394    * \p VariableGroup DoF indices are indexed as
395    * id = base + var_in_vg*ncomp + comp
396    * This method allows for direct access to the base.
397    */
398   dof_id_type vg_dof_base(const unsigned int s,
399                           const unsigned int vg) const;
400 
401   /**
402    * Assigns a set of extra integers to this \p DofObject.  There will
403    * now be \p n_integers associated; this *replaces*, not augments,
404    * any previous count.
405    *
406    * Any newly-added values will initially be DofObject::invalid_id
407    *
408    * If non-integer data is in the set, each datum of type T should be
409    * counted sizeof(T)/sizeof(dof_id_type) times in \p n_integers.
410    */
411   void add_extra_integers (const unsigned int n_integers);
412 
413   /**
414    * Assigns a set of extra integers to this \p DofObject.  There will
415    * now be \p n_integers associated; this *replaces*, not augments,
416    * any previous count.
417    *
418    * Any newly-added values will be copied from \p default_values.
419    *
420    * If non-integer data is in the set, each datum of type T should be
421    * counted sizeof(T)/sizeof(dof_id_type) times in \p n_integers, and
422    * its data should be expressed in \p default_values as per memcpy.
423    */
424   void add_extra_integers (const unsigned int n_integers,
425                            const std::vector<dof_id_type> & default_values);
426 
427   /**
428    * Returns how many extra integers are associated to the \p DofObject
429    *
430    * If non-integer data has been associated, each datum of type T
431    * counts for sizeof(T)/sizeof(dof_id_type) times in the return
432    * value.
433    */
434   unsigned int n_extra_integers () const;
435 
436   /**
437    * Returns whether extra integers are associated to the \p DofObject
438    */
439   bool has_extra_integers () const;
440 
441   /**
442    * An invalid \p id to distinguish an uninitialized \p DofObject
443    */
444   static const dof_id_type invalid_id = static_cast<dof_id_type>(-1);
445 
446   /**
447    * An invalid \p unique_id to distinguish an uninitialized \p DofObject
448    */
449   static const unique_id_type invalid_unique_id = static_cast<unique_id_type>(-1);
450 
451   /**
452    * An invalid \p processor_id to distinguish DoFs that have
453    * not been assigned to a processor.
454    */
455   static const processor_id_type invalid_processor_id = static_cast<processor_id_type>(-1);
456 
457   /**
458    * If we pack our indices into an buffer for communications, how
459    * many ints do we need?
460    */
461   unsigned int packed_indexing_size() const;
462 
463   /**
464    * If we have indices packed into an buffer for communications, how
465    * much of that buffer applies to this dof object?
466    */
467   static unsigned int unpackable_indexing_size
468   (std::vector<largest_id_type>::const_iterator begin);
469 
470   /**
471    * A method for creating our index buffer from packed data -
472    * basically with our current implementation we investigate the size
473    * term and then copy.
474    */
475   void unpack_indexing(std::vector<largest_id_type>::const_iterator begin);
476 
477   /**
478    * A method for creating packed data from our index buffer -
479    * basically a copy with prepended size with our current
480    * implementation.
481    */
482   void pack_indexing(std::back_insert_iterator<std::vector<largest_id_type>> target) const;
483 
484   /**
485    * Print our buffer for debugging.
486    */
487   void debug_buffer () const;
488 
489   /**
490    * Print out info for debugging.
491    */
492   void print_dof_info() const;
493 
494   // Deep copy (or almost-copy) of DofObjects is solely for a couple
495   // tricky internal uses.
496 private:
497 
498   /**
499    * "Copy"-constructor.  Does not copy old_dof_object, but leaves it
500    * null in the new object.
501    */
502   DofObject (const DofObject &);
503 
504   /**
505    * Deep-copying assignment operator
506    */
507   DofObject & operator= (const DofObject & dof_obj);
508 
509   /**
510    * Utility function - for variable \p var in system \p s, figure out what
511    * variable group it lives in.
512    */
513   unsigned int var_to_vg (const unsigned int s,
514                           const unsigned int var) const;
515 
516   /**
517    * Utility function - for variable \p var in system \p s, figure out what
518    * variable group it lives in.
519    */
520   unsigned int system_var_to_vg_var (const unsigned int s,
521                                      const unsigned int vg,
522                                      const unsigned int var) const;
523 
524   /**
525    * A globally unique id, guaranteed not to change as the mesh is repartitioned or adapted
526    */
527 #ifdef LIBMESH_ENABLE_UNIQUE_ID
528   unique_id_type _unique_id;
529 #endif
530 
531   /**
532    * The \p id of the \p DofObject
533    */
534   dof_id_type _id;
535 
536   /**
537    * The \p processor_id of the \p DofObject.
538    * Degrees of freedom are wholly owned by processors,
539    * however they may be duplicated on other processors.
540    *
541    * This is stored as an unsigned short int since we cannot
542    * expect to be solving on 65000+ processors any time soon,
543    * can we??
544    */
545   processor_id_type _processor_id;
546 
547   /**
548    * DoF index information.  This is packed into a contiguous buffer of the following format:
549    *
550    * \verbatim
551    * [hdr end_0 end_1 ... end_{nps-2} (ncv_0 idx_0 ncv_1 idx_1 ... ncv_nv idx_nv)_0
552    *                                  (ncv_0 idx_0 ncv_1 idx_1 ... ncv_nv idx_nv)_1
553    *                                   ...
554    *                                  (ncv_0 idx_0 ncv_1 idx_1 ... ncv_nv idx_nv)_{nps-2} ]
555    * \endverbatim
556    *
557    * 'hdr' determines whether this \p DofObject \p has_extra_integers()
558    * associated with it; iff so then it is negative.
559    *
560    * The total number of "pseudo systems" is nps := abs(hdr).
561    *
562    * The total number of true systems is
563    * \verbatim
564    * ns = hdr,            hdr >= 0
565    *    = abs(hdr) - 1,   otherwise.
566    * \endverbatim
567    *
568    * 'end_s' is the index past the end of the variable group (or
569    * integer) storage for (pseudo) system \p s.
570    *
571    * \note We specifically do not store the end for the last (pseudo)
572    * system - this always _idx_buf.size().
573    *
574    * As a first example, consider the case of 4 systems, with 3, 0, 1,
575    * 2 variable groups, respectively.  The _idx_buf then looks like:
576    *
577    * \verbatim
578    * [4 10 10 12 () (ncv_0 idx_0 ncv_1 idx_1 ncv_2 idx_2) () (ncv_0 idx_0) (ncv_0 idx_0 ncv_1 idx_1)]
579    * [0  1  2  3         4     5     6     7     8     9         10    11      12    13    14    15]
580    * \endverbatim
581    *
582    * The ending index for each (pseudo) system is then given by:
583    *
584    * \verbatim
585    * end_s = _idx_buf.size(),                        s == (nps-1),
586    *       = _idx_buf[s+1] + has_extra_integers(),   otherwise.
587    * \endverbatim
588    *
589    * The starting indices are not specifically stored, but rather inferred as follows:
590    *
591    * start_s = abs(_idx_buf[s])
592    *
593    * Now, the defining characteristic of the \p VariableGroup is that it supports
594    * an arbitrary number of variables of the same type.  At the \p DofObject level, what
595    * that means is that each \p Variable in the \p VariableGroup will have the same number
596    * of nonzero components, and they can all be indexed from the same base number.  We use this
597    * information in the ncv_# and idx_# entries as follows:
598    *
599    * ncv_# = n_vars*ncv_magic + n_comp      for variable group #
600    * idx_# = base_offset                    for variable group #
601    *
602    * the DoF index for a particular component c of variable v within that group is then given by
603    *
604    * idx_var = idx_# + n_comp*v + c
605    *
606    * \note There is a subtlety here - "variable v within that group" usually means nothing to the
607    * user. This class is either indexed with variable group numbers, or variable numbers counted
608    * *within the system*. So for a system with 2 variable groups, 4 and 8 variables each,
609    * the 5th variable in the system is the 1st variable in 2nd variable group.
610    * (Now of course 0-base everything...  but you get the idea.)
611    *
612    * When hdr is *negative* when cast to a signed type, then we
613    * interpret that to mean there exists one pseudo-system following
614    * the true systems, one for which the _idx_buf data stores the
615    * values associated with add_extra_integer entries, not ncv and idx
616    * data associated with system variables.  We still return only the
617    * number of true systems for n_systems(), but we report
618    * has_extra_integers() as true iff hdr is negative, and abs(hdr)
619    * will reflect the total number of pseudo-systems, n_systems()+1.
620    *
621    * E.g. if we had added two extra integers to the example case
622    * above, the _idx_buf then looks like:
623    *
624    * \verbatim
625    * [-5 11 11 13 17 () (ncv_0 idx_0 ncv_1 idx_1 ncv_2 idx_2) () (ncv_0 idx_0) (ncv_0 idx_0 ncv_1 idx_1) (xtra1 xtra2)]
626    * [0   1  2  3  4         5     6     7     8     9    10         11    12      13    14    15    16      17    18]
627    * \endverbatim
628    */
629   typedef dof_id_type index_t;
630   typedef std::vector<index_t> index_buffer_t;
631   index_buffer_t _idx_buf;
632 
633   /**
634    * Above we introduced the chimera ncv, which is a hybrid of the form
635    * ncv = ncv_magic*nv + nc
636    * where nv are the number of identical variables of a given type,
637    * and nc is the number of components for this set of variables.
638    *
639    * It is hoped that by setting this to a power of two, an optimizing compiler
640    * will recognize later that  #/ncv_magic is simply a bitshift
641    */
642   static const index_t ncv_magic = 256; // = 2^8, in case we want to manually bitshift
643   static const index_t ncv_magic_exp = 8; // Let's manually bitshift
644 
645   /**
646    * The starting index for system \p s.
647    */
648   unsigned int start_idx(const unsigned int s) const;
649 
650   /**
651    * The ending index for system \p s.
652    */
653   unsigned int end_idx(const unsigned int s) const;
654 
655   /**
656    * The starting index for an extra_integers pseudosystem
657    */
658   unsigned int start_idx_ints() const;
659 
660   /**
661    * The ending index for an extra_integers pseudosystem
662    */
663   unsigned int end_idx_ints() const;
664 
665   // methods only available for unit testing
666 #ifdef LIBMESH_IS_UNIT_TESTING
667 public:
set_buffer(const std::vector<dof_id_type> & buf)668   void set_buffer (const std::vector<dof_id_type> & buf)
669   { _idx_buf = buf; }
670 #endif
671 };
672 
673 
674 
675 //------------------------------------------------------
676 // Inline functions
677 inline
DofObject()678 DofObject::DofObject () :
679 #ifdef LIBMESH_ENABLE_AMR
680   old_dof_object(nullptr),
681 #endif
682 #ifdef LIBMESH_ENABLE_UNIQUE_ID
683   _unique_id (invalid_unique_id),
684 #endif
685   _id (invalid_id),
686   _processor_id (invalid_processor_id)
687 {
688   this->invalidate();
689 }
690 
691 
692 
693 
694 
695 inline
~DofObject()696 DofObject::~DofObject ()
697 {
698   // Free all memory.
699 #ifdef LIBMESH_ENABLE_AMR
700   this->clear_old_dof_object ();
701 #endif
702   this->clear_dofs ();
703 }
704 
705 
706 
707 inline
invalidate_dofs(const unsigned int sys_num)708 void DofObject::invalidate_dofs (const unsigned int sys_num)
709 {
710   const unsigned int n_sys = this->n_systems();
711   // If the user does not specify the system number...
712   if (sys_num >= n_sys)
713     {
714       for (auto s : make_range(n_sys))
715         for (auto vg : make_range(this->n_var_groups(s)))
716           if (this->n_comp_group(s,vg))
717             this->set_vg_dof_base(s,vg,invalid_id);
718     }
719   // ...otherwise invalidate the dofs for all systems
720   else
721     for (auto vg : make_range(this->n_var_groups(sys_num)))
722       if (this->n_comp_group(sys_num,vg))
723         this->set_vg_dof_base(sys_num,vg,invalid_id);
724 }
725 
726 
727 
728 inline
invalidate_id()729 void DofObject::invalidate_id ()
730 {
731   this->set_id (invalid_id);
732 }
733 
734 
735 
736 inline
invalidate_processor_id()737 void DofObject::invalidate_processor_id ()
738 {
739   this->processor_id (invalid_processor_id);
740 }
741 
742 
743 
744 inline
invalidate()745 void DofObject::invalidate ()
746 {
747   this->invalidate_dofs ();
748   this->invalidate_id ();
749   this->invalidate_processor_id ();
750 }
751 
752 
753 
754 inline
clear_dofs()755 void DofObject::clear_dofs ()
756 {
757   this->set_n_systems(0);
758 }
759 
760 
761 
762 inline
n_dofs(const unsigned int s,const unsigned int var)763 unsigned int DofObject::n_dofs (const unsigned int s,
764                                 const unsigned int var) const
765 {
766   libmesh_assert_less (s, this->n_systems());
767 
768   unsigned int num = 0;
769 
770   // Count all variables
771   if (var == libMesh::invalid_uint)
772     for (auto v : make_range(this->n_vars(s)))
773       num += this->n_comp(s,v);
774 
775   // Only count specified variable
776   else
777     num = this->n_comp(s,var);
778 
779   return num;
780 }
781 
782 
783 
784 inline
id()785 dof_id_type DofObject::id () const
786 {
787   libmesh_assert (this->valid_id());
788   return _id;
789 }
790 
791 
792 
793 inline
set_id()794 dof_id_type & DofObject::set_id ()
795 {
796   return _id;
797 }
798 
799 
800 
801 inline
unique_id()802 unique_id_type DofObject::unique_id () const
803 {
804 #ifdef LIBMESH_ENABLE_UNIQUE_ID
805   libmesh_assert (this->valid_unique_id());
806   return _unique_id;
807 #else
808   return invalid_unique_id;
809 #endif
810 }
811 
812 
813 
814 inline
set_unique_id()815 unique_id_type & DofObject::set_unique_id ()
816 {
817 #ifdef LIBMESH_ENABLE_UNIQUE_ID
818   libmesh_deprecated();
819   return _unique_id;
820 #else
821   libmesh_not_implemented();
822 #endif
823 }
824 
825 
826 
827 inline
set_unique_id(unique_id_type new_id)828 void DofObject::set_unique_id (unique_id_type new_id)
829 {
830 #ifdef LIBMESH_ENABLE_UNIQUE_ID
831   _unique_id = new_id;
832 #else
833   libmesh_ignore(new_id);
834   libmesh_not_implemented();
835 #endif
836 }
837 
838 
839 
840 inline
valid_id()841 bool DofObject::valid_id () const
842 {
843   return (DofObject::invalid_id != _id);
844 }
845 
846 
847 
848 inline
valid_unique_id()849 bool DofObject::valid_unique_id () const
850 {
851 #ifdef LIBMESH_ENABLE_UNIQUE_ID
852   return (DofObject::invalid_unique_id != _unique_id);
853 #else
854   return false;
855 #endif
856 }
857 
858 
859 
860 inline
processor_id()861 processor_id_type DofObject::processor_id () const
862 {
863   return _processor_id;
864 }
865 
866 
867 
868 inline
processor_id()869 processor_id_type & DofObject::processor_id ()
870 {
871   return _processor_id;
872 }
873 
874 
875 
876 inline
processor_id(const processor_id_type pid)877 void DofObject::processor_id (const processor_id_type pid)
878 {
879   this->processor_id() = pid;
880 }
881 
882 
883 
884 inline
valid_processor_id()885 bool DofObject::valid_processor_id () const
886 {
887   return (DofObject::invalid_processor_id != _processor_id);
888 }
889 
890 
891 
892 inline
n_systems()893 unsigned int DofObject::n_systems () const
894 {
895   const int hdr = _idx_buf.empty() ?
896     0 : cast_int<int>(dof_id_signed_type(_idx_buf[0]));
897   return hdr >= 0 ? hdr : (-hdr-1);
898 }
899 
900 
901 
902 inline
n_pseudo_systems()903 unsigned int DofObject::n_pseudo_systems () const
904 {
905   const int hdr = _idx_buf.empty() ?
906     0 : cast_int<int>(dof_id_signed_type(_idx_buf[0]));
907   return std::abs(hdr);
908 }
909 
910 
911 
912 inline
n_var_groups(const unsigned int s)913 unsigned int DofObject::n_var_groups(const unsigned int s) const
914 {
915   libmesh_assert_less (s, this->n_systems());
916 
917   return (this->end_idx(s) - this->start_idx(s)) / 2;
918 }
919 
920 
921 
922 inline
n_vars(const unsigned int s,const unsigned int vg)923 unsigned int DofObject::n_vars(const unsigned int s,
924                                const unsigned int vg) const
925 {
926   libmesh_assert_less (s,  this->n_systems());
927   libmesh_assert_less (vg, this->n_var_groups(s));
928 
929   const unsigned int start_idx_sys = this->start_idx(s);
930 
931   libmesh_assert_less ((start_idx_sys + 2*vg), _idx_buf.size());
932 
933   return (cast_int<unsigned int>
934           (_idx_buf[start_idx_sys + 2*vg]) >> ncv_magic_exp);
935 }
936 
937 
938 
939 inline
n_vars(const unsigned int s)940 unsigned int DofObject::n_vars(const unsigned int s) const
941 {
942   libmesh_assert_less (s, this->n_systems());
943 
944   const unsigned int nvg = this->n_var_groups(s);
945 
946   unsigned int val=0;
947 
948   for (unsigned int vg=0; vg<nvg; vg++)
949     val += this->n_vars(s,vg);
950 
951   return val;
952 }
953 
954 
955 
956 
957 inline
n_comp(const unsigned int s,const unsigned int var)958 unsigned int DofObject::n_comp(const unsigned int s,
959                                const unsigned int var) const
960 {
961   libmesh_assert_less (s,   this->n_systems());
962   libmesh_assert_less (var, this->n_vars(s));
963 
964   return this->n_comp_group(s,this->var_to_vg(s,var));
965 }
966 
967 
968 
969 
970 inline
n_comp_group(const unsigned int s,const unsigned int vg)971 unsigned int DofObject::n_comp_group(const unsigned int s,
972                                      const unsigned int vg) const
973 {
974   libmesh_assert_less (s,  this->n_systems());
975   libmesh_assert_less (vg, this->n_var_groups(s));
976 
977   const unsigned int
978     start_idx_sys = this->start_idx(s);
979 
980   libmesh_assert_less ((start_idx_sys + 2*vg), _idx_buf.size());
981 
982   return (_idx_buf[start_idx_sys + 2*vg] % ncv_magic);
983 }
984 
985 
986 
987 inline
dof_number(const unsigned int s,const unsigned int var,const unsigned int comp)988 dof_id_type DofObject::dof_number(const unsigned int s,
989                                   const unsigned int var,
990                                   const unsigned int comp) const
991 {
992   libmesh_assert_less (s,    this->n_systems());
993   libmesh_assert_less (var,  this->n_vars(s));
994   libmesh_assert_less (comp, this->n_comp(s,var));
995 
996   const std::pair<unsigned int, unsigned int>
997     vg_vig = this->var_to_vg_and_offset(s,var);
998 
999   const unsigned int
1000     n_comp = this->n_comp_group(s,vg_vig.first);
1001 
1002   return this->dof_number(s, vg_vig.first, vg_vig.second,
1003                           comp, n_comp);
1004 }
1005 
1006 
1007 
1008 inline
dof_number(const unsigned int s,const unsigned int vg,const unsigned int vig,const unsigned int comp,const unsigned int n_comp)1009 dof_id_type DofObject::dof_number(const unsigned int s,
1010                                   const unsigned int vg,
1011                                   const unsigned int vig,
1012                                   const unsigned int comp,
1013                                   const unsigned int n_comp) const
1014 {
1015   libmesh_assert_less (s,   this->n_systems());
1016   libmesh_assert_less (vg,  this->n_var_groups(s));
1017   libmesh_assert_less (vig, this->n_vars(s,vg));
1018 
1019   const unsigned int
1020     start_idx_sys = this->start_idx(s);
1021 
1022   libmesh_assert_less ((start_idx_sys + 2*vg + 1), _idx_buf.size());
1023 
1024   const dof_id_type
1025     base_idx = _idx_buf[start_idx_sys + 2*vg + 1];
1026 
1027   // if the first component is invalid, they
1028   // are all invalid
1029   if (base_idx == invalid_id)
1030     return invalid_id;
1031 
1032   // otherwise the index is the first component
1033   // index augmented by the component number
1034   else
1035     return cast_int<dof_id_type>(base_idx + vig*n_comp + comp);
1036 }
1037 
1038 
1039 
1040 inline
1041 void
set_extra_integer(const unsigned int index,const dof_id_type value)1042 DofObject::set_extra_integer(const unsigned int index,
1043                              const dof_id_type value)
1044 {
1045   libmesh_assert_less(index, this->n_extra_integers());
1046   libmesh_assert_less(this->n_pseudo_systems(), _idx_buf.size());
1047 
1048   const unsigned int start_idx_i = this->start_idx_ints();
1049 
1050   libmesh_assert_less(start_idx_i+index, _idx_buf.size());
1051   _idx_buf[start_idx_i+index] = value;
1052 }
1053 
1054 
1055 
1056 inline
1057 dof_id_type
get_extra_integer(const unsigned int index)1058 DofObject::get_extra_integer (const unsigned int index) const
1059 {
1060   libmesh_assert_less(index, this->n_extra_integers());
1061   libmesh_assert_less(this->n_systems(), _idx_buf.size());
1062 
1063   const unsigned int start_idx_i = this->start_idx_ints();
1064 
1065   libmesh_assert_less(start_idx_i+index, _idx_buf.size());
1066   return _idx_buf[start_idx_i+index];
1067 }
1068 
1069 
1070 
1071 template <typename T>
1072 inline
1073 void
set_extra_datum(const unsigned int index,const T value)1074 DofObject::set_extra_datum(const unsigned int index,
1075                            const T value)
1076 {
1077 #ifndef NDEBUG
1078   const unsigned int n_more_integers = (sizeof(T)-1)/sizeof(dof_id_type);
1079 #endif
1080   libmesh_assert_less(index+n_more_integers, this->n_extra_integers());
1081   libmesh_assert_less(this->n_pseudo_systems(), _idx_buf.size());
1082 
1083   const unsigned int start_idx_i = this->start_idx_ints();
1084 
1085   libmesh_assert_less(start_idx_i+index+n_more_integers, _idx_buf.size());
1086   std::memcpy(&_idx_buf[start_idx_i+index], &value, sizeof(T));
1087 }
1088 
1089 
1090 
1091 template <typename T>
1092 inline
1093 T
get_extra_datum(const unsigned int index)1094 DofObject::get_extra_datum (const unsigned int index) const
1095 {
1096 #ifndef NDEBUG
1097   const unsigned int n_more_integers = (sizeof(T)-1)/sizeof(dof_id_type);
1098 #endif
1099   libmesh_assert_less(index+n_more_integers, this->n_extra_integers());
1100   libmesh_assert_less(this->n_systems(), _idx_buf.size());
1101 
1102   const unsigned int start_idx_i = this->start_idx_ints();
1103 
1104   libmesh_assert_less(start_idx_i+index+n_more_integers, _idx_buf.size());
1105   T returnval;
1106   std::memcpy(&returnval, &_idx_buf[start_idx_i+index], sizeof(T));
1107   return returnval;
1108 }
1109 
1110 
1111 
1112 inline
1113 unsigned int
n_extra_integers()1114 DofObject::n_extra_integers () const
1115 {
1116   if (_idx_buf.empty())
1117     return 0;
1118 
1119   const int hdr = dof_id_signed_type(_idx_buf[0]);
1120   if (hdr >= 0)
1121     return 0;
1122 
1123   const unsigned int start_idx_i = this->start_idx_ints();
1124 
1125   return _idx_buf.size() - start_idx_i;
1126 }
1127 
1128 
1129 
1130 inline
1131 bool
has_extra_integers()1132 DofObject::has_extra_integers () const
1133 {
1134   if (_idx_buf.empty())
1135     return 0;
1136 
1137   return (dof_id_signed_type(_idx_buf[0]) < 0);
1138 }
1139 
1140 
1141 
1142 inline
1143 std::pair<unsigned int, unsigned int>
var_to_vg_and_offset(const unsigned int s,const unsigned int var)1144 DofObject::var_to_vg_and_offset(const unsigned int s,
1145                                 const unsigned int var) const
1146 {
1147   std::pair<unsigned int, unsigned int> returnval(0,0);
1148 
1149   unsigned int & vg = returnval.first;
1150   unsigned int & offset = returnval.second;
1151 
1152   unsigned int vg_start = 0;
1153   for (; ; vg++)
1154     {
1155       libmesh_assert_less(vg, this->n_var_groups(s));
1156 
1157       const unsigned int vg_end = vg_start + this->n_vars(s,vg);
1158       if (var < vg_end)
1159         {
1160           offset = var - vg_start;
1161           return returnval;
1162         }
1163       vg_start = vg_end;
1164     }
1165 }
1166 
1167 
1168 
1169 inline
has_dofs(const unsigned int sys)1170 bool DofObject::has_dofs (const unsigned int sys) const
1171 {
1172   if (sys == libMesh::invalid_uint)
1173     {
1174       for (auto s : make_range(this->n_systems()))
1175         if (this->n_vars(s))
1176           return true;
1177     }
1178 
1179   else
1180     {
1181       libmesh_assert_less (sys, this->n_systems());
1182 
1183       if (this->n_vars(sys))
1184         return true;
1185     }
1186 
1187   return false;
1188 }
1189 
1190 
1191 
1192 inline
start_idx(const unsigned int s)1193 unsigned int DofObject::start_idx (const unsigned int s) const
1194 {
1195   libmesh_assert_less (s, this->n_systems());
1196   libmesh_assert_less (s, _idx_buf.size());
1197 
1198   return cast_int<unsigned int>(std::abs(dof_id_signed_type(_idx_buf[s])));
1199 }
1200 
1201 
1202 
1203 inline
end_idx(const unsigned int s)1204 unsigned int DofObject::end_idx (const unsigned int s) const
1205 {
1206   libmesh_assert_less (s, this->n_systems());
1207   libmesh_assert_less (s, _idx_buf.size());
1208 
1209   return ((s+1) == this->n_pseudo_systems()) ?
1210     cast_int<unsigned int>(_idx_buf.size()) :
1211     cast_int<unsigned int>(_idx_buf[s+1]);
1212 }
1213 
1214 
1215 
1216 inline
start_idx_ints()1217 unsigned int DofObject::start_idx_ints () const
1218 {
1219   libmesh_assert (this->has_extra_integers());
1220 
1221   unsigned int n_sys = this->n_systems();
1222 
1223   libmesh_assert_less(this->n_systems(), _idx_buf.size());
1224   return n_sys ? cast_int<unsigned int>(_idx_buf[this->n_systems()]) :
1225                  (n_sys+1);
1226 }
1227 
1228 
1229 
1230 inline
end_idx_ints()1231 unsigned int DofObject::end_idx_ints () const
1232 {
1233   libmesh_assert (this->has_extra_integers());
1234 
1235   return cast_int<unsigned int>(_idx_buf.size());
1236 }
1237 
1238 
1239 
1240 inline
set_vg_dof_base(const unsigned int s,const unsigned int vg,const dof_id_type db)1241 void DofObject::set_vg_dof_base(const unsigned int s,
1242                                 const unsigned int vg,
1243                                 const dof_id_type db)
1244 {
1245   libmesh_assert_less (s,  this->n_systems());
1246   libmesh_assert_less (vg, this->n_var_groups(s));
1247 
1248   const unsigned int
1249     start_idx_sys = this->start_idx(s);
1250 
1251   libmesh_assert_less ((start_idx_sys + 2*vg + 1), _idx_buf.size());
1252 
1253   _idx_buf[start_idx_sys + 2*vg + 1] = db;
1254 
1255   libmesh_assert_equal_to (this->vg_dof_base(s,vg), db);
1256 }
1257 
1258 
1259 
1260 inline
vg_dof_base(const unsigned int s,const unsigned int vg)1261 dof_id_type DofObject::vg_dof_base(const unsigned int s,
1262                                    const unsigned int vg) const
1263 {
1264   libmesh_assert_less (s,  this->n_systems());
1265   libmesh_assert_less (vg, this->n_var_groups(s));
1266 
1267   const unsigned int
1268     start_idx_sys = this->start_idx(s);
1269 
1270   libmesh_assert_less ((start_idx_sys + 2*vg + 1), _idx_buf.size());
1271 
1272   // #ifdef DEBUG
1273   //   std::cout << " [ ";
1274   //   for (auto i : _idx_buf)
1275   //     std::cout << i << " ";
1276   //   std::cout << "]\n";
1277   // #endif
1278 
1279   return _idx_buf[start_idx_sys + 2*vg + 1];
1280 }
1281 
1282 
1283 
1284 inline
var_to_vg(const unsigned int s,const unsigned int var)1285 unsigned int DofObject::var_to_vg (const unsigned int s,
1286                                    const unsigned int var) const
1287 {
1288   const unsigned int
1289     nvg = this->n_var_groups(s);
1290 
1291   for (unsigned int vg=0, vg_end=0; vg<nvg; vg++)
1292     {
1293       vg_end += this->n_vars(s,vg);
1294       if (var < vg_end) return vg;
1295     }
1296 
1297   libmesh_error_msg("Error: could not map variable " << var << " to variable group.");
1298 }
1299 
1300 
1301 
1302 inline
system_var_to_vg_var(const unsigned int s,const unsigned int vg,const unsigned int var)1303 unsigned int DofObject::system_var_to_vg_var (const unsigned int s,
1304                                               const unsigned int vg,
1305                                               const unsigned int var) const
1306 {
1307   unsigned int accumulated_sum=0;
1308 
1309   for (unsigned int vgc=0; vgc<vg; vgc++)
1310     accumulated_sum += this->n_vars(s,vgc);
1311 
1312   libmesh_assert_less_equal (accumulated_sum, var);
1313 
1314   return (var - accumulated_sum);
1315 }
1316 
1317 
1318 } // namespace libMesh
1319 
1320 
1321 #endif // #ifndef LIBMESH_DOF_OBJECT_H
1322