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