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