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