Arcane  4.2.1.0
User documentation
Loading...
Searching...
No Matches
ItemGroupInternal.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* ItemGroupInternal.cc (C) 2000-2026 */
9/* */
10/* Internal part of Arcane's ItemGroup. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/core/internal/ItemGroupInternal.h"
15
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/ITraceMng.h"
18#include "arcane/utils/ArrayUtils.h"
19#include "arcane/utils/ArgumentException.h"
20#include "arcane/utils/Convert.h"
21
22#include "arcane/core/ItemGroupObserver.h"
23#include "arcane/core/IItemFamily.h"
24#include "arcane/core/IMesh.h"
25#include "arcane/core/ItemPrinter.h"
26#include "arcane/core/MeshPartInfo.h"
28#include "arcane/core/internal/IDataInternal.h"
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32
33namespace Arcane
34{
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39ItemGroupInternal::
40ItemGroupInternal()
41: m_internal_api(this)
42, m_sub_parts_by_type(this)
43{
44 _init();
45}
46
47/*---------------------------------------------------------------------------*/
48/*---------------------------------------------------------------------------*/
49
50ItemGroupInternal::
51ItemGroupInternal(IItemFamily* family, const String& name)
52: m_internal_api(this)
53, m_mesh(family->mesh())
54, m_item_family(family)
55, m_variable_name(String("GROUP_") + family->name() + name)
56, m_is_null(false)
57, m_kind(family->itemKind())
58, m_name(name)
59, m_sub_parts_by_type(this)
60{
61 _init();
62}
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
67ItemGroupInternal::
68ItemGroupInternal(IItemFamily* family, ItemGroupImpl* parent, const String& name)
69: m_internal_api(this)
70, m_mesh(parent->mesh())
71, m_item_family(family)
72, m_parent(parent)
73, m_variable_name(String("GROUP_") + m_item_family->name() + name)
74, m_is_null(false)
75, m_kind(family->itemKind())
76, m_name(name)
77, m_sub_parts_by_type(this)
78{
79 _init();
80}
81
82/*---------------------------------------------------------------------------*/
83/*---------------------------------------------------------------------------*/
84
85ItemGroupInternal::
86~ItemGroupInternal()
87{
88 // (HP) TODO: check that there are no more observers at this point
89 // Those of the sub-groups have not been destroyed
90 for (const auto& i : m_observers) {
91 delete i.second;
92 }
93 delete m_variable_items_local_id;
94 delete m_compute_functor;
95}
96
97/*---------------------------------------------------------------------------*/
98/*---------------------------------------------------------------------------*/
99
100void ItemGroupInternal::
101_init()
102{
103 if (m_item_family)
104 m_full_name = m_item_family->fullName() + "_" + m_name;
105
106 // If a mesh is associated and we are not a child group, then the group data
107 // is kept in a variable.
108 if (m_mesh && !m_parent) {
109 int property = IVariable::PSubDomainDepend | IVariable::PPrivate;
110 VariableBuildInfo vbi(m_mesh, m_variable_name, property);
111 m_variable_items_local_id = new VariableArrayInt32(vbi);
112 m_items_local_id = &m_variable_items_local_id->_internalTrueData()->_internalDeprecatedValue();
113 updateTimestamp();
114 }
115
116 m_is_check_simd_padding = arcaneIsCheck();
117 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CHECK_SIMDPADDING", true)) {
118 m_is_check_simd_padding = (v.value() > 0);
119 m_is_print_check_simd_padding = (v.value() > 1);
120 }
121
122 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_PRINT_APPLYSIMDPADDING", true)) {
123 m_is_print_apply_simd_padding = (v.value() > 0);
124 m_is_print_stack_apply_simd_padding = (v.value() > 1);
125 }
126
127 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_USE_LOCK_FOR_ITEMGROUP_UPDATE", true)) {
128 if (v.value() > 0)
129 m_check_need_update_mutex.create();
130 }
131}
132
133/*---------------------------------------------------------------------------*/
134/*---------------------------------------------------------------------------*/
135
136ItemInternalList ItemGroupInternal::
137items() const
138{
139 if (m_item_family)
140 return m_item_family->itemsInternal();
141 return m_mesh->itemsInternal(m_kind);
142}
143
144/*---------------------------------------------------------------------------*/
145/*---------------------------------------------------------------------------*/
146
147Int32 ItemGroupInternal::
148maxLocalId() const
149{
150 return m_item_family->maxLocalId();
151}
152
153/*---------------------------------------------------------------------------*/
154/*---------------------------------------------------------------------------*/
155
156ItemInfoListView ItemGroupInternal::
157itemInfoListView() const
158{
159 if (m_item_family)
160 return m_item_family->itemInfoListView();
161 return m_mesh->itemFamily(m_kind)->itemInfoListView();
162}
163
164/*---------------------------------------------------------------------------*/
165/*---------------------------------------------------------------------------*/
166
167void ItemGroupInternal::
168resetSubGroups()
169{
170 if (!m_is_all_items)
171 ARCANE_FATAL("Call to _resetSubGroups() is only valid for group of AllItems");
172
173 m_own_group = nullptr;
174 m_ghost_group = nullptr;
175 m_interface_group = nullptr;
176 m_node_group = nullptr;
177 m_edge_group = nullptr;
178 m_face_group = nullptr;
179 m_cell_group = nullptr;
180 m_inner_face_group = nullptr;
181 m_outer_face_group = nullptr;
182 m_active_cell_group = nullptr;
183 m_own_active_cell_group = nullptr;
184 m_active_face_group = nullptr;
185 m_own_active_face_group = nullptr;
186 m_inner_active_face_group = nullptr;
187 m_outer_active_face_group = nullptr;
188 m_level_cell_group.clear();
189 m_own_level_cell_group.clear();
190 m_sub_parts_by_type.clear();
191 m_sub_groups.clear();
192}
193
194/*---------------------------------------------------------------------------*/
195/*---------------------------------------------------------------------------*/
196
197void ItemGroupInternal::
198notifyExtendObservers(const Int32ConstArrayView* info)
199{
200 ARCANE_ASSERT((!m_need_recompute || m_is_all_items), ("Operation on invalid group"));
201 for (const auto& i : m_observers) {
202 IItemGroupObserver* obs = i.second;
203 obs->executeExtend(info);
204 }
205 if (m_group_index_table.isUsed())
206 m_group_index_table->update();
207}
208
209/*---------------------------------------------------------------------------*/
210/*---------------------------------------------------------------------------*/
211
212void ItemGroupInternal::
213notifyReduceObservers(const Int32ConstArrayView* info)
214{
215 ARCANE_ASSERT((!m_need_recompute || m_is_all_items), ("Operation on invalid group"));
216 for (const auto& i : m_observers) {
217 IItemGroupObserver* obs = i.second;
218 obs->executeReduce(info);
219 }
220 if (m_group_index_table.isUsed())
221 m_group_index_table->update();
222}
223
224/*---------------------------------------------------------------------------*/
225/*---------------------------------------------------------------------------*/
226
227void ItemGroupInternal::
228notifyCompactObservers(const Int32ConstArrayView* info)
229{
230 ARCANE_ASSERT((!m_need_recompute || m_is_all_items), ("Operation on invalid group"));
231 for (const auto& i : m_observers) {
232 IItemGroupObserver* obs = i.second;
233 obs->executeCompact(info);
234 }
235 if (m_group_index_table.isUsed())
236 m_group_index_table->compact(info);
237}
238
239/*---------------------------------------------------------------------------*/
240/*---------------------------------------------------------------------------*/
241
242void ItemGroupInternal::
243notifyInvalidateObservers()
244{
245#ifndef NO_USER_WARNING
246#warning "(HP) Assertion need fix"
247#endif /* NO_USER_WARNING */
248 // This can happen in case of cascade invalidation
249 // ARCANE_ASSERT((!m_need_recompute),("Operation on invalid group"));
250 for (const auto& i : m_observers) {
251 IItemGroupObserver* obs = i.second;
252 obs->executeInvalidate();
253 }
254 if (m_group_index_table.isUsed())
255 m_group_index_table->update();
256}
257
258/*---------------------------------------------------------------------------*/
259/*---------------------------------------------------------------------------*/
260
261/*!
262 * \brief Checks that the localIds() are contiguous.
263 */
264void ItemGroupInternal::
265checkIsContiguous()
266{
267 m_is_contiguous = false;
268 Int32ConstArrayView lids = itemsLocalId();
269 if (lids.empty()) {
270 m_is_contiguous = false;
271 return;
272 }
273 Int32 first_lid = lids[0];
274
275 bool is_bad = false;
276 for (Integer i = 0, n = lids.size(); i < n; ++i) {
277 if (lids[i] != (first_lid + i)) {
278 is_bad = true;
279 break;
280 }
281 }
282 if (!is_bad)
283 m_is_contiguous = true;
284}
285
286/*---------------------------------------------------------------------------*/
287/*---------------------------------------------------------------------------*/
288
289void ItemGroupInternal::
290applySimdPadding()
291{
292 if (m_is_print_apply_simd_padding) {
293 String stack;
294 if (m_is_print_stack_apply_simd_padding)
295 stack = String(" stack=") + platform::getStackTrace();
296 ITraceMng* tm = m_item_family->traceMng();
297 tm->info() << "ApplySimdPadding group_name=" << m_name << stack;
298 }
299 // Pads the last elements of the array by copying the
300 // last value.
301 m_internal_api.notifySimdPaddingDone();
302 Arcane::applySimdPadding(mutableItemsLocalId());
303}
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
307
308/*!
309 * \brief Fills the last elements of the group to have a complete SIMD vector.
310 *
311 * For vectorization to work, the number of elements
312 * in the group must be a multiple of the size of a SIMD vector. If this is
313 * not the case, the last values of the localId() array are filled
314 * with the last element.
315 *
316 * For example, suppose a SIMD vector size of 8 (which is the maximum
317 * currently with AVX512) and a group \a grp of 13 elements. The group must
318 * therefore be filled as follows:
319 * \code
320 * Int32 last_local_id = grp[12];
321 * grp[13] = grp[14] = grp[15] = last_local_id.
322 * \endcode
323 *
324 * Note that the group size remains 13 elements. The
325 * additional padding is only for iterations via ENUMERATE_SIMD.
326 * Since the localId() array is allocated with the alignment allocator,
327 * it is guaranteed that the allocated memory is sufficient for padding.
328 *
329 * \todo Do not do this in all checkNeedUpdate() but implement a method
330 * that returns a specific enumerator for vectorization.
331 */
332void ItemGroupInternal::
333checkUpdateSimdPadding()
334{
335 if (m_simd_timestamp >= timestamp()) {
336 // Checks if the padding is correct
337 if (m_is_check_simd_padding) {
338 if (m_is_print_check_simd_padding && m_item_family) {
339 ITraceMng* tm = m_item_family->traceMng();
340 tm->info() << "check padding name=" << fullName()
341 << " timestamp=" << timestamp()
342 << " simd_timestamp=" << m_simd_timestamp
343 << " size=" << mutableItemsLocalId().size()
344 << " capacity=" << mutableItemsLocalId().capacity();
345 }
346 ArrayUtils::checkSimdPadding(itemsLocalId());
347 }
348 return;
349 }
350 this->applySimdPadding();
351}
352
353/*---------------------------------------------------------------------------*/
354/*---------------------------------------------------------------------------*/
355
356void ItemGroupInternal::
357_removeItems(SmallSpan<const Int32> items_local_id)
358{
359 if (!((!m_need_recompute && !isAllItems()) || (m_transaction_mode && isAllItems())))
360 ARCANE_FATAL("Operation on invalid group");
361
362 if (m_compute_functor && !m_transaction_mode)
363 ARCANE_FATAL("Cannot remove items on computed group ({0})", name());
364
365 IMesh* amesh = mesh();
366 if (!amesh)
367 throw ArgumentException(A_FUNCINFO, "null group");
368
369 ITraceMng* trace = amesh->traceMng();
370 if (isOwn() && amesh->meshPartInfo().nbPart() != 1)
371 ARCANE_THROW(NotSupportedException, "Cannot remove items if isOwn() is true");
372
373 Int32 nb_item_to_remove = items_local_id.size();
374
375 // Only useful if we have observers
376 UniqueArray<Int32> removed_local_ids;
377
378 if (nb_item_to_remove != 0) { // cannot skip early due to observers
379
380 Int32Array& items_lid = mutableItemsLocalId();
381 const Int32 old_size = items_lid.size();
382 bool has_removed = false;
383
384 if (isAllItems()) {
385 // Algorithm previously in DynamicMeshKindInfo
386 // Removes items from the all_items group by swapping with the
387 // end elements of this group
388 // i.e., persistent memory O(group size), algo O(remove items)
389 has_removed = true;
390 Integer nb_item = old_size;
391 for (Integer i = 0, n = nb_item_to_remove; i < n; ++i) {
392 Int32 removed_local_id = items_local_id[i];
393 Int32 index = m_items_index_in_all_group[removed_local_id];
394 --nb_item;
395 Int32 moved_local_id = items_lid[nb_item];
396 items_lid[index] = moved_local_id;
397 m_items_index_in_all_group[moved_local_id] = index;
398 }
399 items_lid.resize(nb_item);
400 }
401 else {
402 // Algorithm for other groups
403 // Array shifting
404 // i.e., local memory O(group size), algo O(group size)
405 // Marks an array indicating the entities to be removed
406 UniqueArray<bool> remove_flags(maxLocalId(), false);
407 for (Int32 i = 0; i < nb_item_to_remove; ++i)
408 remove_flags[items_local_id[i]] = true;
409
410 {
411 Int32 next_index = 0;
412 for (Int32 i = 0; i < old_size; ++i) {
413 Int32 lid = items_lid[i];
414 if (remove_flags[lid]) {
415 removed_local_ids.add(lid);
416 continue;
417 }
418 items_lid[next_index] = lid;
419 ++next_index;
420 }
421 if (next_index != old_size) {
422 has_removed = true;
423 items_lid.resize(next_index);
424 }
425 }
426 }
427
428 updateTimestamp();
429 if (arcaneIsCheck()) {
430 trace->info(5) << "ItemGroupImpl::removeItems() group <" << name() << "> "
431 << " old_size=" << old_size
432 << " new_size=" << nbItem()
433 << " removed?=" << has_removed;
434 checkValid();
435 }
436 }
437
438 Int32ConstArrayView observation_info(removed_local_ids);
439 notifyReduceObservers(&observation_info);
440}
441
442/*---------------------------------------------------------------------------*/
443/*---------------------------------------------------------------------------*/
444
445void ItemGroupInternal::
446checkValid()
447{
448 ITraceMng* msg = mesh()->traceMng();
449 if (m_need_recompute && m_compute_functor) {
450 msg->debug(Trace::High) << "ItemGroupImpl::checkValid on " << name() << " : skip group to recompute";
451 return;
452 }
453
454 // The following points are checked:
455 // - an entity is present only once in the group
456 // - the entities in the group are not destroyed
457 UniqueArray<bool> presence_checks(maxLocalId());
458 presence_checks.fill(0);
459 Integer nb_error = 0;
460
461 ItemInternalList items(this->items());
462 Integer items_size = items.size();
463 Int32ConstArrayView items_lid(itemsLocalId());
464
465 for (Integer i = 0, is = items_lid.size(); i < is; ++i) {
466 Integer lid = items_lid[i];
467 if (lid >= items_size) {
468 if (nb_error < 10) {
469 msg->error() << "Wrong local index lid=" << lid << " max=" << items_size
470 << " var_max_size=" << maxLocalId();
471 }
472 ++nb_error;
473 continue;
474 }
475 ItemInternal* item = items[lid];
476 if (item->isSuppressed()) {
477 if (nb_error < 10) {
478 msg->error() << "Item " << ItemPrinter(item) << " in group "
479 << name() << " does not exist anymore";
480 }
481 ++nb_error;
482 }
483 if (presence_checks[lid]) {
484 if (nb_error < 10) {
485 msg->error() << "Item " << ItemPrinter(item) << " in group "
486 << name() << " was found twice or more";
487 }
488 ++nb_error;
489 }
490 presence_checks[lid] = true;
491 }
492 if (isAllItems()) {
493 for (Integer i = 0, n = items_lid.size(); i < n; ++i) {
494 Int32 local_id = items_lid[i];
495 Int32 index_in_all_group = m_items_index_in_all_group[local_id];
496 if (index_in_all_group != i) {
497 if (nb_error < 10) {
498 msg->error() << A_FUNCINFO
499 << ": " << itemKindName(m_kind)
500 << ": incoherence between 'local_id' and index in the group 'All' "
501 << " i=" << i
502 << " local_id=" << local_id
503 << " index=" << index_in_all_group;
504 }
505 ++nb_error;
506 }
507 }
508 }
509 if (nb_error != 0) {
510 String parent_name = "none";
511 if (m_parent)
512 parent_name = m_parent->name();
513 ARCANE_FATAL("Error in group name='{0}' parent='{1}' nb_error={2}",
514 name(), parent_name, nb_error);
515 }
516}
517
518/*---------------------------------------------------------------------------*/
519/*---------------------------------------------------------------------------*/
520
521void ItemGroupInternal::
522_notifyDirectRemoveItems(SmallSpan<const Int32> removed_ids, Int32 nb_remaining)
523{
524 mutableItemsLocalId().resize(nb_remaining);
525 updateTimestamp();
526 if (arcaneIsCheck())
527 checkValid();
528 // NOTE: the list \a removed_ids is not necessarily in the same order
529 // as the one obtained via removeItems()
530 Int32ConstArrayView observation_info(removed_ids.smallView());
531 notifyReduceObservers(&observation_info);
532}
533
534/*---------------------------------------------------------------------------*/
535/*---------------------------------------------------------------------------*/
536
537/*---------------------------------------------------------------------------*/
538/*---------------------------------------------------------------------------*/
539
540void ItemGroupImplInternal::
541setAsConstituentGroup()
542{
543 m_p->m_is_constituent_group = true;
544}
545
546/*---------------------------------------------------------------------------*/
547/*---------------------------------------------------------------------------*/
548
549SmallSpan<Int32> ItemGroupImplInternal::
550itemsLocalId()
551{
552 return m_p->itemsLocalId();
553}
554
555/*---------------------------------------------------------------------------*/
556/*---------------------------------------------------------------------------*/
557
558void ItemGroupImplInternal::
559notifyDirectRemoveItems(SmallSpan<const Int32> removed_ids, Int32 nb_remaining)
560{
561 m_p->_notifyDirectRemoveItems(removed_ids, nb_remaining);
562}
563
564/*---------------------------------------------------------------------------*/
565/*---------------------------------------------------------------------------*/
566
567void ItemGroupImplInternal::
568notifySimdPaddingDone()
569{
570 m_p->m_simd_timestamp = m_p->timestamp();
571}
572
573/*---------------------------------------------------------------------------*/
574/*---------------------------------------------------------------------------*/
575
576void ItemGroupImplInternal::
577setMemoryRessourceForItemLocalId(eMemoryRessource mem)
578{
579 VariableArrayInt32* v = m_p->m_variable_items_local_id;
580 if (v)
581 VariableUtils::experimentalChangeAllocator(v->variable(), mem);
582}
583
584/*---------------------------------------------------------------------------*/
585/*---------------------------------------------------------------------------*/
586
587} // End namespace Arcane
588
589/*---------------------------------------------------------------------------*/
590/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Utility functions for variables.
VariableRefArrayT< Int32 > VariableArrayInt32
Array variable of 32-bit integer type.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
bool arcaneIsCheck()
True if running in check mode.
Definition Misc.cc:66
Int32 Integer
Type representing an integer.
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
Definition UtilsTypes.h:476
ConstArrayView< ItemInternal * > ItemInternalList
Type of the internal list of entities.
Definition ItemTypes.h:466
const char * itemKindName(eItemKind kind)
Entity kind name.
Array< Int32 > Int32Array
Dynamic one-dimensional array of 32-bit integers.
Definition UtilsTypes.h:121