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