Arcane  4.2.1.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-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
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
332void ItemGroupInternal::
333checkUpdateSimdPadding()
334{
335 if (m_simd_timestamp >= timestamp()) {
336 // Checks if the padding is correct
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.
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:803
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Definition Span.h:325
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:476
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:121
std::int32_t Int32
Signed integer type of 32 bits.